Skip to content

Commit cfa9149

Browse files
committed
refactor: use generate_trait_impl_text_intransitive for From-like traits
1 parent 12b05d2 commit cfa9149

File tree

4 files changed

+44
-28
lines changed

4 files changed

+44
-28
lines changed

crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use ide_db::{famous_defs::FamousDefs, RootDatabase};
22
use syntax::ast::{self, AstNode, HasName};
33

4-
use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind, Assists};
4+
use crate::{
5+
utils::generate_trait_impl_text_intransitive, AssistContext, AssistId, AssistKind, Assists,
6+
};
57

68
// Assist: generate_from_impl_for_enum
79
//
@@ -70,7 +72,7 @@ pub(crate) fn generate_from_impl_for_enum(
7072
}}"#
7173
)
7274
};
73-
let from_impl = generate_trait_impl_text(&enum_, &from_trait, &impl_code);
75+
let from_impl = generate_trait_impl_text_intransitive(&enum_, &from_trait, &impl_code);
7476
edit.insert(start_offset, from_impl);
7577
},
7678
)

crates/ide-assists/src/handlers/generate_impl.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use syntax::ast::{self, AstNode, HasName};
22

33
use crate::{
4-
utils::{generate_impl_text, generate_trait_impl_text},
4+
utils::{generate_impl_text, generate_trait_impl_text_intransitive},
55
AssistContext, AssistId, AssistKind, Assists,
66
};
77

@@ -89,11 +89,11 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
8989
let start_offset = nominal.syntax().text_range().end();
9090
match ctx.config.snippet_cap {
9191
Some(cap) => {
92-
let snippet = generate_trait_impl_text(&nominal, "$0", "");
92+
let snippet = generate_trait_impl_text_intransitive(&nominal, "$0", "");
9393
edit.insert_snippet(cap, start_offset, snippet);
9494
}
9595
None => {
96-
let text = generate_trait_impl_text(&nominal, "", "");
96+
let text = generate_trait_impl_text_intransitive(&nominal, "", "");
9797
edit.insert(start_offset, text);
9898
}
9999
}

crates/ide-assists/src/utils.rs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::ops;
55
pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
66
use hir::{db::HirDatabase, HirDisplay, Semantics};
77
use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
8-
use itertools::Itertools;
98
use stdx::format_to;
109
use syntax::{
1110
ast::{
@@ -435,52 +434,67 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
435434
Some(end)
436435
}
437436

438-
// Generates the surrounding `impl Type { <code> }` including type and lifetime
439-
// parameters
437+
/// Generates the surrounding `impl Type { <code> }` including type and lifetime
438+
/// parameters.
440439
pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
441-
generate_impl_text_inner(adt, None, code)
440+
generate_impl_text_inner(adt, None, true, code)
442441
}
443442

444-
// Generates the surrounding `impl <trait> for Type { <code> }` including type
445-
// and lifetime parameters
443+
/// Generates the surrounding `impl <trait> for Type { <code> }` including type
444+
/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
445+
///
446+
/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
446447
pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
447-
generate_impl_text_inner(adt, Some(trait_text), code)
448+
generate_impl_text_inner(adt, Some(trait_text), true, code)
449+
}
450+
451+
/// Generates the surrounding `impl <trait> for Type { <code> }` including type
452+
/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
453+
///
454+
/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
455+
pub(crate) fn generate_trait_impl_text_intransitive(
456+
adt: &ast::Adt,
457+
trait_text: &str,
458+
code: &str,
459+
) -> String {
460+
generate_impl_text_inner(adt, Some(trait_text), false, code)
448461
}
449462

450-
fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
463+
fn generate_impl_text_inner(
464+
adt: &ast::Adt,
465+
trait_text: Option<&str>,
466+
trait_is_transitive: bool,
467+
code: &str,
468+
) -> String {
451469
// Ensure lifetime params are before type & const params
452470
let generic_params = adt.generic_param_list().map(|generic_params| {
453471
let lifetime_params =
454472
generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
455-
let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
473+
let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
456474
match param {
457475
ast::TypeOrConstParam::Type(param) => {
458476
let param = param.clone_for_update();
459477
// remove defaults since they can't be specified in impls
460478
param.remove_default();
461-
let mut bounds = param
462-
.type_bound_list()
463-
.map_or_else(Vec::new, |it| it.bounds().collect_vec());
464-
// `{ty_param}: {trait_text}`
479+
let mut bounds =
480+
param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
465481
if let Some(trait_) = trait_text {
466-
// Defense against the following cases:
467-
// - The trait is undetermined, e.g. `$0`.
468-
// - The trait is a `From`, e.g. `From<T>`.
469-
if !trait_.starts_with('$')
470-
&& !matches!(trait_.split_once('<'), Some((left, _right)) if left.trim() == "From")
471-
{
482+
// Add the current trait to `bounds` if the trait is transitive,
483+
// meaning `impl<T> Trait for U<T>` requires `T: Trait`.
484+
if trait_is_transitive {
472485
bounds.push(make::type_bound(trait_));
473486
}
474487
};
488+
// `{ty_param}: {bounds}`
475489
let param =
476490
make::type_param(param.name().unwrap(), make::type_bound_list(bounds));
477-
Some(ast::GenericParam::TypeParam(param))
491+
ast::GenericParam::TypeParam(param)
478492
}
479493
ast::TypeOrConstParam::Const(param) => {
480494
let param = param.clone_for_update();
481495
// remove defaults since they can't be specified in impls
482496
param.remove_default();
483-
Some(ast::GenericParam::ConstParam(param))
497+
ast::GenericParam::ConstParam(param)
484498
}
485499
}
486500
});

crates/syntax/src/ast/make.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -734,8 +734,8 @@ pub fn type_bound_list(
734734
}
735735

736736
pub fn type_param(name: ast::Name, bounds: Option<ast::TypeBoundList>) -> ast::TypeParam {
737-
let bound = bounds.map_or_else(String::new, |it| format!(": {it}"));
738-
ast_from_text(&format!("fn f<{name}{bound}>() {{ }}"))
737+
let bounds = bounds.map_or_else(String::new, |it| format!(": {it}"));
738+
ast_from_text(&format!("fn f<{name}{bounds}>() {{ }}"))
739739
}
740740

741741
pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {

0 commit comments

Comments
 (0)