aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
authoruHOOCCOOHu <[email protected]>2019-09-17 21:15:31 +0100
committeruHOOCCOOHu <[email protected]>2019-09-25 23:02:04 +0100
commit5205c84ec7d6284b258e66a06c3e330c3f9fdd88 (patch)
tree0f91cb3081f435dd547f9183b145ce1c58164ab1 /crates/ra_hir/src
parent870ce4b1a50a07e3a536ab26215804acdfc9ba8a (diff)
Support auto-deref in argument position
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/ty/infer.rs44
-rw-r--r--crates/ra_hir/src/ty/tests.rs118
2 files changed, 161 insertions, 1 deletions
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> {
806 } 806 }
807 } 807 }
808 808
809 fn unify_with_autoderef(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
810 macro_rules! ty_app {
811 ($ctor:pat, $param:pat) => {
812 Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param })
813 };
814 }
815
816 // If given type and expected type are compatible reference,
817 // trigger auto-deref.
818 let (_to_mut, from_ty, to_ty) =
819 match (&*self.resolve_ty_shallow(&from_ty), &*self.resolve_ty_shallow(&to_ty)) {
820 (
821 ty_app!(TypeCtor::Ref(from_mut), from_param),
822 ty_app!(TypeCtor::Ref(to_mut), to_param),
823 ) if *from_mut == Mutability::Mut || from_mut == to_mut => {
824 (to_mut, from_param[0].clone(), to_param[0].clone())
825 }
826 _ => {
827 // Otherwise, just unify
828 return self.unify(&from_ty, &to_ty);
829 }
830 };
831
832 let canonicalized = self.canonicalizer().canonicalize_ty(from_ty);
833 // FIXME: Auto DerefMut
834 for derefed_ty in
835 autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone())
836 {
837 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
838 match (&*self.resolve_ty_shallow(&derefed_ty), &*self.resolve_ty_shallow(&to_ty)) {
839 // Unify when constructor matches.
840 (ty_app!(from_ctor, _), ty_app!(to_ctor, _)) if from_ctor == to_ctor => {
841 return self.unify(&derefed_ty, &to_ty);
842 }
843 _ => {}
844 }
845 }
846
847 false
848 }
849
809 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 850 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
810 let ty = self.infer_expr_inner(tgt_expr, expected); 851 let ty = self.infer_expr_inner(tgt_expr, expected);
811 let could_unify = self.unify(&ty, &expected.ty); 852 let could_unify = self.unify(&ty, &expected.ty);
@@ -1285,7 +1326,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1285 } 1326 }
1286 1327
1287 let param_ty = self.normalize_associated_types_in(param_ty); 1328 let param_ty = self.normalize_associated_types_in(param_ty);
1288 self.infer_expr(arg, &Expectation::has_type(param_ty)); 1329 let arg_ty = self.infer_expr_inner(arg, &Expectation::has_type(param_ty.clone()));
1330 self.unify_with_autoderef(&arg_ty, &param_ty);
1289 } 1331 }
1290 } 1332 }
1291 } 1333 }
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
@@ -801,6 +801,124 @@ fn test2(a1: *const A, a2: *mut A) {
801} 801}
802 802
803#[test] 803#[test]
804fn infer_argument_autoderef() {
805 assert_snapshot!(
806 infer(r#"
807#[lang = "deref"]
808pub trait Deref {
809 type Target: ?Sized;
810 fn deref(&self) -> &Self::Target;
811}
812
813struct A<T>(T);
814
815impl<T: Copy> A<T> {
816 fn foo(&self) -> T {
817 self.0
818 }
819}
820
821struct B<T>(T);
822
823impl<T> Deref for B<T> {
824 type Target = T;
825 fn deref(&self) -> &Self::Target {
826 &self.0
827 }
828}
829
830fn test() {
831 A::foo(&&B(B(A(42))));
832}
833"#),
834 @r###"
835 [76; 80) 'self': &Self
836 [153; 157) 'self': &A<T>
837 [164; 186) '{ ... }': T
838 [174; 178) 'self': &A<T>
839 [174; 180) 'self.0': T
840 [267; 271) 'self': &B<T>
841 [290; 313) '{ ... }': &T
842 [300; 307) '&self.0': &T
843 [301; 305) 'self': &B<T>
844 [301; 307) 'self.0': T
845 [327; 357) '{ ...))); }': ()
846 [333; 339) 'A::foo': fn foo<i32>(&A<T>) -> T
847 [333; 354) 'A::foo...42))))': i32
848 [340; 353) '&&B(B(A(42)))': &&B<B<A<i32>>>
849 [341; 353) '&B(B(A(42)))': &B<B<A<i32>>>
850 [342; 343) 'B': B<B<A<i32>>>(T) -> B<T>
851 [342; 353) 'B(B(A(42)))': B<B<A<i32>>>
852 [344; 345) 'B': B<A<i32>>(T) -> B<T>
853 [344; 352) 'B(A(42))': B<A<i32>>
854 [346; 347) 'A': A<i32>(T) -> A<T>
855 [346; 351) 'A(42)': A<i32>
856 [348; 350) '42': i32
857"###
858 );
859}
860
861#[test]
862fn infer_method_argument_autoderef() {
863 assert_snapshot!(
864 infer(r#"
865#[lang = "deref"]
866pub trait Deref {
867 type Target: ?Sized;
868 fn deref(&self) -> &Self::Target;
869}
870
871struct A<T>(*mut T);
872
873impl<T: Copy> A<T> {
874 fn foo(&self, x: &A<T>) -> T {
875 x
876 }
877}
878
879struct B<T>(T);
880
881impl<T> Deref for B<T> {
882 type Target = T;
883 fn deref(&self) -> &Self::Target {
884 &self.0
885 }
886}
887
888fn test(a: A<i32>) {
889 A(0 as *mut _).foo(&&B(B(a)));
890}
891"#),
892 @r###"
893 [76; 80) 'self': &Self
894 [158; 162) 'self': &A<T>
895 [164; 165) 'x': &A<T>
896 [179; 196) '{ ... }': &A<T>
897 [189; 190) 'x': &A<T>
898 [277; 281) 'self': &B<T>
899 [300; 323) '{ ... }': &T
900 [310; 317) '&self.0': &T
901 [311; 315) 'self': &B<T>
902 [311; 317) 'self.0': T
903 [335; 336) 'a': A<i32>
904 [346; 384) '{ ...))); }': ()
905 [352; 353) 'A': A<i32>(*mut T) -> A<T>
906 [352; 366) 'A(0 as *mut _)': A<i32>
907 [352; 381) 'A(0 as...B(a)))': i32
908 [354; 355) '0': i32
909 [354; 365) '0 as *mut _': *mut i32
910 [371; 380) '&&B(B(a))': &&B<B<A<i32>>>
911 [372; 380) '&B(B(a))': &B<B<A<i32>>>
912 [373; 374) 'B': B<B<A<i32>>>(T) -> B<T>
913 [373; 380) 'B(B(a))': B<B<A<i32>>>
914 [375; 376) 'B': B<A<i32>>(T) -> B<T>
915 [375; 379) 'B(a)': B<A<i32>>
916 [377; 378) 'a': A<i32>
917"###
918 );
919}
920
921#[test]
804fn bug_484() { 922fn bug_484() {
805 assert_snapshot!( 923 assert_snapshot!(
806 infer(r#" 924 infer(r#"