@@ -818,6 +818,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
818818 ForceLeakCheck :: No ,
819819 ) ?;
820820
821+ tracing:: debug!( ?coercion) ;
822+
821823 // Create an obligation for `Source: CoerceUnsized<Target>`.
822824 let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
823825 let pred = ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ;
@@ -1271,7 +1273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12711273 }
12721274 }
12731275
1274- fn sig_for_fn_def_coercion (
1276+ pub ( crate ) fn sig_for_fn_def_coercion (
12751277 & self ,
12761278 fndef : Ty < ' tcx > ,
12771279 expected_safety : Option < hir:: Safety > ,
@@ -1314,7 +1316,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13141316 }
13151317 }
13161318
1317- fn sig_for_closure_coercion (
1319+ pub ( crate ) fn sig_for_closure_coercion (
13181320 & self ,
13191321 closure : Ty < ' tcx > ,
13201322 expected_safety : Option < hir:: Safety > ,
@@ -1600,7 +1602,7 @@ pub(crate) struct CoerceMany<'tcx> {
16001602 expected_ty : Ty < ' tcx > ,
16011603 final_ty : Option < Ty < ' tcx > > ,
16021604 expressions : Vec < ( Option < & ' tcx hir:: Expr < ' tcx > > , Ty < ' tcx > ) > ,
1603- pub ( crate ) force_initial_sub : bool ,
1605+ pub ( crate ) initial_guidance_only : bool ,
16041606}
16051607
16061608impl < ' tcx > CoerceMany < ' tcx > {
@@ -1618,7 +1620,7 @@ impl<'tcx> CoerceMany<'tcx> {
16181620 expected_ty,
16191621 final_ty : None ,
16201622 expressions : Vec :: with_capacity ( capacity) ,
1621- force_initial_sub : false ,
1623+ initial_guidance_only : false ,
16221624 }
16231625 }
16241626
@@ -1736,16 +1738,43 @@ impl<'tcx> CoerceMany<'tcx> {
17361738 // Special-case the first expression we are coercing.
17371739 // To be honest, I'm not entirely sure why we do this.
17381740 // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
1739- if self . force_initial_sub {
1741+ if ! self . initial_guidance_only {
17401742 fcx. coerce (
17411743 expression,
17421744 expression_ty,
17431745 self . expected_ty ,
17441746 AllowTwoPhase :: No ,
17451747 Some ( cause. clone ( ) ) ,
17461748 )
1747- } else {
1749+ } else if false {
17481750 Ok ( expression_ty)
1751+ } else {
1752+ // See `tests/ui/coercion/expected-guidance.rs` for why this is needed.
1753+ // If the expected type is e.g. `Option<?0>` and the first arm match sets it to `Option<X>`, the
1754+ // second arm should be able to observe that `?0` is `X`.
1755+
1756+ let source = fcx. try_structurally_resolve_type ( expression. span , expression_ty) ;
1757+ let target = if fcx. next_trait_solver ( ) {
1758+ fcx. try_structurally_resolve_type ( cause. span , self . expected_ty )
1759+ } else {
1760+ self . expected_ty
1761+ } ;
1762+ let coerce_never =
1763+ fcx. tcx . expr_guaranteed_to_constitute_read_for_never ( expression) ;
1764+ let guidance = crate :: coercion_guidance:: CoerceGuidance :: new (
1765+ fcx,
1766+ cause. clone ( ) ,
1767+ AllowTwoPhase :: No ,
1768+ coerce_never,
1769+ )
1770+ . do_guidance ( source, target) ;
1771+ match guidance {
1772+ Ok ( ok) => {
1773+ fcx. register_infer_ok_obligations ( ok) ;
1774+ Ok ( source)
1775+ }
1776+ Err ( e) => Err ( e) ,
1777+ }
17491778 }
17501779 } else {
17511780 fcx. try_find_coercion_lub (
@@ -2196,6 +2225,7 @@ impl<'tcx> CoerceMany<'tcx> {
21962225 & self ,
21972226 fcx : & FnCtxt < ' a , ' tcx > ,
21982227 cause : & ObligationCause < ' tcx > ,
2228+ mut expected_ty : Ty < ' tcx > ,
21992229 coerce_never : bool ,
22002230 ) -> Ty < ' tcx > {
22012231 let Some ( final_ty) = self . final_ty else {
@@ -2205,7 +2235,7 @@ impl<'tcx> CoerceMany<'tcx> {
22052235 return fcx. tcx . types . never ;
22062236 } ;
22072237
2208- if self . force_initial_sub {
2238+ if ! self . initial_guidance_only {
22092239 return final_ty;
22102240 }
22112241
@@ -2214,32 +2244,39 @@ impl<'tcx> CoerceMany<'tcx> {
22142244 expected_ty = fcx. try_structurally_resolve_type ( cause. span , expected_ty) ;
22152245 }
22162246
2217- // You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2218- // then *also* each expression ty to the `expected_ty`?".
2219- // TODO: investigate and validate the following claim
2220- // Basically, if `expected_ty` is an inference variable, then a coercion
2221- // with the first arm can constrain that because of the `unify` fallback.
2247+ if fcx. next_trait_solver ( ) {
2248+ expected_ty = fcx. try_structurally_resolve_type ( cause. span , expected_ty) ;
2249+ }
22222250
22232251 let final_ty = fcx. try_structurally_resolve_type ( cause. span , final_ty) ;
2252+ let expected_ty = fcx. try_structurally_resolve_type ( cause. span , expected_ty) ;
22242253 debug ! ( "coerce::complete (final_ty): {:?} -> {:?}" , final_ty, expected_ty) ;
22252254
2226- let coerce = Coerce :: new ( fcx, cause. clone ( ) , AllowTwoPhase :: No , coerce_never) ;
2227- let ok = match fcx. commit_if_ok ( |_| coerce. coerce ( final_ty, expected_ty) ) {
2228- Ok ( coerce) => coerce,
2229- Err ( err) => {
2230- let reported = self . report_coercion_error (
2231- fcx,
2232- err,
2233- cause,
2234- None ,
2235- expected_ty,
2236- final_ty,
2237- |_| { } ,
2238- ) ;
2239- return Ty :: new_error ( fcx. tcx , reported) ;
2240- }
2241- } ;
2242- let _ = fcx. register_infer_ok_obligations ( ok) ;
2255+ if true {
2256+ // You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2257+ // then *also* each expression ty to the `expected_ty`?".
2258+ // TODO: investigate and validate the following claim
2259+ // Basically, if `expected_ty` is an inference variable, then a coercion
2260+ // with the first arm can constrain that because of the `unify` fallback.
2261+
2262+ let coerce = Coerce :: new ( fcx, cause. clone ( ) , AllowTwoPhase :: No , coerce_never) ;
2263+ let ok = match fcx. commit_if_ok ( |_| coerce. coerce ( final_ty, expected_ty) ) {
2264+ Ok ( coerce) => coerce,
2265+ Err ( err) => {
2266+ let reported = self . report_coercion_error (
2267+ fcx,
2268+ err,
2269+ cause,
2270+ None ,
2271+ expected_ty,
2272+ final_ty,
2273+ |_| { } ,
2274+ ) ;
2275+ return Ty :: new_error ( fcx. tcx , reported) ;
2276+ }
2277+ } ;
2278+ let _ = fcx. register_infer_ok_obligations ( ok) ;
2279+ }
22432280
22442281 for ( expr, ty) in self . expressions . iter ( ) {
22452282 let source = fcx. try_structurally_resolve_type ( cause. span , * ty) ;
@@ -2273,21 +2310,21 @@ impl<'tcx> CoerceMany<'tcx> {
22732310 if let Err ( guar) = final_ty. error_reported ( ) {
22742311 Ty :: new_error ( fcx. tcx , guar)
22752312 } else {
2276- self . expected_ty
2313+ expected_ty
22772314 }
22782315 }
22792316}
22802317
22812318/// Recursively visit goals to decide whether an unsizing is possible.
22822319/// `Break`s when it isn't, and an error should be raised.
22832320/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item.
2284- struct CoerceVisitor < ' a , ' tcx > {
2285- fcx : & ' a FnCtxt < ' a , ' tcx > ,
2286- span : Span ,
2321+ pub ( crate ) struct CoerceVisitor < ' a , ' tcx > {
2322+ pub ( crate ) fcx : & ' a FnCtxt < ' a , ' tcx > ,
2323+ pub ( crate ) span : Span ,
22872324 /// Whether the coercion is impossible. If so we sometimes still try to
22882325 /// coerce in these cases to emit better errors. This changes the behavior
22892326 /// when hitting the recursion limit.
2290- errored : bool ,
2327+ pub ( crate ) errored : bool ,
22912328}
22922329
22932330impl < ' tcx > ProofTreeVisitor < ' tcx > for CoerceVisitor < ' _ , ' tcx > {
0 commit comments