Skip to content

Commit

Permalink
Validate ExistentialPredicate args
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Sep 30, 2024
1 parent 9368b9f commit 2239f1c
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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, _)| {
Expand Down Expand Up @@ -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)
})
});

Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/reachable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
),
)
})
})
})
Expand Down Expand Up @@ -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());
Expand Down
20 changes: 11 additions & 9 deletions compiler/rustc_smir/src/rustc_internal/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)
}
}

Expand All @@ -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),
)
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_smir/src/rustc_smir/convert/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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),
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_type_ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>,
Expand Down
45 changes: 44 additions & 1 deletion compiler/rustc_type_ir/src/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,16 +289,34 @@ 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);

ExistentialTraitRef {
def_id: trait_ref.def_id,
args: interner.mk_args(&trait_ref.args.as_slice()[1..]),
_use_existential_trait_ref_new_instead: (),
}
}

Expand Down Expand Up @@ -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
Expand All @@ -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> {
Expand All @@ -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: (),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_type_ir/src/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
}
}
Expand Down Expand Up @@ -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))
}
}
}
Expand Down

0 comments on commit 2239f1c

Please sign in to comment.