aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-02-17 13:43:59 +0000
committerFlorian Diebold <[email protected]>2019-02-17 13:44:39 +0000
commit795d718ba17545aedb0475051332aed6db2104ed (patch)
tree652dac8b0a8dbd299f9b2a6696c1714076aab341
parenta1bda3fc084bb6aa4979282b4907db9885fac9af (diff)
Unify with the autorefed/autoderefed receiver type during method resolution
-rw-r--r--crates/ra_hir/src/ty.rs18
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs12
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap16
-rw-r--r--crates/ra_hir/src/ty/tests.rs20
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs2
5 files changed, 55 insertions, 13 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---
2created: "2019-02-17T13:35:06.385679926Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&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]
542fn infer_impl_generics_with_autoderef() {
543 check_inference(
544 "infer_impl_generics_with_autoderef",
545 r#"
546enum Option<T> {
547 Some(T),
548 None,
549}
550impl<T> Option<T> {
551 fn as_ref(&self) -> Option<&T> {}
552}
553fn test(o: Option<u32>) {
554 (&o).as_ref();
555 o.as_ref();
556}
557"#,
558 );
559}
560
561#[test]
542fn infer_generic_chain() { 562fn infer_generic_chain() {
543 check_inference( 563 check_inference(
544 "infer_generic_chain", 564 "infer_generic_chain",
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index be839345f..20fa323ce 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -63,7 +63,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
63} 63}
64 64
65fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 65fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
66 receiver.iterate_methods(ctx.db, |func| { 66 receiver.iterate_methods(ctx.db, |_ty, func| {
67 let sig = func.signature(ctx.db); 67 let sig = func.signature(ctx.db);
68 if sig.has_self_param() { 68 if sig.has_self_param() {
69 CompletionItem::new( 69 CompletionItem::new(