aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2021-05-15 16:01:27 +0100
committerFlorian Diebold <[email protected]>2021-05-21 16:48:34 +0100
commit32fc944263ae0b30eba130fbcf28f4eb5578fdb3 (patch)
tree779b701955168f7472a5ae7e760cb95c6ca604e4 /crates/hir_ty
parenta09079f27aa631b011f6c0703200862d28af81f4 (diff)
Fix handling of diverging branches in match coercion
Fixes #7626.
Diffstat (limited to 'crates/hir_ty')
-rw-r--r--crates/hir_ty/src/infer/coerce.rs17
-rw-r--r--crates/hir_ty/src/tests/coercion.rs39
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]
878fn infer_match_diverging_branch_1() {
879 check_types(
880 r#"
881enum Result<T> { Ok(T), Err }
882fn parse<T>() -> T { loop {} }
883
884fn 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]
897fn infer_match_diverging_branch_2() {
898 // same as 1 except for order of branches
899 check_types(
900 r#"
901enum Result<T> { Ok(T), Err }
902fn parse<T>() -> T { loop {} }
903
904fn test() -> i32 {
905 let a = match parse() {
906 Err => return 0,
907 Ok(val) => val,
908 };
909 a
910 //^ i32
911}
912 "#,
913 )
914}