mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 09:27:27 +00:00
Support auto-deref in argument position
This commit is contained in:
parent
870ce4b1a5
commit
5205c84ec7
2 changed files with 161 additions and 1 deletions
|
@ -806,6 +806,47 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
}
|
||||
|
||||
fn unify_with_autoderef(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
|
||||
macro_rules! ty_app {
|
||||
($ctor:pat, $param:pat) => {
|
||||
Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param })
|
||||
};
|
||||
}
|
||||
|
||||
// If given type and expected type are compatible reference,
|
||||
// trigger auto-deref.
|
||||
let (_to_mut, from_ty, to_ty) =
|
||||
match (&*self.resolve_ty_shallow(&from_ty), &*self.resolve_ty_shallow(&to_ty)) {
|
||||
(
|
||||
ty_app!(TypeCtor::Ref(from_mut), from_param),
|
||||
ty_app!(TypeCtor::Ref(to_mut), to_param),
|
||||
) if *from_mut == Mutability::Mut || from_mut == to_mut => {
|
||||
(to_mut, from_param[0].clone(), to_param[0].clone())
|
||||
}
|
||||
_ => {
|
||||
// Otherwise, just unify
|
||||
return self.unify(&from_ty, &to_ty);
|
||||
}
|
||||
};
|
||||
|
||||
let canonicalized = self.canonicalizer().canonicalize_ty(from_ty);
|
||||
// FIXME: Auto DerefMut
|
||||
for derefed_ty in
|
||||
autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone())
|
||||
{
|
||||
let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
|
||||
match (&*self.resolve_ty_shallow(&derefed_ty), &*self.resolve_ty_shallow(&to_ty)) {
|
||||
// Unify when constructor matches.
|
||||
(ty_app!(from_ctor, _), ty_app!(to_ctor, _)) if from_ctor == to_ctor => {
|
||||
return self.unify(&derefed_ty, &to_ty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
let ty = self.infer_expr_inner(tgt_expr, expected);
|
||||
let could_unify = self.unify(&ty, &expected.ty);
|
||||
|
@ -1285,7 +1326,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
}
|
||||
|
||||
let param_ty = self.normalize_associated_types_in(param_ty);
|
||||
self.infer_expr(arg, &Expectation::has_type(param_ty));
|
||||
let arg_ty = self.infer_expr_inner(arg, &Expectation::has_type(param_ty.clone()));
|
||||
self.unify_with_autoderef(&arg_ty, ¶m_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -800,6 +800,124 @@ fn test2(a1: *const A, a2: *mut A) {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_argument_autoderef() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
#[lang = "deref"]
|
||||
pub trait Deref {
|
||||
type Target: ?Sized;
|
||||
fn deref(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
struct A<T>(T);
|
||||
|
||||
impl<T: Copy> A<T> {
|
||||
fn foo(&self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct B<T>(T);
|
||||
|
||||
impl<T> Deref for B<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn test() {
|
||||
A::foo(&&B(B(A(42))));
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[76; 80) 'self': &Self
|
||||
[153; 157) 'self': &A<T>
|
||||
[164; 186) '{ ... }': T
|
||||
[174; 178) 'self': &A<T>
|
||||
[174; 180) 'self.0': T
|
||||
[267; 271) 'self': &B<T>
|
||||
[290; 313) '{ ... }': &T
|
||||
[300; 307) '&self.0': &T
|
||||
[301; 305) 'self': &B<T>
|
||||
[301; 307) 'self.0': T
|
||||
[327; 357) '{ ...))); }': ()
|
||||
[333; 339) 'A::foo': fn foo<i32>(&A<T>) -> T
|
||||
[333; 354) 'A::foo...42))))': i32
|
||||
[340; 353) '&&B(B(A(42)))': &&B<B<A<i32>>>
|
||||
[341; 353) '&B(B(A(42)))': &B<B<A<i32>>>
|
||||
[342; 343) 'B': B<B<A<i32>>>(T) -> B<T>
|
||||
[342; 353) 'B(B(A(42)))': B<B<A<i32>>>
|
||||
[344; 345) 'B': B<A<i32>>(T) -> B<T>
|
||||
[344; 352) 'B(A(42))': B<A<i32>>
|
||||
[346; 347) 'A': A<i32>(T) -> A<T>
|
||||
[346; 351) 'A(42)': A<i32>
|
||||
[348; 350) '42': i32
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infer_method_argument_autoderef() {
|
||||
assert_snapshot!(
|
||||
infer(r#"
|
||||
#[lang = "deref"]
|
||||
pub trait Deref {
|
||||
type Target: ?Sized;
|
||||
fn deref(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
struct A<T>(*mut T);
|
||||
|
||||
impl<T: Copy> A<T> {
|
||||
fn foo(&self, x: &A<T>) -> T {
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
struct B<T>(T);
|
||||
|
||||
impl<T> Deref for B<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn test(a: A<i32>) {
|
||||
A(0 as *mut _).foo(&&B(B(a)));
|
||||
}
|
||||
"#),
|
||||
@r###"
|
||||
[76; 80) 'self': &Self
|
||||
[158; 162) 'self': &A<T>
|
||||
[164; 165) 'x': &A<T>
|
||||
[179; 196) '{ ... }': &A<T>
|
||||
[189; 190) 'x': &A<T>
|
||||
[277; 281) 'self': &B<T>
|
||||
[300; 323) '{ ... }': &T
|
||||
[310; 317) '&self.0': &T
|
||||
[311; 315) 'self': &B<T>
|
||||
[311; 317) 'self.0': T
|
||||
[335; 336) 'a': A<i32>
|
||||
[346; 384) '{ ...))); }': ()
|
||||
[352; 353) 'A': A<i32>(*mut T) -> A<T>
|
||||
[352; 366) 'A(0 as *mut _)': A<i32>
|
||||
[352; 381) 'A(0 as...B(a)))': i32
|
||||
[354; 355) '0': i32
|
||||
[354; 365) '0 as *mut _': *mut i32
|
||||
[371; 380) '&&B(B(a))': &&B<B<A<i32>>>
|
||||
[372; 380) '&B(B(a))': &B<B<A<i32>>>
|
||||
[373; 374) 'B': B<B<A<i32>>>(T) -> B<T>
|
||||
[373; 380) 'B(B(a))': B<B<A<i32>>>
|
||||
[375; 376) 'B': B<A<i32>>(T) -> B<T>
|
||||
[375; 379) 'B(a)': B<A<i32>>
|
||||
[377; 378) 'a': A<i32>
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bug_484() {
|
||||
assert_snapshot!(
|
||||
|
|
Loading…
Reference in a new issue