Skip to content

Commit

Permalink
Merge pull request #1000 from Nadrieril/cach-fulldef
Browse files Browse the repository at this point in the history
Cache `FullDef` translation and add more information to it
  • Loading branch information
Nadrieril authored Oct 14, 2024
2 parents ce9ea56 + 651ae5a commit e2734c8
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 34 deletions.
4 changes: 3 additions & 1 deletion frontend/exporter/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ macro_rules! mk {
mod types {
use crate::prelude::*;
use rustc_middle::ty;
use std::cell::RefCell;
use std::{cell::RefCell, sync::Arc};

pub struct LocalContextS {
pub vars: HashMap<rustc_middle::thir::LocalVarId, String>,
Expand Down Expand Up @@ -133,6 +133,8 @@ mod types {
pub struct ItemCache<'tcx> {
/// The translated `DefId`.
pub def_id: Option<DefId>,
/// The translated definition.
pub full_def: Option<Arc<FullDef>>,
/// Cache the `Ty` translations.
pub tys: HashMap<ty::Ty<'tcx>, Ty>,
/// Cache the trait resolution engine for each item.
Expand Down
47 changes: 34 additions & 13 deletions frontend/exporter/src/types/copied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3889,25 +3889,46 @@ pub enum PredicateKind {
}

/// Reflects [`rustc_middle::ty::ImplSubject`]
#[derive(AdtInto)]
#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::ImplSubject<'tcx>, state: S as s)]
#[derive_group(Serializers)]
#[derive(Clone, Debug, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum ImplSubject {
Trait(
// Also record the polarity.
#[map({
let polarity = s.base().tcx.impl_polarity(s.owner_id());
TraitPredicate {
trait_ref: x.sinto(s),
is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive),
}
})]
TraitPredicate,
),
Trait {
/// The trait that is implemented by this impl block.
trait_pred: TraitPredicate,
/// The `ImplExpr`s required to satisfy the predicates on the trait declaration. E.g.:
/// ```ignore
/// trait Foo: Bar {}
/// impl Foo for () {} // would supply an `ImplExpr` for `Self: Bar`.
/// ```
required_impl_exprs: Vec<ImplExpr>,
},
Inherent(Ty),
}

#[cfg(feature = "rustc")]
impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ImplSubject> for ty::ImplSubject<'tcx> {
fn sinto(&self, s: &S) -> ImplSubject {
let tcx = s.base().tcx;
match self {
ty::ImplSubject::Inherent(ty) => ImplSubject::Inherent(ty.sinto(s)),
ty::ImplSubject::Trait(trait_ref) => {
// Also record the polarity.
let polarity = tcx.impl_polarity(s.owner_id());
let trait_pred = TraitPredicate {
trait_ref: trait_ref.sinto(s),
is_positive: matches!(polarity, rustc_middle::ty::ImplPolarity::Positive),
};
let required_impl_exprs =
solve_item_traits(s, trait_ref.def_id, trait_ref.args, None);
ImplSubject::Trait {
trait_pred,
required_impl_exprs,
}
}
}
}
}

/// Reflects [`rustc_hir::GenericBounds`]
type GenericBounds = Vec<Clause>;

Expand Down
96 changes: 76 additions & 20 deletions frontend/exporter/src/types/new/full_def.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,75 @@
use crate::prelude::*;
use std::sync::Arc;

#[cfg(feature = "rustc")]
use rustc_middle::ty;
#[cfg(feature = "rustc")]
use rustc_span::def_id::DefId as RDefId;

/// Gathers a lot of definition information about a [`rustc_hir::def_id::DefId`].
#[derive(AdtInto)]
#[args(<'tcx, S: BaseState<'tcx>>, from: rustc_hir::def_id::DefId, state: S as s)]
#[derive_group(Serializers)]
#[derive(Clone, Debug, JsonSchema)]
pub struct FullDef {
#[value(self.sinto(s))]
pub def_id: DefId,
#[value(s.base().tcx.opt_parent(*self).sinto(s))]
/// The enclosing item.
pub parent: Option<DefId>,
#[value(s.base().tcx.def_span(*self).sinto(s))]
/// The span of the definition of this item (e.g. for a function this is is signature).
pub span: Span,
#[value(s.base().tcx.get_attrs_unchecked(*self).sinto(s))]
/// The span of the whole definition (including e.g. the function body).
pub source_span: Option<Span>,
/// The text of the whole definition.
pub source_text: Option<String>,
/// Attributes on this definition, if applicable.
pub attributes: Vec<Attribute>,
#[value(get_def_visibility(s, *self))]
/// Visibility of the definition, for definitions where this makes sense.
pub visibility: Option<bool>,
#[value(s.base().tcx.as_lang_item(*self).map(|litem| litem.name()).sinto(s))]
/// If this definition is a lang item, we store the identifier, e.g. `sized`.
pub lang_item: Option<String>,
#[value(s.base().tcx.get_diagnostic_name(*self).sinto(s))]
/// If this definition is a diagnostic item, we store the identifier, e.g. `box_new`.
pub diagnostic_item: Option<String>,
#[value({
let state_with_id = State { thir: (), mir: (), owner_id: *self, binder: (), base: s.base() };
s.base().tcx.def_kind(*self).sinto(&state_with_id)
})]
pub kind: FullDefKind,
}

