From 5205c84ec7d6284b258e66a06c3e330c3f9fdd88 Mon Sep 17 00:00:00 2001 From: uHOOCCOOHu Date: Wed, 18 Sep 2019 04:15:31 +0800 Subject: Support auto-deref in argument position --- crates/ra_hir/src/ty/infer.rs | 44 +++++++++++++++- crates/ra_hir/src/ty/tests.rs | 118 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 76b4b6faa..746b07a05 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -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); } } } diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f4f63ca93..6076e4025 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -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); + +impl A { + fn foo(&self) -> T { + self.0 + } +} + +struct B(T); + +impl Deref for B { + 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 + [164; 186) '{ ... }': T + [174; 178) 'self': &A + [174; 180) 'self.0': T + [267; 271) 'self': &B + [290; 313) '{ ... }': &T + [300; 307) '&self.0': &T + [301; 305) 'self': &B + [301; 307) 'self.0': T + [327; 357) '{ ...))); }': () + [333; 339) 'A::foo': fn foo(&A) -> T + [333; 354) 'A::foo...42))))': i32 + [340; 353) '&&B(B(A(42)))': &&B>> + [341; 353) '&B(B(A(42)))': &B>> + [342; 343) 'B': B>>(T) -> B + [342; 353) 'B(B(A(42)))': B>> + [344; 345) 'B': B>(T) -> B + [344; 352) 'B(A(42))': B> + [346; 347) 'A': A(T) -> A + [346; 351) 'A(42)': A + [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(*mut T); + +impl A { + fn foo(&self, x: &A) -> T { + x + } +} + +struct B(T); + +impl Deref for B { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +fn test(a: A) { + A(0 as *mut _).foo(&&B(B(a))); +} +"#), + @r###" + [76; 80) 'self': &Self + [158; 162) 'self': &A + [164; 165) 'x': &A + [179; 196) '{ ... }': &A + [189; 190) 'x': &A + [277; 281) 'self': &B + [300; 323) '{ ... }': &T + [310; 317) '&self.0': &T + [311; 315) 'self': &B + [311; 317) 'self.0': T + [335; 336) 'a': A + [346; 384) '{ ...))); }': () + [352; 353) 'A': A(*mut T) -> A + [352; 366) 'A(0 as *mut _)': A + [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>> + [372; 380) '&B(B(a))': &B>> + [373; 374) 'B': B>>(T) -> B + [373; 380) 'B(B(a))': B>> + [375; 376) 'B': B>(T) -> B + [375; 379) 'B(a)': B> + [377; 378) 'a': A +"### + ); +} + #[test] fn bug_484() { assert_snapshot!( -- cgit v1.2.3