Skip to content

Commit f1587ac

Browse files
bors[bot]montekki
andauthored
Merge #4445
4445: Correctly fill default type parameters r=flodiebold a=montekki Fixes #3877 So, basically even if the parameters are omitted from the `impl` block, check the parameters in `trait` if they have a default type, and if they do go from `hir` to `ast::TypeArg`. I've added a helper for that but I am not sure that it's a proper way to go from `hir` to `ast` here. Co-authored-by: Fedor Sakharov <[email protected]>
2 parents 5148d6d + ccd5268 commit f1587ac

File tree

5 files changed

+92
-2
lines changed

5 files changed

+92
-2
lines changed

crates/ra_assists/src/ast_transform.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
22
use rustc_hash::FxHashMap;
33

4-
use hir::{PathResolution, SemanticsScope};
4+
use hir::{HirDisplay, PathResolution, SemanticsScope};
55
use ra_ide_db::RootDatabase;
66
use ra_syntax::{
77
algo::SyntaxRewriter,
@@ -51,7 +51,27 @@ impl<'a> SubstituteTypeParams<'a> {
5151
.into_iter()
5252
// this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
5353
.skip(1)
54-
.zip(substs.into_iter())
54+
// The actual list of trait type parameters may be longer than the one
55+
// used in the `impl` block due to trailing default type parametrs.
56+
// For that case we extend the `substs` with an empty iterator so we
57+
// can still hit those trailing values and check if they actually have
58+
// a default type. If they do, go for that type from `hir` to `ast` so
59+
// the resulting change can be applied correctly.
60+
.zip(substs.into_iter().map(Some).chain(std::iter::repeat(None)))
61+
.filter_map(|(k, v)| match v {
62+
Some(v) => Some((k, v)),
63+
None => {
64+
let default = k.default(source_scope.db)?;
65+
Some((
66+
k,
67+
ast::make::type_ref(
68+
&default
69+
.display_source_code(source_scope.db, source_scope.module()?.into())
70+
.ok()?,
71+
),
72+
))
73+
}
74+
})
5575
.collect();
5676
return SubstituteTypeParams {
5777
source_scope,

crates/ra_assists/src/handlers/add_missing_impl_members.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,56 @@ trait Foo {
615615
struct S;
616616
impl Foo for S {
617617
<|>fn valid(some: u32) -> bool { false }
618+
}"#,
619+
)
620+
}
621+
622+
#[test]
623+
fn test_generic_single_default_parameter() {
624+
check_assist(
625+
add_missing_impl_members,
626+
r#"
627+
trait Foo<T = Self> {
628+
fn bar(&self, other: &T);
629+
}
630+
631+
struct S;
632+
impl Foo for S { <|> }"#,
633+
r#"
634+
trait Foo<T = Self> {
635+
fn bar(&self, other: &T);
636+
}
637+
638+
struct S;
639+
impl Foo for S {
640+
<|>fn bar(&self, other: &Self) {
641+
todo!()
642+
}
643+
}"#,
644+
)
645+
}
646+
647+
#[test]
648+
fn test_generic_default_parameter_is_second() {
649+
check_assist(
650+
add_missing_impl_members,
651+
r#"
652+
trait Foo<T1, T2 = Self> {
653+
fn bar(&self, this: &T1, that: &T2);
654+
}
655+
656+
struct S<T>;
657+
impl Foo<T> for S<T> { <|> }"#,
658+
r#"
659+
trait Foo<T1, T2 = Self> {
660+
fn bar(&self, this: &T1, that: &T2);
661+
}
662+
663+
struct S<T>;
664+
impl Foo<T> for S<T> {
665+
<|>fn bar(&self, this: &T, that: &Self) {
666+
todo!()
667+
}
618668
}"#,
619669
)
620670
}

crates/ra_hir/src/code_model.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,17 @@ impl TypeParam {
989989
ty: InEnvironment { value: ty, environment },
990990
}
991991
}
992+
993+
pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
994+
let params = db.generic_defaults(self.id.parent);
995+
let local_idx = hir_ty::param_idx(db, self.id)?;
996+
let resolver = self.id.parent.resolver(db.upcast());
997+
let environment = TraitEnvironment::lower(db, &resolver);
998+
params.get(local_idx).cloned().map(|ty| Type {
999+
krate: self.id.parent.module(db.upcast()).krate,
1000+
ty: InEnvironment { value: ty, environment },
1001+
})
1002+
}
9921003
}
9931004

9941005
// FIXME: rename from `ImplDef` to `Impl`

crates/ra_hir_ty/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ impl Substs {
427427
}
428428
}
429429

430+
/// Return an index of a parameter in the generic type parameter list by it's id.
431+
pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
432+
generics(db.upcast(), id.parent).param_idx(id)
433+
}
434+
430435
#[derive(Debug, Clone)]
431436
pub struct SubstsBuilder {
432437
vec: Vec<Ty>,

crates/ra_syntax/src/ast/make.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ pub fn name_ref(text: &str) -> ast::NameRef {
1313
ast_from_text(&format!("fn f() {{ {}; }}", text))
1414
}
1515

16+
pub fn type_ref(text: &str) -> ast::TypeRef {
17+
ast_from_text(&format!("impl {} for D {{}};", text))
18+
}
19+
1620
pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
1721
ast_from_text(&format!("use {};", name_ref))
1822
}

0 commit comments

Comments
 (0)