aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-02-07 15:24:09 +0000
committerFlorian Diebold <[email protected]>2020-02-07 17:28:10 +0000
commit6c70619b0126bc0e40bd9df39dcd6e711cac69c5 (patch)
treec9812b922e3f7ec753ff18e0b17b0f54f18ea737 /crates/ra_hir_ty/src
parentdded90a748737c3661aad043524f2248e324c867 (diff)
Deal better with implicit type parameters and argument lists
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs8
-rw-r--r--crates/ra_hir_ty/src/lower.rs41
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs108
-rw-r--r--crates/ra_hir_ty/src/utils.rs7
4 files changed, 138 insertions, 26 deletions
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 8c360bcad..00ae35953 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -647,8 +647,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
647 generic_args: Option<&GenericArgs>, 647 generic_args: Option<&GenericArgs>,
648 receiver_ty: &Ty, 648 receiver_ty: &Ty,
649 ) -> Substs { 649 ) -> Substs {
650 let (total_len, _parent_len, child_len) = 650 let (parent_params, self_params, type_params, impl_trait_params) =
651 def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split()); 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;
652 let mut substs = Vec::with_capacity(total_len); 654 let mut substs = Vec::with_capacity(total_len);
653 // Parent arguments are unknown, except for the receiver type 655 // Parent arguments are unknown, except for the receiver type
654 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 656 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> {
663 // handle provided type arguments 665 // handle provided type arguments
664 if let Some(generic_args) = generic_args { 666 if let Some(generic_args) = generic_args {
665 // if args are provided, it should be all of them, but we can't rely on that 667 // 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) {
667 match arg { 669 match arg {
668 GenericArg::Type(type_ref) => { 670 GenericArg::Type(type_ref) => {
669 let ty = self.make_ty(type_ref); 671 let ty = self.make_ty(type_ref);
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 4168e7509..d2df3fe2b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -161,15 +161,19 @@ impl Ty {
161 ImplTraitLoweringMode::Variable => { 161 ImplTraitLoweringMode::Variable => {
162 let idx = ctx.impl_trait_counter.get(); 162 let idx = ctx.impl_trait_counter.get();
163 ctx.impl_trait_counter.set(idx + 1); 163 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) =
165 if let Some(def) = ctx.resolver.generic_def() { 165 if let Some(def) = ctx.resolver.generic_def() {
166 let generics = generics(ctx.db, def); 166 let generics = generics(ctx.db, def);
167 generics.provenance_split() 167 generics.provenance_split()
168 } else { 168 } else {
169 (0, 0, 0) 169 (0, 0, 0, 0)
170 }; 170 };
171 // assert!((idx as usize) < impl_trait_params); // TODO return position impl trait 171 Ty::Bound(
172 Ty::Bound(idx as u32 + self_params as u32 + list_params as u32) 172 idx as u32
173 + parent_params as u32
174 + self_params as u32
175 + list_params as u32,
176 )
173 } 177 }
174 ImplTraitLoweringMode::Disallowed => { 178 ImplTraitLoweringMode::Disallowed => {
175 // FIXME: report error 179 // FIXME: report error
@@ -420,26 +424,23 @@ pub(super) fn substs_from_path_segment(
420 ctx: &TyLoweringContext<'_, impl HirDatabase>, 424 ctx: &TyLoweringContext<'_, impl HirDatabase>,
421 segment: PathSegment<'_>, 425 segment: PathSegment<'_>,
422 def_generic: Option<GenericDefId>, 426 def_generic: Option<GenericDefId>,
423 add_self_param: bool, 427 _add_self_param: bool,
424) -> Substs { 428) -> Substs {
425 let mut substs = Vec::new(); 429 let mut substs = Vec::new();
426 let def_generics = def_generic.map(|def| generics(ctx.db, def.into())); 430 let def_generics = def_generic.map(|def| generics(ctx.db, def.into()));
427 431
428 let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split()); 432 let (parent_params, self_params, type_params, impl_trait_params) =
429 substs.extend(iter::repeat(Ty::Unknown).take(parent_len)); 433 def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split());
430 if add_self_param { 434 substs.extend(iter::repeat(Ty::Unknown).take(parent_params));
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 }
438 if let Some(generic_args) = &segment.args_and_bindings { 435 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 };
439 // if args are provided, it should be all of them, but we can't rely on that 442 // 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 }; 443 for arg in generic_args.args.iter().skip(skip).take(expected_num) {
441 let child_len = child_len - self_param_correction;
442 for arg in generic_args.args.iter().take(child_len) {
443 match arg { 444 match arg {
444 GenericArg::Type(type_ref) => { 445 GenericArg::Type(type_ref) => {
445 let ty = Ty::from_hir(ctx, type_ref); 446 let ty = Ty::from_hir(ctx, type_ref);
@@ -448,9 +449,9 @@ pub(super) fn substs_from_path_segment(
448 } 449 }
449 } 450 }
450 } 451 }
452 let total_len = parent_params + self_params + type_params + impl_trait_params;
451 // add placeholders for args that were not provided 453 // add placeholders for args that were not provided
452 let supplied_params = substs.len(); 454 for _ in substs.len()..total_len {
453 for _ in supplied_params..total_len {
454 substs.push(Ty::Unknown); 455 substs.push(Ty::Unknown);
455 } 456 }
456 assert_eq!(substs.len(), total_len); 457 assert_eq!(substs.len(), total_len);
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 134cea8d8..f90dadc08 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -906,6 +906,114 @@ fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
906} 906}
907 907
908#[test] 908#[test]
909fn argument_impl_trait_type_args_1() {
910 assert_snapshot!(
911 infer_with_mismatches(r#"
912trait Trait {}
913trait 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}
918fn foo<T>(x: impl Trait) -> T { loop {} }
919struct S;
920impl Trait for S {}
921struct F;
922impl Foo for F {}
923
924fn 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]
975fn argument_impl_trait_type_args_2() {
976 assert_snapshot!(
977 infer_with_mismatches(r#"
978trait Trait {}
979struct S;
980impl Trait for S {}
981struct F<T>;
982impl<T> F<T> {
983 fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
984}
985
986fn 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
1016#[test]
909#[ignore] 1017#[ignore]
910fn impl_trait() { 1018fn impl_trait() {
911 assert_snapshot!( 1019 assert_snapshot!(
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index e307d958d..508ae9046 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -145,8 +145,9 @@ impl Generics {
145 (parent + child, parent, child) 145 (parent + child, parent, child)
146 } 146 }
147 147
148 /// (self, type param list, impl trait) 148 /// (parent total, self param, type param list, impl trait)
149 pub(crate) fn provenance_split(&self) -> (usize, usize, usize) { 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());
150 let self_params = self 151 let self_params = self
151 .params 152 .params
152 .types 153 .types
@@ -165,7 +166,7 @@ impl Generics {
165 .iter() 166 .iter()
166 .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait) 167 .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait)
167 .count(); 168 .count();
168 (self_params, list_params, impl_trait_params) 169 (parent, self_params, list_params, impl_trait_params)
169 } 170 }
170 171
171 pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<u32> { 172 pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<u32> {