@@ -1084,24 +1084,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1084
1084
} )
1085
1085
}
1086
1086
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.
1088
1089
///
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 {
1096
1095
let cause = self . cause ( DUMMY_SP , ObligationCauseCode :: ExprAssignable ) ;
1097
1096
// We don't ever need two-phase here since we throw out the result of the coercion.
1098
1097
// 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 ) ;
1100
1099
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 {
1102
1121
return false ;
1103
1122
} ;
1104
- let ocx = ObligationCtxt :: new ( self ) ;
1105
1123
ocx. register_obligations ( ok. obligations ) ;
1106
1124
ocx. select_where_possible ( ) . is_empty ( )
1107
1125
} )
@@ -1370,7 +1388,7 @@ pub fn can_coerce<'tcx>(
1370
1388
) -> bool {
1371
1389
let root_ctxt = crate :: typeck_root_ctxt:: TypeckRootCtxt :: new ( tcx, body_id) ;
1372
1390
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)
1374
1392
}
1375
1393
1376
1394
/// CoerceMany encapsulates the pattern you should use when you have
0 commit comments