mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Unify with the autorefed/autoderefed receiver type during method resolution
This commit is contained in:
parent
a1bda3fc08
commit
795d718ba1
5 changed files with 55 additions and 13 deletions
|
@ -1381,12 +1381,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
Expr::MethodCall { receiver, args, method_name, generic_args } => {
|
Expr::MethodCall { receiver, args, method_name, generic_args } => {
|
||||||
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
|
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
|
||||||
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
|
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
|
||||||
let (method_ty, def_generics) = match resolved {
|
let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
|
||||||
Some(func) => {
|
Some((ty, func)) => {
|
||||||
self.write_method_resolution(tgt_expr, func);
|
self.write_method_resolution(tgt_expr, func);
|
||||||
(self.db.type_for_def(func.into()), Some(func.generic_params(self.db)))
|
(ty, self.db.type_for_def(func.into()), Some(func.generic_params(self.db)))
|
||||||
}
|
}
|
||||||
None => (Ty::Unknown, None),
|
None => (Ty::Unknown, receiver_ty, None),
|
||||||
};
|
};
|
||||||
// handle provided type arguments
|
// handle provided type arguments
|
||||||
let method_ty = if let Some(generic_args) = generic_args {
|
let method_ty = if let Some(generic_args) = generic_args {
|
||||||
|
@ -1429,9 +1429,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
|
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
|
||||||
};
|
};
|
||||||
// TODO we would have to apply the autoderef/autoref steps here
|
// Apply autoref so the below unification works correctly
|
||||||
// to get the correct receiver type to unify...
|
let actual_receiver_ty = match expected_receiver_ty {
|
||||||
self.unify(&expected_receiver_ty, &receiver_ty);
|
Ty::Ref(_, mutability) => Ty::Ref(Arc::new(derefed_receiver_ty), mutability),
|
||||||
|
_ => derefed_receiver_ty,
|
||||||
|
};
|
||||||
|
self.unify(&expected_receiver_ty, &actual_receiver_ty);
|
||||||
|
|
||||||
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
|
let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
|
||||||
for (arg, param) in args.iter().zip(param_iter) {
|
for (arg, param) in args.iter().zip(param_iter) {
|
||||||
self.infer_expr(*arg, &Expectation::has_type(param));
|
self.infer_expr(*arg, &Expectation::has_type(param));
|
||||||
|
|
|
@ -118,11 +118,13 @@ impl Ty {
|
||||||
// TODO: cache this as a query?
|
// TODO: cache this as a query?
|
||||||
// - if so, what signature? (TyFingerprint, Name)?
|
// - if so, what signature? (TyFingerprint, Name)?
|
||||||
// - or maybe cache all names and def_ids of methods per fingerprint?
|
// - or maybe cache all names and def_ids of methods per fingerprint?
|
||||||
pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> {
|
/// Look up the method with the given name, returning the actual autoderefed
|
||||||
self.iterate_methods(db, |f| {
|
/// receiver type (but without autoref applied yet).
|
||||||
|
pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> {
|
||||||
|
self.iterate_methods(db, |ty, f| {
|
||||||
let sig = f.signature(db);
|
let sig = f.signature(db);
|
||||||
if sig.name() == name && sig.has_self_param() {
|
if sig.name() == name && sig.has_self_param() {
|
||||||
Some(f)
|
Some((ty.clone(), f))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -134,7 +136,7 @@ impl Ty {
|
||||||
pub fn iterate_methods<T>(
|
pub fn iterate_methods<T>(
|
||||||
self,
|
self,
|
||||||
db: &impl HirDatabase,
|
db: &impl HirDatabase,
|
||||||
mut callback: impl FnMut(Function) -> Option<T>,
|
mut callback: impl FnMut(&Ty, Function) -> Option<T>,
|
||||||
) -> Option<T> {
|
) -> Option<T> {
|
||||||
// For method calls, rust first does any number of autoderef, and then one
|
// For method calls, rust first does any number of autoderef, and then one
|
||||||
// autoref (i.e. when the method takes &self or &mut self). We just ignore
|
// autoref (i.e. when the method takes &self or &mut self). We just ignore
|
||||||
|
@ -156,7 +158,7 @@ impl Ty {
|
||||||
for item in impl_block.items(db) {
|
for item in impl_block.items(db) {
|
||||||
match item {
|
match item {
|
||||||
ImplItem::Method(f) => {
|
ImplItem::Method(f) => {
|
||||||
if let Some(result) = callback(f) {
|
if let Some(result) = callback(&derefed_ty, f) {
|
||||||
return Some(result);
|
return Some(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
---
|
||||||
|
created: "2019-02-17T13:35:06.385679926Z"
|
||||||
|
creator: insta@0.6.2
|
||||||
|
source: crates/ra_hir/src/ty/tests.rs
|
||||||
|
expression: "&result"
|
||||||
|
---
|
||||||
|
[78; 82) 'self': &Option<T>
|
||||||
|
[98; 100) '{}': ()
|
||||||
|
[111; 112) 'o': Option<u32>
|
||||||
|
[127; 165) '{ ...f(); }': ()
|
||||||
|
[133; 146) '(&o).as_ref()': Option<&u32>
|
||||||
|
[134; 136) '&o': &Option<u32>
|
||||||
|
[135; 136) 'o': Option<u32>
|
||||||
|
[152; 153) 'o': Option<u32>
|
||||||
|
[152; 162) 'o.as_ref()': Option<&u32>
|
||||||
|
|
|
@ -538,6 +538,26 @@ fn test() -> i128 {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn infer_impl_generics_with_autoderef() {
|
||||||
|
check_inference(
|
||||||
|
"infer_impl_generics_with_autoderef",
|
||||||
|
r#"
|
||||||
|
enum Option<T> {
|
||||||
|
Some(T),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
impl<T> Option<T> {
|
||||||
|
fn as_ref(&self) -> Option<&T> {}
|
||||||
|
}
|
||||||
|
fn test(o: Option<u32>) {
|
||||||
|
(&o).as_ref();
|
||||||
|
o.as_ref();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_generic_chain() {
|
fn infer_generic_chain() {
|
||||||
check_inference(
|
check_inference(
|
||||||
|
|
|
@ -63,7 +63,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
|
fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
|
||||||
receiver.iterate_methods(ctx.db, |func| {
|
receiver.iterate_methods(ctx.db, |_ty, func| {
|
||||||
let sig = func.signature(ctx.db);
|
let sig = func.signature(ctx.db);
|
||||||
if sig.has_self_param() {
|
if sig.has_self_param() {
|
||||||
CompletionItem::new(
|
CompletionItem::new(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue