@@ -139,8 +139,8 @@ impl CoerceMany {
139139} ;
140140if let Some ( sig) = sig {
141141let 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, CoerceNever :: Yes ) ;
143+ let result2 = ctx. table . coerce_inner ( expr_ty. clone ( ) , & target_ty, CoerceNever :: Yes ) ;
144144if let ( Ok ( result1) , Ok ( result2) ) = ( result1, result2) {
145145 ctx. table . register_infer_ok ( InferOk { value : ( ) , goals : result1. goals } ) ;
146146for & e in & self . expressions {
@@ -159,9 +159,9 @@ impl CoerceMany {
159159// type is a type variable and the new one is `!`, trying it the other
160160// way around first would mean we make the type variable `!`, instead of
161161// 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 ( ) , CoerceNever :: Yes ) {
163163self . 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, CoerceNever :: Yes ) {
165165self . final_ty = Some ( res) ;
166166} else {
167167match cause {
@@ -197,7 +197,7 @@ pub(crate) fn coerce(
197197let vars = table. fresh_subst ( tys. binders . as_slice ( Interner ) ) ;
198198let ty1_with_vars = vars. apply ( tys. value . 0 . clone ( ) , Interner ) ;
199199let 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, CoerceNever :: Yes ) ?;
201201// default any type vars that weren't unified back to their original bound vars
202202// (kind of hacky)
203203let find_var = |iv| {
@@ -219,6 +219,12 @@ pub(crate) fn coerce(
219219Ok ( ( adjustments, table. resolve_with_fallback ( ty, & fallback) ) )
220220}
221221
222+ #[ derive( Clone , Copy , PartialEq , Eq ) ]
223+ pub ( crate ) enum CoerceNever {
224+ Yes ,
225+ No ,
226+ }
227+
222228impl InferenceContext < ' _ > {
223229/// Unify two types, but may coerce the first one to the second one
224230/// using "implicit coercion rules" if needed.
@@ -227,10 +233,16 @@ impl InferenceContext<'_> {
227233expr : Option < ExprId > ,
228234from_ty : & Ty ,
229235to_ty : & Ty ,
236+ // [Comment from rustc](https://github.com/rust-lang/rust/blob/4cc494bbfe9911d24f3ee521f98d5c6bb7e3ffe8/compiler/rustc_hir_typeck/src/coercion.rs#L85-L89)
237+ // Whether we allow `NeverToAny` coercions. This is unsound if we're
238+ // coercing a place expression without it counting as a read in the MIR.
239+ // This is a side-effect of HIR not really having a great distinction
240+ // between places and values.
241+ coerce_never : CoerceNever ,
230242) -> Result < Ty , TypeError > {
231243let from_ty = self . resolve_ty_shallow ( from_ty) ;
232244let to_ty = self . resolve_ty_shallow ( to_ty) ;
233- let ( adjustments, ty) = self . table . coerce ( & from_ty, & to_ty) ?;
245+ let ( adjustments, ty) = self . table . coerce ( & from_ty, & to_ty, coerce_never ) ?;
234246if let Some ( expr) = expr {
235247self . write_expr_adj ( expr, adjustments) ;
236248}
@@ -245,10 +257,11 @@ impl InferenceTable<'_> {
245257& mut self ,
246258from_ty : & Ty ,
247259to_ty : & Ty ,
260+ coerce_never : CoerceNever ,
248261) -> Result < ( Vec < Adjustment > , Ty ) , TypeError > {
249262let from_ty = self . resolve_ty_shallow ( from_ty) ;
250263let to_ty = self . resolve_ty_shallow ( to_ty) ;
251- match self . coerce_inner ( from_ty, & to_ty) {
264+ match self . coerce_inner ( from_ty, & to_ty, coerce_never ) {
252265Ok ( InferOk { value : ( adjustments, ty) , goals } ) => {
253266self . register_infer_ok ( InferOk { value : ( ) , goals } ) ;
254267Ok ( ( adjustments, ty) )
@@ -260,19 +273,23 @@ impl InferenceTable<'_> {
260273}
261274}
262275
263- fn coerce_inner ( & mut self , from_ty : Ty , to_ty : & Ty ) -> CoerceResult {
276+ fn coerce_inner ( & mut self , from_ty : Ty , to_ty : & Ty , coerce_never : CoerceNever ) -> CoerceResult {
264277if 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`.
272278if let TyKind :: InferenceVar ( tv, TyVariableKind :: General ) = to_ty. kind ( Interner ) {
273279self . set_diverging ( * tv, true ) ;
274280}
275- return success ( simple ( Adjust :: NeverToAny ) ( to_ty. clone ( ) ) , to_ty. clone ( ) , vec ! [ ] ) ;
281+ if coerce_never == CoerceNever :: Yes {
282+ // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
283+ // type variable, we want `?T` to fallback to `!` if not
284+ // otherwise constrained. An example where this arises:
285+ //
286+ // let _: Option<?T> = Some({ return; });
287+ //
288+ // here, we would coerce from `!` to `?T`.
289+ return success ( simple ( Adjust :: NeverToAny ) ( to_ty. clone ( ) ) , to_ty. clone ( ) , vec ! [ ] ) ;
290+ } else {
291+ return self . unify_and ( & from_ty, to_ty, identity) ;
292+ }
276293}
277294
278295// If we are coercing into a TAIT, coerce into its proxy inference var, instead.
0 commit comments