diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-17 20:59:51 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-25 23:04:43 +0100 |
commit | bf161fa3e58d57d9b15bd965405036d834f18595 (patch) | |
tree | 62f7103143462ed75544985b7c3ad0cb2ddda96b | |
parent | 4bb66df6de6a832f53f09128ea038fc1c0068515 (diff) |
Better handle never type and branch merging
Split out tests for never type to another file
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 152 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 161 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests/never_type.rs | 258 |
5 files changed, 392 insertions, 181 deletions
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index fe119b97c..b2111be05 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -13,4 +13,5 @@ test_utils::marks!( | |||
13 | infer_while_let | 13 | infer_while_let |
14 | macro_rules_from_other_crates_are_visible_with_macro_use | 14 | macro_rules_from_other_crates_are_visible_with_macro_use |
15 | prelude_is_macro_use | 15 | prelude_is_macro_use |
16 | coerce_merge_fail_fallback | ||
16 | ); | 17 | ); |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index def787fb1..cbbba8b23 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -297,23 +297,35 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
297 | fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 297 | fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
298 | match (ty1, ty2) { | 298 | match (ty1, ty2) { |
299 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, | 299 | (Ty::Unknown, _) | (_, Ty::Unknown) => true, |
300 | |||
300 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 301 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
301 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 302 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
302 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) => { | 303 | | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2))) |
304 | | ( | ||
305 | Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)), | ||
306 | Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)), | ||
307 | ) => { | ||
303 | // both type vars are unknown since we tried to resolve them | 308 | // both type vars are unknown since we tried to resolve them |
304 | self.var_unification_table.union(*tv1, *tv2); | 309 | self.var_unification_table.union(*tv1, *tv2); |
305 | true | 310 | true |
306 | } | 311 | } |
312 | |||
313 | // The order of MaybeNeverTypeVar matters here. | ||
314 | // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar. | ||
315 | // Unifying MaybeNeverTypeVar and other concrete type will let the former become it. | ||
307 | (Ty::Infer(InferTy::TypeVar(tv)), other) | 316 | (Ty::Infer(InferTy::TypeVar(tv)), other) |
308 | | (other, Ty::Infer(InferTy::TypeVar(tv))) | 317 | | (other, Ty::Infer(InferTy::TypeVar(tv))) |
309 | | (Ty::Infer(InferTy::IntVar(tv)), other) | 318 | | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other) |
310 | | (other, Ty::Infer(InferTy::IntVar(tv))) | 319 | | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv))) |
311 | | (Ty::Infer(InferTy::FloatVar(tv)), other) | 320 | | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_))) |
312 | | (other, Ty::Infer(InferTy::FloatVar(tv))) => { | 321 | | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv))) |
322 | | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_))) | ||
323 | | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => { | ||
313 | // the type var is unknown since we tried to resolve it | 324 | // the type var is unknown since we tried to resolve it |
314 | self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); | 325 | self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); |
315 | true | 326 | true |
316 | } | 327 | } |
328 | |||
317 | _ => false, | 329 | _ => false, |
318 | } | 330 | } |
319 | } | 331 | } |
@@ -330,6 +342,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
330 | Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) | 342 | Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown))) |
331 | } | 343 | } |
332 | 344 | ||
345 | fn new_maybe_never_type_var(&mut self) -> Ty { | ||
346 | Ty::Infer(InferTy::MaybeNeverTypeVar( | ||
347 | self.var_unification_table.new_key(TypeVarValue::Unknown), | ||
348 | )) | ||
349 | } | ||
350 | |||
333 | /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. | 351 | /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. |
334 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { | 352 | fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { |
335 | match ty { | 353 | match ty { |
@@ -817,6 +835,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
817 | ty | 835 | ty |
818 | } | 836 | } |
819 | 837 | ||
838 | /// Merge two types from different branches, with possible implicit coerce. | ||
839 | /// | ||
840 | /// Note that it is only possible that one type are coerced to another. | ||
841 | /// Coercing both types to another least upper bound type is not possible in rustc, | ||
842 | /// which will simply result in "incompatible types" error. | ||
843 | fn coerce_merge_branch<'t>(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { | ||
844 | if self.coerce(ty1, ty2) { | ||
845 | ty2.clone() | ||
846 | } else if self.coerce(ty2, ty1) { | ||
847 | ty1.clone() | ||
848 | } else { | ||
849 | tested_by!(coerce_merge_fail_fallback); | ||
850 | // For incompatible types, we use the latter one as result | ||
851 | // to be better recovery for `if` without `else`. | ||
852 | ty2.clone() | ||
853 | } | ||
854 | } | ||
855 | |||
820 | /// Unify two types, but may coerce the first one to the second one | 856 | /// Unify two types, but may coerce the first one to the second one |
821 | /// using "implicit coercion rules" if needed. | 857 | /// using "implicit coercion rules" if needed. |
822 | /// | 858 | /// |
@@ -828,12 +864,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
828 | } | 864 | } |
829 | 865 | ||
830 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { | 866 | fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { |
831 | match (&mut from_ty, &*to_ty) { | 867 | match (&from_ty, to_ty) { |
832 | // Top and bottom type | 868 | // Never type will make type variable to fallback to Never Type instead of Unknown. |
869 | (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => { | ||
870 | let var = self.new_maybe_never_type_var(); | ||
871 | self.var_unification_table.union_value(*tv, TypeVarValue::Known(var)); | ||
872 | return true; | ||
873 | } | ||
833 | (ty_app!(TypeCtor::Never), _) => return true, | 874 | (ty_app!(TypeCtor::Never), _) => return true, |
834 | 875 | ||
835 | // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. | 876 | // Trivial cases, this should go after `never` check to |
877 | // avoid infer result type to be never | ||
878 | _ => { | ||
879 | if self.unify_inner_trivial(&from_ty, &to_ty) { | ||
880 | return true; | ||
881 | } | ||
882 | } | ||
883 | } | ||
836 | 884 | ||
885 | // Pointer weakening and function to pointer | ||
886 | match (&mut from_ty, to_ty) { | ||
837 | // `*mut T`, `&mut T, `&T`` -> `*const T` | 887 | // `*mut T`, `&mut T, `&T`` -> `*const T` |
838 | // `&mut T` -> `&T` | 888 | // `&mut T` -> `&T` |
839 | // `&mut T` -> `*mut T` | 889 | // `&mut T` -> `*mut T` |
@@ -866,71 +916,67 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
866 | } | 916 | } |
867 | } | 917 | } |
868 | 918 | ||
869 | // Trivial cases, this should go after `never` check to | 919 | _ => {} |
870 | // avoid infer result type to be never | ||
871 | _ => { | ||
872 | if self.unify_inner_trivial(&from_ty, &to_ty) { | ||
873 | return true; | ||
874 | } | ||
875 | } | ||
876 | } | 920 | } |
877 | 921 | ||
878 | // Try coerce or unify | 922 | // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. |
879 | match (&from_ty, &to_ty) { | 923 | match (&from_ty, &to_ty) { |
880 | // FIXME: Solve `FromTy: CoerceUnsized<ToTy>` instead of listing common impls here. | 924 | // Mutilibity is checked above |
881 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) | 925 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) |
882 | | (ty_app!(TypeCtor::RawPtr(_), st1), ty_app!(TypeCtor::RawPtr(_), st2)) => { | 926 | | (ty_app!(TypeCtor::RawPtr(_), st1), ty_app!(TypeCtor::RawPtr(_), st2)) => { |
883 | match self.try_coerce_unsized(&st1[0], &st2[0], 0) { | 927 | if self.try_coerce_unsized(&st1[0], &st2[0], 0) { |
884 | Some(ret) => return ret, | 928 | return true; |
885 | None => {} | ||
886 | } | 929 | } |
887 | } | 930 | } |
888 | _ => {} | 931 | _ => {} |
889 | } | 932 | } |
890 | 933 | ||
891 | // Auto Deref if cannot coerce | 934 | // Auto Deref if cannot coerce |
892 | match (&from_ty, &to_ty) { | 935 | match (&from_ty, to_ty) { |
936 | // FIXME: DerefMut | ||
893 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => { | 937 | (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => { |
894 | self.unify_autoderef_behind_ref(&st1[0], &st2[0]) | 938 | self.unify_autoderef_behind_ref(&st1[0], &st2[0]) |
895 | } | 939 | } |
896 | 940 | ||
897 | // Normal unify | 941 | // Otherwise, normal unify |
898 | _ => self.unify(&from_ty, &to_ty), | 942 | _ => self.unify(&from_ty, to_ty), |
899 | } | 943 | } |
900 | } | 944 | } |
901 | 945 | ||
902 | /// Coerce a type to a DST if `FromTy: Unsize<ToTy>` | 946 | /// Coerce a type to a DST if `FromTy: Unsize<ToTy>` |
903 | /// | 947 | /// |
904 | /// See: `https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html` | 948 | /// See: `https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html` |
905 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> { | 949 | fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> bool { |
906 | if depth > 1000 { | 950 | if depth > 1000 { |
907 | panic!("Infinite recursion in coercion"); | 951 | panic!("Infinite recursion in coercion"); |
908 | } | 952 | } |
909 | 953 | ||
910 | // FIXME: Correctly handle | ||
911 | match (&from_ty, &to_ty) { | 954 | match (&from_ty, &to_ty) { |
912 | // `[T; N]` -> `[T]` | 955 | // `[T; N]` -> `[T]` |
913 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { | 956 | (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => { |
914 | Some(self.unify(&st1[0], &st2[0])) | 957 | self.unify(&st1[0], &st2[0]) |
915 | } | 958 | } |
916 | 959 | ||
917 | // `T` -> `dyn Trait` when `T: Trait` | 960 | // `T` -> `dyn Trait` when `T: Trait` |
918 | (_, Ty::Dyn(_)) => { | 961 | (_, Ty::Dyn(_)) => { |
919 | // FIXME: Check predicates | 962 | // FIXME: Check predicates |
920 | Some(true) | 963 | true |
921 | } | 964 | } |
922 | 965 | ||
923 | (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) if ctor1 == ctor2 => { | 966 | ( |
967 | ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1), | ||
968 | ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2), | ||
969 | ) if struct1 == struct2 => { | ||
970 | // FIXME: Check preconditions here | ||
924 | for (ty1, ty2) in st1.iter().zip(st2.iter()) { | 971 | for (ty1, ty2) in st1.iter().zip(st2.iter()) { |
925 | match self.try_coerce_unsized(ty1, ty2, depth + 1) { | 972 | if !self.try_coerce_unsized(ty1, ty2, depth + 1) { |
926 | Some(true) => {} | 973 | return false; |
927 | ret => return ret, | ||
928 | } | 974 | } |
929 | } | 975 | } |
930 | Some(true) | 976 | true |
931 | } | 977 | } |
932 | 978 | ||
933 | _ => None, | 979 | _ => false, |
934 | } | 980 | } |
935 | } | 981 | } |
936 | 982 | ||
@@ -980,18 +1026,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
980 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 1026 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
981 | 1027 | ||
982 | let then_ty = self.infer_expr_inner(*then_branch, &expected); | 1028 | let then_ty = self.infer_expr_inner(*then_branch, &expected); |
983 | self.coerce(&then_ty, &expected.ty); | ||
984 | |||
985 | let else_ty = match else_branch { | 1029 | let else_ty = match else_branch { |
986 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), | 1030 | Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), |
987 | None => Ty::unit(), | 1031 | None => Ty::unit(), |
988 | }; | 1032 | }; |
989 | if !self.coerce(&else_ty, &expected.ty) { | 1033 | |
990 | self.coerce(&expected.ty, &else_ty); | 1034 | self.coerce_merge_branch(&then_ty, &else_ty) |
991 | else_ty.clone() | ||
992 | } else { | ||
993 | expected.ty.clone() | ||
994 | } | ||
995 | } | 1035 | } |
996 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 1036 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), |
997 | Expr::TryBlock { body } => { | 1037 | Expr::TryBlock { body } => { |
@@ -1087,11 +1127,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1087 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), | 1127 | .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), |
1088 | Expr::Match { expr, arms } => { | 1128 | Expr::Match { expr, arms } => { |
1089 | let input_ty = self.infer_expr(*expr, &Expectation::none()); | 1129 | let input_ty = self.infer_expr(*expr, &Expectation::none()); |
1090 | let mut expected = match expected.ty { | 1130 | |
1091 | Ty::Unknown => Expectation::has_type(Ty::simple(TypeCtor::Never)), | 1131 | let mut result_ty = self.new_maybe_never_type_var(); |
1092 | _ => expected.clone(), | ||
1093 | }; | ||
1094 | let mut all_never = true; | ||
1095 | 1132 | ||
1096 | for arm in arms { | 1133 | for arm in arms { |
1097 | for &pat in &arm.pats { | 1134 | for &pat in &arm.pats { |
@@ -1103,22 +1140,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1103 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), | 1140 | &Expectation::has_type(Ty::simple(TypeCtor::Bool)), |
1104 | ); | 1141 | ); |
1105 | } | 1142 | } |
1143 | |||
1106 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); | 1144 | let arm_ty = self.infer_expr_inner(arm.expr, &expected); |
1107 | match &arm_ty { | 1145 | result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); |
1108 | ty_app!(TypeCtor::Never) => (), | ||
1109 | _ => all_never = false, | ||
1110 | } | ||
1111 | if !self.coerce(&arm_ty, &expected.ty) { | ||
1112 | self.coerce(&expected.ty, &arm_ty); | ||
1113 | expected = Expectation::has_type(arm_ty); | ||
1114 | } | ||
1115 | } | 1146 | } |
1116 | 1147 | ||
1117 | if all_never { | 1148 | result_ty |
1118 | Ty::simple(TypeCtor::Never) | ||
1119 | } else { | ||
1120 | expected.ty | ||
1121 | } | ||
1122 | } | 1149 | } |
1123 | Expr::Path(p) => { | 1150 | Expr::Path(p) => { |
1124 | // FIXME this could be more efficient... | 1151 | // FIXME this could be more efficient... |
@@ -1558,12 +1585,16 @@ pub enum InferTy { | |||
1558 | TypeVar(TypeVarId), | 1585 | TypeVar(TypeVarId), |
1559 | IntVar(TypeVarId), | 1586 | IntVar(TypeVarId), |
1560 | FloatVar(TypeVarId), | 1587 | FloatVar(TypeVarId), |
1588 | MaybeNeverTypeVar(TypeVarId), | ||
1561 | } | 1589 | } |
1562 | 1590 | ||
1563 | impl InferTy { | 1591 | impl InferTy { |
1564 | fn to_inner(self) -> TypeVarId { | 1592 | fn to_inner(self) -> TypeVarId { |
1565 | match self { | 1593 | match self { |
1566 | InferTy::TypeVar(ty) | InferTy::IntVar(ty) | InferTy::FloatVar(ty) => ty, | 1594 | InferTy::TypeVar(ty) |
1595 | | InferTy::IntVar(ty) | ||
1596 | | InferTy::FloatVar(ty) | ||
1597 | | InferTy::MaybeNeverTypeVar(ty) => ty, | ||
1567 | } | 1598 | } |
1568 | } | 1599 | } |
1569 | 1600 | ||
@@ -1576,6 +1607,7 @@ impl InferTy { | |||
1576 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float( | 1607 | InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float( |
1577 | primitive::UncertainFloatTy::Known(primitive::FloatTy::f64()), | 1608 | primitive::UncertainFloatTy::Known(primitive::FloatTy::f64()), |
1578 | )), | 1609 | )), |
1610 | InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), | ||
1579 | } | 1611 | } |
1580 | } | 1612 | } |
1581 | } | 1613 | } |
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index 9a0d2d8f9..b6ebee3b1 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -63,6 +63,7 @@ where | |||
63 | InferTy::TypeVar(_) => InferTy::TypeVar(root), | 63 | InferTy::TypeVar(_) => InferTy::TypeVar(root), |
64 | InferTy::IntVar(_) => InferTy::IntVar(root), | 64 | InferTy::IntVar(_) => InferTy::IntVar(root), |
65 | InferTy::FloatVar(_) => InferTy::FloatVar(root), | 65 | InferTy::FloatVar(_) => InferTy::FloatVar(root), |
66 | InferTy::MaybeNeverTypeVar(_) => InferTy::MaybeNeverTypeVar(root), | ||
66 | }; | 67 | }; |
67 | let position = self.add(free_var); | 68 | let position = self.add(free_var); |
68 | Ty::Bound(position as u32) | 69 | Ty::Bound(position as u32) |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 2ce0039b1..081bfe37c 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -20,6 +20,8 @@ use crate::{ | |||
20 | // against snapshots of the expected results using insta. Use cargo-insta to | 20 | // against snapshots of the expected results using insta. Use cargo-insta to |
21 | // update the snapshots. | 21 | // update the snapshots. |
22 | 22 | ||
23 | mod never_type; | ||
24 | |||
23 | #[test] | 25 | #[test] |
24 | fn infer_await() { | 26 | fn infer_await() { |
25 | let (mut db, pos) = MockDatabase::with_position( | 27 | let (mut db, pos) = MockDatabase::with_position( |
@@ -1078,6 +1080,42 @@ fn test(i: i32) { | |||
1078 | } | 1080 | } |
1079 | 1081 | ||
1080 | #[test] | 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] | ||
1081 | fn bug_484() { | 1119 | fn bug_484() { |
1082 | assert_snapshot!( | 1120 | assert_snapshot!( |
1083 | infer(r#" | 1121 | infer(r#" |
@@ -2458,7 +2496,6 @@ fn extra_compiler_flags() { | |||
2458 | } | 2496 | } |
2459 | "#), | 2497 | "#), |
2460 | @r###" | 2498 | @r###" |
2461 | |||
2462 | [27; 323) '{ ... } }': () | 2499 | [27; 323) '{ ... } }': () |
2463 | [33; 321) 'for co... }': () | 2500 | [33; 321) 'for co... }': () |
2464 | [37; 44) 'content': &{unknown} | 2501 | [37; 44) 'content': &{unknown} |
@@ -2472,8 +2509,8 @@ fn extra_compiler_flags() { | |||
2472 | [135; 167) '{ ... }': &&{unknown} | 2509 | [135; 167) '{ ... }': &&{unknown} |
2473 | [149; 157) '&content': &&{unknown} | 2510 | [149; 157) '&content': &&{unknown} |
2474 | [150; 157) 'content': &{unknown} | 2511 | [150; 157) 'content': &{unknown} |
2475 | [182; 189) 'content': &&{unknown} | 2512 | [182; 189) 'content': &{unknown} |
2476 | [192; 314) 'if ICE... }': &&{unknown} | 2513 | [192; 314) 'if ICE... }': &{unknown} |
2477 | [195; 232) 'ICE_RE..._VALUE': {unknown} | 2514 | [195; 232) 'ICE_RE..._VALUE': {unknown} |
2478 | [195; 248) 'ICE_RE...&name)': bool | 2515 | [195; 248) 'ICE_RE...&name)': bool |
2479 | [242; 247) '&name': &&&{unknown} | 2516 | [242; 247) '&name': &&&{unknown} |
@@ -4683,121 +4720,3 @@ fn no_such_field_diagnostics() { | |||
4683 | "### | 4720 | "### |
4684 | ); | 4721 | ); |
4685 | } | 4722 | } |
4686 | |||
4687 | mod branching_with_never_tests { | ||
4688 | use super::type_at; | ||
4689 | |||
4690 | #[test] | ||
4691 | fn if_never() { | ||
4692 | let t = type_at( | ||
4693 | r#" | ||
4694 | //- /main.rs | ||
4695 | fn test() { | ||
4696 | let i = if true { | ||
4697 | loop {} | ||
4698 | } else { | ||
4699 | 3.0 | ||
4700 | }; | ||
4701 | i<|> | ||
4702 | () | ||
4703 | } | ||
4704 | "#, | ||
4705 | ); | ||
4706 | assert_eq!(t, "f64"); | ||
4707 | } | ||
4708 | |||
4709 | #[test] | ||
4710 | fn if_else_never() { | ||
4711 | let t = type_at( | ||
4712 | r#" | ||
4713 | //- /main.rs | ||
4714 | fn test(input: bool) { | ||
4715 | let i = if input { | ||
4716 | 2.0 | ||
4717 | } else { | ||
4718 | return | ||
4719 | }; | ||
4720 | i<|> | ||
4721 | () | ||
4722 | } | ||
4723 | "#, | ||
4724 | ); | ||
4725 | assert_eq!(t, "f64"); | ||
4726 | } | ||
4727 | |||
4728 | #[test] | ||
4729 | fn match_first_arm_never() { | ||
4730 | let t = type_at( | ||
4731 | r#" | ||
4732 | //- /main.rs | ||
4733 | fn test(a: i32) { | ||
4734 | let i = match a { | ||
4735 | 1 => return, | ||
4736 | 2 => 2.0, | ||
4737 | 3 => loop {}, | ||
4738 | _ => 3.0, | ||
4739 | }; | ||
4740 | i<|> | ||
4741 | () | ||
4742 | } | ||
4743 | "#, | ||
4744 | ); | ||
4745 | assert_eq!(t, "f64"); | ||
4746 | } | ||
4747 | |||
4748 | #[test] | ||
4749 | fn match_second_arm_never() { | ||
4750 | let t = type_at( | ||
4751 | r#" | ||
4752 | //- /main.rs | ||
4753 | fn test(a: i32) { | ||
4754 | let i = match a { | ||
4755 | 1 => 3.0, | ||
4756 | 2 => loop {}, | ||
4757 | 3 => 3.0, | ||
4758 | _ => return, | ||
4759 | }; | ||
4760 | i<|> | ||
4761 | () | ||
4762 | } | ||
4763 | "#, | ||
4764 | ); | ||
4765 | assert_eq!(t, "f64"); | ||
4766 | } | ||
4767 | |||
4768 | #[test] | ||
4769 | fn match_all_arms_never() { | ||
4770 | let t = type_at( | ||
4771 | r#" | ||
4772 | //- /main.rs | ||
4773 | fn test(a: i32) { | ||
4774 | let i = match a { | ||
4775 | 2 => return, | ||
4776 | _ => loop {}, | ||
4777 | }; | ||
4778 | i<|> | ||
4779 | () | ||
4780 | } | ||
4781 | "#, | ||
4782 | ); | ||
4783 | assert_eq!(t, "!"); | ||
4784 | } | ||
4785 | |||
4786 | #[test] | ||
4787 | fn match_no_never_arms() { | ||
4788 | let t = type_at( | ||
4789 | r#" | ||
4790 | //- /main.rs | ||
4791 | fn test(a: i32) { | ||
4792 | let i = match a { | ||
4793 | 2 => 2.0, | ||
4794 | _ => 3.0, | ||
4795 | }; | ||
4796 | i<|> | ||
4797 | () | ||
4798 | } | ||
4799 | "#, | ||
4800 | ); | ||
4801 | assert_eq!(t, "f64"); | ||
4802 | } | ||
4803 | } | ||
diff --git a/crates/ra_hir/src/ty/tests/never_type.rs b/crates/ra_hir/src/ty/tests/never_type.rs new file mode 100644 index 000000000..b9af918e9 --- /dev/null +++ b/crates/ra_hir/src/ty/tests/never_type.rs | |||
@@ -0,0 +1,258 @@ | |||
1 | use super::type_at; | ||
2 | |||
3 | #[test] | ||
4 | fn infer_never1() { | ||
5 | let t = type_at( | ||
6 | r#" | ||
7 | //- /main.rs | ||
8 | fn test() { | ||
9 | let t = return; | ||
10 | t<|>; | ||
11 | } | ||
12 | "#, | ||
13 | ); | ||
14 | assert_eq!(t, "!"); | ||
15 | } | ||
16 | |||
17 | #[test] | ||
18 | fn infer_never2() { | ||
19 | let t = type_at( | ||
20 | r#" | ||
21 | //- /main.rs | ||
22 | trait Foo { fn gen() -> Self; } | ||
23 | impl Foo for ! { fn gen() -> Self { loop {} } } | ||
24 | impl Foo for () { fn gen() -> Self { loop {} } } | ||
25 | |||
26 | fn test() { | ||
27 | let a = Foo::gen(); | ||
28 | if false { a } else { loop {} }; | ||
29 | a<|>; | ||
30 | } | ||
31 | "#, | ||
32 | ); | ||
33 | assert_eq!(t, "!"); | ||
34 | } | ||
35 | |||
36 | #[test] | ||
37 | fn infer_never3() { | ||
38 | let t = type_at( | ||
39 | r#" | ||
40 | //- /main.rs | ||
41 | trait Foo { fn gen() -> Self; } | ||
42 | impl Foo for ! { fn gen() -> Self { loop {} } } | ||
43 | impl Foo for () { fn gen() -> Self { loop {} } } | ||
44 | |||
45 | fn test() { | ||
46 | let a = Foo::gen(); | ||
47 | if false { loop {} } else { a }; | ||
48 | a<|>; | ||
49 | } | ||
50 | "#, | ||
51 | ); | ||
52 | assert_eq!(t, "!"); | ||
53 | } | ||
54 | |||
55 | #[test] | ||
56 | fn never_type_in_generic_args() { | ||
57 | let t = type_at( | ||
58 | r#" | ||
59 | //- /main.rs | ||
60 | enum Option<T> { None, Some(T) } | ||
61 | |||
62 | fn test() { | ||
63 | let a = if true { Option::None } else { Option::Some(return) }; | ||
64 | a<|>; | ||
65 | } | ||
66 | "#, | ||
67 | ); | ||
68 | assert_eq!(t, "Option<!>"); | ||
69 | } | ||
70 | |||
71 | #[test] | ||
72 | fn never_type_can_be_reinferred1() { | ||
73 | let t = type_at( | ||
74 | r#" | ||
75 | //- /main.rs | ||
76 | trait Foo { fn gen() -> Self; } | ||
77 | impl Foo for ! { fn gen() -> Self { loop {} } } | ||
78 | impl Foo for () { fn gen() -> Self { loop {} } } | ||
79 | |||
80 | fn test() { | ||
81 | let a = Foo::gen(); | ||
82 | if false { loop {} } else { a }; | ||
83 | a<|>; | ||
84 | if false { a }; | ||
85 | } | ||
86 | "#, | ||
87 | ); | ||
88 | assert_eq!(t, "()"); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn never_type_can_be_reinferred2() { | ||
93 | let t = type_at( | ||
94 | r#" | ||
95 | //- /main.rs | ||
96 | enum Option<T> { None, Some(T) } | ||
97 | |||
98 | fn test() { | ||
99 | let a = if true { Option::None } else { Option::Some(return) }; | ||
100 | a<|>; | ||
101 | match 42 { | ||
102 | 42 => a, | ||
103 | _ => Option::Some(42), | ||
104 | }; | ||
105 | } | ||
106 | "#, | ||
107 | ); | ||
108 | assert_eq!(t, "Option<i32>"); | ||
109 | } | ||
110 | #[test] | ||
111 | fn never_type_can_be_reinferred3() { | ||
112 | let t = type_at( | ||
113 | r#" | ||
114 | //- /main.rs | ||
115 | enum Option<T> { None, Some(T) } | ||
116 | |||
117 | fn test() { | ||
118 | let a = if true { Option::None } else { Option::Some(return) }; | ||
119 | a<|>; | ||
120 | match 42 { | ||
121 | 42 => a, | ||
122 | _ => Option::Some("str"), | ||
123 | }; | ||
124 | } | ||
125 | "#, | ||
126 | ); | ||
127 | assert_eq!(t, "Option<&str>"); | ||
128 | } | ||
129 | |||
130 | #[test] | ||
131 | fn match_no_arm() { | ||
132 | let t = type_at( | ||
133 | r#" | ||
134 | //- /main.rs | ||
135 | enum Void {} | ||
136 | |||
137 | fn test(a: Void) { | ||
138 | let t = match a {}; | ||
139 | t<|>; | ||
140 | } | ||
141 | "#, | ||
142 | ); | ||
143 | assert_eq!(t, "!"); | ||
144 | } | ||
145 | |||
146 | #[test] | ||
147 | fn if_never() { | ||
148 | let t = type_at( | ||
149 | r#" | ||
150 | //- /main.rs | ||
151 | fn test() { | ||
152 | let i = if true { | ||
153 | loop {} | ||
154 | } else { | ||
155 | 3.0 | ||
156 | }; | ||
157 | i<|> | ||
158 | () | ||
159 | } | ||
160 | "#, | ||
161 | ); | ||
162 | assert_eq!(t, "f64"); | ||
163 | } | ||
164 | |||
165 | #[test] | ||
166 | fn if_else_never() { | ||
167 | let t = type_at( | ||
168 | r#" | ||
169 | //- /main.rs | ||
170 | fn test(input: bool) { | ||
171 | let i = if input { | ||
172 | 2.0 | ||
173 | } else { | ||
174 | return | ||
175 | }; | ||
176 | i<|> | ||
177 | () | ||
178 | } | ||
179 | "#, | ||
180 | ); | ||
181 | assert_eq!(t, "f64"); | ||
182 | } | ||
183 | |||
184 | #[test] | ||
185 | fn match_first_arm_never() { | ||
186 | let t = type_at( | ||
187 | r#" | ||
188 | //- /main.rs | ||
189 | fn test(a: i32) { | ||
190 | let i = match a { | ||
191 | 1 => return, | ||
192 | 2 => 2.0, | ||
193 | 3 => loop {}, | ||
194 | _ => 3.0, | ||
195 | }; | ||
196 | i<|> | ||
197 | () | ||
198 | } | ||
199 | "#, | ||
200 | ); | ||
201 | assert_eq!(t, "f64"); | ||
202 | } | ||
203 | |||
204 | #[test] | ||
205 | fn match_second_arm_never() { | ||
206 | let t = type_at( | ||
207 | r#" | ||
208 | //- /main.rs | ||
209 | fn test(a: i32) { | ||
210 | let i = match a { | ||
211 | 1 => 3.0, | ||
212 | 2 => loop {}, | ||
213 | 3 => 3.0, | ||
214 | _ => return, | ||
215 | }; | ||
216 | i<|> | ||
217 | () | ||
218 | } | ||
219 | "#, | ||
220 | ); | ||
221 | assert_eq!(t, "f64"); | ||
222 | } | ||
223 | |||
224 | #[test] | ||
225 | fn match_all_arms_never() { | ||
226 | let t = type_at( | ||
227 | r#" | ||
228 | //- /main.rs | ||
229 | fn test(a: i32) { | ||
230 | let i = match a { | ||
231 | 2 => return, | ||
232 | _ => loop {}, | ||
233 | }; | ||
234 | i<|> | ||
235 | () | ||
236 | } | ||
237 | "#, | ||
238 | ); | ||
239 | assert_eq!(t, "!"); | ||
240 | } | ||
241 | |||
242 | #[test] | ||
243 | fn match_no_never_arms() { | ||
244 | let t = type_at( | ||
245 | r#" | ||
246 | //- /main.rs | ||
247 | fn test(a: i32) { | ||
248 | let i = match a { | ||
249 | 2 => 2.0, | ||
250 | _ => 3.0, | ||
251 | }; | ||
252 | i<|> | ||
253 | () | ||
254 | } | ||
255 | "#, | ||
256 | ); | ||
257 | assert_eq!(t, "f64"); | ||
258 | } | ||