Use CoerceMany in BreakableContext

This commit is contained in:
Lukas Wirth 2021-07-09 14:56:49 +02:00
parent e968d834ca
commit 9272942b92
3 changed files with 26 additions and 36 deletions

View file

@ -35,9 +35,9 @@ use stdx::impl_from;
use syntax::SmolStr; use syntax::SmolStr;
use crate::{ use crate::{
db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, Substitution, TraitEnvironment, to_assoc_type_id, AliasEq, AliasTy, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
TraitRef, Ty, TyBuilder, TyExt, TyKind, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
}; };
// This lint has a false positive here. See the link below for details. // This lint has a false positive here. See the link below for details.
@ -349,7 +349,7 @@ struct InferenceContext<'a> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct BreakableContext { struct BreakableContext {
may_break: bool, may_break: bool,
break_ty: Ty, coerce: CoerceMany,
label: Option<name::Name>, label: Option<name::Name>,
} }

View file

@ -48,17 +48,6 @@ impl CoerceMany {
CoerceMany { expected_ty: expected } CoerceMany { expected_ty: expected }
} }
pub(super) fn once(
ctx: &mut InferenceContext<'_>,
expected: Ty,
expr: Option<ExprId>,
expr_ty: &Ty,
) -> Ty {
let mut this = CoerceMany::new(expected);
this.coerce(ctx, expr, expr_ty);
this.complete()
}
/// Merge two types from different branches, with possible coercion. /// Merge two types from different branches, with possible coercion.
/// ///
/// Mostly this means trying to coerce one to the other, but /// Mostly this means trying to coerce one to the other, but

View file

@ -163,7 +163,7 @@ impl<'a> InferenceContext<'a> {
let break_ty = self.table.new_type_var(); let break_ty = self.table.new_type_var();
self.breakables.push(BreakableContext { self.breakables.push(BreakableContext {
may_break: false, may_break: false,
break_ty: break_ty.clone(), coerce: CoerceMany::new(break_ty.clone()),
label: label.map(|label| self.body[label].name.clone()), label: label.map(|label| self.body[label].name.clone()),
}); });
let ty = self.infer_block( let ty = self.infer_block(
@ -174,7 +174,7 @@ impl<'a> InferenceContext<'a> {
); );
let ctxt = self.breakables.pop().expect("breakable stack broken"); let ctxt = self.breakables.pop().expect("breakable stack broken");
if ctxt.may_break { if ctxt.may_break {
ctxt.break_ty ctxt.coerce.complete()
} else { } else {
ty ty
} }
@ -202,18 +202,16 @@ impl<'a> InferenceContext<'a> {
Expr::Loop { body, label } => { Expr::Loop { body, label } => {
self.breakables.push(BreakableContext { self.breakables.push(BreakableContext {
may_break: false, may_break: false,
break_ty: self.table.new_type_var(), coerce: CoerceMany::new(self.table.new_type_var()),
label: label.map(|label| self.body[label].name.clone()), label: label.map(|label| self.body[label].name.clone()),
}); });
self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
let ctxt = self.breakables.pop().expect("breakable stack broken"); let ctxt = self.breakables.pop().expect("breakable stack broken");
if ctxt.may_break {
self.diverges = Diverges::Maybe;
}
if ctxt.may_break { if ctxt.may_break {
ctxt.break_ty self.diverges = Diverges::Maybe;
ctxt.coerce.complete()
} else { } else {
TyKind::Never.intern(&Interner) TyKind::Never.intern(&Interner)
} }
@ -221,8 +219,7 @@ impl<'a> InferenceContext<'a> {
Expr::While { condition, body, label } => { Expr::While { condition, body, label } => {
self.breakables.push(BreakableContext { self.breakables.push(BreakableContext {
may_break: false, may_break: false,
break_ty: self.err_ty(), coerce: CoerceMany::new(self.err_ty()),
label: label.map(|label| self.body[label].name.clone()), label: label.map(|label| self.body[label].name.clone()),
}); });
// while let is desugared to a match loop, so this is always simple while // while let is desugared to a match loop, so this is always simple while
@ -241,7 +238,7 @@ impl<'a> InferenceContext<'a> {
self.breakables.push(BreakableContext { self.breakables.push(BreakableContext {
may_break: false, may_break: false,
break_ty: self.err_ty(), coerce: CoerceMany::new(self.err_ty()),
label: label.map(|label| self.body[label].name.clone()), label: label.map(|label| self.body[label].name.clone()),
}); });
let pat_ty = let pat_ty =
@ -383,31 +380,35 @@ impl<'a> InferenceContext<'a> {
} }
Expr::Continue { .. } => TyKind::Never.intern(&Interner), Expr::Continue { .. } => TyKind::Never.intern(&Interner),
Expr::Break { expr, label } => { Expr::Break { expr, label } => {
let expr = *expr; let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
let last_ty = Some(ctxt) => {
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { // avoiding the borrowck
ctxt.break_ty.clone() mem::replace(
} else { &mut ctxt.coerce,
self.err_ty() CoerceMany::new(self.result.standard_types.unknown.clone()),
)
}
None => CoerceMany::new(self.result.standard_types.unknown.clone()),
}; };
let val_ty = if let Some(expr) = expr { let val_ty = if let Some(expr) = *expr {
self.infer_expr(expr, &Expectation::none()) self.infer_expr(expr, &Expectation::none())
} else { } else {
TyBuilder::unit() TyBuilder::unit()
}; };
// FIXME: create a synthetic `()` during lowering so we have something to refer to here? // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
let merged_type = CoerceMany::once(self, last_ty, expr, &val_ty); coerce.coerce(self, *expr, &val_ty);
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
ctxt.break_ty = merged_type; ctxt.coerce = coerce;
ctxt.may_break = true; ctxt.may_break = true;
} else { } else {
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
expr: tgt_expr, expr: tgt_expr,
}); });
} };
TyKind::Never.intern(&Interner) TyKind::Never.intern(&Interner)
} }
Expr::Return { expr } => { Expr::Return { expr } => {