diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-17 21:15:31 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-25 23:02:04 +0100 |
commit | 5205c84ec7d6284b258e66a06c3e330c3f9fdd88 (patch) | |
tree | 0f91cb3081f435dd547f9183b145ce1c58164ab1 /crates/ra_hir/src | |
parent | 870ce4b1a50a07e3a536ab26215804acdfc9ba8a (diff) |
Support auto-deref in argument position
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 44 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 118 |
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, ¶m_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] |
804 | fn infer_argument_autoderef() { | ||
805 | assert_snapshot!( | ||
806 | infer(r#" | ||
807 | #[lang = "deref"] | ||
808 | pub trait Deref { | ||
809 | type Target: ?Sized; | ||
810 | fn deref(&self) -> &Self::Target; | ||
811 | } | ||
812 | |||
813 | struct A<T>(T); | ||
814 | |||
815 | impl<T: Copy> A<T> { | ||
816 | fn foo(&self) -> T { | ||
817 | self.0 | ||
818 | } | ||
819 | } | ||
820 | |||
821 | struct B<T>(T); | ||
822 | |||
823 | impl<T> Deref for B<T> { | ||
824 | type Target = T; | ||
825 | fn deref(&self) -> &Self::Target { | ||
826 | &self.0 | ||
827 | } | ||
828 | } | ||
829 | |||
830 | fn 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] | ||
862 | fn infer_method_argument_autoderef() { | ||
863 | assert_snapshot!( | ||
864 | infer(r#" | ||
865 | #[lang = "deref"] | ||
866 | pub trait Deref { | ||
867 | type Target: ?Sized; | ||
868 | fn deref(&self) -> &Self::Target; | ||
869 | } | ||
870 | |||
871 | struct A<T>(*mut T); | ||
872 | |||
873 | impl<T: Copy> A<T> { | ||
874 | fn foo(&self, x: &A<T>) -> T { | ||
875 | x | ||
876 | } | ||
877 | } | ||
878 | |||
879 | struct B<T>(T); | ||
880 | |||
881 | impl<T> Deref for B<T> { | ||
882 | type Target = T; | ||
883 | fn deref(&self) -> &Self::Target { | ||
884 | &self.0 | ||
885 | } | ||
886 | } | ||
887 | |||
888 | fn 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] | ||
804 | fn bug_484() { | 922 | fn bug_484() { |
805 | assert_snapshot!( | 923 | assert_snapshot!( |
806 | infer(r#" | 924 | infer(r#" |