Skip to content

Commit

Permalink
Introduce trait_obj_ty query
Browse files Browse the repository at this point in the history
This query computes the trait object, complete with associated type
projections for its supertraits, from a trait ref.

This is intended for use by CFI labeling, to allow it to determine the
abstract type that will be used by a receiver, based on the instantiated
trait that defines the vtable.
  • Loading branch information
maurer committed Mar 24, 2024
1 parent 6a92312 commit c71a011
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,15 @@ rustc_queries! {
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
}

/// Construct a type for a trait object corresponding to `trait_ref`. This type will have all
/// associated types for it and its supertraits expanded and resolved as additional predicates.
///
/// The provided `trait_ref` must be sufficiently instantiated that all associated types can be
/// successfully resolved.
query trait_object_ty(trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
desc { "Compute the trait object type for calling a method on a trait" }
}
}

rustc_query_append! { define_callbacks! }
Expand Down
29 changes: 29 additions & 0 deletions compiler/rustc_trait_selection/src/traits/vtable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::errors::DumpVTableEntries;
use crate::traits;
use crate::traits::{impossible_predicates, is_vtable_safe_method};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
Expand All @@ -13,6 +14,7 @@ use rustc_span::{sym, Span};
use smallvec::SmallVec;

use std::fmt::Debug;
use std::iter;
use std::ops::ControlFlow;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -232,6 +234,32 @@ fn own_existential_vtable_entries_iter(
own_entries
}

fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
let principal_pred = poly_trait_ref.map_bound(|trait_ref| {
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
});
let assoc_preds = traits::supertraits(tcx, poly_trait_ref).flat_map(|super_poly_trait_ref| {
tcx.associated_items(super_poly_trait_ref.def_id())
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.map(move |assoc_ty| {
super_poly_trait_ref.map_bound(|super_trait_ref| {
let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args);
let resolved = tcx
.normalize_erasing_regions(ty::ParamEnv::reveal_all(), 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(),
})
})
})
});
let preds =
tcx.mk_poly_existential_predicates_from_iter(iter::once(principal_pred).chain(assoc_preds));
Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn)
}

/// Given a trait `trait_ref`, iterates the vtable entries
/// that come from `trait_ref`, including its supertraits.
fn vtable_entries<'tcx>(
Expand Down Expand Up @@ -404,6 +432,7 @@ pub(super) fn provide(providers: &mut Providers) {
own_existential_vtable_entries,
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
trait_object_ty,
..*providers
};
}

0 comments on commit c71a011

Please sign in to comment.