mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 21:25:25 +00:00 
			
		
		
		
	split ted from gen_trait_fn_body
This commit is contained in:
		
							parent
							
								
									48ccbe0cd8
								
							
						
					
					
						commit
						4a0527f78c
					
				
					 4 changed files with 65 additions and 88 deletions
				
			
		| 
						 | 
					@ -2,6 +2,7 @@ use hir::HasSource;
 | 
				
			||||||
use syntax::{
 | 
					use syntax::{
 | 
				
			||||||
    Edition,
 | 
					    Edition,
 | 
				
			||||||
    ast::{self, AstNode, make},
 | 
					    ast::{self, AstNode, make},
 | 
				
			||||||
 | 
					    ted,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
| 
						 | 
					@ -157,19 +158,21 @@ fn add_missing_impl_members_inner(
 | 
				
			||||||
            &target_scope,
 | 
					            &target_scope,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut editor = edit.make_editor(impl_def.syntax());
 | 
				
			||||||
        if let Some(cap) = ctx.config.snippet_cap {
 | 
					        if let Some(cap) = ctx.config.snippet_cap {
 | 
				
			||||||
            let mut placeholder = None;
 | 
					            let mut placeholder = None;
 | 
				
			||||||
            if let DefaultMethods::No = mode {
 | 
					            if let DefaultMethods::No = mode {
 | 
				
			||||||
                if let ast::AssocItem::Fn(func) = &first_new_item {
 | 
					                if let ast::AssocItem::Fn(func) = &first_new_item {
 | 
				
			||||||
                    if try_gen_trait_body(
 | 
					                    if let Some(body) = try_gen_trait_body(
 | 
				
			||||||
                        ctx,
 | 
					                        ctx,
 | 
				
			||||||
                        func,
 | 
					                        func,
 | 
				
			||||||
                        trait_ref,
 | 
					                        trait_ref,
 | 
				
			||||||
                        &impl_def,
 | 
					                        &impl_def,
 | 
				
			||||||
                        target_scope.krate().edition(ctx.sema.db),
 | 
					                        target_scope.krate().edition(ctx.sema.db),
 | 
				
			||||||
                    )
 | 
					                    ) && let Some(func_body) = func.body()
 | 
				
			||||||
                    .is_none()
 | 
					 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
 | 
					                        ted::replace(func_body.syntax(), body.syntax());
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
 | 
					                        if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            if m.syntax().text() == "todo!()" {
 | 
					                            if m.syntax().text() == "todo!()" {
 | 
				
			||||||
| 
						 | 
					@ -195,7 +198,7 @@ fn try_gen_trait_body(
 | 
				
			||||||
    trait_ref: hir::TraitRef<'_>,
 | 
					    trait_ref: hir::TraitRef<'_>,
 | 
				
			||||||
    impl_def: &ast::Impl,
 | 
					    impl_def: &ast::Impl,
 | 
				
			||||||
    edition: Edition,
 | 
					    edition: Edition,
 | 
				
			||||||
) -> Option<()> {
 | 
					) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    let trait_path = make::ext::ident_path(
 | 
					    let trait_path = make::ext::ident_path(
 | 
				
			||||||
        &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
 | 
					        &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,7 @@ fn add_assist(
 | 
				
			||||||
            &annotated_name,
 | 
					            &annotated_name,
 | 
				
			||||||
            trait_,
 | 
					            trait_,
 | 
				
			||||||
            replace_trait_path,
 | 
					            replace_trait_path,
 | 
				
			||||||
 | 
					            impl_is_unsafe,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
 | 
					        update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -142,13 +143,7 @@ fn add_assist(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        match (ctx.config.snippet_cap, impl_def_with_items) {
 | 
					        match (ctx.config.snippet_cap, impl_def_with_items) {
 | 
				
			||||||
            (None, None) => {
 | 
					            (None, None) => {
 | 
				
			||||||
                let impl_def = generate_trait_impl(adt, trait_path);
 | 
					                let impl_def = generate_trait_impl(impl_is_unsafe, adt, trait_path);
 | 
				
			||||||
                if impl_is_unsafe {
 | 
					 | 
				
			||||||
                    ted::insert(
 | 
					 | 
				
			||||||
                        Position::first_child_of(impl_def.syntax()),
 | 
					 | 
				
			||||||
                        make::token(T![unsafe]),
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ted::insert_all(
 | 
					                ted::insert_all(
 | 
				
			||||||
                    insert_after,
 | 
					                    insert_after,
 | 
				
			||||||
| 
						 | 
					@ -156,26 +151,13 @@ fn add_assist(
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (None, Some((impl_def, _))) => {
 | 
					            (None, Some((impl_def, _))) => {
 | 
				
			||||||
                if impl_is_unsafe {
 | 
					 | 
				
			||||||
                    ted::insert(
 | 
					 | 
				
			||||||
                        Position::first_child_of(impl_def.syntax()),
 | 
					 | 
				
			||||||
                        make::token(T![unsafe]),
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                ted::insert_all(
 | 
					                ted::insert_all(
 | 
				
			||||||
                    insert_after,
 | 
					                    insert_after,
 | 
				
			||||||
                    vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
 | 
					                    vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (Some(cap), None) => {
 | 
					            (Some(cap), None) => {
 | 
				
			||||||
                let impl_def = generate_trait_impl(adt, trait_path);
 | 
					                let impl_def = generate_trait_impl(impl_is_unsafe, adt, trait_path);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                if impl_is_unsafe {
 | 
					 | 
				
			||||||
                    ted::insert(
 | 
					 | 
				
			||||||
                        Position::first_child_of(impl_def.syntax()),
 | 
					 | 
				
			||||||
                        make::token(T![unsafe]),
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if let Some(l_curly) = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
 | 
					                if let Some(l_curly) = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
| 
						 | 
					@ -188,26 +170,13 @@ fn add_assist(
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (Some(cap), Some((impl_def, first_assoc_item))) => {
 | 
					            (Some(cap), Some((impl_def, first_assoc_item))) => {
 | 
				
			||||||
                let mut added_snippet = false;
 | 
					                if let ast::AssocItem::Fn(ref func) = first_assoc_item
 | 
				
			||||||
 | 
					                    && let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
 | 
				
			||||||
                if impl_is_unsafe {
 | 
					                    && m.syntax().text() == "todo!()"
 | 
				
			||||||
                    ted::insert(
 | 
					                {
 | 
				
			||||||
                        Position::first_child_of(impl_def.syntax()),
 | 
					 | 
				
			||||||
                        make::token(T![unsafe]),
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 | 
					 | 
				
			||||||
                    if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) {
 | 
					 | 
				
			||||||
                        if m.syntax().text() == "todo!()" {
 | 
					 | 
				
			||||||
                    // Make the `todo!()` a placeholder
 | 
					                    // Make the `todo!()` a placeholder
 | 
				
			||||||
                    builder.add_placeholder_snippet(cap, m);
 | 
					                    builder.add_placeholder_snippet(cap, m);
 | 
				
			||||||
                            added_snippet = true;
 | 
					                } else {
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if !added_snippet {
 | 
					 | 
				
			||||||
                    // If we haven't already added a snippet, add a tabstop before the generated function
 | 
					                    // If we haven't already added a snippet, add a tabstop before the generated function
 | 
				
			||||||
                    builder.add_tabstop_before(cap, first_assoc_item);
 | 
					                    builder.add_tabstop_before(cap, first_assoc_item);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -228,6 +197,7 @@ fn impl_def_from_trait(
 | 
				
			||||||
    annotated_name: &ast::Name,
 | 
					    annotated_name: &ast::Name,
 | 
				
			||||||
    trait_: Option<hir::Trait>,
 | 
					    trait_: Option<hir::Trait>,
 | 
				
			||||||
    trait_path: &ast::Path,
 | 
					    trait_path: &ast::Path,
 | 
				
			||||||
 | 
					    impl_is_unsafe: bool,
 | 
				
			||||||
) -> Option<(ast::Impl, ast::AssocItem)> {
 | 
					) -> Option<(ast::Impl, ast::AssocItem)> {
 | 
				
			||||||
    let trait_ = trait_?;
 | 
					    let trait_ = trait_?;
 | 
				
			||||||
    let target_scope = sema.scope(annotated_name.syntax())?;
 | 
					    let target_scope = sema.scope(annotated_name.syntax())?;
 | 
				
			||||||
| 
						 | 
					@ -245,14 +215,18 @@ fn impl_def_from_trait(
 | 
				
			||||||
    if trait_items.is_empty() {
 | 
					    if trait_items.is_empty() {
 | 
				
			||||||
        return None;
 | 
					        return None;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
 | 
					    let impl_def = generate_trait_impl(impl_is_unsafe, adt, make::ty_path(trait_path.clone()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let first_assoc_item =
 | 
					    let first_assoc_item =
 | 
				
			||||||
        add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope);
 | 
					        add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generate a default `impl` function body for the derived trait.
 | 
					    // Generate a default `impl` function body for the derived trait.
 | 
				
			||||||
    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 | 
					    if let ast::AssocItem::Fn(ref func) = first_assoc_item {
 | 
				
			||||||
        let _ = gen_trait_fn_body(func, trait_path, adt, None);
 | 
					        if let Some(body) = gen_trait_fn_body(func, trait_path, adt, None)
 | 
				
			||||||
 | 
					            && let Some(func_body) = func.body()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            ted::replace(func_body.syntax(), body.syntax());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Some((impl_def, first_assoc_item))
 | 
					    Some((impl_def, first_assoc_item))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -668,19 +668,19 @@ pub(crate) fn generate_impl_with_item(
 | 
				
			||||||
    adt: &ast::Adt,
 | 
					    adt: &ast::Adt,
 | 
				
			||||||
    body: Option<ast::AssocItemList>,
 | 
					    body: Option<ast::AssocItemList>,
 | 
				
			||||||
) -> ast::Impl {
 | 
					) -> ast::Impl {
 | 
				
			||||||
    generate_impl_inner(adt, None, true, body)
 | 
					    generate_impl_inner(false, adt, None, true, body)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl {
 | 
					pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl {
 | 
				
			||||||
    generate_impl_inner(adt, None, true, None)
 | 
					    generate_impl_inner(false, adt, None, true, None)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generates the corresponding `impl <trait> for Type {}` including type
 | 
					/// Generates the corresponding `impl <trait> for Type {}` including type
 | 
				
			||||||
/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
 | 
					/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
 | 
					/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
 | 
				
			||||||
pub(crate) fn generate_trait_impl(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
 | 
					pub(crate) fn generate_trait_impl(is_unsafe: bool, adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
 | 
				
			||||||
    generate_impl_inner(adt, Some(trait_), true, None)
 | 
					    generate_impl_inner(is_unsafe, adt, Some(trait_), true, None)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generates the corresponding `impl <trait> for Type {}` including type
 | 
					/// Generates the corresponding `impl <trait> for Type {}` including type
 | 
				
			||||||
| 
						 | 
					@ -688,10 +688,11 @@ pub(crate) fn generate_trait_impl(adt: &ast::Adt, trait_: ast::Type) -> ast::Imp
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
 | 
					/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
 | 
				
			||||||
pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
 | 
					pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
 | 
				
			||||||
    generate_impl_inner(adt, Some(trait_), false, None)
 | 
					    generate_impl_inner(false, adt, Some(trait_), false, None)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn generate_impl_inner(
 | 
					fn generate_impl_inner(
 | 
				
			||||||
 | 
					    is_unsafe: bool,
 | 
				
			||||||
    adt: &ast::Adt,
 | 
					    adt: &ast::Adt,
 | 
				
			||||||
    trait_: Option<ast::Type>,
 | 
					    trait_: Option<ast::Type>,
 | 
				
			||||||
    trait_is_transitive: bool,
 | 
					    trait_is_transitive: bool,
 | 
				
			||||||
| 
						 | 
					@ -735,7 +736,7 @@ fn generate_impl_inner(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let impl_ = match trait_ {
 | 
					    let impl_ = match trait_ {
 | 
				
			||||||
        Some(trait_) => make::impl_trait(
 | 
					        Some(trait_) => make::impl_trait(
 | 
				
			||||||
            false,
 | 
					            is_unsafe,
 | 
				
			||||||
            None,
 | 
					            None,
 | 
				
			||||||
            None,
 | 
					            None,
 | 
				
			||||||
            generic_params,
 | 
					            generic_params,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,7 @@
 | 
				
			||||||
//! This module contains functions to generate default trait impl function bodies where possible.
 | 
					//! This module contains functions to generate default trait impl function bodies where possible.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use hir::TraitRef;
 | 
					use hir::TraitRef;
 | 
				
			||||||
use syntax::{
 | 
					use syntax::ast::{self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit, make};
 | 
				
			||||||
    ast::{self, AstNode, BinaryOp, CmpOp, HasName, LogicOp, edit::AstNodeEdit, make},
 | 
					 | 
				
			||||||
    ted,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate custom trait bodies without default implementation where possible.
 | 
					/// Generate custom trait bodies without default implementation where possible.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					@ -18,21 +15,33 @@ pub(crate) fn gen_trait_fn_body(
 | 
				
			||||||
    trait_path: &ast::Path,
 | 
					    trait_path: &ast::Path,
 | 
				
			||||||
    adt: &ast::Adt,
 | 
					    adt: &ast::Adt,
 | 
				
			||||||
    trait_ref: Option<TraitRef<'_>>,
 | 
					    trait_ref: Option<TraitRef<'_>>,
 | 
				
			||||||
) -> Option<()> {
 | 
					) -> Option<ast::BlockExpr> {
 | 
				
			||||||
 | 
					    let _ = func.body()?;
 | 
				
			||||||
    match trait_path.segment()?.name_ref()?.text().as_str() {
 | 
					    match trait_path.segment()?.name_ref()?.text().as_str() {
 | 
				
			||||||
        "Clone" => gen_clone_impl(adt, func),
 | 
					        "Clone" => {
 | 
				
			||||||
        "Debug" => gen_debug_impl(adt, func),
 | 
					            stdx::always!(func.name().is_some_and(|name| name.text() == "clone"));
 | 
				
			||||||
        "Default" => gen_default_impl(adt, func),
 | 
					            gen_clone_impl(adt)
 | 
				
			||||||
        "Hash" => gen_hash_impl(adt, func),
 | 
					        }
 | 
				
			||||||
        "PartialEq" => gen_partial_eq(adt, func, trait_ref),
 | 
					        "Debug" => gen_debug_impl(adt),
 | 
				
			||||||
        "PartialOrd" => gen_partial_ord(adt, func, trait_ref),
 | 
					        "Default" => gen_default_impl(adt),
 | 
				
			||||||
 | 
					        "Hash" => {
 | 
				
			||||||
 | 
					            stdx::always!(func.name().is_some_and(|name| name.text() == "hash"));
 | 
				
			||||||
 | 
					            gen_hash_impl(adt)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        "PartialEq" => {
 | 
				
			||||||
 | 
					            stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
 | 
				
			||||||
 | 
					            gen_partial_eq(adt, trait_ref)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        "PartialOrd" => {
 | 
				
			||||||
 | 
					            stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
 | 
				
			||||||
 | 
					            gen_partial_ord(adt, trait_ref)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        _ => None,
 | 
					        _ => None,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate a `Clone` impl based on the fields and members of the target type.
 | 
					/// Generate a `Clone` impl based on the fields and members of the target type.
 | 
				
			||||||
fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
					fn gen_clone_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    stdx::always!(func.name().is_some_and(|name| name.text() == "clone"));
 | 
					 | 
				
			||||||
    fn gen_clone_call(target: ast::Expr) -> ast::Expr {
 | 
					    fn gen_clone_call(target: ast::Expr) -> ast::Expr {
 | 
				
			||||||
        let method = make::name_ref("clone");
 | 
					        let method = make::name_ref("clone");
 | 
				
			||||||
        make::expr_method_call(target, method, make::arg_list(None)).into()
 | 
					        make::expr_method_call(target, method, make::arg_list(None)).into()
 | 
				
			||||||
| 
						 | 
					@ -139,12 +148,11 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 | 
					    let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 | 
				
			||||||
    ted::replace(func.body()?.syntax(), body.syntax());
 | 
					    Some(body)
 | 
				
			||||||
    Some(())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate a `Debug` impl based on the fields and members of the target type.
 | 
					/// Generate a `Debug` impl based on the fields and members of the target type.
 | 
				
			||||||
fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
					fn gen_debug_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    let annotated_name = adt.name()?;
 | 
					    let annotated_name = adt.name()?;
 | 
				
			||||||
    match adt {
 | 
					    match adt {
 | 
				
			||||||
        // `Debug` cannot be derived for unions, so no default impl can be provided.
 | 
					        // `Debug` cannot be derived for unions, so no default impl can be provided.
 | 
				
			||||||
| 
						 | 
					@ -248,8 +256,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let body = make::block_expr(None, Some(match_expr.into()));
 | 
					            let body = make::block_expr(None, Some(match_expr.into()));
 | 
				
			||||||
            let body = body.indent(ast::edit::IndentLevel(1));
 | 
					            let body = body.indent(ast::edit::IndentLevel(1));
 | 
				
			||||||
            ted::replace(func.body()?.syntax(), body.syntax());
 | 
					            Some(body)
 | 
				
			||||||
            Some(())
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ast::Adt::Struct(strukt) => {
 | 
					        ast::Adt::Struct(strukt) => {
 | 
				
			||||||
| 
						 | 
					@ -296,14 +303,13 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
				
			||||||
            let method = make::name_ref("finish");
 | 
					            let method = make::name_ref("finish");
 | 
				
			||||||
            let expr = make::expr_method_call(expr, method, make::arg_list(None)).into();
 | 
					            let expr = make::expr_method_call(expr, method, make::arg_list(None)).into();
 | 
				
			||||||
            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 | 
					            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 | 
				
			||||||
            ted::replace(func.body()?.syntax(), body.syntax());
 | 
					            Some(body)
 | 
				
			||||||
            Some(())
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate a `Debug` impl based on the fields and members of the target type.
 | 
					/// 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_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    fn gen_default_call() -> Option<ast::Expr> {
 | 
					    fn gen_default_call() -> Option<ast::Expr> {
 | 
				
			||||||
        let fn_name = make::ext::path_from_idents(["Default", "default"])?;
 | 
					        let fn_name = make::ext::path_from_idents(["Default", "default"])?;
 | 
				
			||||||
        Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)).into())
 | 
					        Some(make::expr_call(make::expr_path(fn_name), make::arg_list(None)).into())
 | 
				
			||||||
| 
						 | 
					@ -342,15 +348,13 @@ fn gen_default_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 | 
					            let body = make::block_expr(None, Some(expr)).indent(ast::edit::IndentLevel(1));
 | 
				
			||||||
            ted::replace(func.body()?.syntax(), body.syntax());
 | 
					            Some(body)
 | 
				
			||||||
            Some(())
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate a `Hash` impl based on the fields and members of the target type.
 | 
					/// Generate a `Hash` impl based on the fields and members of the target type.
 | 
				
			||||||
fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
					fn gen_hash_impl(adt: &ast::Adt) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    stdx::always!(func.name().is_some_and(|name| name.text() == "hash"));
 | 
					 | 
				
			||||||
    fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 | 
					    fn gen_hash_call(target: ast::Expr) -> ast::Stmt {
 | 
				
			||||||
        let method = make::name_ref("hash");
 | 
					        let method = make::name_ref("hash");
 | 
				
			||||||
        let arg = make::expr_path(make::ext::ident_path("state"));
 | 
					        let arg = make::expr_path(make::ext::ident_path("state"));
 | 
				
			||||||
| 
						 | 
					@ -400,13 +404,11 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ted::replace(func.body()?.syntax(), body.syntax());
 | 
					    Some(body)
 | 
				
			||||||
    Some(())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Generate a `PartialEq` impl based on the fields and members of the target type.
 | 
					/// Generate a `PartialEq` impl based on the fields and members of the target type.
 | 
				
			||||||
fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
 | 
					fn gen_partial_eq(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    stdx::always!(func.name().is_some_and(|name| name.text() == "eq"));
 | 
					 | 
				
			||||||
    fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
 | 
					    fn gen_eq_chain(expr: Option<ast::Expr>, cmp: ast::Expr) -> Option<ast::Expr> {
 | 
				
			||||||
        match expr {
 | 
					        match expr {
 | 
				
			||||||
            Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
 | 
					            Some(expr) => Some(make::expr_bin_op(expr, BinaryOp::LogicOp(LogicOp::And), cmp)),
 | 
				
			||||||
| 
						 | 
					@ -595,12 +597,10 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ted::replace(func.body()?.syntax(), body.syntax());
 | 
					    Some(body)
 | 
				
			||||||
    Some(())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_>>) -> Option<()> {
 | 
					fn gen_partial_ord(adt: &ast::Adt, trait_ref: Option<TraitRef<'_>>) -> Option<ast::BlockExpr> {
 | 
				
			||||||
    stdx::always!(func.name().is_some_and(|name| name.text() == "partial_cmp"));
 | 
					 | 
				
			||||||
    fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
 | 
					    fn gen_partial_eq_match(match_target: ast::Expr) -> Option<ast::Stmt> {
 | 
				
			||||||
        let mut arms = vec![];
 | 
					        let mut arms = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -686,8 +686,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef<'_
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ted::replace(func.body()?.syntax(), body.syntax());
 | 
					    Some(body)
 | 
				
			||||||
    Some(())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn make_discriminant() -> Option<ast::Expr> {
 | 
					fn make_discriminant() -> Option<ast::Expr> {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue