@@ -817,6 +817,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
817817 ForceLeakCheck :: No ,
818818 ) ?;
819819
820+ tracing:: debug!( ?coercion) ;
821+
820822 // Create an obligation for `Source: CoerceUnsized<Target>`.
821823 let cause = self . cause ( self . cause . span , ObligationCauseCode :: Coercion { source, target } ) ;
822824 let pred = ty:: TraitRef :: new ( self . tcx , coerce_unsized_did, [ coerce_source, coerce_target] ) ;
@@ -1270,7 +1272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12701272 }
12711273 }
12721274
1273- fn sig_for_fn_def_coercion (
1275+ pub ( crate ) fn sig_for_fn_def_coercion (
12741276 & self ,
12751277 fndef : Ty < ' tcx > ,
12761278 expected_safety : Option < hir:: Safety > ,
@@ -1313,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13131315 }
13141316 }
13151317
1316- fn sig_for_closure_coercion (
1318+ pub ( crate ) fn sig_for_closure_coercion (
13171319 & self ,
13181320 closure : Ty < ' tcx > ,
13191321 expected_safety : Option < hir:: Safety > ,
@@ -1504,13 +1506,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15041506 target
15051507 }
15061508 Err ( coerce_mutual_err) => {
1507- let new_to_expected_res = self . coerce (
1508- new,
1509- new_ty,
1510- expected_ty,
1511- AllowTwoPhase :: No ,
1512- Some ( cause. clone ( ) ) ,
1513- ) ;
1509+ let new_to_expected_res =
1510+ self . coerce ( new, new_ty, expected_ty, AllowTwoPhase :: No , Some ( cause. clone ( ) ) ) ;
15141511 match new_to_expected_res {
15151512 Ok ( t) => t,
15161513 Err ( _) => return Err ( coerce_mutual_err) ,
@@ -1581,7 +1578,7 @@ pub(crate) struct CoerceMany<'tcx> {
15811578 expected_ty : Ty < ' tcx > ,
15821579 final_ty : Option < Ty < ' tcx > > ,
15831580 expressions : Vec < ( Option < & ' tcx hir:: Expr < ' tcx > > , Ty < ' tcx > ) > ,
1584- pub ( crate ) force_initial_sub : bool
1581+ pub ( crate ) initial_guidance_only : bool ,
15851582}
15861583
15871584impl < ' tcx > CoerceMany < ' tcx > {
@@ -1595,7 +1592,12 @@ impl<'tcx> CoerceMany<'tcx> {
15951592 /// Creates a `CoerceMany` with a given capacity.
15961593 #[ tracing:: instrument( ) ]
15971594 pub ( crate ) fn with_capacity ( expected_ty : Ty < ' tcx > , capacity : usize ) -> Self {
1598- CoerceMany { expected_ty, final_ty : None , expressions : Vec :: with_capacity ( capacity) , force_initial_sub : false }
1595+ CoerceMany {
1596+ expected_ty,
1597+ final_ty : None ,
1598+ expressions : Vec :: with_capacity ( capacity) ,
1599+ initial_guidance_only : false ,
1600+ }
15991601 }
16001602
16011603 /// Returns the "expected type" with which this coercion was
@@ -1712,16 +1714,43 @@ impl<'tcx> CoerceMany<'tcx> {
17121714 // Special-case the first expression we are coercing.
17131715 // To be honest, I'm not entirely sure why we do this.
17141716 // We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
1715- if self . force_initial_sub {
1717+ if ! self . initial_guidance_only {
17161718 fcx. coerce (
17171719 expression,
17181720 expression_ty,
17191721 self . expected_ty ,
17201722 AllowTwoPhase :: No ,
17211723 Some ( cause. clone ( ) ) ,
17221724 )
1723- } else {
1725+ } else if false {
17241726 Ok ( expression_ty)
1727+ } else {
1728+ // See `tests/ui/coercion/expected-guidance.rs` for why this is needed.
1729+ // If the expected type is e.g. `Option<?0>` and the first arm match sets it to `Option<X>`, the
1730+ // second arm should be able to observe that `?0` is `X`.
1731+
1732+ let source = fcx. try_structurally_resolve_type ( expression. span , expression_ty) ;
1733+ let target = if fcx. next_trait_solver ( ) {
1734+ fcx. try_structurally_resolve_type ( cause. span , self . expected_ty )
1735+ } else {
1736+ self . expected_ty
1737+ } ;
1738+ let coerce_never =
1739+ fcx. tcx . expr_guaranteed_to_constitute_read_for_never ( expression) ;
1740+ let guidance = crate :: coercion_guidance:: CoerceGuidance :: new (
1741+ fcx,
1742+ cause. clone ( ) ,
1743+ AllowTwoPhase :: No ,
1744+ coerce_never,
1745+ )
1746+ . do_guidance ( source, target) ;
1747+ match guidance {
1748+ Ok ( ok) => {
1749+ fcx. register_infer_ok_obligations ( ok) ;
1750+ Ok ( source)
1751+ }
1752+ Err ( e) => Err ( e) ,
1753+ }
17251754 }
17261755 } else {
17271756 fcx. try_find_coercion_lub (
@@ -1749,12 +1778,7 @@ impl<'tcx> CoerceMany<'tcx> {
17491778 // Another example is `break` with no argument expression.
17501779 assert ! ( expression_ty. is_unit( ) , "if let hack without unit type" ) ;
17511780 for ( expr, expr_ty) in self . expressions . iter ( ) {
1752- let coerce = Coerce :: new (
1753- fcx,
1754- cause. clone ( ) ,
1755- AllowTwoPhase :: No ,
1756- true ,
1757- ) ;
1781+ let coerce = Coerce :: new ( fcx, cause. clone ( ) , AllowTwoPhase :: No , true ) ;
17581782 let ok = match fcx. commit_if_ok ( |_| coerce. coerce ( * expr_ty, expression_ty) ) {
17591783 Ok ( coerce) => coerce,
17601784 Err ( e) => {
@@ -1843,8 +1867,7 @@ impl<'tcx> CoerceMany<'tcx> {
18431867 E0069 ,
18441868 "`return;` in a function whose return type is not `()`"
18451869 ) ;
1846- if let Some ( value) = fcx. err_ctxt ( ) . ty_kind_suggestion ( fcx. param_env , found)
1847- {
1870+ if let Some ( value) = fcx. err_ctxt ( ) . ty_kind_suggestion ( fcx. param_env , found) {
18481871 err. span_suggestion_verbose (
18491872 cause. span . shrink_to_hi ( ) ,
18501873 "give the `return` a value of the expected type" ,
@@ -1901,10 +1924,7 @@ impl<'tcx> CoerceMany<'tcx> {
19011924 rpit_def_id,
19021925 arm_ty,
19031926 prior_arm_ty,
1904- prior_non_diverging_arms
1905- . iter ( )
1906- . chain ( std:: iter:: once ( & arm_span) )
1907- . copied ( ) ,
1927+ prior_non_diverging_arms. iter ( ) . chain ( std:: iter:: once ( & arm_span) ) . copied ( ) ,
19081928 ) ;
19091929 }
19101930 }
@@ -2181,6 +2201,7 @@ impl<'tcx> CoerceMany<'tcx> {
21812201 & self ,
21822202 fcx : & FnCtxt < ' a , ' tcx > ,
21832203 cause : & ObligationCause < ' tcx > ,
2204+ mut expected_ty : Ty < ' tcx > ,
21842205 coerce_never : bool ,
21852206 ) -> Ty < ' tcx > {
21862207 let Some ( final_ty) = self . final_ty else {
@@ -2190,69 +2211,70 @@ impl<'tcx> CoerceMany<'tcx> {
21902211 return fcx. tcx . types . never ;
21912212 } ;
21922213
2193- if self . force_initial_sub {
2214+ if ! self . initial_guidance_only {
21942215 return final_ty;
21952216 }
2196-
2197- let mut expected_ty = self . expected_ty ;
2198- if fcx. next_trait_solver ( ) {
2199- expected_ty = fcx. try_structurally_resolve_type (
2200- cause. span ,
2201- expected_ty,
2202- ) ;
2217+
2218+ if true {
2219+ //return final_ty;
22032220 }
22042221
2205- // You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2206- // then *also* each expression ty to the `expected_ty`?".
2207- // TODO: investigate and validate the following claim
2208- // Basically, if `expected_ty` is an inference variable, then a coercion
2209- // with the first arm can constrain that because of the `unify` fallback.
2222+ if fcx. next_trait_solver ( ) {
2223+ expected_ty = fcx. try_structurally_resolve_type ( cause. span , expected_ty) ;
2224+ }
22102225
22112226 let final_ty = fcx. try_structurally_resolve_type ( cause. span , final_ty) ;
2227+ let expected_ty = fcx. try_structurally_resolve_type ( cause. span , expected_ty) ;
22122228 debug ! ( "coerce::complete (final_ty): {:?} -> {:?}" , final_ty, expected_ty) ;
22132229
2214- let coerce = Coerce :: new (
2215- fcx,
2216- cause. clone ( ) ,
2217- AllowTwoPhase :: No ,
2218- coerce_never,
2219- ) ;
2220- let ok = match fcx. commit_if_ok ( |_| coerce. coerce ( final_ty, expected_ty) ) {
2221- Ok ( coerce) => coerce,
2222- Err ( err) => {
2223- let reported = self . report_coercion_error (
2224- fcx,
2225- err,
2226- cause,
2227- None ,
2228- expected_ty,
2229- final_ty,
2230- |_| { }
2231- ) ;
2232- return Ty :: new_error ( fcx. tcx , reported) ;
2233- }
2234- } ;
2235- let _ = fcx. register_infer_ok_obligations ( ok) ;
2230+ if true {
2231+ // You may ask "Why do we coerce the `final_ty` to the `expected_ty`, and
2232+ // then *also* each expression ty to the `expected_ty`?".
2233+ // TODO: investigate and validate the following claim
2234+ // Basically, if `expected_ty` is an inference variable, then a coercion
2235+ // with the first arm can constrain that because of the `unify` fallback.
2236+
2237+ let coerce = Coerce :: new ( fcx, cause. clone ( ) , AllowTwoPhase :: No , coerce_never) ;
2238+ let ok = match fcx. commit_if_ok ( |_| coerce. coerce ( final_ty, expected_ty) ) {
2239+ Ok ( coerce) => coerce,
2240+ Err ( err) => {
2241+ let reported = self . report_coercion_error (
2242+ fcx,
2243+ err,
2244+ cause,
2245+ None ,
2246+ expected_ty,
2247+ final_ty,
2248+ |_| { } ,
2249+ ) ;
2250+ return Ty :: new_error ( fcx. tcx , reported) ;
2251+ }
2252+ } ;
2253+ let _ = fcx. register_infer_ok_obligations ( ok) ;
2254+ }
22362255
22372256 for ( expr, ty) in self . expressions . iter ( ) {
22382257 let source = fcx. try_structurally_resolve_type ( cause. span , * ty) ;
22392258 debug ! ( "coerce::complete (expression): {:?} -> {:?}" , source, expected_ty) ;
22402259
2241- let coerce = Coerce :: new (
2242- fcx,
2243- cause. clone ( ) ,
2244- AllowTwoPhase :: No ,
2245- coerce_never,
2246- ) ;
2260+ let coerce = Coerce :: new ( fcx, cause. clone ( ) , AllowTwoPhase :: No , coerce_never) ;
22472261 let ok = match fcx. commit_if_ok ( |_| coerce. coerce ( source, expected_ty) ) {
22482262 Ok ( coerce) => coerce,
22492263 Err ( e) => {
2250- let reported = self . report_coercion_error ( fcx, e, cause, * expr, expected_ty, source, |_| { } ) ;
2264+ let reported = self . report_coercion_error (
2265+ fcx,
2266+ e,
2267+ cause,
2268+ * expr,
2269+ expected_ty,
2270+ source,
2271+ |_| { } ,
2272+ ) ;
22512273 return Ty :: new_error ( fcx. tcx , reported) ;
22522274 }
22532275 } ;
22542276 let ( adjustments, _) = fcx. register_infer_ok_obligations ( ok) ;
2255-
2277+
22562278 if let Some ( expr) = expr {
22572279 fcx. set_adjustments ( expr, adjustments. clone ( ) ) ;
22582280 }
@@ -2263,17 +2285,17 @@ impl<'tcx> CoerceMany<'tcx> {
22632285 if let Err ( guar) = final_ty. error_reported ( ) {
22642286 Ty :: new_error ( fcx. tcx , guar)
22652287 } else {
2266- self . expected_ty
2288+ expected_ty
22672289 }
22682290 }
22692291}
22702292
22712293/// Recursively visit goals to decide whether an unsizing is possible.
22722294/// `Break`s when it isn't, and an error should be raised.
22732295/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item.
2274- struct CoerceVisitor < ' a , ' tcx > {
2275- fcx : & ' a FnCtxt < ' a , ' tcx > ,
2276- span : Span ,
2296+ pub ( crate ) struct CoerceVisitor < ' a , ' tcx > {
2297+ pub ( crate ) fcx : & ' a FnCtxt < ' a , ' tcx > ,
2298+ pub ( crate ) span : Span ,
22772299}
22782300
22792301impl < ' tcx > ProofTreeVisitor < ' tcx > for CoerceVisitor < ' _ , ' tcx > {
0 commit comments