@@ -1084,24 +1084,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10841084 } )
10851085 }
10861086
1087- /// Same as `coerce()`, but without side-effects.
1087+ /// Probe whether `expr_ty` can be coerced to `target_ty`. This has no side-effects,
1088+ /// and may return false positives if types are not yet fully constrained by inference.
10881089 ///
1089- /// Returns false if the coercion creates any obligations that result in
1090- /// errors.
1091- pub ( crate ) fn can_coerce ( & self , expr_ty : Ty < ' tcx > , target : Ty < ' tcx > ) -> bool {
1092- // FIXME(-Znext-solver): We need to structurally resolve both types here.
1093- let source = self . resolve_vars_with_obligations ( expr_ty) ;
1094- debug ! ( "coercion::can_with_predicates({:?} -> {:?})" , source, target) ;
1095-
1090+ /// Returns false if the coercion is not possible, or if the coercion creates any
1091+ /// sub-obligations that result in errors.
1092+ ///
1093+ /// This should only be used for diagnostics.
1094+ pub ( crate ) fn may_coerce ( & self , expr_ty : Ty < ' tcx > , target_ty : Ty < ' tcx > ) -> bool {
10961095 let cause = self . cause ( DUMMY_SP , ObligationCauseCode :: ExprAssignable ) ;
10971096 // We don't ever need two-phase here since we throw out the result of the coercion.
10981097 // We also just always set `coerce_never` to true, since this is a heuristic.
1099- let coerce = Coerce :: new ( self , cause, AllowTwoPhase :: No , true ) ;
1098+ let coerce = Coerce :: new ( self , cause. clone ( ) , AllowTwoPhase :: No , true ) ;
11001099 self . probe ( |_| {
1101- let Ok ( ok) = coerce. coerce ( source, target) else {
1100+ // Make sure to structurally resolve the types, since we use
1101+ // the `TyKind`s heavily in coercion.
1102+ let ocx = ObligationCtxt :: new ( self ) ;
1103+ let structurally_resolve = |ty| {
1104+ let ty = self . shallow_resolve ( ty) ;
1105+ if self . next_trait_solver ( )
1106+ && let ty:: Alias ( ..) = ty. kind ( )
1107+ {
1108+ ocx. structurally_normalize ( & cause, self . param_env , ty)
1109+ } else {
1110+ Ok ( ty)
1111+ }
1112+ } ;
1113+ let Ok ( expr_ty) = structurally_resolve ( expr_ty) else {
1114+ return false ;
1115+ } ;
1116+ let Ok ( target_ty) = structurally_resolve ( target_ty) else {
1117+ return false ;
1118+ } ;
1119+
1120+ let Ok ( ok) = coerce. coerce ( expr_ty, target_ty) else {
11021121 return false ;
11031122 } ;
1104- let ocx = ObligationCtxt :: new ( self ) ;
11051123 ocx. register_obligations ( ok. obligations ) ;
11061124 ocx. select_where_possible ( ) . is_empty ( )
11071125 } )
@@ -1370,7 +1388,7 @@ pub fn can_coerce<'tcx>(
13701388) -> bool {
13711389 let root_ctxt = crate :: typeck_root_ctxt:: TypeckRootCtxt :: new ( tcx, body_id) ;
13721390 let fn_ctxt = FnCtxt :: new ( & root_ctxt, param_env, body_id) ;
1373- fn_ctxt. can_coerce ( ty, output_ty)
1391+ fn_ctxt. may_coerce ( ty, output_ty)
13741392}
13751393
13761394/// CoerceMany encapsulates the pattern you should use when you have
0 commit comments