aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authoruHOOCCOOHu <[email protected]>2019-09-18 17:36:12 +0100
committeruHOOCCOOHu <[email protected]>2019-09-25 23:16:52 +0100
commit5807e261c27e4964fc6a8d2b8cf02e548292b940 (patch)
treeb6bfef565281c2fec4b584a4e2759ff1c5b417e5 /crates
parentbf161fa3e58d57d9b15bd965405036d834f18595 (diff)
Support custom `CoerceUnsized`
Split out tests about coercion
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty/infer.rs207
-rw-r--r--crates/ra_hir/src/ty/tests.rs202
-rw-r--r--crates/ra_hir/src/ty/tests/coercion.rs278
-rw-r--r--crates/ra_hir/src/ty/tests/never_type.rs36
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
193macro_rules! ty_app { 200macro_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
23mod never_type; 23mod never_type;
24mod coercion;
24 25
25#[test] 26#[test]
26fn infer_await() { 27fn infer_await() {
@@ -926,196 +927,6 @@ fn test(a: A<i32>) {
926} 927}
927 928
928#[test] 929#[test]
929fn infer_if_coerce() {
930 assert_snapshot!(
931 infer(r#"
932fn foo<T>(x: &[T]) -> &[T] { loop {} }
933fn 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]
965fn infer_if_else_coerce() {
966 assert_snapshot!(
967 infer(r#"
968fn foo<T>(x: &[T]) -> &[T] { loop {} }
969fn 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]
1001fn infer_match_first_coerce() {
1002 assert_snapshot!(
1003 infer(r#"
1004fn foo<T>(x: &[T]) -> &[T] { loop {} }
1005fn 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]
1042fn infer_match_second_coerce() {
1043 assert_snapshot!(
1044 infer(r#"
1045fn foo<T>(x: &[T]) -> &[T] { loop {} }
1046fn 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]
1083fn coerce_merge_one_by_one1() {
1084 covers!(coerce_merge_fail_fallback);
1085
1086 assert_snapshot!(
1087 infer(r#"
1088fn 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]
1119fn bug_484() { 930fn 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 @@
1use insta::assert_snapshot;
2use test_utils::covers;
3
4// Infer with some common definitions and impls.
5fn 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]
23fn infer_let_stmt_coerce() {
24 assert_snapshot!(
25 infer(r#"
26fn 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]
40fn infer_custom_coerce_unsized() {
41 assert_snapshot!(
42 infer(r#"
43struct A<T: ?Sized>(*const T);
44struct B<T: ?Sized>(*const T);
45struct C<T: ?Sized> { inner: *const T }
46
47impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {}
48impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {}
49
50fn foo1<T>(x: A<[T]>) -> A<[T]> { x }
51fn foo2<T>(x: B<[T]>) -> B<[T]> { x }
52fn foo3<T>(x: C<[T]>) -> C<[T]> { x }
53
54fn 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]
91fn infer_if_coerce() {
92 assert_snapshot!(
93 infer(r#"
94fn foo<T>(x: &[T]) -> &[T] { loop {} }
95fn 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]
127fn infer_if_else_coerce() {
128 assert_snapshot!(
129 infer(r#"
130fn foo<T>(x: &[T]) -> &[T] { loop {} }
131fn 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]
163fn infer_match_first_coerce() {
164 assert_snapshot!(
165 infer(r#"
166fn foo<T>(x: &[T]) -> &[T] { loop {} }
167fn 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]
204fn infer_match_second_coerce() {
205 assert_snapshot!(
206 infer(r#"
207fn foo<T>(x: &[T]) -> &[T] { loop {} }
208fn 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]
245fn coerce_merge_one_by_one1() {
246 covers!(coerce_merge_fail_fallback);
247
248 assert_snapshot!(
249 infer(r#"
250fn 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
22trait Foo { fn gen() -> Self; } 22fn gen<T>() -> T { loop {} }
23impl Foo for ! { fn gen() -> Self { loop {} } }
24impl Foo for () { fn gen() -> Self { loop {} } }
25 23
26fn test() { 24fn 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
41trait Foo { fn gen() -> Self; } 39fn gen<T>() -> T { loop {} }
42impl Foo for ! { fn gen() -> Self { loop {} } }
43impl Foo for () { fn gen() -> Self { loop {} } }
44 40
45fn test() { 41fn 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
76trait Foo { fn gen() -> Self; } 72fn gen<T>() -> T { loop {} }
77impl Foo for ! { fn gen() -> Self { loop {} } }
78impl Foo for () { fn gen() -> Self { loop {} } }
79 73
80fn test() { 74fn 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 );