@@ -139,8 +139,8 @@ impl CoerceMany {
139
139
} ;
140
140
if let Some ( sig) = sig {
141
141
let target_ty = TyKind :: Function ( sig. to_fn_ptr ( ) ) . intern ( Interner ) ;
142
- let result1 = ctx. table . coerce_inner ( self . merged_ty ( ) , & target_ty) ;
143
- let result2 = ctx. table . coerce_inner ( expr_ty. clone ( ) , & target_ty) ;
142
+ let result1 = ctx. table . coerce_inner ( self . merged_ty ( ) , & target_ty, true ) ;
143
+ let result2 = ctx. table . coerce_inner ( expr_ty. clone ( ) , & target_ty, true ) ;
144
144
if let ( Ok ( result1) , Ok ( result2) ) = ( result1, result2) {
145
145
ctx. table . register_infer_ok ( InferOk { value : ( ) , goals : result1. goals } ) ;
146
146
for & e in & self . expressions {
@@ -159,9 +159,9 @@ impl CoerceMany {
159
159
// type is a type variable and the new one is `!`, trying it the other
160
160
// way around first would mean we make the type variable `!`, instead of
161
161
// just marking it as possibly diverging.
162
- if let Ok ( res) = ctx. coerce ( expr, & expr_ty, & self . merged_ty ( ) ) {
162
+ if let Ok ( res) = ctx. coerce ( expr, & expr_ty, & self . merged_ty ( ) , true ) {
163
163
self . final_ty = Some ( res) ;
164
- } else if let Ok ( res) = ctx. coerce ( expr, & self . merged_ty ( ) , & expr_ty) {
164
+ } else if let Ok ( res) = ctx. coerce ( expr, & self . merged_ty ( ) , & expr_ty, true ) {
165
165
self . final_ty = Some ( res) ;
166
166
} else {
167
167
match cause {
@@ -197,7 +197,7 @@ pub(crate) fn coerce(
197
197
let vars = table. fresh_subst ( tys. binders . as_slice ( Interner ) ) ;
198
198
let ty1_with_vars = vars. apply ( tys. value . 0 . clone ( ) , Interner ) ;
199
199
let ty2_with_vars = vars. apply ( tys. value . 1 . clone ( ) , Interner ) ;
200
- let ( adjustments, ty) = table. coerce ( & ty1_with_vars, & ty2_with_vars) ?;
200
+ let ( adjustments, ty) = table. coerce ( & ty1_with_vars, & ty2_with_vars, true ) ?;
201
201
// default any type vars that weren't unified back to their original bound vars
202
202
// (kind of hacky)
203
203
let find_var = |iv| {
@@ -227,10 +227,16 @@ impl InferenceContext<'_> {
227
227
expr : Option < ExprId > ,
228
228
from_ty : & Ty ,
229
229
to_ty : & Ty ,
230
+ // [Comment from rustc](https://github.com/rust-lang/rust/blob/4cc494bbfe9911d24f3ee521f98d5c6bb7e3ffe8/compiler/rustc_hir_typeck/src/coercion.rs#L85-L89)
231
+ // Whether we allow `NeverToAny` coercions. This is unsound if we're
232
+ // coercing a place expression without it counting as a read in the MIR.
233
+ // This is a side-effect of HIR not really having a great distinction
234
+ // between places and values.
235
+ coerce_never : bool ,
230
236
) -> Result < Ty , TypeError > {
231
237
let from_ty = self . resolve_ty_shallow ( from_ty) ;
232
238
let to_ty = self . resolve_ty_shallow ( to_ty) ;
233
- let ( adjustments, ty) = self . table . coerce ( & from_ty, & to_ty) ?;
239
+ let ( adjustments, ty) = self . table . coerce ( & from_ty, & to_ty, coerce_never ) ?;
234
240
if let Some ( expr) = expr {
235
241
self . write_expr_adj ( expr, adjustments) ;
236
242
}
@@ -245,10 +251,11 @@ impl InferenceTable<'_> {
245
251
& mut self ,
246
252
from_ty : & Ty ,
247
253
to_ty : & Ty ,
254
+ coerce_never : bool ,
248
255
) -> Result < ( Vec < Adjustment > , Ty ) , TypeError > {
249
256
let from_ty = self . resolve_ty_shallow ( from_ty) ;
250
257
let to_ty = self . resolve_ty_shallow ( to_ty) ;
251
- match self . coerce_inner ( from_ty, & to_ty) {
258
+ match self . coerce_inner ( from_ty, & to_ty, coerce_never ) {
252
259
Ok ( InferOk { value : ( adjustments, ty) , goals } ) => {
253
260
self . register_infer_ok ( InferOk { value : ( ) , goals } ) ;
254
261
Ok ( ( adjustments, ty) )
@@ -260,19 +267,23 @@ impl InferenceTable<'_> {
260
267
}
261
268
}
262
269
263
- fn coerce_inner ( & mut self , from_ty : Ty , to_ty : & Ty ) -> CoerceResult {
270
+ fn coerce_inner ( & mut self , from_ty : Ty , to_ty : & Ty , coerce_never : bool ) -> CoerceResult {
264
271
if from_ty. is_never ( ) {
265
- // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
266
- // type variable, we want `?T` to fallback to `!` if not
267
- // otherwise constrained. An example where this arises:
268
- //
269
- // let _: Option<?T> = Some({ return; });
270
- //
271
- // here, we would coerce from `!` to `?T`.
272
272
if let TyKind :: InferenceVar ( tv, TyVariableKind :: General ) = to_ty. kind ( Interner ) {
273
273
self . set_diverging ( * tv, true ) ;
274
274
}
275
- return success ( simple ( Adjust :: NeverToAny ) ( to_ty. clone ( ) ) , to_ty. clone ( ) , vec ! [ ] ) ;
275
+ if coerce_never {
276
+ // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
277
+ // type variable, we want `?T` to fallback to `!` if not
278
+ // otherwise constrained. An example where this arises:
279
+ //
280
+ // let _: Option<?T> = Some({ return; });
281
+ //
282
+ // here, we would coerce from `!` to `?T`.
283
+ return success ( simple ( Adjust :: NeverToAny ) ( to_ty. clone ( ) ) , to_ty. clone ( ) , vec ! [ ] ) ;
284
+ } else {
285
+ return self . unify_and ( & from_ty, to_ty, identity) ;
286
+ }
276
287
}
277
288
278
289
// If we are coercing into a TAIT, coerce into its proxy inference var, instead.
0 commit comments