Fix ICE in transmutability error reporting when type aliases are normalized

This commit is contained in:
zedddie 2026-01-25 20:34:56 +01:00
parent 370143facf
commit a257fb960f
No known key found for this signature in database
GPG key ID: B352C3C2894405A7
3 changed files with 114 additions and 2 deletions

View file

@ -254,9 +254,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
LangItem::TransmuteTrait,
) {
// Recompute the safe transmute reason and use that for the error reporting
let (report_obligation, report_pred) =
self.select_transmute_obligation_for_reporting(
&obligation,
main_trait_predicate,
root_obligation,
);
match self.get_safe_transmute_error_and_reason(
obligation.clone(),
main_trait_predicate,
report_obligation,
report_pred,
span,
) {
GetSafeTransmuteErrorAndReason::Silent => {
@ -2793,6 +2800,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
})
}
fn select_transmute_obligation_for_reporting(
&self,
obligation: &PredicateObligation<'tcx>,
trait_predicate: ty::PolyTraitPredicate<'tcx>,
root_obligation: &PredicateObligation<'tcx>,
) -> (PredicateObligation<'tcx>, ty::PolyTraitPredicate<'tcx>) {
let ocx = ObligationCtxt::new(self);
let normalized_predicate = self.tcx.erase_and_anonymize_regions(
self.tcx.instantiate_bound_regions_with_erased(trait_predicate),
);
let trait_ref = normalized_predicate.trait_ref;
let Ok(assume) = ocx.structurally_normalize_const(
&obligation.cause,
obligation.param_env,
trait_ref.args.const_at(2),
) else {
return (obligation.clone(), trait_predicate);
};
let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else {
return (obligation.clone(), trait_predicate);
};
let is_normalized_yes = matches!(
rustc_transmute::TransmuteTypeEnv::new(self.tcx).is_transmutable(
trait_ref.args.type_at(1),
trait_ref.args.type_at(0),
assume,
),
rustc_transmute::Answer::Yes,
);
// If the normalized check unexpectedly passes, fall back to root obligation for reporting.
if is_normalized_yes
&& let ty::PredicateKind::Clause(ty::ClauseKind::Trait(root_pred)) =
root_obligation.predicate.kind().skip_binder()
&& root_pred.def_id() == trait_predicate.def_id()
{
return (root_obligation.clone(), root_obligation.predicate.kind().rebind(root_pred));
}
(obligation.clone(), trait_predicate)
}
fn get_safe_transmute_error_and_reason(
&self,
obligation: PredicateObligation<'tcx>,

View file

@ -0,0 +1,31 @@
//! regression test for https://github.com/rust-lang/rust/issues/151462
//@compile-flags: -Znext-solver=globally
#![feature(lazy_type_alias, transmutability)]
#![allow(incomplete_features)]
mod assert {
use std::mem::{Assume, TransmuteFrom};
pub fn is_maybe_transmutable<Src, Dst>()
where
Src: TransmuteFrom<
Src,
{
Assume {
alignment: true,
lifetimes: true,
safety: true,
validity: true,
}
},
>,
{
}
}
fn test() {
type JustUnit = ();
assert::is_maybe_transmutable::<JustUnit, ()>();
//~^ ERROR `JustUnit` cannot be safely transmuted into `JustUnit`
}
fn main() {}

View file

@ -0,0 +1,29 @@
error[E0277]: `JustUnit` cannot be safely transmuted into `JustUnit`
--> $DIR/type-alias-normalization.rs:27:37
|
LL | assert::is_maybe_transmutable::<JustUnit, ()>();
| ^^^^^^^^ analyzing the transmutability of `JustUnit` is not yet supported
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/type-alias-normalization.rs:10:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this function
LL | where
LL | Src: TransmuteFrom<
| ______________^
LL | | Src,
LL | | {
LL | | Assume {
... |
LL | | },
LL | | >,
| |_________^ required by this bound in `is_maybe_transmutable`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
LL | fn test() where (): TransmuteFrom<(), Assume { alignment: true, lifetimes: true, safety: true, validity: true }> {
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.