mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Use CoerceMany
in BreakableContext
This commit is contained in:
parent
e968d834ca
commit
9272942b92
3 changed files with 26 additions and 36 deletions
|
@ -35,9 +35,9 @@ use stdx::impl_from;
|
|||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy,
|
||||
DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, Substitution, TraitEnvironment,
|
||||
TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
|
||||
to_assoc_type_id, AliasEq, AliasTy, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
|
||||
Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
};
|
||||
|
||||
// This lint has a false positive here. See the link below for details.
|
||||
|
@ -349,7 +349,7 @@ struct InferenceContext<'a> {
|
|||
#[derive(Clone, Debug)]
|
||||
struct BreakableContext {
|
||||
may_break: bool,
|
||||
break_ty: Ty,
|
||||
coerce: CoerceMany,
|
||||
label: Option<name::Name>,
|
||||
}
|
||||
|
||||
|
|
|
@ -48,17 +48,6 @@ impl CoerceMany {
|
|||
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.
|
||||
///
|
||||
/// Mostly this means trying to coerce one to the other, but
|
||||
|
|
|
@ -163,7 +163,7 @@ impl<'a> InferenceContext<'a> {
|
|||
let break_ty = self.table.new_type_var();
|
||||
self.breakables.push(BreakableContext {
|
||||
may_break: false,
|
||||
break_ty: break_ty.clone(),
|
||||
coerce: CoerceMany::new(break_ty.clone()),
|
||||
label: label.map(|label| self.body[label].name.clone()),
|
||||
});
|
||||
let ty = self.infer_block(
|
||||
|
@ -174,7 +174,7 @@ impl<'a> InferenceContext<'a> {
|
|||
);
|
||||
let ctxt = self.breakables.pop().expect("breakable stack broken");
|
||||
if ctxt.may_break {
|
||||
ctxt.break_ty
|
||||
ctxt.coerce.complete()
|
||||
} else {
|
||||
ty
|
||||
}
|
||||
|
@ -202,18 +202,16 @@ impl<'a> InferenceContext<'a> {
|
|||
Expr::Loop { body, label } => {
|
||||
self.breakables.push(BreakableContext {
|
||||
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()),
|
||||
});
|
||||
self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
|
||||
|
||||
let ctxt = self.breakables.pop().expect("breakable stack broken");
|
||||
if ctxt.may_break {
|
||||
self.diverges = Diverges::Maybe;
|
||||
}
|
||||
|
||||
if ctxt.may_break {
|
||||
ctxt.break_ty
|
||||
self.diverges = Diverges::Maybe;
|
||||
ctxt.coerce.complete()
|
||||
} else {
|
||||
TyKind::Never.intern(&Interner)
|
||||
}
|
||||
|
@ -221,8 +219,7 @@ impl<'a> InferenceContext<'a> {
|
|||
Expr::While { condition, body, label } => {
|
||||
self.breakables.push(BreakableContext {
|
||||
may_break: false,
|
||||
break_ty: self.err_ty(),
|
||||
|
||||
coerce: CoerceMany::new(self.err_ty()),
|
||||
label: label.map(|label| self.body[label].name.clone()),
|
||||
});
|
||||
// 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 {
|
||||
may_break: false,
|
||||
break_ty: self.err_ty(),
|
||||
coerce: CoerceMany::new(self.err_ty()),
|
||||
label: label.map(|label| self.body[label].name.clone()),
|
||||
});
|
||||
let pat_ty =
|
||||
|
@ -383,31 +380,35 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
Expr::Continue { .. } => TyKind::Never.intern(&Interner),
|
||||
Expr::Break { expr, label } => {
|
||||
let expr = *expr;
|
||||
let last_ty =
|
||||
if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
|
||||
ctxt.break_ty.clone()
|
||||
} else {
|
||||
self.err_ty()
|
||||
let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) {
|
||||
Some(ctxt) => {
|
||||
// avoiding the borrowck
|
||||
mem::replace(
|
||||
&mut ctxt.coerce,
|
||||
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())
|
||||
} else {
|
||||
TyBuilder::unit()
|
||||
};
|
||||
|
||||
// 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()) {
|
||||
ctxt.break_ty = merged_type;
|
||||
ctxt.coerce = coerce;
|
||||
ctxt.may_break = true;
|
||||
} else {
|
||||
self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
|
||||
expr: tgt_expr,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TyKind::Never.intern(&Interner)
|
||||
}
|
||||
Expr::Return { expr } => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue