Skip to content

Commit d448329

Browse files
committed
fix handling of blocks with CoerceMany
1 parent f837064 commit d448329

File tree

2 files changed

+51
-88
lines changed

2 files changed

+51
-88
lines changed

src/librustc_typeck/check/coercion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ pub struct CoerceMany<'gcx, 'tcx, 'exprs, E>
926926

927927
/// The type of a `CoerceMany` that is storing up the expressions into
928928
/// a buffer. We use this in `check/mod.rs` for things like `break`.
929-
pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'static, hir::Expr>;
929+
pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P<hir::Expr>>;
930930

931931
#[derive(Clone)] // (*)
932932
enum Expressions<'gcx, 'exprs, E>

src/librustc_typeck/check/mod.rs

Lines changed: 50 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ use dep_graph::DepNode;
8686
use fmt_macros::{Parser, Piece, Position};
8787
use hir::def::{Def, CtorKind};
8888
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
89+
use rustc_back::slice::ref_slice;
8990
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin, TypeTrace};
9091
use rustc::infer::type_variable::{self, TypeVariableOrigin};
9192
use rustc::ty::subst::{Kind, Subst, Substs};
@@ -4108,102 +4109,64 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
41084109
replace(&mut *fcx_ps, unsafety_state)
41094110
};
41104111

4111-
let mut ty = if blk.targeted_by_break {
4112-
let unified = self.next_ty_var(TypeVariableOrigin::TypeInference(blk.span));
4113-
let coerce_to = expected.only_has_type(self).unwrap_or(unified);
4114-
let ctxt = BreakableCtxt {
4115-
unified: unified,
4116-
coerce_to: coerce_to,
4117-
break_exprs: vec![],
4118-
may_break: false,
4112+
// In some cases, blocks have just one exit, but other blocks
4113+
// can be targeted by multiple breaks. This cannot happen in
4114+
// normal Rust syntax today, but it can happen when we desugar
4115+
// a `do catch { ... }` expression.
4116+
//
4117+
// Example 1:
4118+
//
4119+
// 'a: { if true { break 'a Err(()); } Ok(()) }
4120+
//
4121+
// Here we would wind up with two coercions, one from
4122+
// `Err(())` and the other from the tail expression
4123+
// `Ok(())`. If the tail expression is omitted, that's a
4124+
// "forced unit" -- unless the block diverges, in which
4125+
// case we can ignore the tail expression (e.g., `'a: {
4126+
// break 'a 22; }` would not force the type of the block
4127+
// to be `()`).
4128+
let tail_expr = blk.expr.as_ref();
4129+
let coerce_to_ty = expected.coercion_target_type(self, blk.span);
4130+
let coerce = if blk.targeted_by_break {
4131+
CoerceMany::new(coerce_to_ty)
4132+
} else {
4133+
let tail_expr: &[P<hir::Expr>] = match tail_expr {
4134+
Some(e) => ref_slice(e),
4135+
None => &[],
41194136
};
4137+
CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
4138+
};
41204139

4121-
let (mut ctxt, (e_ty, cause)) = self.with_breakable_ctxt(blk.id, ctxt, || {
4122-
for s in &blk.stmts {
4123-
self.check_stmt(s);
4124-
}
4125-
let coerce_to = {
4126-
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
4127-
enclosing_breakables.find_breakable(blk.id).coerce_to
4128-
};
4129-
let e_ty;
4130-
let cause;
4131-
match blk.expr {
4132-
Some(ref e) => {
4133-
e_ty = self.check_expr_with_hint(e, coerce_to);
4134-
cause = self.misc(e.span);
4135-
},
4136-
None => {
4137-
e_ty = if self.diverges.get().always() {
4138-
self.tcx.types.never
4139-
} else {
4140-
self.tcx.mk_nil()
4141-
};
4142-
cause = self.misc(blk.span);
4143-
}
4144-
};
4145-
4146-
(e_ty, cause)
4147-
});
4148-
4149-
if let ExpectHasType(ety) = expected {
4150-
if let Some(ref e) = blk.expr {
4151-
let result = if !ctxt.may_break {
4152-
self.try_coerce(e, e_ty, ctxt.coerce_to)
4153-
} else {
4154-
self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(),
4155-
ctxt.unified, e, e_ty)
4156-
};
4157-
match result {
4158-
Ok(ty) => ctxt.unified = ty,
4159-
Err(err) =>
4160-
self.report_mismatched_types(&cause, ctxt.unified, e_ty, err).emit(),
4161-
}
4162-
} else if self.diverges.get().always() {
4163-
// No tail expression and the body diverges; ignore
4164-
// the expected type, and keep `!` as the type of the
4165-
// block.
4166-
} else {
4167-
self.check_block_no_expr(blk, self.tcx.mk_nil(), e_ty);
4168-
};
4140+
let ctxt = BreakableCtxt {
4141+
coerce: Some(coerce),
4142+
may_break: false,
4143+
};
41694144

4170-
ctxt.unified
4171-
} else {
4145+
let (ctxt, ()) = self.with_breakable_ctxt(blk.id, ctxt, || {
41724146
for s in &blk.stmts {
41734147
self.check_stmt(s);
41744148
}
41754149

4176-
let mut ty = match blk.expr {
4177-
Some(ref e) => self.check_expr_with_expectation(e, expected),
4178-
None => if self.diverges.get().always() {
4179-
self.tcx.types.never
4180-
} else {
4181-
self.tcx.mk_nil()
4182-
},
4183-
};
4150+
// check the tail expression **without** holding the
4151+
// `enclosing_breakables` lock below.
4152+
let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
41844153

4185-
if let ExpectHasType(ety) = expected {
4186-
if let Some(ref e) = blk.expr {
4187-
// Coerce the tail expression to the right type.
4188-
self.demand_coerce(e, ty, ety);
4189-
4190-
// We already applied the type (and potentially errored),
4191-
// use the expected type to avoid further errors out.
4192-
ty = ety;
4193-
} else if self.diverges.get().always() {
4194-
// No tail expression and the body diverges; ignore
4195-
// the expected type, and keep `!` as the type of the
4196-
// block.
4197-
} else {
4198-
self.check_block_no_expr(blk, ty, ety);
4199-
4200-
// We already applied the type (and potentially errored),
4201-
// use the expected type to avoid further errors out.
4202-
ty = ety;
4203-
}
4154+
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
4155+
let mut ctxt = enclosing_breakables.find_breakable(blk.id);
4156+
let mut coerce = ctxt.coerce.as_mut().unwrap();
4157+
if let Some(tail_expr_ty) = tail_expr_ty {
4158+
let tail_expr = tail_expr.unwrap();
4159+
coerce.coerce(self,
4160+
&self.misc(tail_expr.span),
4161+
tail_expr,
4162+
tail_expr_ty,
4163+
self.diverges.get()); // TODO
4164+
} else if !self.diverges.get().always() {
4165+
coerce.coerce_forced_unit(self, &self.misc(blk.span));
42044166
}
4205-
ty
4206-
};
4167+
});
4168+
4169+
let mut ty = ctxt.coerce.unwrap().complete(self);
42074170

42084171
if self.has_errors.get() || ty.references_error() {
42094172
ty = self.tcx.types.err

0 commit comments

Comments
 (0)