diff options
author | Florian Diebold <[email protected]> | 2019-02-17 13:43:59 +0000 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-02-17 13:44:39 +0000 |
commit | 795d718ba17545aedb0475051332aed6db2104ed (patch) | |
tree | 652dac8b0a8dbd299f9b2a6696c1714076aab341 /crates/ra_hir/src | |
parent | a1bda3fc084bb6aa4979282b4907db9885fac9af (diff) |
Unify with the autorefed/autoderefed receiver type during method resolution
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 20 |
4 files changed, 54 insertions, 12 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index f32c77faf..562ad1f49 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -1381,12 +1381,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1381 | Expr::MethodCall { receiver, args, method_name, generic_args } => { | 1381 | Expr::MethodCall { receiver, args, method_name, generic_args } => { |
1382 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); | 1382 | let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); |
1383 | let resolved = receiver_ty.clone().lookup_method(self.db, method_name); | 1383 | let resolved = receiver_ty.clone().lookup_method(self.db, method_name); |
1384 | let (method_ty, def_generics) = match resolved { | 1384 | let (derefed_receiver_ty, method_ty, def_generics) = match resolved { |
1385 | Some(func) => { | 1385 | Some((ty, func)) => { |
1386 | self.write_method_resolution(tgt_expr, func); | 1386 | self.write_method_resolution(tgt_expr, func); |
1387 | (self.db.type_for_def(func.into()), Some(func.generic_params(self.db))) | 1387 | (ty, self.db.type_for_def(func.into()), Some(func.generic_params(self.db))) |
1388 | } | 1388 | } |
1389 | None => (Ty::Unknown, None), | 1389 | None => (Ty::Unknown, receiver_ty, None), |
1390 | }; | 1390 | }; |
1391 | // handle provided type arguments | 1391 | // handle provided type arguments |
1392 | let method_ty = if let Some(generic_args) = generic_args { | 1392 | let method_ty = if let Some(generic_args) = generic_args { |
@@ -1429,9 +1429,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1429 | } | 1429 | } |
1430 | _ => (Ty::Unknown, Vec::new(), Ty::Unknown), | 1430 | _ => (Ty::Unknown, Vec::new(), Ty::Unknown), |
1431 | }; | 1431 | }; |
1432 | // TODO we would have to apply the autoderef/autoref steps here | 1432 | // Apply autoref so the below unification works correctly |
1433 | // to get the correct receiver type to unify... | 1433 | let actual_receiver_ty = match expected_receiver_ty { |
1434 | self.unify(&expected_receiver_ty, &receiver_ty); | 1434 | Ty::Ref(_, mutability) => Ty::Ref(Arc::new(derefed_receiver_ty), mutability), |
1435 | _ => derefed_receiver_ty, | ||
1436 | }; | ||
1437 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | ||
1438 | |||
1435 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 1439 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); |
1436 | for (arg, param) in args.iter().zip(param_iter) { | 1440 | for (arg, param) in args.iter().zip(param_iter) { |
1437 | self.infer_expr(*arg, &Expectation::has_type(param)); | 1441 | self.infer_expr(*arg, &Expectation::has_type(param)); |
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_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 1eca68dc5..5eb9c4f5b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -539,6 +539,26 @@ fn test() -> i128 { | |||
539 | } | 539 | } |
540 | 540 | ||
541 | #[test] | 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] | ||
542 | fn infer_generic_chain() { | 562 | fn infer_generic_chain() { |
543 | check_inference( | 563 | check_inference( |
544 | "infer_generic_chain", | 564 | "infer_generic_chain", |