Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d6fc4a9

Browse files
committed
Simplify breakables handling
1 parent 643c3a5 commit d6fc4a9

File tree

2 files changed

+48
-46
lines changed

2 files changed

+48
-46
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,8 +418,11 @@ pub(crate) struct InferenceContext<'a> {
418418

419419
#[derive(Clone, Debug)]
420420
struct BreakableContext {
421+
/// Whether this context contains at least one break expression.
421422
may_break: bool,
423+
/// The coercion target of the context.
422424
coerce: CoerceMany,
425+
/// The optional label of the context.
423426
label: Option<name::Name>,
424427
}
425428

crates/hir-ty/src/infer/expr.rs

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use chalk_ir::{
1010
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
1111
};
1212
use hir_def::{
13-
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp},
13+
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
1414
generics::TypeOrConstParamData,
1515
path::{GenericArg, GenericArgs},
1616
resolver::resolver_for_expr,
@@ -120,20 +120,16 @@ impl<'a> InferenceContext<'a> {
120120
let ty = match label {
121121
Some(_) => {
122122
let break_ty = self.table.new_type_var();
123-
self.breakables.push(BreakableContext {
124-
may_break: false,
125-
coerce: CoerceMany::new(break_ty.clone()),
126-
label: label.map(|label| self.body[label].name.clone()),
123+
let (ctx, ty) = self.with_breakable_ctx(break_ty.clone(), *label, |this| {
124+
this.infer_block(
125+
tgt_expr,
126+
statements,
127+
*tail,
128+
&Expectation::has_type(break_ty),
129+
)
127130
});
128-
let ty = self.infer_block(
129-
tgt_expr,
130-
statements,
131-
*tail,
132-
&Expectation::has_type(break_ty),
133-
);
134-
let ctxt = self.breakables.pop().expect("breakable stack broken");
135-
if ctxt.may_break {
136-
ctxt.coerce.complete()
131+
if ctx.may_break {
132+
ctx.coerce.complete()
137133
} else {
138134
ty
139135
}
@@ -166,54 +162,42 @@ impl<'a> InferenceContext<'a> {
166162
TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty))
167163
.intern(Interner)
168164
}
169-
Expr::Loop { body, label } => {
170-
self.breakables.push(BreakableContext {
171-
may_break: false,
172-
coerce: CoerceMany::new(self.table.new_type_var()),
173-
label: label.map(|label| self.body[label].name.clone()),
165+
&Expr::Loop { body, label } => {
166+
let ty = self.table.new_type_var();
167+
let (ctx, ()) = self.with_breakable_ctx(ty, label, |this| {
168+
this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
174169
});
175-
self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
176170

177-
let ctxt = self.breakables.pop().expect("breakable stack broken");
178-
179-
if ctxt.may_break {
171+
if ctx.may_break {
180172
self.diverges = Diverges::Maybe;
181-
ctxt.coerce.complete()
173+
ctx.coerce.complete()
182174
} else {
183175
TyKind::Never.intern(Interner)
184176
}
185177
}
186-
Expr::While { condition, body, label } => {
187-
self.breakables.push(BreakableContext {
188-
may_break: false,
189-
coerce: CoerceMany::new(self.err_ty()),
190-
label: label.map(|label| self.body[label].name.clone()),
178+
&Expr::While { condition, body, label } => {
179+
self.with_breakable_ctx(self.err_ty(), label, |this| {
180+
this.infer_expr(
181+
condition,
182+
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
183+
);
184+
this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
191185
});
192-
self.infer_expr(
193-
*condition,
194-
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
195-
);
196-
self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
197-
let _ctxt = self.breakables.pop().expect("breakable stack broken");
186+
198187
// the body may not run, so it diverging doesn't mean we diverge
199188
self.diverges = Diverges::Maybe;
200189
TyBuilder::unit()
201190
}
202-
Expr::For { iterable, body, pat, label } => {
203-
let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
204-
205-
self.breakables.push(BreakableContext {
206-
may_break: false,
207-
coerce: CoerceMany::new(self.err_ty()),
208-
label: label.map(|label| self.body[label].name.clone()),
209-
});
191+
&Expr::For { iterable, body, pat, label } => {
192+
let iterable_ty = self.infer_expr(iterable, &Expectation::none());
210193
let pat_ty =
211194
self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
212195

213-
self.infer_pat(*pat, &pat_ty, BindingMode::default());
196+
self.infer_pat(pat, &pat_ty, BindingMode::default());
197+
let (_ctx, ()) = self.with_breakable_ctx(self.err_ty(), label, |this| {
198+
this.infer_expr(body, &Expectation::has_type(TyBuilder::unit()));
199+
});
214200

215-
self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
216-
let _ctxt = self.breakables.pop().expect("breakable stack broken");
217201
// the body may not run, so it diverging doesn't mean we diverge
218202
self.diverges = Diverges::Maybe;
219203
TyBuilder::unit()
@@ -1472,4 +1456,19 @@ impl<'a> InferenceContext<'a> {
14721456
},
14731457
})
14741458
}
1459+
1460+
fn with_breakable_ctx<T>(
1461+
&mut self,
1462+
ty: Ty,
1463+
label: Option<LabelId>,
1464+
cb: impl FnOnce(&mut Self) -> T,
1465+
) -> (BreakableContext, T) {
1466+
self.breakables.push({
1467+
let label = label.map(|label| self.body[label].name.clone());
1468+
BreakableContext { may_break: false, coerce: CoerceMany::new(ty), label }
1469+
});
1470+
let res = cb(self);
1471+
let ctx = self.breakables.pop().expect("breakable stack broken");
1472+
(ctx, res)
1473+
}
14751474
}

0 commit comments

Comments
 (0)