Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Queryify Vtable methods #45137

Merged
merged 5 commits into from
Oct 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,7 @@ define_dep_nodes!( <'tcx>
[] SpecializationGraph(DefId),
[] ObjectSafety(DefId),
[] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> },
[] VtableMethods { trait_ref: PolyTraitRef<'tcx> },

[] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
[] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> },
Expand Down
92 changes: 48 additions & 44 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,53 +650,55 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
/// Given a trait `trait_ref`, iterates the vtable entries
/// that come from `trait_ref`, including its supertraits.
#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait.
pub fn get_vtable_methods<'a, 'tcx>(
fn vtable_methods<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
-> impl Iterator<Item=Option<(DefId, &'tcx Substs<'tcx>)>> + 'a
-> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>
{
debug!("get_vtable_methods({:?})", trait_ref);

supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
let trait_methods = tcx.associated_items(trait_ref.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Method);

// Now list each method's DefId and Substs (for within its trait).
// If the method can never be called from this object, produce None.
trait_methods.map(move |trait_method| {
debug!("get_vtable_methods: trait_method={:?}", trait_method);
let def_id = trait_method.def_id;

// Some methods cannot be called on an object; skip those.
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
debug!("get_vtable_methods: not vtable safe");
return None;
}

// the method may have some early-bound lifetimes, add
// regions for those
let substs = Substs::for_item(tcx, def_id,
|_, _| tcx.types.re_erased,
|def, _| trait_ref.substs().type_for_def(def));

// the trait type may have higher-ranked lifetimes in it;
// so erase them if they appear, so that we get the type
// at some particular call site
let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));

// It's possible that the method relies on where clauses that
// do not hold for this particular set of type parameters.
// Note that this method could then never be called, so we
// do not want to try and trans it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
if !normalize_and_test_predicates(tcx, predicates.predicates) {
debug!("get_vtable_methods: predicates do not hold");
return None;
}

Some((def_id, substs))
})
})
debug!("vtable_methods({:?})", trait_ref);

Rc::new(
supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
let trait_methods = tcx.associated_items(trait_ref.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Method);

// Now list each method's DefId and Substs (for within its trait).
// If the method can never be called from this object, produce None.
trait_methods.map(move |trait_method| {
debug!("vtable_methods: trait_method={:?}", trait_method);
let def_id = trait_method.def_id;

// Some methods cannot be called on an object; skip those.
if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) {
debug!("vtable_methods: not vtable safe");
return None;
}

// the method may have some early-bound lifetimes, add
// regions for those
let substs = Substs::for_item(tcx, def_id,
|_, _| tcx.types.re_erased,
|def, _| trait_ref.substs().type_for_def(def));

// the trait type may have higher-ranked lifetimes in it;
// so erase them if they appear, so that we get the type
// at some particular call site
let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));

// It's possible that the method relies on where clauses that
// do not hold for this particular set of type parameters.
// Note that this method could then never be called, so we
// do not want to try and trans it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
if !normalize_and_test_predicates(tcx, predicates.predicates) {
debug!("vtable_methods: predicates do not hold");
return None;
}

Some((def_id, substs))
})
}).collect()
)
}

impl<'tcx,O> Obligation<'tcx,O> {
Expand Down Expand Up @@ -836,6 +838,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
trans_fulfill_obligation: trans::trans_fulfill_obligation,
vtable_methods,
..*providers
};
}
Expand All @@ -846,6 +849,7 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
trans_fulfill_obligation: trans::trans_fulfill_obligation,
vtable_methods,
..*providers
};
}
6 changes: 6 additions & 0 deletions src/librustc/ty/maps/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,12 @@ impl<'tcx> QueryDescription for queries::has_clone_closures<'tcx> {
}
}

impl<'tcx> QueryDescription for queries::vtable_methods<'tcx> {
fn describe(tcx: TyCtxt, key: ty::PolyTraitRef<'tcx> ) -> String {
format!("finding all methods for trait {}", tcx.item_path_str(key.def_id()))
}
}

impl<'tcx> QueryDescription for queries::has_copy_closures<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
format!("seeing if the crate has enabled `Copy` closures")
Expand Down
9 changes: 9 additions & 0 deletions src/librustc/ty/maps/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
}
}

impl<'tcx> Key for ty::PolyTraitRef<'tcx>{
fn map_crate(&self) -> CrateNum {
self.def_id().krate
}
fn default_span(&self, tcx: TyCtxt) -> Span {
tcx.def_span(self.def_id())
}
}

impl<'tcx> Key for Ty<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/ty/maps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ define_maps! { <'tcx>
[] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
[] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
[] fn is_mir_available: IsMirAvailable(DefId) -> bool,
[] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
-> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,

[] fn trans_fulfill_obligation: fulfill_obligation_dep_node(
(ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>,
Expand Down Expand Up @@ -470,3 +472,7 @@ fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstru
fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
DepConstructor::OutputFilenames
}

fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> {
DepConstructor::VtableMethods{ trait_ref }
}
104 changes: 5 additions & 99 deletions src/librustc/ty/maps/plumbing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,7 @@ macro_rules! define_maps {

define_provider_struct! {
tcx: $tcx,
input: ($(([$($modifiers)*] [$name] [$K] [$V]))*),
output: ()
input: ($(([$($modifiers)*] [$name] [$K] [$V]))*)
}

impl<$tcx> Copy for Providers<$tcx> {}
Expand All @@ -480,78 +479,19 @@ macro_rules! define_maps {
}

macro_rules! define_map_struct {
// Initial state
(tcx: $tcx:tt,
input: $input:tt) => {
define_map_struct! {
tcx: $tcx,
input: $input,
output: ()
}
};

// Final output
(tcx: $tcx:tt,
input: (),
output: ($($output:tt)*)) => {
input: ($(([$(modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
pub struct Maps<$tcx> {
providers: IndexVec<CrateNum, Providers<$tcx>>,
query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,
$($output)*
}
};

// Field recognized and ready to shift into the output
(tcx: $tcx:tt,
ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]),
input: $input:tt,
output: ($($output:tt)*)) => {
define_map_struct! {
tcx: $tcx,
input: $input,
output: ($($output)*
$(#[$attr])* $($pub)* $name: RefCell<QueryMap<queries::$name<$tcx>>>,)
}
};

// No modifiers left? This is a private item.
(tcx: $tcx:tt,
input: (([] $attrs:tt $name:tt) $($input:tt)*),
output: $output:tt) => {
define_map_struct! {
tcx: $tcx,
ready: ([] $attrs $name),
input: ($($input)*),
output: $output
}
};

// Skip other modifiers
(tcx: $tcx:tt,
input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
output: $output:tt) => {
define_map_struct! {
tcx: $tcx,
input: (([$($modifiers)*] $($fields)*) $($input)*),
output: $output
$($(#[$attr])* $name: RefCell<QueryMap<queries::$name<$tcx>>>,)*
}
};
}

macro_rules! define_provider_struct {
// Initial state:
(tcx: $tcx:tt, input: $input:tt) => {
define_provider_struct! {
tcx: $tcx,
input: $input,
output: ()
}
};

// Final state:
(tcx: $tcx:tt,
input: (),
output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => {
input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks fine. It does mean we lose the ability to have modifiers that adjust the type of a query's field. At present, we are not using this capability (we used to be...), so that's probably ok, but we could also just lift the recursion-limit, right?

I'm ok either way, but let's also rebase and remove the merge commit.

pub struct Providers<$tcx> {
$(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)*
}
Expand All @@ -566,41 +506,6 @@ macro_rules! define_provider_struct {
}
}
};

// Something ready to shift:
(tcx: $tcx:tt,
ready: ($name:tt $K:tt $V:tt),
input: $input:tt,
output: ($($output:tt)*)) => {
define_provider_struct! {
tcx: $tcx,
input: $input,
output: ($($output)* ($name $K $V))
}
};

// Regular queries produce a `V` only.
(tcx: $tcx:tt,
input: (([] $name:tt $K:tt $V:tt) $($input:tt)*),
output: $output:tt) => {
define_provider_struct! {
tcx: $tcx,
ready: ($name $K $V),
input: ($($input)*),
output: $output
}
};

// Skip modifiers.
(tcx: $tcx:tt,
input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*),
output: $output:tt) => {
define_provider_struct! {
tcx: $tcx,
input: (([$($modifiers)*] $($fields)*) $($input)*),
output: $output
}
};
}


Expand Down Expand Up @@ -749,6 +654,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
DepKind::CodegenUnit |
DepKind::CompileCodegenUnit |
DepKind::FulfillObligation |
DepKind::VtableMethods |

// These are just odd
DepKind::Null |
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,8 +849,8 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
assert!(!poly_trait_ref.has_escaping_regions());

// Walk all methods of the trait, including those of its supertraits
let methods = traits::get_vtable_methods(tcx, poly_trait_ref);
let methods = methods.filter_map(|method| method)
let methods = tcx.vtable_methods(poly_trait_ref);
let methods = methods.iter().cloned().filter_map(|method| method)
.map(|(def_id, substs)| ty::Instance::resolve(
tcx,
ty::ParamEnv::empty(traits::Reveal::All),
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/meth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
// except according to those terms.

use llvm::ValueRef;
use rustc::traits;
use callee;
use common::*;
use builder::Builder;
Expand Down Expand Up @@ -87,7 +86,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

if let Some(trait_ref) = trait_ref {
let trait_ref = trait_ref.with_self_ty(tcx, ty);
let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| {
let methods = tcx.vtable_methods(trait_ref);
let methods = methods.iter().cloned().map(|opt_mth| {
opt_mth.map_or(nullptr, |(def_id, substs)| {
callee::resolve_and_get_fn(ccx, def_id, substs)
})
Expand Down