diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_ty/src/infer/coerce.rs | 17 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/coercion.rs | 39 |
2 files changed, 52 insertions, 4 deletions
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs index 27f59c8bb..4d80b4a08 100644 --- a/crates/hir_ty/src/infer/coerce.rs +++ b/crates/hir_ty/src/infer/coerce.rs | |||
@@ -45,6 +45,10 @@ impl<'a> InferenceContext<'a> { | |||
45 | /// - if we were concerned with lifetime subtyping, we'd need to look for a | 45 | /// - if we were concerned with lifetime subtyping, we'd need to look for a |
46 | /// least upper bound. | 46 | /// least upper bound. |
47 | pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { | 47 | pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { |
48 | let ty1 = self.resolve_ty_shallow(ty1); | ||
49 | let ty1 = ty1.as_ref(); | ||
50 | let ty2 = self.resolve_ty_shallow(ty2); | ||
51 | let ty2 = ty2.as_ref(); | ||
48 | // Special case: two function types. Try to coerce both to | 52 | // Special case: two function types. Try to coerce both to |
49 | // pointers to have a chance at getting a match. See | 53 | // pointers to have a chance at getting a match. See |
50 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 | 54 | // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 |
@@ -71,12 +75,17 @@ impl<'a> InferenceContext<'a> { | |||
71 | } | 75 | } |
72 | } | 76 | } |
73 | 77 | ||
74 | if self.coerce(ty1, ty2) { | 78 | // It might not seem like it, but order is important here: ty1 is our |
75 | ty2.clone() | 79 | // "previous" type, ty2 is the "new" one being added. If the previous |
76 | } else if self.coerce(ty2, ty1) { | 80 | // type is a type variable and the new one is `!`, trying it the other |
81 | // way around first would mean we make the type variable `!`, instead of | ||
82 | // just marking it as possibly diverging. | ||
83 | if self.coerce(ty2, ty1) { | ||
77 | ty1.clone() | 84 | ty1.clone() |
85 | } else if self.coerce(ty1, ty2) { | ||
86 | ty2.clone() | ||
78 | } else { | 87 | } else { |
79 | // FIXME record a type mismatch | 88 | // TODO record a type mismatch |
80 | cov_mark::hit!(coerce_merge_fail_fallback); | 89 | cov_mark::hit!(coerce_merge_fail_fallback); |
81 | ty1.clone() | 90 | ty1.clone() |
82 | } | 91 | } |
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs index 67295b663..bb568ea37 100644 --- a/crates/hir_ty/src/tests/coercion.rs +++ b/crates/hir_ty/src/tests/coercion.rs | |||
@@ -873,3 +873,42 @@ fn foo(c: i32) { | |||
873 | "#, | 873 | "#, |
874 | ) | 874 | ) |
875 | } | 875 | } |
876 | |||
877 | #[test] | ||
878 | fn infer_match_diverging_branch_1() { | ||
879 | check_types( | ||
880 | r#" | ||
881 | enum Result<T> { Ok(T), Err } | ||
882 | fn parse<T>() -> T { loop {} } | ||
883 | |||
884 | fn test() -> i32 { | ||
885 | let a = match parse() { | ||
886 | Ok(val) => val, | ||
887 | Err => return 0, | ||
888 | }; | ||
889 | a | ||
890 | //^ i32 | ||
891 | } | ||
892 | "#, | ||
893 | ) | ||
894 | } | ||
895 | |||
896 | #[test] | ||
897 | fn infer_match_diverging_branch_2() { | ||
898 | // same as 1 except for order of branches | ||
899 | check_types( | ||
900 | r#" | ||
901 | enum Result<T> { Ok(T), Err } | ||
902 | fn parse<T>() -> T { loop {} } | ||
903 | |||
904 | fn test() -> i32 { | ||
905 | let a = match parse() { | ||
906 | Err => return 0, | ||
907 | Ok(val) => val, | ||
908 | }; | ||
909 | a | ||
910 | //^ i32 | ||
911 | } | ||
912 | "#, | ||
913 | ) | ||
914 | } | ||