mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Properly coerce never types
This commit is contained in:
parent
8b612251fd
commit
89f3cc587d
3 changed files with 46 additions and 57 deletions
|
@ -11,10 +11,4 @@ test_utils::marks!(
|
|||
match_ergonomics_ref
|
||||
trait_resolution_on_fn_type
|
||||
infer_while_let
|
||||
match_first_arm_never
|
||||
match_second_arm_never
|
||||
match_all_arms_never
|
||||
match_no_never_arms
|
||||
if_never
|
||||
if_else_never
|
||||
);
|
||||
|
|
|
@ -297,7 +297,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
| (other, Ty::Infer(InferTy::IntVar(tv)))
|
||||
| (Ty::Infer(InferTy::FloatVar(tv)), other)
|
||||
| (other, Ty::Infer(InferTy::FloatVar(tv)))
|
||||
if !Self::is_never(other) =>
|
||||
if !is_never(other) =>
|
||||
{
|
||||
// the type var is unknown since we tried to resolve it
|
||||
self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
|
||||
|
@ -984,24 +984,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Expr::If { condition, then_branch, else_branch } => {
|
||||
// if let is desugared to match, so this is always simple if
|
||||
self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
|
||||
let then_ty = self.infer_expr(*then_branch, expected);
|
||||
|
||||
let mut branch_tys = Vec::with_capacity(2);
|
||||
let then_ty = self.infer_expr(*then_branch, &expected);
|
||||
match else_branch {
|
||||
Some(else_branch) => {
|
||||
let else_ty = self.infer_expr(*else_branch, expected);
|
||||
if Self::is_never(&then_ty) {
|
||||
tested_by!(if_never);
|
||||
else_ty
|
||||
} else {
|
||||
tested_by!(if_else_never);
|
||||
then_ty
|
||||
}
|
||||
branch_tys.push(self.infer_expr(*else_branch, &expected));
|
||||
}
|
||||
None => {
|
||||
// no else branch -> unit
|
||||
self.unify(&then_ty, &Ty::unit()); // actually coerce
|
||||
then_ty
|
||||
}
|
||||
}
|
||||
};
|
||||
branch_tys.push(then_ty);
|
||||
calculate_least_upper_bound(expected.ty.clone(), branch_tys)
|
||||
}
|
||||
Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
|
||||
Expr::TryBlock { body } => {
|
||||
|
@ -1081,15 +1077,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Expr::MethodCall { receiver, args, method_name, generic_args } => self
|
||||
.infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()),
|
||||
Expr::Match { expr, arms } => {
|
||||
let input_ty = self.infer_expr(*expr, &Expectation::none());
|
||||
let expected = if expected.ty == Ty::Unknown {
|
||||
Expectation::has_type(self.new_type_var())
|
||||
} else {
|
||||
expected.clone()
|
||||
};
|
||||
let input_ty = self.infer_expr(*expr, &Expectation::none());
|
||||
|
||||
let mut resulting_match_ty = None;
|
||||
let mut all_arms_never = !arms.is_empty();
|
||||
let mut arm_tys = Vec::with_capacity(arms.len());
|
||||
|
||||
for arm in arms {
|
||||
for &pat in &arm.pats {
|
||||
|
@ -1101,28 +1096,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
&Expectation::has_type(Ty::simple(TypeCtor::Bool)),
|
||||
);
|
||||
}
|
||||
let arm_ty = self.infer_expr(arm.expr, &expected);
|
||||
if all_arms_never && Self::is_never(&arm_ty) {
|
||||
tested_by!(match_first_arm_never);
|
||||
resulting_match_ty = Some(arm_ty);
|
||||
} else {
|
||||
tested_by!(match_second_arm_never);
|
||||
all_arms_never = false;
|
||||
resulting_match_ty = None;
|
||||
}
|
||||
}
|
||||
|
||||
if let (Ty::Infer(expected_tv), Some(match_ty)) =
|
||||
(&expected.ty, &resulting_match_ty)
|
||||
{
|
||||
tested_by!(match_all_arms_never);
|
||||
self.var_unification_table
|
||||
.union_value(expected_tv.to_inner(), TypeVarValue::Known(match_ty.clone()));
|
||||
match_ty.clone()
|
||||
} else {
|
||||
tested_by!(match_no_never_arms);
|
||||
expected.ty
|
||||
arm_tys.push(self.infer_expr(arm.expr, &expected));
|
||||
}
|
||||
calculate_least_upper_bound(expected.ty.clone(), arm_tys)
|
||||
}
|
||||
Expr::Path(p) => {
|
||||
// FIXME this could be more efficient...
|
||||
|
@ -1397,14 +1373,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
ty
|
||||
}
|
||||
|
||||
fn is_never(ty: &Ty) -> bool {
|
||||
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn infer_block(
|
||||
&mut self,
|
||||
statements: &[Statement],
|
||||
|
@ -1653,3 +1621,37 @@ mod diagnostics {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_never(ty: &Ty) -> bool {
|
||||
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }) = ty {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn calculate_least_upper_bound(expected_ty: Ty, actual_tys: Vec<Ty>) -> Ty {
|
||||
let mut all_never = true;
|
||||
let mut last_never_ty = None;
|
||||
let mut least_upper_bound = expected_ty;
|
||||
|
||||
for actual_ty in actual_tys {
|
||||
if is_never(&actual_ty) {
|
||||
last_never_ty = Some(actual_ty);
|
||||
} else {
|
||||
all_never = false;
|
||||
least_upper_bound = match (&actual_ty, &least_upper_bound) {
|
||||
(_, Ty::Unknown)
|
||||
| (Ty::Infer(_), Ty::Infer(InferTy::TypeVar(_)))
|
||||
| (Ty::Apply(_), _) => actual_ty,
|
||||
_ => least_upper_bound,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if all_never && last_never_ty.is_some() {
|
||||
last_never_ty.unwrap()
|
||||
} else {
|
||||
least_upper_bound
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3597,11 +3597,9 @@ fn no_such_field_diagnostics() {
|
|||
|
||||
mod branching_with_never_tests {
|
||||
use super::type_at;
|
||||
use test_utils::covers;
|
||||
|
||||
#[test]
|
||||
fn match_first_arm_never() {
|
||||
covers!(match_first_arm_never);
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
@ -3622,7 +3620,6 @@ fn test(a: i32) {
|
|||
|
||||
#[test]
|
||||
fn if_never() {
|
||||
covers!(if_never);
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
@ -3642,7 +3639,6 @@ fn test() {
|
|||
|
||||
#[test]
|
||||
fn if_else_never() {
|
||||
covers!(if_else_never);
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
@ -3662,7 +3658,6 @@ fn test(input: bool) {
|
|||
|
||||
#[test]
|
||||
fn match_second_arm_never() {
|
||||
covers!(match_second_arm_never);
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
@ -3683,7 +3678,6 @@ fn test(a: i32) {
|
|||
|
||||
#[test]
|
||||
fn match_all_arms_never() {
|
||||
covers!(match_all_arms_never);
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
@ -3702,7 +3696,6 @@ fn test(a: i32) {
|
|||
|
||||
#[test]
|
||||
fn match_no_never_arms() {
|
||||
covers!(match_no_never_arms);
|
||||
let t = type_at(
|
||||
r#"
|
||||
//- /main.rs
|
||||
|
|
Loading…
Reference in a new issue