Validate ExistentialPredicate args

This commit is contained in:
Michael Goulet 2024-09-30 01:00:38 -04:00
parent 9368b9f57e
commit 2239f1c5cd
10 changed files with 103 additions and 32 deletions

View File

@ -250,7 +250,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
})
.collect();
let args = tcx.mk_args(&args);
let span = i.bottom().1;
let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| {
@ -283,7 +282,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.emit();
}
ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args)
})
});

View File

@ -279,6 +279,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.debug_assert_args_compatible(def_id, args);
}
/// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
/// are compatible with the `DefId`. Since we're missing a `Self` type, stick on
/// a dummy self type and forward to `debug_assert_args_compatible`.
fn debug_assert_existential_args_compatible(
self,
def_id: Self::DefId,
args: Self::GenericArgs,
) {
// FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible`
// to avoid needing to reintern the set of args...
if cfg!(debug_assertions) {
self.debug_assert_args_compatible(
def_id,
self.mk_args_from_iter(
[self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()),
),
);
}
}
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
where
I: Iterator<Item = T>,

View File

@ -322,7 +322,7 @@ impl<'tcx> ReachableContext<'tcx> {
self.visit(ty);
// Manually visit to actually see the trait's `DefId`. Type visitors won't see it
if let Some(trait_ref) = dyn_ty.principal() {
let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
let ExistentialTraitRef { def_id, args, .. } = trait_ref.skip_binder();
self.visit_def_id(def_id, "", &"");
self.visit(args);
}

View File

@ -32,8 +32,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility,
use rustc_middle::query::Providers;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
TypeVisitable, TypeVisitor,
self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitor,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
@ -246,10 +246,10 @@ where
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
ty::ExistentialPredicate::AutoTrait(def_id) => {
ty::ExistentialTraitRef { def_id, args: GenericArgs::empty() }
ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
}
};
let ty::ExistentialTraitRef { def_id, args: _ } = trait_ref;
let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
}
}

View File

@ -245,11 +245,15 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
alias_ty.to_ty(tcx),
);
debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
def_id: assoc_ty.def_id,
args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
term: resolved.into(),
})
ty::ExistentialPredicate::Projection(
ty::ExistentialProjection::erase_self_ty(
tcx,
ty::ProjectionPredicate {
projection_term: alias_ty.into(),
term: resolved.into(),
},
),
)
})
})
})
@ -318,10 +322,11 @@ pub fn transform_instance<'tcx>(
.lang_items()
.drop_trait()
.unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args(
tcx,
def_id,
args: List::empty(),
});
ty::List::empty(),
));
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
instance.args = tcx.mk_args_trait(self_ty, List::empty());

View File

@ -380,11 +380,12 @@ impl RustcInternal for ExistentialProjection {
type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>;
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
rustc_ty::ExistentialProjection {
def_id: self.def_id.0.internal(tables, tcx),
args: self.generic_args.internal(tables, tcx),
term: self.term.internal(tables, tcx),
}
rustc_ty::ExistentialProjection::new_from_args(
tcx,
self.def_id.0.internal(tables, tcx),
self.generic_args.internal(tables, tcx),
self.term.internal(tables, tcx),
)
}
}
@ -403,10 +404,11 @@ impl RustcInternal for ExistentialTraitRef {
type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>;
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
rustc_ty::ExistentialTraitRef {
def_id: self.def_id.0.internal(tables, tcx),
args: self.generic_args.internal(tables, tcx),
}
rustc_ty::ExistentialTraitRef::new_from_args(
tcx,
self.def_id.0.internal(tables, tcx),
self.generic_args.internal(tables, tcx),
)
}
}

View File

@ -68,7 +68,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> {
type T = stable_mir::ty::ExistentialTraitRef;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
let ty::ExistentialTraitRef { def_id, args } = self;
let ty::ExistentialTraitRef { def_id, args, .. } = self;
stable_mir::ty::ExistentialTraitRef {
def_id: tables.trait_def(*def_id),
generic_args: args.stable(tables),
@ -95,7 +95,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> {
type T = stable_mir::ty::ExistentialProjection;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
let ty::ExistentialProjection { def_id, args, term } = self;
let ty::ExistentialProjection { def_id, args, term, .. } = self;
stable_mir::ty::ExistentialProjection {
def_id: tables.trait_def(*def_id),
generic_args: args.stable(tables),

View File

@ -15,9 +15,7 @@ use crate::solve::{
CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{
search_graph, {self as ty},
};
use crate::{self as ty, search_graph};
pub trait Interner:
Sized
@ -173,6 +171,10 @@ pub trait Interner:
fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
/// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
/// are compatible with the `DefId`.
fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
where
I: Iterator<Item = T>,

View File

@ -289,9 +289,26 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
pub struct ExistentialTraitRef<I: Interner> {
pub def_id: I::DefId,
pub args: I::GenericArgs,
/// This field exists to prevent the creation of `ExistentialTraitRef` without
/// calling [`ExistentialTraitRef::new_from_args`].
_use_existential_trait_ref_new_instead: (),
}
impl<I: Interner> ExistentialTraitRef<I> {
pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self {
interner.debug_assert_existential_args_compatible(trait_def_id, args);
Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () }
}
pub fn new(
interner: I,
trait_def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
) -> Self {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, trait_def_id, args)
}
pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> {
// Assert there is a Self.
trait_ref.args.type_at(0);
@ -299,6 +316,7 @@ impl<I: Interner> ExistentialTraitRef<I> {
ExistentialTraitRef {
def_id: trait_ref.def_id,
args: interner.mk_args(&trait_ref.args.as_slice()[1..]),
_use_existential_trait_ref_new_instead: (),
}
}
@ -336,9 +354,33 @@ pub struct ExistentialProjection<I: Interner> {
pub def_id: I::DefId,
pub args: I::GenericArgs,
pub term: I::Term,
/// This field exists to prevent the creation of `ExistentialProjection`
/// without using [`ExistentialProjection::new_from_args`].
use_existential_projection_new_instead: (),
}
impl<I: Interner> ExistentialProjection<I> {
pub fn new_from_args(
interner: I,
def_id: I::DefId,
args: I::GenericArgs,
term: I::Term,
) -> ExistentialProjection<I> {
interner.debug_assert_existential_args_compatible(def_id, args);
Self { def_id, args, term, use_existential_projection_new_instead: () }
}
pub fn new(
interner: I,
def_id: I::DefId,
args: impl IntoIterator<Item: Into<I::GenericArg>>,
term: I::Term,
) -> ExistentialProjection<I> {
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
Self::new_from_args(interner, def_id, args, term)
}
/// Extracts the underlying existential trait reference from this projection.
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
/// then this function would return an `exists T. T: Iterator` existential trait
@ -347,7 +389,7 @@ impl<I: Interner> ExistentialProjection<I> {
let def_id = interner.parent(self.def_id);
let args_count = interner.generics_of(def_id).count() - 1;
let args = interner.mk_args(&self.args.as_slice()[..args_count]);
ExistentialTraitRef { def_id, args }
ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () }
}
pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
@ -372,6 +414,7 @@ impl<I: Interner> ExistentialProjection<I> {
def_id: projection_predicate.projection_term.def_id,
args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
term: projection_predicate.term,
use_existential_projection_new_instead: (),
}
}
}

View File

@ -308,7 +308,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
a.args,
b.args,
)?;
Ok(ty::ExistentialProjection { def_id: a.def_id, args, term })
Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term))
}
}
}
@ -348,7 +348,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> {
}))
} else {
let args = relate_args_invariantly(relation, a.args, b.args)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args))
}
}
}