Rollup merge of #150861 - folding-cleanups, r=lcnr

Folding/`ReErased` cleanups

Various cleanups I found while reading this code closely, mostly involving folding and the use of `ReErased`.

r? @lcnr
This commit is contained in:
Matthias Krüger 2026-01-12 13:32:07 +01:00 committed by GitHub
commit 79445c315e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 25 additions and 74 deletions

View file

@ -1520,7 +1520,6 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
// Unwrap potential addrspacecast
let vtable = find_vtable_behind_cast(vtable);
let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty);
let trait_ref_self = cx.tcx.erase_and_anonymize_regions(trait_ref_self);
let trait_def_id = trait_ref_self.def_id;
let trait_vis = cx.tcx.visibility(trait_def_id);

View file

@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint};
use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{FloatTy, PolyExistentialPredicate, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, ty};
use rustc_span::{Symbol, sym};
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
@ -243,13 +243,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
ocx.register_obligations(preds.iter().map(|pred: PolyExistentialPredicate<'_>| {
let pred = pred.with_self_ty(tcx, tp_ty);
// Lifetimes can only be 'static because of the bound on T
let pred = pred.fold_with(&mut ty::BottomUpFolder {
tcx,
ty_op: |ty| ty,
lt_op: |lt| {
if lt == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { lt }
},
ct_op: |ct| ct,
let pred = ty::fold_regions(tcx, pred, |r, _| {
if r == tcx.lifetimes.re_erased { tcx.lifetimes.re_static } else { r }
});
Obligation::new(tcx, ObligationCause::dummy(), param_env, pred)
}));

View file

@ -508,23 +508,18 @@ fn sanity_check_found_hidden_type<'tcx>(
return Ok(());
}
}
let strip_vars = |ty: Ty<'tcx>| {
ty.fold_with(&mut BottomUpFolder {
tcx,
ty_op: |t| t,
ct_op: |c| c,
lt_op: |l| match l.kind() {
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
_ => l,
},
let erase_re_vars = |ty: Ty<'tcx>| {
fold_regions(tcx, ty, |r, _| match r.kind() {
RegionKind::ReVar(_) => tcx.lifetimes.re_erased,
_ => r,
})
};
// Closures frequently end up containing erased lifetimes in their final representation.
// These correspond to lifetime variables that never got resolved, so we patch this up here.
ty.ty = strip_vars(ty.ty);
ty.ty = erase_re_vars(ty.ty);
// Get the hidden type.
let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
let hidden_ty = strip_vars(hidden_ty);
let hidden_ty = erase_re_vars(hidden_ty);
// If the hidden types differ, emit a type mismatch diagnostic.
if hidden_ty == ty.ty {

View file

@ -86,8 +86,8 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
fn is_transmutable(
&self,
dst: <Self::Interner as Interner>::Ty,
src: <Self::Interner as Interner>::Ty,
dst: <Self::Interner as Interner>::Ty,
assume: <Self::Interner as Interner>::Const,
) -> Result<Certainty, NoSolution>;
}

View file

@ -1170,8 +1170,8 @@ where
pub(super) fn is_transmutable(
&mut self,
dst: I::Ty,
src: I::Ty,
dst: I::Ty,
assume: I::Const,
) -> Result<Certainty, NoSolution> {
self.delegate.is_transmutable(dst, src, assume)

View file

@ -2781,11 +2781,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
self.tcx.instantiate_bound_regions_with_erased(trait_pred),
);
let src_and_dst = rustc_transmute::Types {
dst: trait_pred.trait_ref.args.type_at(0),
src: trait_pred.trait_ref.args.type_at(1),
};
let ocx = ObligationCtxt::new(self);
let Ok(assume) = ocx.structurally_normalize_const(
&obligation.cause,
@ -2812,7 +2807,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx)
.is_transmutable(src_and_dst, assume)
.is_transmutable(src, dst, assume)
{
Answer::No(reason) => {
let safe_transmute_explanation = match reason {

View file

@ -294,8 +294,8 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
fn is_transmutable(
&self,
dst: Ty<'tcx>,
src: Ty<'tcx>,
dst: Ty<'tcx>,
assume: ty::Const<'tcx>,
) -> Result<Certainty, NoSolution> {
// Erase regions because we compute layouts in `rustc_transmute`,
@ -307,9 +307,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
};
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx)
.is_transmutable(rustc_transmute::Types { src, dst }, assume)
{
match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx).is_transmutable(src, dst, assume) {
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
}

View file

@ -365,8 +365,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?src, ?dst);
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx);
let maybe_transmutable =
transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume);
let maybe_transmutable = transmute_env.is_transmutable(src, dst, assume);
let fully_flattened = match maybe_transmutable {
Answer::No(_) => Err(SelectionError::Unimplemented)?,

View file

@ -93,15 +93,6 @@ mod rustc {
use super::*;
/// The source and destination types of a transmutation.
#[derive(Debug, Clone, Copy)]
pub struct Types<'tcx> {
/// The source type.
pub src: Ty<'tcx>,
/// The destination type.
pub dst: Ty<'tcx>,
}
pub struct TransmuteTypeEnv<'tcx> {
tcx: TyCtxt<'tcx>,
}
@ -113,13 +104,12 @@ mod rustc {
pub fn is_transmutable(
&mut self,
types: Types<'tcx>,
src: Ty<'tcx>,
dst: Ty<'tcx>,
assume: crate::Assume,
) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
crate::maybe_transmutable::MaybeTransmutableQuery::new(
types.src, types.dst, assume, self.tcx,
)
.answer()
crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, self.tcx)
.answer()
}
}

