Structurally resolve in may_coerce

This commit is contained in:
Michael Goulet 2024-10-15 13:47:43 -04:00
parent e3eba2d920
commit 9070abab4b
3 changed files with 61 additions and 2 deletions

View File

@ -1094,12 +1094,31 @@ pub(crate) fn may_coerce(&self, expr_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> bool
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
// We don't ever need two-phase here since we throw out the result of the coercion.
// We also just always set `coerce_never` to true, since this is a heuristic.
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
let coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true);
self.probe(|_| {
// Make sure to structurally resolve the types, since we use
// the `TyKind`s heavily in coercion.
let ocx = ObligationCtxt::new(self);
let structurally_resolve = |ty| {
let ty = self.shallow_resolve(ty);
if self.next_trait_solver()
&& let ty::Alias(..) = ty.kind()
{
ocx.structurally_normalize(&cause, self.param_env, ty)
} else {
Ok(ty)
}
};
let Ok(expr_ty) = structurally_resolve(expr_ty) else {
return false;
};
let Ok(target_ty) = structurally_resolve(target_ty) else {
return false;
};
let Ok(ok) = coerce.coerce(expr_ty, target_ty) else {
return false;
};
let ocx = ObligationCtxt::new(self);
ocx.register_obligations(ok.obligations);
ocx.select_where_possible().is_empty()
})

View File

@ -0,0 +1,19 @@
//@ compile-flags: -Znext-solver
trait Mirror {
type Assoc;
}
impl<T> Mirror for T {
type Assoc = T;
}
fn arg() -> &'static [i32; 1] { todo!() }
fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
fn main() {
// Should suggest to reverse the args...
// but if we don't normalize the expected, then we don't.
arg_error((), || ());
//~^ ERROR arguments to this function are incorrect
}

View File

@ -0,0 +1,21 @@
error[E0308]: arguments to this function are incorrect
--> $DIR/coerce-in-may-coerce.rs:17:5
|
LL | arg_error((), || ());
| ^^^^^^^^^ -- ----- expected `()`, found `{closure@$DIR/coerce-in-may-coerce.rs:17:19: 17:21}`
| |
| expected `<fn() as Mirror>::Assoc`, found `()`
|
note: function defined here
--> $DIR/coerce-in-may-coerce.rs:12:4
|
LL | fn arg_error(x: <fn() as Mirror>::Assoc, y: ()) { todo!() }
| ^^^^^^^^^ -------------------------- -----
help: swap these arguments
|
LL | arg_error(|| (), ());
| ~~~~~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.