Skip to content

Commit 6c70619

Browse files
committed
Deal better with implicit type parameters and argument lists
1 parent dded90a commit 6c70619

File tree

4 files changed

+138
-26
lines changed

4 files changed

+138
-26
lines changed

crates/ra_hir_ty/src/infer/expr.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
647647
generic_args: Option<&GenericArgs>,
648648
receiver_ty: &Ty,
649649
) -> Substs {
650-
let (total_len, _parent_len, child_len) =
651-
def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split());
650+
let (parent_params, self_params, type_params, impl_trait_params) =
651+
def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split());
652+
assert_eq!(self_params, 0); // method shouldn't have another Self param
653+
let total_len = parent_params + type_params + impl_trait_params;
652654
let mut substs = Vec::with_capacity(total_len);
653655
// Parent arguments are unknown, except for the receiver type
654656
if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
@@ -663,7 +665,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
663665
// handle provided type arguments
664666
if let Some(generic_args) = generic_args {
665667
// if args are provided, it should be all of them, but we can't rely on that
666-
for arg in generic_args.args.iter().take(child_len) {
668+
for arg in generic_args.args.iter().take(type_params) {
667669
match arg {
668670
GenericArg::Type(type_ref) => {
669671
let ty = self.make_ty(type_ref);

crates/ra_hir_ty/src/lower.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,19 @@ impl Ty {
161161
ImplTraitLoweringMode::Variable => {
162162
let idx = ctx.impl_trait_counter.get();
163163
ctx.impl_trait_counter.set(idx + 1);
164-
let (self_params, list_params, _impl_trait_params) =
164+
let (parent_params, self_params, list_params, _impl_trait_params) =
165165
if let Some(def) = ctx.resolver.generic_def() {
166166
let generics = generics(ctx.db, def);
167167
generics.provenance_split()
168168
} else {
169-
(0, 0, 0)
169+
(0, 0, 0, 0)
170170
};
171-
// assert!((idx as usize) < impl_trait_params); // TODO return position impl trait
172-
Ty::Bound(idx as u32 + self_params as u32 + list_params as u32)
171+
Ty::Bound(
172+
idx as u32
173+
+ parent_params as u32
174+
+ self_params as u32
175+
+ list_params as u32,
176+
)
173177
}
174178
ImplTraitLoweringMode::Disallowed => {
175179
// FIXME: report error
@@ -420,26 +424,23 @@ pub(super) fn substs_from_path_segment(
420424
ctx: &TyLoweringContext<'_, impl HirDatabase>,
421425
segment: PathSegment<'_>,
422426
def_generic: Option<GenericDefId>,
423-
add_self_param: bool,
427+
_add_self_param: bool,
424428
) -> Substs {
425429
let mut substs = Vec::new();
426430
let def_generics = def_generic.map(|def| generics(ctx.db, def.into()));
427431

428-
let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split());
429-
substs.extend(iter::repeat(Ty::Unknown).take(parent_len));
430-
if add_self_param {
431-
// FIXME this add_self_param argument is kind of a hack: Traits have the
432-
// Self type as an implicit first type parameter, but it can't be
433-
// actually provided in the type arguments
434-
// (well, actually sometimes it can, in the form of type-relative paths: `<Foo as Default>::default()`)
435-
// TODO handle this using type param provenance (if there's a self param, and not one provided, add unknown)
436-
substs.push(Ty::Unknown);
437-
}
432+
let (parent_params, self_params, type_params, impl_trait_params) =
433+
def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split());
434+
substs.extend(iter::repeat(Ty::Unknown).take(parent_params));
438435
if let Some(generic_args) = &segment.args_and_bindings {
436+
if !generic_args.has_self_type {
437+
substs.extend(iter::repeat(Ty::Unknown).take(self_params));
438+
}
439+
let expected_num =
440+
if generic_args.has_self_type { self_params + type_params } else { type_params };
441+
let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
439442
// if args are provided, it should be all of them, but we can't rely on that
440-
let self_param_correction = if add_self_param { 1 } else { 0 };
441-
let child_len = child_len - self_param_correction;
442-
for arg in generic_args.args.iter().take(child_len) {
443+
for arg in generic_args.args.iter().skip(skip).take(expected_num) {
443444
match arg {
444445
GenericArg::Type(type_ref) => {
445446
let ty = Ty::from_hir(ctx, type_ref);
@@ -448,9 +449,9 @@ pub(super) fn substs_from_path_segment(
448449
}
449450
}
450451
}
452+
let total_len = parent_params + self_params + type_params + impl_trait_params;
451453
// add placeholders for args that were not provided
452-
let supplied_params = substs.len();
453-
for _ in supplied_params..total_len {
454+
for _ in substs.len()..total_len {
454455
substs.push(Ty::Unknown);
455456
}
456457
assert_eq!(substs.len(), total_len);

crates/ra_hir_ty/src/tests/traits.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,114 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
905905
);
906906
}
907907

908+
#[test]
909+
fn argument_impl_trait_type_args_1() {
910+
assert_snapshot!(
911+
infer_with_mismatches(r#"
912+
trait Trait {}
913+
trait Foo {
914+
// this function has an implicit Self param, an explicit type param,
915+
// and an implicit impl Trait param!
916+
fn bar<T>(x: impl Trait) -> T { loop {} }
917+
}
918+
fn foo<T>(x: impl Trait) -> T { loop {} }
919+
struct S;
920+
impl Trait for S {}
921+
struct F;
922+
impl Foo for F {}
923+
924+
fn test() {
925+
Foo::bar(S);
926+
<F as Foo>::bar(S);
927+
F::bar(S);
928+
Foo::bar::<u32>(S);
929+
<F as Foo>::bar::<u32>(S);
930+
931+
foo(S);
932+
foo::<u32>(S);
933+
foo::<u32, i32>(S); // we should ignore the extraneous i32
934+
}
935+
"#, true),
936+
@r###"
937+
[156; 157) 'x': impl Trait
938+
[176; 187) '{ loop {} }': T
939+
[178; 185) 'loop {}': !
940+
[183; 185) '{}': ()
941+
[200; 201) 'x': impl Trait
942+
[220; 231) '{ loop {} }': T
943+
[222; 229) 'loop {}': !
944+
[227; 229) '{}': ()
945+
[301; 510) '{ ... i32 }': ()
946+
[307; 315) 'Foo::bar': fn bar<{unknown}, {unknown}, S>(S) -> {unknown}
947+
[307; 318) 'Foo::bar(S)': {unknown}
948+
[316; 317) 'S': S
949+
[324; 339) '<F as Foo>::bar': fn bar<F, {unknown}, S>(S) -> {unknown}
950+
[324; 342) '<F as ...bar(S)': {unknown}
951+
[340; 341) 'S': S
952+
[348; 354) 'F::bar': fn bar<F, {unknown}, S>(S) -> {unknown}
953+
[348; 357) 'F::bar(S)': {unknown}
954+
[355; 356) 'S': S
955+
[363; 378) 'Foo::bar::<u32>': fn bar<{unknown}, u32, S>(S) -> u32
956+
[363; 381) 'Foo::b...32>(S)': u32
957+
[379; 380) 'S': S
958+
[387; 409) '<F as ...:<u32>': fn bar<F, u32, S>(S) -> u32
959+
[387; 412) '<F as ...32>(S)': u32
960+
[410; 411) 'S': S
961+
[419; 422) 'foo': fn foo<{unknown}, S>(S) -> {unknown}
962+
[419; 425) 'foo(S)': {unknown}
963+
[423; 424) 'S': S
964+
[431; 441) 'foo::<u32>': fn foo<u32, S>(S) -> u32
965+
[431; 444) 'foo::<u32>(S)': u32
966+
[442; 443) 'S': S
967+
[450; 465) 'foo::<u32, i32>': fn foo<u32, S>(S) -> u32
968+
[450; 468) 'foo::<...32>(S)': u32
969+
[466; 467) 'S': S
970+
"###
971+
);
972+
}
973+
974+
#[test]
975+
fn argument_impl_trait_type_args_2() {
976+
assert_snapshot!(
977+
infer_with_mismatches(r#"
978+
trait Trait {}
979+
struct S;
980+
impl Trait for S {}
981+
struct F<T>;
982+
impl<T> F<T> {
983+
fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
984+
}
985+
986+
fn test() {
987+
F.foo(S);
988+
F::<u32>.foo(S);
989+
F::<u32>.foo::<i32>(S);
990+
F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored
991+
}
992+
"#, true),
993+
@r###"
994+
[88; 92) 'self': F<T>
995+
[94; 95) 'x': impl Trait
996+
[119; 130) '{ loop {} }': (T, U)
997+
[121; 128) 'loop {}': !
998+
[126; 128) '{}': ()
999+
[144; 284) '{ ...ored }': ()
1000+
[150; 151) 'F': F<{unknown}>
1001+
[150; 158) 'F.foo(S)': ({unknown}, {unknown})
1002+
[156; 157) 'S': S
1003+
[164; 172) 'F::<u32>': F<u32>
1004+
[164; 179) 'F::<u32>.foo(S)': (u32, {unknown})
1005+
[177; 178) 'S': S
1006+
[185; 193) 'F::<u32>': F<u32>
1007+
[185; 207) 'F::<u3...32>(S)': (u32, i32)
1008+
[205; 206) 'S': S
1009+
[213; 221) 'F::<u32>': F<u32>
1010+
[213; 240) 'F::<u3...32>(S)': (u32, i32)
1011+
[238; 239) 'S': S
1012+
"###
1013+
);
1014+
}
1015+
9081016
#[test]
9091017
#[ignore]
9101018
fn impl_trait() {

crates/ra_hir_ty/src/utils.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,9 @@ impl Generics {
145145
(parent + child, parent, child)
146146
}
147147

148-
/// (self, type param list, impl trait)
149-
pub(crate) fn provenance_split(&self) -> (usize, usize, usize) {
148+
/// (parent total, self param, type param list, impl trait)
149+
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize) {
150+
let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
150151
let self_params = self
151152
.params
152153
.types
@@ -165,7 +166,7 @@ impl Generics {
165166
.iter()
166167
.filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait)
167168
.count();
168-
(self_params, list_params, impl_trait_params)
169+
(parent, self_params, list_params, impl_trait_params)
169170
}
170171

171172
pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<u32> {

0 commit comments

Comments
 (0)