View file

@ -222,8 +222,6 @@ fn resolve_associated_item<'tcx>(
return Err(guar);
}
let args = tcx.erase_and_anonymize_regions(args);
// We check that the impl item is compatible with the trait item
// because otherwise we may ICE in const eval due to type mismatches,
// signature incompatibilities, etc.

View file

@ -74,7 +74,7 @@ bitflags::bitflags! {
/// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10;
/// Does this have `Free` aliases?
const HAS_TY_FREE_ALIAS = 1 << 11;
const HAS_TY_FREE_ALIAS = 1 << 11;
/// Does this have `Opaque`?
const HAS_TY_OPAQUE = 1 << 12;
/// Does this have `Inherent`?
@ -135,7 +135,7 @@ bitflags::bitflags! {
const HAS_TY_CORO = 1 << 24;
/// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`?
const HAS_CANONICAL_BOUND = 1 << 25;
const HAS_CANONICAL_BOUND = 1 << 25;
}
}

View file

@ -12,7 +12,7 @@ use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::{Visitor, walk_expr};
use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::{GenericArgKind, Region, RegionKind, Ty, TyCtxt, TypeVisitable, TypeVisitor};
use rustc_middle::ty::{GenericArgKind, RegionKind, Ty, TypeVisitableExt};
use rustc_span::Span;
use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
@ -303,13 +303,13 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
if self.sig_drop_holder != SigDropHolder::None {
let parent_ty = self.cx.typeck_results().expr_ty(parent_expr);
if !ty_has_erased_regions(parent_ty) && !parent_expr.is_syntactic_place_expr() {
if !parent_ty.has_erased_regions() && !parent_expr.is_syntactic_place_expr() {
self.replace_current_sig_drop(parent_expr.span, parent_ty.is_unit(), 0);
self.sig_drop_holder = SigDropHolder::Moved;
}
let (peel_ref_ty, peel_ref_times) = ty_peel_refs(parent_ty);
if !ty_has_erased_regions(peel_ref_ty) && is_copy(self.cx, peel_ref_ty) {
if !peel_ref_ty.has_erased_regions() && is_copy(self.cx, peel_ref_ty) {
self.replace_current_sig_drop(parent_expr.span, peel_ref_ty.is_unit(), peel_ref_times);
self.sig_drop_holder = SigDropHolder::Moved;
}
@ -399,24 +399,6 @@ fn ty_peel_refs(mut ty: Ty<'_>) -> (Ty<'_>, usize) {
(ty, n)
}
fn ty_has_erased_regions(ty: Ty<'_>) -> bool {
struct V;
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for V {
type Result = ControlFlow<()>;
fn visit_region(&mut self, region: Region<'tcx>) -> Self::Result {
if region.is_erased() {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
}
ty.visit_with(&mut V).is_break()
}
impl<'tcx> Visitor<'tcx> for SigDropHelper<'_, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
// We've emitted a lint on some neighborhood expression. That lint will suggest to move out the

View file

@ -232,8 +232,8 @@ impl<'db> SolverDelegate for SolverContext<'db> {
fn is_transmutable(
&self,
_dst: Ty<'db>,
_src: Ty<'db>,
_dst: Ty<'db>,
_assume: <Self::Interner as rustc_type_ir::Interner>::Const,
) -> Result<Certainty, NoSolution> {
// It's better to return some value while not fully implement