diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 207 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 202 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/coercion.rs | 278 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/never_type.rs | 36 |
4 files changed, 476 insertions, 247 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index cbbba8b23..ba63050a9 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -42,6 +42,7 @@ use crate::{ | |||
42 | RecordFieldPat, Statement, UnaryOp, | 42 | RecordFieldPat, Statement, UnaryOp, |
43 | }, | 43 | }, |
44 | generics::{GenericParams, HasGenericParams}, | 44 | generics::{GenericParams, HasGenericParams}, |
45 | lang_item::LangItemTarget, | ||
45 | name, | 46 | name, |
46 | nameres::Namespace, | 47 | nameres::Namespace, |
47 | path::{known, GenericArg, GenericArgs}, | 48 | path::{known, GenericArg, GenericArgs}, |
@@ -188,6 +189,12 @@ struct InferenceContext<'a, D: HirDatabase> { | |||
188 | result: InferenceResult, | 189 | result: InferenceResult, |
189 | /// The return type of the function being inferred. | 190 | /// The return type of the function being inferred. |
190 | return_ty: Ty, | 191 | return_ty: Ty, |
192 | |||
193 | /// Impls of `CoerceUnsized` used in coercion. | ||
194 | /// (from_ty_ctor, to_ty_ctor) => coerce_generic_index | ||
195 | // FIXME: Use trait solver for this. | ||
196 | // Chalk seems unable to work well with builtin impl of `Unsize` now. | ||
197 | coerce_unsized_map: FxHashMap<(TypeCtor, TypeCtor), usize>, | ||
191 | } | 198 | } |
192 | 199 | ||
193 | macro_rules! ty_app { | 200 | macro_rules! ty_app { |
@@ -207,12 +214,52 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
207 | obligations: Vec::default(), | 214 | obligations: Vec::default(), |
208 | return_ty: Ty::Unknown, // set in collect_fn_signature | 215 | return_ty: Ty::Unknown, // set in collect_fn_signature |
209 | trait_env: lower::trait_env(db, &resolver), | 216 | trait_env: lower::trait_env(db, &resolver), |
217 | coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), | ||
210 | db, | 218 | db, |
211 | body, | 219 | body, |
212 | resolver, | 220 | resolver, |
213 | } | 221 | } |
214 | } | 222 | } |
215 | 223 | ||
224 | fn init_coerce_unsized_map( | ||
225 | db: &'a D, | ||
226 | resolver: &Resolver, | ||
227 | ) -> FxHashMap<(TypeCtor, TypeCtor), usize> { | ||
228 | let krate = resolver.krate().unwrap(); | ||
229 | let impls = match db.lang_item(krate, "coerce_unsized".into()) { | ||
230 | Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate, trait_), | ||
231 | _ => return FxHashMap::default(), | ||
232 | }; | ||
233 | |||
234 | impls | ||
235 | .iter() | ||
236 | .filter_map(|impl_block| { | ||
237 | // `CoerseUnsized` has one generic parameter for the target type. | ||
238 | let trait_ref = impl_block.target_trait_ref(db)?; | ||
239 | let cur_from_ty = trait_ref.substs.0.get(0)?; | ||
240 | let cur_to_ty = trait_ref.substs.0.get(1)?; | ||
241 | |||
242 | match (&cur_from_ty, cur_to_ty) { | ||
243 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => { | ||
244 | // FIXME: We return the first non-equal bound as the type parameter to coerce to unsized type. | ||
245 | // This works for smart-pointer-like coercion, which covers all impls from std. | ||
246 | st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { | ||
247 | match (ty1, ty2) { | ||
248 | (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. }) | ||
249 | if p1 != p2 => | ||
250 | { | ||
251 | Some(((*ctor1, *ctor2), i)) | ||
252 | } | ||
253 | _ => None, | ||
254 | } | ||
255 | }) | ||
256 | } | ||
257 | _ => None, | ||
258 | } | ||
259 | }) | ||
260 | .collect() | ||
261 | } | ||
262 | |||
216 | fn resolve_all(mut self) -> InferenceResult { | 263 | fn resolve_all(mut self) -> InferenceResult { |
217 | // FIXME resolve obligations as well (use Guidance if necessary) | 264 | // FIXME resolve obligations as well (use Guidance if necessary) |
218 | let mut result = mem::replace(&mut self.result, InferenceResult::default()); | 265 | let mut result = mem::replace(&mut self.result, InferenceResult::default()); |
@@ -919,16 +966,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
919 | _ => {} | 966 | _ => {} |
920 | } | 967 | } |
921 | 968 | ||
922 | // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. | 969 | if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) { |
923 | match (&from_ty, &to_ty) { | 970 | return ret; |
924 | // Mutilibity is checked above | ||
925 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) | ||
926 | | (ty_app!(TypeCtor::RawPtr(_), st1), ty_app!(TypeCtor::RawPtr(_), st2)) => { | ||
927 | if self.try_coerce_unsized(&st1[0], &st2[0], 0) { | ||
928 | return true; | ||
929 | } | ||
930 | } | ||
931 | _ => {} | ||
932 | } | 971 | } |
933 | 972 | ||
934 | // Auto Deref if cannot coerce | 973 | // Auto Deref if cannot coerce |
@@ -943,10 +982,43 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
943 | } | 982 | } |
944 | } | 983 | } |
945 | 984 | ||
946 | /// Coerce a type to a DST if `FromTy: Unsize<ToTy>` | 985 | /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>` |
947 | /// | 986 | /// |
948 | /// See: `https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html` | 987 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html |
949 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> bool { | 988 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { |
989 | let (ctor1, st1, ctor2, st2) = match (from_ty, to_ty) { | ||
990 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => (ctor1, st1, ctor2, st2), | ||
991 | _ => return None, | ||
992 | }; | ||
993 | |||
994 | let coerce_generic_index = *self.coerce_unsized_map.get(&(*ctor1, *ctor2))?; | ||
995 | |||
996 | // Check `Unsize` first | ||
997 | match self.check_unsize_and_coerce( | ||
998 | st1.0.get(coerce_generic_index)?, | ||
999 | st2.0.get(coerce_generic_index)?, | ||
1000 | 0, | ||
1001 | ) { | ||
1002 | Some(true) => {} | ||
1003 | ret => return ret, | ||
1004 | } | ||
1005 | |||
1006 | let ret = st1 | ||
1007 | .iter() | ||
1008 | .zip(st2.iter()) | ||
1009 | .enumerate() | ||
1010 | .filter(|&(idx, _)| idx != coerce_generic_index) | ||
1011 | .all(|(_, (ty1, ty2))| self.unify(ty1, ty2)); | ||
1012 | |||
1013 | Some(ret) | ||
1014 | } | ||
1015 | |||
1016 | /// Check if `from_ty: Unsize<to_ty>`, and coerce to `to_ty` if it holds. | ||
1017 | /// | ||
1018 | /// It should not be directly called. It is only used by `try_coerce_unsized`. | ||
1019 | /// | ||
1020 | /// See: https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html | ||
1021 | fn check_unsize_and_coerce(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> { | ||
950 | if depth > 1000 { | 1022 | if depth > 1000 { |
951 | panic!("Infinite recursion in coercion"); | 1023 | panic!("Infinite recursion in coercion"); |
952 | } | 1024 | } |
@@ -954,29 +1026,113 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
954 | match (&from_ty, &to_ty) { | 1026 | match (&from_ty, &to_ty) { |
955 | // `[T; N]` -> `[T]` | 1027 | // `[T; N]` -> `[T]` |
956 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { | 1028 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { |
957 | self.unify(&st1[0], &st2[0]) | 1029 | Some(self.unify(&st1[0], &st2[0])) |
958 | } | 1030 | } |
959 | 1031 | ||
960 | // `T` -> `dyn Trait` when `T: Trait` | 1032 | // `T` -> `dyn Trait` when `T: Trait` |
961 | (_, Ty::Dyn(_)) => { | 1033 | (_, Ty::Dyn(_)) => { |
962 | // FIXME: Check predicates | 1034 | // FIXME: Check predicates |
963 | true | 1035 | Some(true) |
964 | } | 1036 | } |
965 | 1037 | ||
1038 | // `(..., T)` -> `(..., U)` when `T: Unsize<U>` | ||
1039 | ( | ||
1040 | ty_app!(TypeCtor::Tuple { cardinality: len1 }, st1), | ||
1041 | ty_app!(TypeCtor::Tuple { cardinality: len2 }, st2), | ||
1042 | ) => { | ||
1043 | if len1 != len2 || *len1 == 0 { | ||
1044 | return None; | ||
1045 | } | ||
1046 | |||
1047 | match self.check_unsize_and_coerce( | ||
1048 | st1.last().unwrap(), | ||
1049 | st2.last().unwrap(), | ||
1050 | depth + 1, | ||
1051 | ) { | ||
1052 | Some(true) => {} | ||
1053 | ret => return ret, | ||
1054 | } | ||
1055 | |||
1056 | let ret = st1[..st1.len() - 1] | ||
1057 | .iter() | ||
1058 | .zip(&st2[..st2.len() - 1]) | ||
1059 | .all(|(ty1, ty2)| self.unify(ty1, ty2)); | ||
1060 | |||
1061 | Some(ret) | ||
1062 | } | ||
1063 | |||
1064 | // Foo<..., T, ...> is Unsize<Foo<..., U, ...>> if: | ||
1065 | // - T: Unsize<U> | ||
1066 | // - Foo is a struct | ||
1067 | // - Only the last field of Foo has a type involving T | ||
1068 | // - T is not part of the type of any other fields | ||
1069 | // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T> | ||
966 | ( | 1070 | ( |
967 | ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1), | 1071 | ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1), |
968 | ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2), | 1072 | ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2), |
969 | ) if struct1 == struct2 => { | 1073 | ) if struct1 == struct2 => { |
970 | // FIXME: Check preconditions here | 1074 | let fields = struct1.fields(self.db); |
971 | for (ty1, ty2) in st1.iter().zip(st2.iter()) { | 1075 | let (last_field, prev_fields) = fields.split_last()?; |
972 | if !self.try_coerce_unsized(ty1, ty2, depth + 1) { | 1076 | |
973 | return false; | 1077 | // Get the generic parameter involved in the last field. |
1078 | let unsize_generic_index = { | ||
1079 | let mut index = None; | ||
1080 | let mut multiple_param = false; | ||
1081 | last_field.ty(self.db).walk(&mut |ty| match ty { | ||
1082 | &Ty::Param { idx, .. } => { | ||
1083 | if index.is_none() { | ||
1084 | index = Some(idx); | ||
1085 | } else if Some(idx) != index { | ||
1086 | multiple_param = true; | ||
1087 | } | ||
1088 | } | ||
1089 | _ => {} | ||
1090 | }); | ||
1091 | |||
1092 | if multiple_param { | ||
1093 | return None; | ||
974 | } | 1094 | } |
1095 | index? | ||
1096 | }; | ||
1097 | |||
1098 | // Check other fields do not involve it. | ||
1099 | let mut multiple_used = false; | ||
1100 | prev_fields.iter().for_each(|field| { | ||
1101 | field.ty(self.db).walk(&mut |ty| match ty { | ||
1102 | &Ty::Param { idx, .. } if idx == unsize_generic_index => { | ||
1103 | multiple_used = true | ||
1104 | } | ||
1105 | _ => {} | ||
1106 | }) | ||
1107 | }); | ||
1108 | if multiple_used { | ||
1109 | return None; | ||
975 | } | 1110 | } |
976 | true | 1111 | |
1112 | let unsize_generic_index = unsize_generic_index as usize; | ||
1113 | |||
1114 | // Check `Unsize` first | ||
1115 | match self.check_unsize_and_coerce( | ||
1116 | st1.get(unsize_generic_index)?, | ||
1117 | st2.get(unsize_generic_index)?, | ||
1118 | depth + 1, | ||
1119 | ) { | ||
1120 | Some(true) => {} | ||
1121 | ret => return ret, | ||
1122 | } | ||
1123 | |||
1124 | // Then unify other parameters | ||
1125 | let ret = st1 | ||
1126 | .iter() | ||
1127 | .zip(st2.iter()) | ||
1128 | .enumerate() | ||
1129 | .filter(|&(idx, _)| idx != unsize_generic_index) | ||
1130 | .all(|(_, (ty1, ty2))| self.unify(ty1, ty2)); | ||
1131 | |||
1132 | Some(ret) | ||
977 | } | 1133 | } |
978 | 1134 | ||
979 | _ => false, | 1135 | _ => None, |
980 | } | 1136 | } |
981 | } | 1137 | } |
982 | 1138 | ||
@@ -1433,12 +1589,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1433 | let decl_ty = | 1589 | let decl_ty = |
1434 | type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); | 1590 | type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown); |
1435 | let decl_ty = self.insert_type_vars(decl_ty); | 1591 | let decl_ty = self.insert_type_vars(decl_ty); |
1436 | let ty = if let Some(expr) = initializer { | 1592 | if let Some(expr) = initializer { |
1437 | self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty)) | 1593 | self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone())); |
1438 | } else { | 1594 | } |
1439 | decl_ty | ||
1440 | }; | ||
1441 | 1595 | ||
1596 | let ty = self.resolve_ty_as_possible(&mut vec![], decl_ty); | ||
1442 | self.infer_pat(*pat, &ty, BindingMode::default()); | 1597 | self.infer_pat(*pat, &ty, BindingMode::default()); |
1443 | } | 1598 | } |
1444 | Statement::Expr(expr) => { | 1599 | Statement::Expr(expr) => { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 081bfe37c..cd5a05092 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -21,6 +21,7 @@ use crate::{ | |||
21 | // update the snapshots. | 21 | // update the snapshots. |
22 | 22 | ||
23 | mod never_type; | 23 | mod never_type; |
24 | mod coercion; | ||
24 | 25 | ||
25 | #[test] | 26 | #[test] |
26 | fn infer_await() { | 27 | fn infer_await() { |
@@ -926,196 +927,6 @@ fn test(a: A<i32>) { | |||
926 | } | 927 | } |
927 | 928 | ||
928 | #[test] | 929 | #[test] |
929 | fn infer_if_coerce() { | ||
930 | assert_snapshot!( | ||
931 | infer(r#" | ||
932 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
933 | fn test() { | ||
934 | let x = if true { | ||
935 | foo(&[1]) | ||
936 | } else { | ||
937 | &[1] | ||
938 | }; | ||
939 | } | ||
940 | "#), | ||
941 | @r###" | ||
942 | [11; 12) 'x': &[T] | ||
943 | [28; 39) '{ loop {} }': ! | ||
944 | [30; 37) 'loop {}': ! | ||
945 | [35; 37) '{}': () | ||
946 | [50; 126) '{ ... }; }': () | ||
947 | [60; 61) 'x': &[i32] | ||
948 | [64; 123) 'if tru... }': &[i32] | ||
949 | [67; 71) 'true': bool | ||
950 | [72; 97) '{ ... }': &[i32] | ||
951 | [82; 85) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
952 | [82; 91) 'foo(&[1])': &[i32] | ||
953 | [86; 90) '&[1]': &[i32;_] | ||
954 | [87; 90) '[1]': [i32;_] | ||
955 | [88; 89) '1': i32 | ||
956 | [103; 123) '{ ... }': &[i32;_] | ||
957 | [113; 117) '&[1]': &[i32;_] | ||
958 | [114; 117) '[1]': [i32;_] | ||
959 | [115; 116) '1': i32 | ||
960 | "### | ||
961 | ); | ||
962 | } | ||
963 | |||
964 | #[test] | ||
965 | fn infer_if_else_coerce() { | ||
966 | assert_snapshot!( | ||
967 | infer(r#" | ||
968 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
969 | fn test() { | ||
970 | let x = if true { | ||
971 | &[1] | ||
972 | } else { | ||
973 | foo(&[1]) | ||
974 | }; | ||
975 | } | ||
976 | "#), | ||
977 | @r###" | ||
978 | [11; 12) 'x': &[T] | ||
979 | [28; 39) '{ loop {} }': ! | ||
980 | [30; 37) 'loop {}': ! | ||
981 | [35; 37) '{}': () | ||
982 | [50; 126) '{ ... }; }': () | ||
983 | [60; 61) 'x': &[i32] | ||
984 | [64; 123) 'if tru... }': &[i32] | ||
985 | [67; 71) 'true': bool | ||
986 | [72; 92) '{ ... }': &[i32;_] | ||
987 | [82; 86) '&[1]': &[i32;_] | ||
988 | [83; 86) '[1]': [i32;_] | ||
989 | [84; 85) '1': i32 | ||
990 | [98; 123) '{ ... }': &[i32] | ||
991 | [108; 111) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
992 | [108; 117) 'foo(&[1])': &[i32] | ||
993 | [112; 116) '&[1]': &[i32;_] | ||
994 | [113; 116) '[1]': [i32;_] | ||
995 | [114; 115) '1': i32 | ||
996 | "### | ||
997 | ); | ||
998 | } | ||
999 | |||
1000 | #[test] | ||
1001 | fn infer_match_first_coerce() { | ||
1002 | assert_snapshot!( | ||
1003 | infer(r#" | ||
1004 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
1005 | fn test(i: i32) { | ||
1006 | let x = match i { | ||
1007 | 2 => foo(&[2]), | ||
1008 | 1 => &[1], | ||
1009 | _ => &[3], | ||
1010 | }; | ||
1011 | } | ||
1012 | "#), | ||
1013 | @r###" | ||
1014 | [11; 12) 'x': &[T] | ||
1015 | [28; 39) '{ loop {} }': ! | ||
1016 | [30; 37) 'loop {}': ! | ||
1017 | [35; 37) '{}': () | ||
1018 | [48; 49) 'i': i32 | ||
1019 | [56; 150) '{ ... }; }': () | ||
1020 | [66; 67) 'x': &[i32] | ||
1021 | [70; 147) 'match ... }': &[i32] | ||
1022 | [76; 77) 'i': i32 | ||
1023 | [88; 89) '2': i32 | ||
1024 | [93; 96) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
1025 | [93; 102) 'foo(&[2])': &[i32] | ||
1026 | [97; 101) '&[2]': &[i32;_] | ||
1027 | [98; 101) '[2]': [i32;_] | ||
1028 | [99; 100) '2': i32 | ||
1029 | [112; 113) '1': i32 | ||
1030 | [117; 121) '&[1]': &[i32;_] | ||
1031 | [118; 121) '[1]': [i32;_] | ||
1032 | [119; 120) '1': i32 | ||
1033 | [131; 132) '_': i32 | ||
1034 | [136; 140) '&[3]': &[i32;_] | ||
1035 | [137; 140) '[3]': [i32;_] | ||
1036 | [138; 139) '3': i32 | ||
1037 | "### | ||
1038 | ); | ||
1039 | } | ||
1040 | |||
1041 | #[test] | ||
1042 | fn infer_match_second_coerce() { | ||
1043 | assert_snapshot!( | ||
1044 | infer(r#" | ||
1045 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
1046 | fn test(i: i32) { | ||
1047 | let x = match i { | ||
1048 | 1 => &[1], | ||
1049 | 2 => foo(&[2]), | ||
1050 | _ => &[3], | ||
1051 | }; | ||
1052 | } | ||
1053 | "#), | ||
1054 | @r###" | ||
1055 | [11; 12) 'x': &[T] | ||
1056 | [28; 39) '{ loop {} }': ! | ||
1057 | [30; 37) 'loop {}': ! | ||
1058 | [35; 37) '{}': () | ||
1059 | [48; 49) 'i': i32 | ||
1060 | [56; 150) '{ ... }; }': () | ||
1061 | [66; 67) 'x': &[i32] | ||
1062 | [70; 147) 'match ... }': &[i32] | ||
1063 | [76; 77) 'i': i32 | ||
1064 | [88; 89) '1': i32 | ||
1065 | [93; 97) '&[1]': &[i32;_] | ||
1066 | [94; 97) '[1]': [i32;_] | ||
1067 | [95; 96) '1': i32 | ||
1068 | [107; 108) '2': i32 | ||
1069 | [112; 115) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
1070 | [112; 121) 'foo(&[2])': &[i32] | ||
1071 | [116; 120) '&[2]': &[i32;_] | ||
1072 | [117; 120) '[2]': [i32;_] | ||
1073 | [118; 119) '2': i32 | ||
1074 | [131; 132) '_': i32 | ||
1075 | [136; 140) '&[3]': &[i32;_] | ||
1076 | [137; 140) '[3]': [i32;_] | ||
1077 | [138; 139) '3': i32 | ||
1078 | "### | ||
1079 | ); | ||
1080 | } | ||
1081 | |||
1082 | #[test] | ||
1083 | fn coerce_merge_one_by_one1() { | ||
1084 | covers!(coerce_merge_fail_fallback); | ||
1085 | |||
1086 | assert_snapshot!( | ||
1087 | infer(r#" | ||
1088 | fn test() { | ||
1089 | let t = &mut 1; | ||
1090 | let x = match 1 { | ||
1091 | 1 => t as *mut i32, | ||
1092 | 2 => t as &i32, | ||
1093 | _ => t as *const i32, | ||
1094 | }; | ||
1095 | } | ||
1096 | "#), | ||
1097 | @r###" | ||
1098 | [11; 145) '{ ... }; }': () | ||
1099 | [21; 22) 't': &mut i32 | ||
1100 | [25; 31) '&mut 1': &mut i32 | ||
1101 | [30; 31) '1': i32 | ||
1102 | [41; 42) 'x': *const i32 | ||
1103 | [45; 142) 'match ... }': *const i32 | ||
1104 | [51; 52) '1': i32 | ||
1105 | [63; 64) '1': i32 | ||
1106 | [68; 69) 't': &mut i32 | ||
1107 | [68; 81) 't as *mut i32': *mut i32 | ||
1108 | [91; 92) '2': i32 | ||
1109 | [96; 97) 't': &mut i32 | ||
1110 | [96; 105) 't as &i32': &i32 | ||
1111 | [115; 116) '_': i32 | ||
1112 | [120; 121) 't': &mut i32 | ||
1113 | [120; 135) 't as *const i32': *const i32 | ||
1114 | "### | ||
1115 | ); | ||
1116 | } | ||
1117 | |||
1118 | #[test] | ||
1119 | fn bug_484() { | 930 | fn bug_484() { |
1120 | assert_snapshot!( | 931 | assert_snapshot!( |
1121 | infer(r#" | 932 | infer(r#" |
@@ -1302,7 +1113,6 @@ fn test(x: &str, y: isize) { | |||
1302 | } | 1113 | } |
1303 | "#), | 1114 | "#), |
1304 | @r###" | 1115 | @r###" |
1305 | |||
1306 | [9; 10) 'x': &str | 1116 | [9; 10) 'x': &str |
1307 | [18; 19) 'y': isize | 1117 | [18; 19) 'y': isize |
1308 | [28; 324) '{ ... 3]; }': () | 1118 | [28; 324) '{ ... 3]; }': () |
@@ -1355,7 +1165,7 @@ fn test(x: &str, y: isize) { | |||
1355 | [260; 263) '"b"': &str | 1165 | [260; 263) '"b"': &str |
1356 | [275; 276) 'x': [u8;_] | 1166 | [275; 276) 'x': [u8;_] |
1357 | [288; 290) '[]': [u8;_] | 1167 | [288; 290) '[]': [u8;_] |
1358 | [300; 301) 'z': &[u8;_] | 1168 | [300; 301) 'z': &[u8] |
1359 | [311; 321) '&[1, 2, 3]': &[u8;_] | 1169 | [311; 321) '&[1, 2, 3]': &[u8;_] |
1360 | [312; 321) '[1, 2, 3]': [u8;_] | 1170 | [312; 321) '[1, 2, 3]': [u8;_] |
1361 | [313; 314) '1': u8 | 1171 | [313; 314) '1': u8 |
@@ -2288,10 +2098,9 @@ fn test() { | |||
2288 | } | 2098 | } |
2289 | "#), | 2099 | "#), |
2290 | @r###" | 2100 | @r###" |
2291 | |||
2292 | [11; 48) '{ ...&y]; }': () | 2101 | [11; 48) '{ ...&y]; }': () |
2293 | [21; 22) 'y': &{unknown} | 2102 | [21; 22) 'y': &{unknown} |
2294 | [25; 32) 'unknown': &{unknown} | 2103 | [25; 32) 'unknown': &&{unknown} |
2295 | [38; 45) '[y, &y]': [&&{unknown};_] | 2104 | [38; 45) '[y, &y]': [&&{unknown};_] |
2296 | [39; 40) 'y': &{unknown} | 2105 | [39; 40) 'y': &{unknown} |
2297 | [42; 44) '&y': &&{unknown} | 2106 | [42; 44) '&y': &&{unknown} |
@@ -2313,12 +2122,11 @@ fn test() { | |||
2313 | } | 2122 | } |
2314 | "#), | 2123 | "#), |
2315 | @r###" | 2124 | @r###" |
2316 | |||
2317 | [11; 80) '{ ...x)]; }': () | 2125 | [11; 80) '{ ...x)]; }': () |
2318 | [21; 22) 'x': &&{unknown} | 2126 | [21; 22) 'x': &&{unknown} |
2319 | [25; 32) 'unknown': &&{unknown} | 2127 | [25; 32) 'unknown': &&&{unknown} |
2320 | [42; 43) 'y': &&{unknown} | 2128 | [42; 43) 'y': &&{unknown} |
2321 | [46; 53) 'unknown': &&{unknown} | 2129 | [46; 53) 'unknown': &&&{unknown} |
2322 | [59; 77) '[(x, y..., &x)]': [(&&{unknown}, &&{unknown});_] | 2130 | [59; 77) '[(x, y..., &x)]': [(&&{unknown}, &&{unknown});_] |
2323 | [60; 66) '(x, y)': (&&{unknown}, &&{unknown}) | 2131 | [60; 66) '(x, y)': (&&{unknown}, &&{unknown}) |
2324 | [61; 62) 'x': &&{unknown} | 2132 | [61; 62) 'x': &&{unknown} |
diff --git a/crates/ra_hir/src/ty/tests/coercion.rs b/crates/ra_hir/src/ty/tests/coercion.rs new file mode 100644 index 000000000..d80d3fb6f --- /dev/null +++ b/crates/ra_hir/src/ty/tests/coercion.rs | |||
@@ -0,0 +1,278 @@ | |||
1 | use insta::assert_snapshot; | ||
2 | use test_utils::covers; | ||
3 | |||
4 | // Infer with some common definitions and impls. | ||
5 | fn infer(source: &str) -> String { | ||
6 | let defs = r#" | ||
7 | #[lang = "sized"] | ||
8 | pub trait Sized {} | ||
9 | #[lang = "unsize"] | ||
10 | pub trait Unsize<T: ?Sized> {} | ||
11 | #[lang = "coerce_unsized"] | ||
12 | pub trait CoerceUnsized<T> {} | ||
13 | |||
14 | impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} | ||
15 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} | ||
16 | "#; | ||
17 | |||
18 | // Append to the end to keep positions unchanged. | ||
19 | super::infer(&format!("{}{}", source, defs)) | ||
20 | } | ||
21 | |||
22 | #[test] | ||
23 | fn infer_let_stmt_coerce() { | ||
24 | assert_snapshot!( | ||
25 | infer(r#" | ||
26 | fn test() { | ||
27 | let x: &[i32] = &[1]; | ||
28 | } | ||
29 | "#), | ||
30 | @r###" | ||
31 | [11; 40) '{ ...[1]; }': () | ||
32 | [21; 22) 'x': &[i32] | ||
33 | [33; 37) '&[1]': &[i32;_] | ||
34 | [34; 37) '[1]': [i32;_] | ||
35 | [35; 36) '1': i32 | ||
36 | "###); | ||
37 | } | ||
38 | |||
39 | #[test] | ||
40 | fn infer_custom_coerce_unsized() { | ||
41 | assert_snapshot!( | ||
42 | infer(r#" | ||
43 | struct A<T: ?Sized>(*const T); | ||
44 | struct B<T: ?Sized>(*const T); | ||
45 | struct C<T: ?Sized> { inner: *const T } | ||
46 | |||
47 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} | ||
48 | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} | ||
49 | |||
50 | fn foo1<T>(x: A<[T]>) -> A<[T]> { x } | ||
51 | fn foo2<T>(x: B<[T]>) -> B<[T]> { x } | ||
52 | fn foo3<T>(x: C<[T]>) -> C<[T]> { x } | ||
53 | |||
54 | fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { | ||
55 | let d = foo1(a); | ||
56 | let e = foo2(b); | ||
57 | let f = foo3(c); | ||
58 | } | ||
59 | "#), | ||
60 | @r###" | ||
61 | [258; 259) 'x': A<[T]> | ||
62 | [279; 284) '{ x }': A<[T]> | ||
63 | [281; 282) 'x': A<[T]> | ||
64 | [296; 297) 'x': B<[T]> | ||
65 | [317; 322) '{ x }': B<[T]> | ||
66 | [319; 320) 'x': B<[T]> | ||
67 | [334; 335) 'x': C<[T]> | ||
68 | [355; 360) '{ x }': C<[T]> | ||
69 | [357; 358) 'x': C<[T]> | ||
70 | [370; 371) 'a': A<[u8;_]> | ||
71 | [385; 386) 'b': B<[u8;_]> | ||
72 | [400; 401) 'c': C<[u8;_]> | ||
73 | [415; 481) '{ ...(c); }': () | ||
74 | [425; 426) 'd': A<[{unknown}]> | ||
75 | [429; 433) 'foo1': fn foo1<{unknown}>(A<[T]>) -> A<[T]> | ||
76 | [429; 436) 'foo1(a)': A<[{unknown}]> | ||
77 | [434; 435) 'a': A<[u8;_]> | ||
78 | [446; 447) 'e': B<[u8]> | ||
79 | [450; 454) 'foo2': fn foo2<u8>(B<[T]>) -> B<[T]> | ||
80 | [450; 457) 'foo2(b)': B<[u8]> | ||
81 | [455; 456) 'b': B<[u8;_]> | ||
82 | [467; 468) 'f': C<[u8]> | ||
83 | [471; 475) 'foo3': fn foo3<u8>(C<[T]>) -> C<[T]> | ||
84 | [471; 478) 'foo3(c)': C<[u8]> | ||
85 | [476; 477) 'c': C<[u8;_]> | ||
86 | "### | ||
87 | ); | ||
88 | } | ||
89 | |||
90 | #[test] | ||
91 | fn infer_if_coerce() { | ||
92 | assert_snapshot!( | ||
93 | infer(r#" | ||
94 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
95 | fn test() { | ||
96 | let x = if true { | ||
97 | foo(&[1]) | ||
98 | } else { | ||
99 | &[1] | ||
100 | }; | ||
101 | } | ||
102 | "#), | ||
103 | @r###" | ||
104 | [11; 12) 'x': &[T] | ||
105 | [28; 39) '{ loop {} }': ! | ||
106 | [30; 37) 'loop {}': ! | ||
107 | [35; 37) '{}': () | ||
108 | [50; 126) '{ ... }; }': () | ||
109 | [60; 61) 'x': &[i32] | ||
110 | [64; 123) 'if tru... }': &[i32] | ||
111 | [67; 71) 'true': bool | ||
112 | [72; 97) '{ ... }': &[i32] | ||
113 | [82; 85) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
114 | [82; 91) 'foo(&[1])': &[i32] | ||
115 | [86; 90) '&[1]': &[i32;_] | ||
116 | [87; 90) '[1]': [i32;_] | ||
117 | [88; 89) '1': i32 | ||
118 | [103; 123) '{ ... }': &[i32;_] | ||
119 | [113; 117) '&[1]': &[i32;_] | ||
120 | [114; 117) '[1]': [i32;_] | ||
121 | [115; 116) '1': i32 | ||
122 | "### | ||
123 | ); | ||
124 | } | ||
125 | |||
126 | #[test] | ||
127 | fn infer_if_else_coerce() { | ||
128 | assert_snapshot!( | ||
129 | infer(r#" | ||
130 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
131 | fn test() { | ||
132 | let x = if true { | ||
133 | &[1] | ||
134 | } else { | ||
135 | foo(&[1]) | ||
136 | }; | ||
137 | } | ||
138 | "#), | ||
139 | @r###" | ||
140 | [11; 12) 'x': &[T] | ||
141 | [28; 39) '{ loop {} }': ! | ||
142 | [30; 37) 'loop {}': ! | ||
143 | [35; 37) '{}': () | ||
144 | [50; 126) '{ ... }; }': () | ||
145 | [60; 61) 'x': &[i32] | ||
146 | [64; 123) 'if tru... }': &[i32] | ||
147 | [67; 71) 'true': bool | ||
148 | [72; 92) '{ ... }': &[i32;_] | ||
149 | [82; 86) '&[1]': &[i32;_] | ||
150 | [83; 86) '[1]': [i32;_] | ||
151 | [84; 85) '1': i32 | ||
152 | [98; 123) '{ ... }': &[i32] | ||
153 | [108; 111) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
154 | [108; 117) 'foo(&[1])': &[i32] | ||
155 | [112; 116) '&[1]': &[i32;_] | ||
156 | [113; 116) '[1]': [i32;_] | ||
157 | [114; 115) '1': i32 | ||
158 | "### | ||
159 | ); | ||
160 | } | ||
161 | |||
162 | #[test] | ||
163 | fn infer_match_first_coerce() { | ||
164 | assert_snapshot!( | ||
165 | infer(r#" | ||
166 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
167 | fn test(i: i32) { | ||
168 | let x = match i { | ||
169 | 2 => foo(&[2]), | ||
170 | 1 => &[1], | ||
171 | _ => &[3], | ||
172 | }; | ||
173 | } | ||
174 | "#), | ||
175 | @r###" | ||
176 | [11; 12) 'x': &[T] | ||
177 | [28; 39) '{ loop {} }': ! | ||
178 | [30; 37) 'loop {}': ! | ||
179 | [35; 37) '{}': () | ||
180 | [48; 49) 'i': i32 | ||
181 | [56; 150) '{ ... }; }': () | ||
182 | [66; 67) 'x': &[i32] | ||
183 | [70; 147) 'match ... }': &[i32] | ||
184 | [76; 77) 'i': i32 | ||
185 | [88; 89) '2': i32 | ||
186 | [93; 96) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
187 | [93; 102) 'foo(&[2])': &[i32] | ||
188 | [97; 101) '&[2]': &[i32;_] | ||
189 | [98; 101) '[2]': [i32;_] | ||
190 | [99; 100) '2': i32 | ||
191 | [112; 113) '1': i32 | ||
192 | [117; 121) '&[1]': &[i32;_] | ||
193 | [118; 121) '[1]': [i32;_] | ||
194 | [119; 120) '1': i32 | ||
195 | [131; 132) '_': i32 | ||
196 | [136; 140) '&[3]': &[i32;_] | ||
197 | [137; 140) '[3]': [i32;_] | ||
198 | [138; 139) '3': i32 | ||
199 | "### | ||
200 | ); | ||
201 | } | ||
202 | |||
203 | #[test] | ||
204 | fn infer_match_second_coerce() { | ||
205 | assert_snapshot!( | ||
206 | infer(r#" | ||
207 | fn foo<T>(x: &[T]) -> &[T] { loop {} } | ||
208 | fn test(i: i32) { | ||
209 | let x = match i { | ||
210 | 1 => &[1], | ||
211 | 2 => foo(&[2]), | ||
212 | _ => &[3], | ||
213 | }; | ||
214 | } | ||
215 | "#), | ||
216 | @r###" | ||
217 | [11; 12) 'x': &[T] | ||
218 | [28; 39) '{ loop {} }': ! | ||
219 | [30; 37) 'loop {}': ! | ||
220 | [35; 37) '{}': () | ||
221 | [48; 49) 'i': i32 | ||
222 | [56; 150) '{ ... }; }': () | ||
223 | [66; 67) 'x': &[i32] | ||
224 | [70; 147) 'match ... }': &[i32] | ||
225 | [76; 77) 'i': i32 | ||
226 | [88; 89) '1': i32 | ||
227 | [93; 97) '&[1]': &[i32;_] | ||
228 | [94; 97) '[1]': [i32;_] | ||
229 | [95; 96) '1': i32 | ||
230 | [107; 108) '2': i32 | ||
231 | [112; 115) 'foo': fn foo<i32>(&[T]) -> &[T] | ||
232 | [112; 121) 'foo(&[2])': &[i32] | ||
233 | [116; 120) '&[2]': &[i32;_] | ||
234 | [117; 120) '[2]': [i32;_] | ||
235 | [118; 119) '2': i32 | ||
236 | [131; 132) '_': i32 | ||
237 | [136; 140) '&[3]': &[i32;_] | ||
238 | [137; 140) '[3]': [i32;_] | ||
239 | [138; 139) '3': i32 | ||
240 | "### | ||
241 | ); | ||
242 | } | ||
243 | |||
244 | #[test] | ||
245 | fn coerce_merge_one_by_one1() { | ||
246 | covers!(coerce_merge_fail_fallback); | ||
247 | |||
248 | assert_snapshot!( | ||
249 | infer(r#" | ||
250 | fn test() { | ||
251 | let t = &mut 1; | ||
252 | let x = match 1 { | ||
253 | 1 => t as *mut i32, | ||
254 | 2 => t as &i32, | ||
255 | _ => t as *const i32, | ||
256 | }; | ||
257 | } | ||
258 | "#), | ||
259 | @r###" | ||
260 | [11; 145) '{ ... }; }': () | ||
261 | [21; 22) 't': &mut i32 | ||
262 | [25; 31) '&mut 1': &mut i32 | ||
263 | [30; 31) '1': i32 | ||
264 | [41; 42) 'x': *const i32 | ||
265 | [45; 142) 'match ... }': *const i32 | ||
266 | [51; 52) '1': i32 | ||
267 | [63; 64) '1': i32 | ||
268 | [68; 69) 't': &mut i32 | ||
269 | [68; 81) 't as *mut i32': *mut i32 | ||
270 | [91; 92) '2': i32 | ||
271 | [96; 97) 't': &mut i32 | ||
272 | [96; 105) 't as &i32': &i32 | ||
273 | [115; 116) '_': i32 | ||
274 | [120; 121) 't': &mut i32 | ||
275 | [120; 135) 't as *const i32': *const i32 | ||
276 | "### | ||
277 | ); | ||
278 | } | ||
diff --git a/crates/ra_hir/src/ty/tests/never_type.rs b/crates/ra_hir/src/ty/tests/never_type.rs index b9af918e9..c202f545a 100644 --- a/crates/ra_hir/src/ty/tests/never_type.rs +++ b/crates/ra_hir/src/ty/tests/never_type.rs | |||
@@ -19,12 +19,10 @@ fn infer_never2() { | |||
19 | let t = type_at( | 19 | let t = type_at( |
20 | r#" | 20 | r#" |
21 | //- /main.rs | 21 | //- /main.rs |
22 | trait Foo { fn gen() -> Self; } | 22 | fn gen<T>() -> T { loop {} } |
23 | impl Foo for ! { fn gen() -> Self { loop {} } } | ||
24 | impl Foo for () { fn gen() -> Self { loop {} } } | ||
25 | 23 | ||
26 | fn test() { | 24 | fn test() { |
27 | let a = Foo::gen(); | 25 | let a = gen(); |
28 | if false { a } else { loop {} }; | 26 | if false { a } else { loop {} }; |
29 | a<|>; | 27 | a<|>; |
30 | } | 28 | } |
@@ -38,12 +36,10 @@ fn infer_never3() { | |||
38 | let t = type_at( | 36 | let t = type_at( |
39 | r#" | 37 | r#" |
40 | //- /main.rs | 38 | //- /main.rs |
41 | trait Foo { fn gen() -> Self; } | 39 | fn gen<T>() -> T { loop {} } |
42 | impl Foo for ! { fn gen() -> Self { loop {} } } | ||
43 | impl Foo for () { fn gen() -> Self { loop {} } } | ||
44 | 40 | ||
45 | fn test() { | 41 | fn test() { |
46 | let a = Foo::gen(); | 42 | let a = gen(); |
47 | if false { loop {} } else { a }; | 43 | if false { loop {} } else { a }; |
48 | a<|>; | 44 | a<|>; |
49 | } | 45 | } |
@@ -73,12 +69,10 @@ fn never_type_can_be_reinferred1() { | |||
73 | let t = type_at( | 69 | let t = type_at( |
74 | r#" | 70 | r#" |
75 | //- /main.rs | 71 | //- /main.rs |
76 | trait Foo { fn gen() -> Self; } | 72 | fn gen<T>() -> T { loop {} } |
77 | impl Foo for ! { fn gen() -> Self { loop {} } } | ||
78 | impl Foo for () { fn gen() -> Self { loop {} } } | ||
79 | 73 | ||
80 | fn test() { | 74 | fn test() { |
81 | let a = Foo::gen(); | 75 | let a = gen(); |
82 | if false { loop {} } else { a }; | 76 | if false { loop {} } else { a }; |
83 | a<|>; | 77 | a<|>; |
84 | if false { a }; | 78 | if false { a }; |
@@ -154,8 +148,7 @@ fn test() { | |||
154 | } else { | 148 | } else { |
155 | 3.0 | 149 | 3.0 |
156 | }; | 150 | }; |
157 | i<|> | 151 | i<|>; |
158 | () | ||
159 | } | 152 | } |
160 | "#, | 153 | "#, |
161 | ); | 154 | ); |
@@ -173,8 +166,7 @@ fn test(input: bool) { | |||
173 | } else { | 166 | } else { |
174 | return | 167 | return |
175 | }; | 168 | }; |
176 | i<|> | 169 | i<|>; |
177 | () | ||
178 | } | 170 | } |
179 | "#, | 171 | "#, |
180 | ); | 172 | ); |
@@ -193,8 +185,7 @@ fn test(a: i32) { | |||
193 | 3 => loop {}, | 185 | 3 => loop {}, |
194 | _ => 3.0, | 186 | _ => 3.0, |
195 | }; | 187 | }; |
196 | i<|> | 188 | i<|>; |
197 | () | ||
198 | } | 189 | } |
199 | "#, | 190 | "#, |
200 | ); | 191 | ); |
@@ -213,8 +204,7 @@ fn test(a: i32) { | |||
213 | 3 => 3.0, | 204 | 3 => 3.0, |
214 | _ => return, | 205 | _ => return, |
215 | }; | 206 | }; |
216 | i<|> | 207 | i<|>; |
217 | () | ||
218 | } | 208 | } |
219 | "#, | 209 | "#, |
220 | ); | 210 | ); |
@@ -231,8 +221,7 @@ fn test(a: i32) { | |||
231 | 2 => return, | 221 | 2 => return, |
232 | _ => loop {}, | 222 | _ => loop {}, |
233 | }; | 223 | }; |
234 | i<|> | 224 | i<|>; |
235 | () | ||
236 | } | 225 | } |
237 | "#, | 226 | "#, |
238 | ); | 227 | ); |
@@ -249,8 +238,7 @@ fn test(a: i32) { | |||
249 | 2 => 2.0, | 238 | 2 => 2.0, |
250 | _ => 3.0, | 239 | _ => 3.0, |
251 | }; | 240 | }; |
252 | i<|> | 241 | i<|>; |
253 | () | ||
254 | } | 242 | } |
255 | "#, | 243 | "#, |
256 | ); | 244 | ); |