@@ -86,6 +86,7 @@ use dep_graph::DepNode;
86
86
use fmt_macros:: { Parser , Piece , Position } ;
87
87
use hir:: def:: { Def , CtorKind } ;
88
88
use hir:: def_id:: { CrateNum , DefId , LOCAL_CRATE } ;
89
+ use rustc_back:: slice:: ref_slice;
89
90
use rustc:: infer:: { self , InferCtxt , InferOk , RegionVariableOrigin , TypeTrace } ;
90
91
use rustc:: infer:: type_variable:: { self , TypeVariableOrigin } ;
91
92
use rustc:: ty:: subst:: { Kind , Subst , Substs } ;
@@ -4108,102 +4109,64 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
4108
4109
replace ( & mut * fcx_ps, unsafety_state)
4109
4110
} ;
4110
4111
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 => & [ ] ,
4119
4136
} ;
4137
+ CoerceMany :: with_coercion_sites ( coerce_to_ty, tail_expr)
4138
+ } ;
4120
4139
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
+ } ;
4169
4144
4170
- ctxt. unified
4171
- } else {
4145
+ let ( ctxt, ( ) ) = self . with_breakable_ctxt ( blk. id , ctxt, || {
4172
4146
for s in & blk. stmts {
4173
4147
self . check_stmt ( s) ;
4174
4148
}
4175
4149
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) ) ;
4184
4153
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 ) ) ;
4204
4166
}
4205
- ty
4206
- } ;
4167
+ } ) ;
4168
+
4169
+ let mut ty = ctxt. coerce . unwrap ( ) . complete ( self ) ;
4207
4170
4208
4171
if self . has_errors . get ( ) || ty. references_error ( ) {
4209
4172
ty = self . tcx . types . err
0 commit comments