#[cfg(feature = "rustc")]
impl<'tcx, S: BaseState<'tcx>> SInto<S, Arc<FullDef>> for RDefId {
fn sinto(&self, s: &S) -> Arc<FullDef> {
if let Some(full_def) = s.with_item_cache(*self, |cache| cache.full_def.clone()) {
return full_def;
}
let tcx = s.base().tcx;
let def_id = *self;
let kind = {
let state_with_id = with_owner_id(s.base(), (), (), def_id);
tcx.def_kind(def_id).sinto(&state_with_id)
};

let source_span = def_id.as_local().map(|ldid| tcx.source_span(ldid));
let source_text = source_span
.filter(|source_span| source_span.ctxt().is_root())
.and_then(|source_span| tcx.sess.source_map().span_to_snippet(source_span).ok());
let full_def = FullDef {
def_id: self.sinto(s),
parent: tcx.opt_parent(def_id).sinto(s),
span: tcx.def_span(def_id).sinto(s),
source_span: source_span.sinto(s),
source_text,
attributes: tcx.get_attrs_unchecked(def_id).sinto(s),
visibility: get_def_visibility(tcx, def_id),
lang_item: s
.base()
.tcx
.as_lang_item(def_id)
.map(|litem| litem.name())
.sinto(s),
diagnostic_item: tcx.get_diagnostic_name(def_id).sinto(s),
kind,
};
let full_def: Arc<FullDef> = Arc::new(full_def);
s.with_item_cache(*self, |cache| cache.full_def = Some(full_def.clone()));
full_def
}
}

/// Imbues [`rustc_hir::def::DefKind`] with a lot of extra information.
/// Important: the `owner_id()` must be the id of this definition.
#[derive(AdtInto)]
Expand Down Expand Up @@ -77,7 +111,7 @@ pub enum FullDefKind {
generics: TyGenerics,
#[value(get_generic_predicates(s, s.owner_id()))]
predicates: GenericPredicates,
// `predicates_of` has the special `Self: Trait` clause as its last element.
/// The special `Self: Trait` clause.
#[value({
use ty::Upcast;
let tcx = s.base().tcx;
Expand All @@ -86,8 +120,17 @@ pub enum FullDefKind {
})]
self_predicate: TraitPredicate,
/// Associated items, in definition order.
#[value(s.base().tcx.associated_items(s.owner_id()).in_definition_order().collect::<Vec<_>>().sinto(s))]
items: Vec<AssocItem>,
#[value(
s
.base()
.tcx
.associated_items(s.owner_id())
.in_definition_order()
.map(|assoc| (assoc, assoc.def_id))
.collect::<Vec<_>>()
.sinto(s)
)]
items: Vec<(AssocItem, Arc<FullDef>)>,
},
/// Type alias: `type Foo = Bar;`
TyAlias {
Expand Down Expand Up @@ -240,8 +283,17 @@ pub enum FullDefKind {
#[value(s.base().tcx.impl_subject(s.owner_id()).instantiate_identity().sinto(s))]
impl_subject: ImplSubject,
/// Associated items, in definition order.
#[value(s.base().tcx.associated_items(s.owner_id()).in_definition_order().collect::<Vec<_>>().sinto(s))]
items: Vec<AssocItem>,
#[value(
s
.base()
.tcx
.associated_items(s.owner_id())
.in_definition_order()
.map(|assoc| (assoc, assoc.def_id))
.collect::<Vec<_>>()
.sinto(s)
)]
items: Vec<(AssocItem, Arc<FullDef>)>,
},
/// A field in a struct, enum or union. e.g.
/// - `bar` in `struct Foo { bar: u8 }`
Expand All @@ -254,6 +306,11 @@ pub enum FullDefKind {
}

impl FullDef {
#[cfg(feature = "rustc")]
pub fn rust_def_id(&self) -> RDefId {
(&self.def_id).into()
}

pub fn kind(&self) -> &FullDefKind {
&self.kind
}
Expand Down Expand Up @@ -330,9 +387,8 @@ impl FullDef {
/// Gets the visibility (`pub` or not) of the definition. Returns `None` for defs that don't have a
/// meaningful visibility.
#[cfg(feature = "rustc")]
fn get_def_visibility<'tcx, S: BaseState<'tcx>>(s: &S, def_id: RDefId) -> Option<bool> {
fn get_def_visibility<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: RDefId) -> Option<bool> {
use rustc_hir::def::DefKind::*;
let tcx = s.base().tcx;
match tcx.def_kind(def_id) {
AssocConst
| AssocFn
Expand Down

0 comments on commit e2734c8

Please sign in to comment.