Fix match type inference for Never match arms

This commit is contained in:
Kirill Bulatov 2019-08-12 01:01:15 +03:00
parent f63cfd5fca
commit 0ce05633a1
2 changed files with 32 additions and 6 deletions

View File

@ -280,8 +280,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
let ty1 = self.resolve_ty_shallow(ty1); let ty1 = self.resolve_ty_shallow(ty1);
let ty2 = self.resolve_ty_shallow(ty2); let ty2 = self.resolve_ty_shallow(ty2);
match (&*ty1, &*ty2) { match (&*ty1, &*ty2) {
(Ty::Unknown, ..) => true, (Ty::Unknown, _) | (_, Ty::Unknown) => true,
(.., Ty::Unknown) => true,
(Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => { (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1) self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
} }
@ -297,7 +296,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
| (Ty::Infer(InferTy::IntVar(tv)), other) | (Ty::Infer(InferTy::IntVar(tv)), other)
| (other, Ty::Infer(InferTy::IntVar(tv))) | (other, Ty::Infer(InferTy::IntVar(tv)))
| (Ty::Infer(InferTy::FloatVar(tv)), other) | (Ty::Infer(InferTy::FloatVar(tv)), other)
| (other, Ty::Infer(InferTy::FloatVar(tv))) => { | (other, Ty::Infer(InferTy::FloatVar(tv)))
if !Self::is_never(other) =>
{
// the type var is unknown since we tried to resolve it // the type var is unknown since we tried to resolve it
self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone())); self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
true true
@ -1080,6 +1081,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
}; };
let input_ty = self.infer_expr(*expr, &Expectation::none()); let input_ty = self.infer_expr(*expr, &Expectation::none());
let mut resulting_match_ty = None;
let mut all_arms_never = !arms.is_empty();
for arm in arms { for arm in arms {
for &pat in &arm.pats { for &pat in &arm.pats {
let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default()); let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
@ -1090,11 +1094,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
&Expectation::has_type(Ty::simple(TypeCtor::Bool)), &Expectation::has_type(Ty::simple(TypeCtor::Bool)),
); );
} }
self.infer_expr(arm.expr, &expected); let arm_ty = self.infer_expr(arm.expr, &expected);
if all_arms_never && Self::is_never(&arm_ty) {
resulting_match_ty = Some(arm_ty);
} else {
all_arms_never = false;
resulting_match_ty = None;
}
} }
if let (Ty::Infer(expected_tv), Some(match_ty)) =
(&expected.ty, &resulting_match_ty)
{
self.var_unification_table
.union_value(expected_tv.to_inner(), TypeVarValue::Known(match_ty.clone()));
match_ty.clone()
} else {
expected.ty expected.ty
} }
}
Expr::Path(p) => { Expr::Path(p) => {
// FIXME this could be more efficient... // FIXME this could be more efficient...
let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
@ -1368,6 +1386,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
ty ty
} }
fn is_never(ty: &Ty) -> bool {
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty {
true
} else {
false
}
}
fn infer_block( fn infer_block(
&mut self, &mut self,
statements: &[Statement], statements: &[Statement],

View File

@ -3600,7 +3600,7 @@ mod match_with_never_tests {
use super::type_at; use super::type_at;
#[test] #[test]
fn match_compex_arm_ty() { fn match_complex_arm_ty() {
let t = type_at( let t = type_at(
r#" r#"
//- /main.rs //- /main.rs