From 97ec6a27ecb9bd643903c343397e69fd2c01d77e Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Thu, 12 Aug 2021 12:17:09 +0200 Subject: [PATCH] add `make::ext::path_from_idents` --- .../src/utils/gen_trait_fn_body.rs | 49 ++++++++++--------- crates/syntax/src/ast/make.rs | 12 +++++ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/crates/ide_assists/src/utils/gen_trait_fn_body.rs b/crates/ide_assists/src/utils/gen_trait_fn_body.rs index 5916e5676e8..111fa0b23fc 100644 --- a/crates/ide_assists/src/utils/gen_trait_fn_body.rs +++ b/crates/ide_assists/src/utils/gen_trait_fn_body.rs @@ -38,7 +38,8 @@ fn gen_clone_call(target: ast::Expr) -> ast::Expr { let list = enum_.variant_list()?; let mut arms = vec![]; for variant in list.variants() { - let variant_name = make_variant_path(&variant)?; + let name = variant.name()?; + let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?; match variant.field_list() { // => match self { Self::Name { x } => Self::Name { x: x.clone() } } @@ -148,7 +149,8 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let mut arms = vec![]; for variant in list.variants() { let name = variant.name()?; - let variant_name = make::path_pat(make::path_from_text(&format!("Self::{}", name))); + let variant_name = + make::path_pat(make::ext::path_from_idents(["Self", &format!("{}", name)])?); let target = make::expr_path(make::ext::ident_path("f").into()); let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into(); @@ -220,9 +222,9 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { /// Generate a `Debug` impl based on the fields and members of the target type. fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { - fn gen_default_call() -> ast::Expr { - let fn_name = make::path_from_text(&"Default::default"); - make::expr_call(make::expr_path(fn_name), make::arg_list(None)) + fn gen_default_call() -> Option { + let fn_name = make::ext::path_from_idents(["Default", "default"])?; + Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None))) } match adt { // `Debug` cannot be derived for unions, so no default impl can be provided. @@ -234,7 +236,7 @@ fn gen_default_call() -> ast::Expr { Some(ast::FieldList::RecordFieldList(field_list)) => { let mut fields = vec![]; for field in field_list.fields() { - let method_call = gen_default_call(); + let method_call = gen_default_call()?; let name_ref = make::name_ref(&field.name()?.to_string()); let field = make::record_expr_field(name_ref, Some(method_call)); fields.push(field); @@ -245,7 +247,10 @@ fn gen_default_call() -> ast::Expr { } Some(ast::FieldList::TupleFieldList(field_list)) => { let struct_name = make::expr_path(make::ext::ident_path("Self")); - let fields = field_list.fields().map(|_| gen_default_call()); + let fields = field_list + .fields() + .map(|_| gen_default_call()) + .collect::>>()?; make::expr_call(struct_name, make::arg_list(fields)) } None => { @@ -276,7 +281,7 @@ fn gen_hash_call(target: ast::Expr) -> ast::Stmt { // => std::mem::discriminant(self).hash(state); ast::Adt::Enum(_) => { - let fn_name = make_discriminant(); + let fn_name = make_discriminant()?; let arg = make::expr_path(make::ext::ident_path("self")); let fn_call = make::expr_call(fn_name, make::arg_list(Some(arg))); @@ -336,6 +341,10 @@ fn gen_record_pat(record_name: ast::Path, fields: Vec) -> a make::record_pat_with_fields(record_name, list) } + fn gen_variant_path(variant: &ast::Variant) -> Option { + make::ext::path_from_idents(["Self", &variant.name()?.to_string()]) + } + fn gen_tuple_field(field_name: &String) -> ast::Pat { ast::Pat::IdentPat(make::ident_pat(false, false, make::name(field_name))) } @@ -344,15 +353,15 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat { // generate this code `Self` for the time being. let body = match adt { - // `PartialEq` cannot be derived for unions, so no default impl can be provided. + // `Hash` cannot be derived for unions, so no default impl can be provided. ast::Adt::Union(_) => return None, ast::Adt::Enum(enum_) => { // => std::mem::discriminant(self) == std::mem::discriminant(other) let lhs_name = make::expr_path(make::ext::ident_path("self")); - let lhs = make::expr_call(make_discriminant(), make::arg_list(Some(lhs_name.clone()))); + let lhs = make::expr_call(make_discriminant()?, make::arg_list(Some(lhs_name.clone()))); let rhs_name = make::expr_path(make::ext::ident_path("other")); - let rhs = make::expr_call(make_discriminant(), make::arg_list(Some(rhs_name.clone()))); + let rhs = make::expr_call(make_discriminant()?, make::arg_list(Some(rhs_name.clone()))); let eq_check = make::expr_op(ast::BinOp::EqualityTest, lhs, rhs); let mut case_count = 0; @@ -381,8 +390,8 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat { expr = gen_eq_chain(expr, cmp); } - let left = gen_record_pat(make_variant_path(&variant)?, l_fields); - let right = gen_record_pat(make_variant_path(&variant)?, r_fields); + let left = gen_record_pat(gen_variant_path(&variant)?, l_fields); + let right = gen_record_pat(gen_variant_path(&variant)?, r_fields); let tuple = make::tuple_pat(vec![left.into(), right.into()]); if let Some(expr) = expr { @@ -410,8 +419,8 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat { expr = gen_eq_chain(expr, cmp); } - let left = make::tuple_struct_pat(make_variant_path(&variant)?, l_fields); - let right = make::tuple_struct_pat(make_variant_path(&variant)?, r_fields); + let left = make::tuple_struct_pat(gen_variant_path(&variant)?, l_fields); + let right = make::tuple_struct_pat(gen_variant_path(&variant)?, r_fields); let tuple = make::tuple_pat(vec![left.into(), right.into()]); if let Some(expr) = expr { @@ -466,7 +475,7 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat { make::block_expr(None, expr).indent(ast::edit::IndentLevel(1)) } - // No fields in the body means there's nothing to compare. + // No fields in the body means there's nothing to hash. None => { let expr = make::expr_literal("true").into(); make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1)) @@ -478,10 +487,6 @@ fn gen_tuple_field(field_name: &String) -> ast::Pat { Some(()) } -fn make_discriminant() -> ast::Expr { - make::expr_path(make::path_from_text("core::mem::discriminant")) -} - -fn make_variant_path(variant: &ast::Variant) -> Option { - Some(make::path_from_text(&format!("Self::{}", &variant.name()?))) +fn make_discriminant() -> Option { + Some(make::expr_path(make::ext::path_from_idents(["core", "mem", "discriminant"])?)) } diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 74f2e5c314c..e6fab72ac05 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -32,6 +32,18 @@ pub fn ident_path(ident: &str) -> ast::Path { path_unqualified(path_segment(name_ref(ident))) } + pub fn path_from_idents<'a>( + parts: impl std::iter::IntoIterator, + ) -> Option { + let mut iter = parts.into_iter(); + let base = ext::ident_path(iter.next()?); + let path = iter.fold(base, |base, s| { + let path = ext::ident_path(s); + path_concat(base, path) + }); + Some(path) + } + pub fn expr_unreachable() -> ast::Expr { expr_from_text("unreachable!()") }