// This is done to handle the case where, for example, the static
// method of a private type is used, but the type itself is never
// called directly.
- if let Some(impl_list) =
- self.tcx.maps.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
- for &impl_did in impl_list.iter() {
- for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
- if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) {
- if self.live_symbols.contains(&item_node_id) {
- return true;
- }
+ let def_id = self.tcx.hir.local_def_id(id);
+ let inherent_impls = self.tcx.inherent_impls(def_id);
+ for &impl_did in inherent_impls.iter() {
+ for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
+ if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) {
+ if self.live_symbols.contains(&item_node_id) {
+ return true;
}
}
}
use ty::{self, Ty, TyCtxt};
use syntax::ast;
use syntax::symbol::Symbol;
+use syntax_pos::DUMMY_SP;
use std::cell::Cell;
thread_local! {
- static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false)
+ static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
+ static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
}
-/// Enforces that item_path_str always returns an absolute path.
-/// This is useful when building symbols that contain types,
-/// where we want the crate name to be part of the symbol.
+/// Enforces that item_path_str always returns an absolute path and
+/// also enables "type-based" impl paths. This is used when building
+/// symbols that contain types, where we want the crate name to be
+/// part of the symbol.
pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
FORCE_ABSOLUTE.with(|force| {
let old = force.get();
})
}
+/// Force us to name impls with just the filename/line number. We
+/// normally try to use types. But at some points, notably while printing
+/// cycle errors, this can result in extra or suboptimal error output,
+/// so this variable disables that check.
+pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
+ FORCE_IMPL_FILENAME_LINE.with(|force| {
+ let old = force.get();
+ force.set(true);
+ let result = f();
+ force.set(old);
+ result
+ })
+}
+
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Returns a string identifying this def-id. This string is
/// suitable for user output. It is relative to the current crate
{
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
- let use_types = if !impl_def_id.is_local() {
- // always have full types available for extern crates
- true
- } else {
- // for local crates, check whether type info is
- // available; typeck might not have completed yet
- self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) &&
- self.maps.type_of.borrow().contains_key(&impl_def_id)
+ // Always use types for non-local impls, where types are always
+ // available, and filename/line-number is mostly uninteresting.
+ let use_types = !impl_def_id.is_local() || {
+ // Otherwise, use filename/line-number if forced.
+ let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
+ !force_no_types && {
+ // Otherwise, use types if we can query them without inducing a cycle.
+ ty::queries::impl_trait_ref::try_get(self, DUMMY_SP, impl_def_id).is_ok() &&
+ ty::queries::type_of::try_get(self, DUMMY_SP, impl_def_id).is_ok()
+ }
};
if !use_types {
use mir;
use session::CompileResult;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::item_path;
use ty::subst::Substs;
use util::nodemap::NodeSet;
use rustc_data_structures::indexed_vec::IndexVec;
use std::cell::{RefCell, RefMut};
+use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use syntax_pos::{Span, DUMMY_SP};
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn report_cycle(self, CycleError { span, cycle }: CycleError) {
- assert!(!cycle.is_empty());
-
- let mut err = struct_span_err!(self.sess, span, E0391,
- "unsupported cyclic reference between types/traits detected");
- err.span_label(span, &format!("cyclic reference"));
-
- err.span_note(cycle[0].0, &format!("the cycle begins when {}...",
- cycle[0].1.describe(self)));
-
- for &(span, ref query) in &cycle[1..] {
- err.span_note(span, &format!("...which then requires {}...",
- query.describe(self)));
- }
+ // Subtle: release the refcell lock before invoking `describe()`
+ // below by dropping `cycle`.
+ let stack = cycle.to_vec();
+ mem::drop(cycle);
+
+ assert!(!stack.is_empty());
+
+ // Disable naming impls with types in this path, since that
+ // sometimes cycles itself, leading to extra cycle errors.
+ // (And cycle errors around impls tend to occur during the
+ // collect/coherence phases anyhow.)
+ item_path::with_forced_impl_filename_line(|| {
+ let mut err =
+ struct_span_err!(self.sess, span, E0391,
+ "unsupported cyclic reference between types/traits detected");
+ err.span_label(span, &format!("cyclic reference"));
+
+ err.span_note(stack[0].0, &format!("the cycle begins when {}...",
+ stack[0].1.describe(self)));
+
+ for &(span, ref query) in &stack[1..] {
+ err.span_note(span, &format!("...which then requires {}...",
+ query.describe(self)));
+ }
- err.note(&format!("...which then again requires {}, completing the cycle.",
- cycle[0].1.describe(self)));
+ err.note(&format!("...which then again requires {}, completing the cycle.",
+ stack[0].1.describe(self)));
- err.emit();
+ err.emit();
+ });
}
fn cycle_check<F, R>(self, span: Span, query: Query<'gcx>, compute: F)
macro_rules! define_maps {
(<$tcx:tt>
$($(#[$attr:meta])*
- pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
+ [$($pub:tt)*] $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
pub struct Maps<$tcx> {
providers: IndexVec<CrateNum, Providers<$tcx>>,
query_stack: RefCell<Vec<(Span, Query<$tcx>)>>,
- $($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
+ $($(#[$attr])* $($pub)* $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
}
impl<$tcx> Maps<$tcx> {
-> Result<R, CycleError<'a, $tcx>>
where F: FnOnce(&$V) -> R
{
+ debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})",
+ stringify!($name),
+ key,
+ span);
+
if let Some(result) = tcx.maps.$name.borrow().get(&key) {
return Ok(f(result));
}
// the driver creates (using several `rustc_*` crates).
define_maps! { <'tcx>
/// Records the type of every item.
- pub type_of: ItemSignature(DefId) -> Ty<'tcx>,
+ [] type_of: ItemSignature(DefId) -> Ty<'tcx>,
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
/// associated generics and predicates.
- pub generics_of: ItemSignature(DefId) -> &'tcx ty::Generics,
- pub predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+ [] generics_of: ItemSignature(DefId) -> &'tcx ty::Generics,
+ [] predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
/// Maps from the def-id of a trait to the list of
/// super-predicates. This is a subset of the full list of
/// evaluate them even during type conversion, often before the
/// full predicates are available (note that supertraits have
/// additional acyclicity requirements).
- pub super_predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+ [] super_predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
/// To avoid cycles within the predicates of a single item we compute
/// per-type-parameter predicates for resolving `T::AssocTy`.
- pub type_param_predicates: TypeParamPredicates((DefId, DefId))
+ [] type_param_predicates: TypeParamPredicates((DefId, DefId))
-> ty::GenericPredicates<'tcx>,
- pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
- pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
- pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
- pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
- pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
+ [] trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
+ [] adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
+ [] adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
+ [] adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
+ [] adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
- pub is_foreign_item: IsForeignItem(DefId) -> bool,
+ [] is_foreign_item: IsForeignItem(DefId) -> bool,
/// Maps from def-id of a type or region parameter to its
/// (inferred) variance.
- pub variances_of: ItemSignature(DefId) -> Rc<Vec<ty::Variance>>,
+ [pub] variances_of: ItemSignature(DefId) -> Rc<Vec<ty::Variance>>,
/// Maps from an impl/trait def-id to a list of the def-ids of its items
- pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
+ [] associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
/// Maps from a trait item to the trait item "descriptor"
- pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
+ [] associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
- pub impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
- pub impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity,
+ [] impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
+ [] impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity,
/// Maps a DefId of a type to a list of its inherent impls.
/// Contains implementations of methods that are inherent to a type.
/// Methods in these implementations don't need to be exported.
- pub inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
+ [] inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
/// Maps from the def-id of a function/method or const/static
/// to its MIR. Mutation is done at an item granularity to
///
/// Note that cross-crate MIR appears to be always borrowed
/// (in the `RefCell` sense) to prevent accidental mutation.
- pub mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
+ [pub] mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
/// Maps DefId's that have an associated Mir to the result
/// of the MIR qualify_consts pass. The actual meaning of
/// the value isn't known except to the pass itself.
- pub mir_const_qualif: Mir(DefId) -> u8,
+ [] mir_const_qualif: Mir(DefId) -> u8,
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
- pub closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
+ [] closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
- pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
+ [] closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
/// Caches CoerceUnsized kinds for impls on custom types.
- pub coerce_unsized_info: ItemSignature(DefId)
+ [] coerce_unsized_info: ItemSignature(DefId)
-> ty::adjustment::CoerceUnsizedInfo,
- pub typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult,
+ [] typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult,
- pub typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
+ [] typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
- pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
+ [] has_typeck_tables: TypeckTables(DefId) -> bool,
- pub borrowck: BorrowCheck(DefId) -> (),
+ [] coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
+
+ [] borrowck: BorrowCheck(DefId) -> (),
/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.
/// (Defined only for LOCAL_CRATE)
- pub crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls,
+ [] crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls,
/// Checks all types in the krate for overlap in their inherent impls. Reports errors.
/// Not meant to be used directly outside of coherence.
/// (Defined only for LOCAL_CRATE)
- pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
+ [] crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
/// Results of evaluating const items or constants embedded in
/// other items (such as enum variant explicit discriminants).
- pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>))
+ [] const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>))
-> const_val::EvalResult<'tcx>,
/// Performs the privacy check and computes "access levels".
- pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
+ [] privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
- pub reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
+ [] reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
- pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>,
+ [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>,
- pub def_symbol_name: SymbolName(DefId) -> ty::SymbolName,
- pub symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName,
+ [] def_symbol_name: SymbolName(DefId) -> ty::SymbolName,
+ [] symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName,
- pub describe_def: meta_data_node(DefId) -> Option<Def>
+ [] describe_def: meta_data_node(DefId) -> Option<Def>
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
fn meta_data_node(def_id: DefId) -> DepNode<DefId> {
DepNode::MetaData(def_id)
-}
\ No newline at end of file
+}
})
}
+ pub fn opt_associated_item(self, def_id: DefId) -> Option<AssociatedItem> {
+ let is_associated_item = if let Some(node_id) = self.hir.as_local_node_id(def_id) {
+ match self.hir.get(node_id) {
+ hir_map::NodeTraitItem(_) | hir_map::NodeImplItem(_) => true,
+ _ => false,
+ }
+ } else {
+ match self.describe_def(def_id).expect("no def for def-id") {
+ Def::AssociatedConst(_) | Def::Method(_) | Def::AssociatedTy(_) => true,
+ _ => false,
+ }
+ };
+
+ if is_associated_item {
+ Some(self.associated_item(def_id))
+ } else {
+ None
+ }
+ }
+
fn associated_item_from_trait_item_ref(self,
parent_def_id: DefId,
parent_vis: &hir::Visibility,
None
}
} else {
- self.maps.associated_item.borrow().get(&def_id).cloned()
+ self.opt_associated_item(def_id)
};
match item {
if def_id.krate != LOCAL_CRATE {
return self.sess.cstore.trait_of_item(def_id);
}
- match self.maps.associated_item.borrow().get(&def_id) {
- Some(associated_item) => {
+ self.opt_associated_item(def_id)
+ .and_then(|associated_item| {
match associated_item.container {
TraitContainer(def_id) => Some(def_id),
ImplContainer(_) => None
}
- }
- None => None
- }
+ })
}
/// Construct a parameter environment suitable for static contexts or other contexts where there
}
}
- ref r => {
- panic!("unexpected container of associated items: {:?}", r)
- }
+ _ => { }
}
- panic!("associated item not found for def_id: {:?}", def_id);
+
+ span_bug!(parent_item.span,
+ "unexpected parent of trait or impl item or item not found: {:?}",
+ parent_item.node)
}
/// Calculates the Sized-constraint.
PlainImpl,
}
-pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
+pub fn method_context(cx: &LateContext, id: ast::NodeId) -> MethodLateContext {
let def_id = cx.tcx.hir.local_def_id(id);
- match cx.tcx.maps.associated_item.borrow().get(&def_id) {
- None => span_bug!(span, "missing method descriptor?!"),
- Some(item) => {
- match item.container {
- ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
- ty::ImplContainer(cid) => {
- match cx.tcx.impl_trait_ref(cid) {
- Some(_) => MethodLateContext::TraitImpl,
- None => MethodLateContext::PlainImpl,
- }
- }
+ let item = cx.tcx.associated_item(def_id);
+ match item.container {
+ ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
+ ty::ImplContainer(cid) => {
+ match cx.tcx.impl_trait_ref(cid) {
+ Some(_) => MethodLateContext::TraitImpl,
+ None => MethodLateContext::PlainImpl,
}
}
}
id: ast::NodeId) {
match fk {
FnKind::Method(name, ..) => {
- match method_context(cx, id, span) {
+ match method_context(cx, id) {
MethodLateContext::PlainImpl => {
self.check_snake_case(cx, "method", &name.as_str(), Some(span))
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
// If the method is an impl for a trait, don't doc.
- if method_context(cx, impl_item.id, impl_item.span) == MethodLateContext::TraitImpl {
+ if method_context(cx, impl_item.id) == MethodLateContext::TraitImpl {
return;
}
EntryKind::AssociatedType(container) => {
(ty::AssociatedKind::Type, container, false)
}
- _ => bug!()
+ _ => bug!("cannot get associated-item of `{:?}`", def_key)
};
ty::AssociatedItem {
// Encodes the inherent implementations of a structure, enumeration, or trait.
fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
debug!("EntryBuilder::encode_inherent_implementations({:?})", def_id);
- match self.tcx.maps.inherent_impls.borrow().get(&def_id) {
- None => LazySeq::empty(),
- Some(implementations) => {
- self.lazy_seq(implementations.iter().map(|&def_id| {
- assert!(def_id.is_local());
- def_id.index
- }))
- }
+ let implementations = self.tcx.inherent_impls(def_id);
+ if implementations.is_empty() {
+ LazySeq::empty()
+ } else {
+ self.lazy_seq(implementations.iter().map(|&def_id| {
+ assert!(def_id.is_local());
+ def_id.index
+ }))
}
}
where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
{
let item_def_id = self.tcx.hir.local_def_id(item_id);
- match self.tcx.maps.typeck_tables_of.borrow().get(&item_def_id) {
- Some(tables) => {
- let old_tables = self.save_ctxt.tables;
- self.save_ctxt.tables = tables;
- f(self);
- self.save_ctxt.tables = old_tables;
- }
- None => f(self),
+ if self.tcx.has_typeck_tables(item_def_id) {
+ let tables = self.tcx.typeck_tables_of(item_def_id);
+ let old_tables = self.save_ctxt.tables;
+ self.save_ctxt.tables = tables;
+ f(self);
+ self.save_ctxt.tables = old_tables;
+ } else {
+ f(self)
}
}
*providers = Providers {
typeck_item_bodies,
typeck_tables_of,
+ has_typeck_tables,
closure_type,
closure_kind,
adt_destructor,
tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
}
-fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- -> &'tcx ty::TypeckTables<'tcx> {
- // Closures' tables come from their outermost function,
- // as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id);
- if outer_def_id != def_id {
- return tcx.typeck_tables_of(outer_def_id);
- }
-
- let id = tcx.hir.as_local_node_id(def_id).unwrap();
- let span = tcx.hir.span(id);
- let unsupported = || {
- span_bug!(span, "can't type-check body of {:?}", def_id);
- };
-
- // Figure out what primary body this item has.
- let mut fn_decl = None;
- let body_id = match tcx.hir.get(id) {
+/// If this def-id is a "primary tables entry", returns `Some((body_id, decl))`
+/// with information about it's body-id and fn-decl (if any). Otherwise,
+/// returns `None`.
+///
+/// If this function returns "some", then `typeck_tables(def_id)` will
+/// succeed; if it returns `None`, then `typeck_tables(def_id)` may or
+/// may not succeed. In some cases where this function returns `None`
+/// (notably closures), `typeck_tables(def_id)` would wind up
+/// redirecting to the owning function.
+fn primary_body_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ id: ast::NodeId)
+ -> Option<(hir::BodyId, Option<&'tcx hir::FnDecl>)>
+{
+ match tcx.hir.get(id) {
hir::map::NodeItem(item) => {
match item.node {
hir::ItemConst(_, body) |
- hir::ItemStatic(_, _, body) => body,
- hir::ItemFn(ref decl, .., body) => {
- fn_decl = Some(decl);
- body
- }
- _ => unsupported()
+ hir::ItemStatic(_, _, body) =>
+ Some((body, None)),
+ hir::ItemFn(ref decl, .., body) =>
+ Some((body, Some(decl))),
+ _ =>
+ None,
}
}
hir::map::NodeTraitItem(item) => {
match item.node {
- hir::TraitItemKind::Const(_, Some(body)) => body,
- hir::TraitItemKind::Method(ref sig,
- hir::TraitMethod::Provided(body)) => {
- fn_decl = Some(&sig.decl);
- body
- }
- _ => unsupported()
+ hir::TraitItemKind::Const(_, Some(body)) =>
+ Some((body, None)),
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) =>
+ Some((body, Some(&sig.decl))),
+ _ =>
+ None,
}
}
hir::map::NodeImplItem(item) => {
match item.node {
- hir::ImplItemKind::Const(_, body) => body,
- hir::ImplItemKind::Method(ref sig, body) => {
- fn_decl = Some(&sig.decl);
- body
- }
- _ => unsupported()
+ hir::ImplItemKind::Const(_, body) =>
+ Some((body, None)),
+ hir::ImplItemKind::Method(ref sig, body) =>
+ Some((body, Some(&sig.decl))),
+ _ =>
+ None,
}
}
hir::map::NodeExpr(expr) => {
// Assume that everything other than closures
// is a constant "initializer" expression.
match expr.node {
- hir::ExprClosure(..) => {
- // We should've bailed out above for closures.
- span_bug!(expr.span, "unexpected closure")
- }
- _ => hir::BodyId { node_id: expr.id }
+ hir::ExprClosure(..) =>
+ None,
+ _ =>
+ Some((hir::BodyId { node_id: expr.id }, None)),
}
}
- _ => unsupported()
- };
+ _ => None,
+ }
+}
+
+fn has_typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> bool {
+ // Closures' tables come from their outermost function,
+ // as they are part of the same "inference environment".
+ let outer_def_id = tcx.closure_base_def_id(def_id);
+ if outer_def_id != def_id {
+ return tcx.has_typeck_tables(outer_def_id);
+ }
+
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ primary_body_of(tcx, id).is_some()
+}
+
+fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> &'tcx ty::TypeckTables<'tcx> {
+ // Closures' tables come from their outermost function,
+ // as they are part of the same "inference environment".
+ let outer_def_id = tcx.closure_base_def_id(def_id);
+ if outer_def_id != def_id {
+ return tcx.typeck_tables_of(outer_def_id);
+ }
+
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let span = tcx.hir.span(id);
+
+ // Figure out what primary body this item has.
+ let (body_id, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| {
+ span_bug!(span, "can't type-check body of {:?}", def_id);
+ });
let body = tcx.hir.body(body_id);
Inherited::build(tcx, id).enter(|inh| {
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut used_trait_imports = DefIdSet();
for &body_id in tcx.hir.krate().bodies.keys() {
- let item_id = tcx.hir.body_owner(body_id);
- let item_def_id = tcx.hir.local_def_id(item_id);
-
- // this will have been written by the main typeck pass
- if let Some(tables) = tcx.maps.typeck_tables_of.borrow().get(&item_def_id) {
- let imports = &tables.used_trait_imports;
- debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
- used_trait_imports.extend(imports);
- } else {
- debug!("GatherVisitor: item_def_id={:?} with no imports", item_def_id);
- }
+ let item_def_id = tcx.hir.body_owner_def_id(body_id);
+ let tables = tcx.typeck_tables_of(item_def_id);
+ let imports = &tables.used_trait_imports;
+ debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
+ used_trait_imports.extend(imports);
}
let mut visitor = CheckVisitor { tcx, used_trait_imports };
//
// [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
+ thread_local! {
+ static EMPTY_DEF_ID_VEC: Rc<Vec<DefId>> = Rc::new(vec![])
+ }
+
let result = tcx.dep_graph.with_ignore(|| {
let crate_map = tcx.crate_inherent_impls(ty_def_id.krate);
match crate_map.inherent_impls.get(&ty_def_id) {
Some(v) => v.clone(),
- None => Rc::new(vec![]),
+ None => EMPTY_DEF_ID_VEC.with(|v| v.clone())
}
});