diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-17 13:56:22 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-17 13:56:22 +0000 |
commit | f937d11ad892036fa93b25a2c19d10dcebe4ab24 (patch) | |
tree | 71f3719509f3fb46f5d2ce5a93da42ea67b23b70 /crates/ra_hir/src/ty | |
parent | edd4c1d8a6c270fe39ae881c23c722c658c87c32 (diff) | |
parent | 3c7c7e5a04306f8b68dffef2b5ca84628ed81ce2 (diff) |
Merge #843
843: Impl generics r=matklad a=flodiebold
This handles type parameters on impls when typing method calls.
~One remaining problem is that the autoderefs aren't applied during the unification of the method receiver type with the actual receiver type, which means that the type parameters are only correctly inferred if no autoderefs happened.~
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty')
5 files changed, 141 insertions, 32 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 8d1076774..94b757af2 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -118,11 +118,13 @@ impl Ty { | |||
118 | // TODO: cache this as a query? | 118 | // TODO: cache this as a query? |
119 | // - if so, what signature? (TyFingerprint, Name)? | 119 | // - if so, what signature? (TyFingerprint, Name)? |
120 | // - or maybe cache all names and def_ids of methods per fingerprint? | 120 | // - or maybe cache all names and def_ids of methods per fingerprint? |
121 | pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> { | 121 | /// Look up the method with the given name, returning the actual autoderefed |
122 | self.iterate_methods(db, |f| { | 122 | /// receiver type (but without autoref applied yet). |
123 | pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> { | ||
124 | self.iterate_methods(db, |ty, f| { | ||
123 | let sig = f.signature(db); | 125 | let sig = f.signature(db); |
124 | if sig.name() == name && sig.has_self_param() { | 126 | if sig.name() == name && sig.has_self_param() { |
125 | Some(f) | 127 | Some((ty.clone(), f)) |
126 | } else { | 128 | } else { |
127 | None | 129 | None |
128 | } | 130 | } |
@@ -134,7 +136,7 @@ impl Ty { | |||
134 | pub fn iterate_methods<T>( | 136 | pub fn iterate_methods<T>( |
135 | self, | 137 | self, |
136 | db: &impl HirDatabase, | 138 | db: &impl HirDatabase, |
137 | mut callback: impl FnMut(Function) -> Option<T>, | 139 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
138 | ) -> Option<T> { | 140 | ) -> Option<T> { |
139 | // For method calls, rust first does any number of autoderef, and then one | 141 | // For method calls, rust first does any number of autoderef, and then one |
140 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | 142 | // autoref (i.e. when the method takes &self or &mut self). We just ignore |
@@ -156,7 +158,7 @@ impl Ty { | |||
156 | for item in impl_block.items(db) { | 158 | for item in impl_block.items(db) { |
157 | match item { | 159 | match item { |
158 | ImplItem::Method(f) => { | 160 | ImplItem::Method(f) => { |
159 | if let Some(result) = callback(f) { | 161 | if let Some(result) = callback(&derefed_ty, f) { |
160 | return Some(result); | 162 | return Some(result); |
161 | } | 163 | } |
162 | } | 164 | } |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap index 626f31252..d1ce87b0a 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap | |||
@@ -1,36 +1,36 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-01-27T14:52:29.938713255+00:00" | 2 | created: "2019-02-16T20:53:59.655361804Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | expression: "&result" | ||
5 | source: crates/ra_hir/src/ty/tests.rs | 4 | source: crates/ra_hir/src/ty/tests.rs |
5 | expression: "&result" | ||
6 | --- | 6 | --- |
7 | [53; 57) 'self': A<[unknown]> | 7 | [53; 57) 'self': A<T2> |
8 | [65; 87) '{ ... }': [unknown] | 8 | [65; 87) '{ ... }': T2 |
9 | [75; 79) 'self': A<[unknown]> | 9 | [75; 79) 'self': A<T2> |
10 | [75; 81) 'self.x': [unknown] | 10 | [75; 81) 'self.x': T2 |
11 | [99; 100) 't': T | 11 | [99; 100) 't': T |
12 | [110; 115) '{ t }': T | 12 | [110; 115) '{ t }': T |
13 | [112; 113) 't': T | 13 | [112; 113) 't': T |
14 | [135; 261) '{ ....x() }': i128 | 14 | [135; 261) '{ ....x() }': i128 |
15 | [146; 147) 'x': i32 | 15 | [146; 147) 'x': i128 |
16 | [150; 151) '1': i32 | 16 | [150; 151) '1': i128 |
17 | [162; 163) 'y': i32 | 17 | [162; 163) 'y': i128 |
18 | [166; 168) 'id': fn id<i32>(T) -> T | 18 | [166; 168) 'id': fn id<i128>(T) -> T |
19 | [166; 171) 'id(x)': i32 | 19 | [166; 171) 'id(x)': i128 |
20 | [169; 170) 'x': i32 | 20 | [169; 170) 'x': i128 |
21 | [182; 183) 'a': A<i32> | 21 | [182; 183) 'a': A<i128> |
22 | [186; 200) 'A { x: id(y) }': A<i32> | 22 | [186; 200) 'A { x: id(y) }': A<i128> |
23 | [193; 195) 'id': fn id<i32>(T) -> T | 23 | [193; 195) 'id': fn id<i128>(T) -> T |
24 | [193; 198) 'id(y)': i32 | 24 | [193; 198) 'id(y)': i128 |
25 | [196; 197) 'y': i32 | 25 | [196; 197) 'y': i128 |
26 | [211; 212) 'z': i32 | 26 | [211; 212) 'z': i128 |
27 | [215; 217) 'id': fn id<i32>(T) -> T | 27 | [215; 217) 'id': fn id<i128>(T) -> T |
28 | [215; 222) 'id(a.x)': i32 | 28 | [215; 222) 'id(a.x)': i128 |
29 | [218; 219) 'a': A<i32> | 29 | [218; 219) 'a': A<i128> |
30 | [218; 221) 'a.x': i32 | 30 | [218; 221) 'a.x': i128 |
31 | [233; 234) 'b': A<i32> | 31 | [233; 234) 'b': A<i128> |
32 | [237; 247) 'A { x: z }': A<i32> | 32 | [237; 247) 'A { x: z }': A<i128> |
33 | [244; 245) 'z': i32 | 33 | [244; 245) 'z': i128 |
34 | [254; 255) 'b': A<i32> | 34 | [254; 255) 'b': A<i128> |
35 | [254; 259) 'b.x()': i128 | 35 | [254; 259) 'b.x()': i128 |
36 | 36 | ||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap new file mode 100644 index 000000000..44f00a52e --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap | |||
@@ -0,0 +1,39 @@ | |||
1 | --- | ||
2 | created: "2019-02-16T21:58:14.029368845Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [74; 78) 'self': A<X, Y> | ||
8 | [85; 107) '{ ... }': X | ||
9 | [95; 99) 'self': A<X, Y> | ||
10 | [95; 101) 'self.x': X | ||
11 | [117; 121) 'self': A<X, Y> | ||
12 | [128; 150) '{ ... }': Y | ||
13 | [138; 142) 'self': A<X, Y> | ||
14 | [138; 144) 'self.y': Y | ||
15 | [163; 167) 'self': A<X, Y> | ||
16 | [169; 170) 't': T | ||
17 | [188; 223) '{ ... }': (X, Y, T) | ||
18 | [198; 217) '(self.....y, t)': (X, Y, T) | ||
19 | [199; 203) 'self': A<X, Y> | ||
20 | [199; 205) 'self.x': X | ||
21 | [207; 211) 'self': A<X, Y> | ||
22 | [207; 213) 'self.y': Y | ||
23 | [215; 216) 't': T | ||
24 | [245; 342) '{ ...(1); }': () | ||
25 | [255; 256) 'a': A<u64, i64> | ||
26 | [259; 281) 'A { x:...1i64 }': A<u64, i64> | ||
27 | [266; 270) '1u64': u64 | ||
28 | [275; 279) '1i64': i64 | ||
29 | [287; 288) 'a': A<u64, i64> | ||
30 | [287; 292) 'a.x()': u64 | ||
31 | [298; 299) 'a': A<u64, i64> | ||
32 | [298; 303) 'a.y()': i64 | ||
33 | [309; 310) 'a': A<u64, i64> | ||
34 | [309; 319) 'a.z(1i128)': (u64, i64, i128) | ||
35 | [313; 318) '1i128': i128 | ||
36 | [325; 326) 'a': A<u64, i64> | ||
37 | [325; 339) 'a.z::<u128>(1)': (u64, i64, u128) | ||
38 | [337; 338) '1': u128 | ||
39 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap new file mode 100644 index 000000000..f609eaf7c --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap | |||
@@ -0,0 +1,16 @@ | |||
1 | --- | ||
2 | created: "2019-02-17T13:35:06.385679926Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [78; 82) 'self': &Option<T> | ||
8 | [98; 100) '{}': () | ||
9 | [111; 112) 'o': Option<u32> | ||
10 | [127; 165) '{ ...f(); }': () | ||
11 | [133; 146) '(&o).as_ref()': Option<&u32> | ||
12 | [134; 136) '&o': &Option<u32> | ||
13 | [135; 136) 'o': Option<u32> | ||
14 | [152; 153) 'o': Option<u32> | ||
15 | [152; 162) 'o.as_ref()': Option<&u32> | ||
16 | |||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 203f1fe4d..5eb9c4f5b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -507,6 +507,58 @@ fn test() { | |||
507 | } | 507 | } |
508 | 508 | ||
509 | #[test] | 509 | #[test] |
510 | fn infer_impl_generics() { | ||
511 | check_inference( | ||
512 | "infer_impl_generics", | ||
513 | r#" | ||
514 | struct A<T1, T2> { | ||
515 | x: T1, | ||
516 | y: T2, | ||
517 | } | ||
518 | impl<Y, X> A<X, Y> { | ||
519 | fn x(self) -> X { | ||
520 | self.x | ||
521 | } | ||
522 | fn y(self) -> Y { | ||
523 | self.y | ||
524 | } | ||
525 | fn z<T>(self, t: T) -> (X, Y, T) { | ||
526 | (self.x, self.y, t) | ||
527 | } | ||
528 | } | ||
529 | |||
530 | fn test() -> i128 { | ||
531 | let a = A { x: 1u64, y: 1i64 }; | ||
532 | a.x(); | ||
533 | a.y(); | ||
534 | a.z(1i128); | ||
535 | a.z::<u128>(1); | ||
536 | } | ||
537 | "#, | ||
538 | ); | ||
539 | } | ||
540 | |||
541 | #[test] | ||
542 | fn infer_impl_generics_with_autoderef() { | ||
543 | check_inference( | ||
544 | "infer_impl_generics_with_autoderef", | ||
545 | r#" | ||
546 | enum Option<T> { | ||
547 | Some(T), | ||
548 | None, | ||
549 | } | ||
550 | impl<T> Option<T> { | ||
551 | fn as_ref(&self) -> Option<&T> {} | ||
552 | } | ||
553 | fn test(o: Option<u32>) { | ||
554 | (&o).as_ref(); | ||
555 | o.as_ref(); | ||
556 | } | ||
557 | "#, | ||
558 | ); | ||
559 | } | ||
560 | |||
561 | #[test] | ||
510 | fn infer_generic_chain() { | 562 | fn infer_generic_chain() { |
511 | check_inference( | 563 | check_inference( |
512 | "infer_generic_chain", | 564 | "infer_generic_chain", |