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 {
|
fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||||
let ty = self.infer_expr_inner(tgt_expr, expected);
|
let ty = self.infer_expr_inner(tgt_expr, expected);
|
||||||
let could_unify = self.unify(&ty, &expected.ty);
|
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);
|
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]
|
#[test]
|
||||||
fn bug_484() {
|
fn bug_484() {
|
||||||
assert_snapshot!(
|
assert_snapshot!(
|
||||||
|
|
Loading…
Reference in a new issue