diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e99ffa95ed63c..351feaba0346a 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -103,11 +103,11 @@ pub enum DepNode { // nodes. Often we map multiple tables to the same node if there // is no point in distinguishing them (e.g., both the type and // predicates for an item wind up in `ItemSignature`). - ImplOrTraitItems(D), + AssociatedItems(D), ItemSignature(D), FieldTy(D), SizedConstraint(D), - ImplOrTraitItemDefIds(D), + AssociatedItemDefIds(D), InherentImpls(D), // The set of impls for a given trait. Ultimately, it would be @@ -153,10 +153,10 @@ impl DepNode { TransCrateItem, TypeckItemType, TypeckItemBody, - ImplOrTraitItems, + AssociatedItems, ItemSignature, FieldTy, - ImplOrTraitItemDefIds, + AssociatedItemDefIds, InherentImpls, TraitImpls, ReprHints, @@ -219,11 +219,11 @@ impl DepNode { RvalueCheck(ref d) => op(d).map(RvalueCheck), TransCrateItem(ref d) => op(d).map(TransCrateItem), TransInlinedItem(ref d) => op(d).map(TransInlinedItem), - ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems), + AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), FieldTy(ref d) => op(d).map(FieldTy), SizedConstraint(ref d) => op(d).map(SizedConstraint), - ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds), + AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 59a5147ed1c16..a1f226ab11d80 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -147,7 +147,7 @@ pub trait CrateStore<'tcx> { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec; + fn associated_item_def_ids(&self, def_id: DefId) -> Vec; fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; @@ -157,8 +157,8 @@ pub trait CrateStore<'tcx> { // trait/impl-item info fn trait_of_item(&self, def_id: DefId) -> Option; - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option>; + fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option; // flags fn is_const_fn(&self, did: DefId) -> bool; @@ -311,8 +311,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec - { bug!("impl_or_trait_items") } + fn associated_item_def_ids(&self, def_id: DefId) -> Vec + { bug!("associated_items") } fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("impl_trait_ref") } fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } @@ -323,8 +323,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // trait/impl-item info fn trait_of_item(&self, def_id: DefId) -> Option { bug!("trait_of_item") } - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> { bug!("impl_or_trait_item") } + fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option { bug!("associated_item") } // flags fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 7fc698fdbebf5..294cdd3b7614b 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -471,11 +471,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // 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. - let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); if let Some(impl_list) = self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) { - for impl_did in impl_list.iter() { - for &item_did in &impl_items[impl_did][..] { + 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.map.as_local_node_id(item_did) { if self.live_symbols.contains(&item_node_id) { return true; diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0543d1303a5f1..0127ac9dc7223 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -227,8 +227,8 @@ impl OverloadedCallType { } fn from_method_id(tcx: TyCtxt, method_id: DefId) -> OverloadedCallType { - let method = tcx.impl_or_trait_item(method_id); - OverloadedCallType::from_trait_id(tcx, method.container().id()) + let method = tcx.associated_item(method_id); + OverloadedCallType::from_trait_id(tcx, method.container.id()) } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index f1755c82b8cbd..d79833998d6c8 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -529,14 +529,11 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // items. hir::ItemImpl(.., Some(ref t), _, ref impl_items) => { let trait_did = tcx.expect_def(t.ref_id).def_id(); - let trait_items = tcx.trait_items(trait_did); - for impl_item in impl_items { - let item = trait_items.iter().find(|item| { - item.name() == impl_item.name - }).unwrap(); + let item = tcx.associated_items(trait_did) + .find(|item| item.name == impl_item.name).unwrap(); if warn_about_defns { - maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb); + maybe_do_stability_check(tcx, item.def_id, impl_item.span, cb); } } } @@ -685,15 +682,8 @@ fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool { } fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool { - match tcx.trait_item_of_item(id) { - Some(trait_method_id) if trait_method_id != id => { - is_staged_api(tcx, trait_method_id) - } - _ => { - *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( - || tcx.sess.cstore.is_staged_api(id.krate)) - } - } + *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( + || tcx.sess.cstore.is_staged_api(id.krate)) } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3522c738c160c..7e70fdb92e68b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -663,25 +663,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { in the supertrait listing" } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) => { - buf = format!("method `{}` has no receiver", - method.name); + buf = format!("method `{}` has no receiver", name); &buf } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => { buf = format!("method `{}` references the `Self` type \ in its arguments or return type", - method.name); + name); &buf } - ObjectSafetyViolation::Method(method, + ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => { - buf = format!("method `{}` has generic type parameters", - method.name); + buf = format!("method `{}` has generic type parameters", name); &buf } }; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 017b34d914f80..36405df6325af 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -578,18 +578,14 @@ pub fn get_vtable_methods<'a, 'tcx>( supertraits(tcx, trait_ref).flat_map(move |trait_ref| { tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); - let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id()); - let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| { - match tcx.impl_or_trait_item(trait_item_def_ids[i]) { - ty::MethodTraitItem(m) => Some(m), - _ => None - } - }); + 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) { @@ -599,21 +595,21 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those - let substs = Substs::for_item(tcx, trait_method.def_id, - |_, _| tcx.mk_region(ty::ReErased), - |def, _| trait_ref.substs().type_for_def(def)); + let substs = Substs::for_item(tcx, def_id, + |_, _| tcx.mk_region(ty::ReErased), + |def, _| trait_ref.substs().type_for_def(def)); // 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 = trait_method.predicates.instantiate_own(tcx, substs); + let predicates = tcx.lookup_predicates(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((trait_method.def_id, substs)) + Some((def_id, substs)) }) }) } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 5f7b71518291a..c783bd561bb1a 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -22,11 +22,10 @@ use super::elaborate_predicates; use hir::def_id::DefId; use traits; use ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use std::rc::Rc; use syntax::ast; #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation<'tcx> { +pub enum ObjectSafetyViolation { /// Self : Sized declared on the trait SizedSelf, @@ -35,7 +34,7 @@ pub enum ObjectSafetyViolation<'tcx> { SupertraitSelf, /// Method has something illegal - Method(Rc>, MethodViolationCode), + Method(ast::Name, MethodViolationCode), } /// Reasons a method might not be object-safe. @@ -77,7 +76,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// because `object_safety_violations` can't be used during /// type collection. pub fn astconv_object_safety_violations(self, trait_def_id: DefId) - -> Vec> + -> Vec { let mut violations = vec![]; @@ -93,7 +92,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn object_safety_violations(self, trait_def_id: DefId) - -> Vec> + -> Vec { traits::supertrait_def_ids(self, trait_def_id) .flat_map(|def_id| self.object_safety_violations_for_trait(def_id)) @@ -101,21 +100,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } fn object_safety_violations_for_trait(self, trait_def_id: DefId) - -> Vec> + -> Vec { // Check methods for violations. - let mut violations: Vec<_> = - self.trait_items(trait_def_id).iter() + let mut violations: Vec<_> = self.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Method) .filter_map(|item| { - match *item { - ty::MethodTraitItem(ref m) => { - self.object_safety_violation_for_method(trait_def_id, &m) - .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) - } - _ => None, - } - }) - .collect(); + self.object_safety_violation_for_method(trait_def_id, &item) + .map(|code| ObjectSafetyViolation::Method(item.name, code)) + }).collect(); // Check the trait itself. if self.trait_has_sized_self(trait_def_id) { @@ -198,7 +191,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns `Some(_)` if this method makes the containing trait not object safe. fn object_safety_violation_for_method(self, trait_def_id: DefId, - method: &ty::Method<'gcx>) + method: &ty::AssociatedItem) -> Option { // Any method that has a `Self : Sized` requisite is otherwise @@ -216,7 +209,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// otherwise ensure that they cannot be used when `Self=Trait`. pub fn is_vtable_safe_method(self, trait_def_id: DefId, - method: &ty::Method<'gcx>) + method: &ty::AssociatedItem) -> bool { // Any method that has a `Self : Sized` requisite can't be called. @@ -233,26 +226,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `Self:Sized`. fn virtual_call_violation_for_method(self, trait_def_id: DefId, - method: &ty::Method<'tcx>) + method: &ty::AssociatedItem) -> Option { // The method's first parameter must be something that derefs (or // autorefs) to `&self`. For now, we only accept `self`, `&self` // and `Box`. - match method.explicit_self { - ty::ExplicitSelfCategory::Static => { - return Some(MethodViolationCode::StaticMethod); - } - - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => { - } + if !method.method_has_self_argument { + return Some(MethodViolationCode::StaticMethod); } // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = method.fty.sig; + let ref sig = self.lookup_item_type(method.def_id).ty.fn_sig(); for &input_ty in &sig.0.inputs[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -263,7 +249,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !method.generics.types.is_empty() { + if !self.lookup_generics(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index ce882c48377f7..b1ab61b09757e 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -33,8 +33,6 @@ use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use util::common::FN_OUTPUT_NAME; -use std::rc::Rc; - /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -945,7 +943,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // an error when we confirm the candidate // (which will ultimately lead to `normalize_to_error` // being invoked). - node_item.item.ty.is_some() + node_item.item.has_value } else { node_item.item.defaultness.is_default() }; @@ -1305,7 +1303,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( match assoc_ty { Some(node_item) => { - let ty = node_item.item.ty.unwrap_or_else(|| { + let ty = if !node_item.item.has_value { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type // checker method `check_impl_items_against_trait`, so here we @@ -1314,7 +1312,9 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( node_item.item.name, obligation.predicate.trait_ref); tcx.types.err - }); + } else { + tcx.lookup_item_type(node_item.item.def_id).ty + }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { ty: ty.subst(tcx, substs), @@ -1339,27 +1339,25 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( selcx: &SelectionContext<'cx, 'gcx, 'tcx>, impl_def_id: DefId, assoc_ty_name: ast::Name) - -> Option>>> + -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; if selcx.projection_mode() == Reveal::ExactMatch { let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(selcx.tcx()) { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == assoc_ty_name { - return Some(specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: assoc_ty, - }); - } + if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name { + return Some(specialization_graph::NodeItem { + node: specialization_graph::Node::Impl(impl_def_id), + item: item, + }); } } None } else { selcx.tcx().lookup_trait_def(trait_def_id) .ancestors(impl_def_id) - .type_defs(selcx.tcx(), assoc_ty_name) + .defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type) .next() } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 4eef6944974c0..91c40a5cc8516 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -120,7 +120,8 @@ pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); let trait_def = tcx.lookup_trait_def(trait_def_id); - match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() { + let ancestors = trait_def.ancestors(impl_data.impl_def_id); + match ancestors.defs(tcx, name, ty::AssociatedKind::Method).next() { Some(node_item) => { let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index c746145474c75..5a6809f1fad68 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; - use super::{OverlapError, specializes}; use hir::def_id::DefId; use traits::{self, Reveal}; -use ty::{self, TyCtxt, ImplOrTraitItem, TraitDef, TypeFoldable}; +use ty::{self, TyCtxt, TraitDef, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; use syntax::ast::Name; use util::nodemap::{DefIdMap, FxHashMap}; @@ -285,12 +283,10 @@ impl<'a, 'gcx, 'tcx> Node { } /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeItems<'a, 'gcx> { - NodeItems { - tcx: tcx.global_tcx(), - items: tcx.impl_or_trait_items(self.def_id()), - idx: 0, - } + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> impl Iterator + 'a { + tcx.associated_items(self.def_id()) } pub fn def_id(&self) -> DefId { @@ -301,28 +297,6 @@ impl<'a, 'gcx, 'tcx> Node { } } -/// An iterator over the items defined within a trait or impl. -pub struct NodeItems<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - items: Rc>, - idx: usize -} - -impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { - type Item = ImplOrTraitItem<'tcx>; - fn next(&mut self) -> Option> { - if self.idx < self.items.len() { - let item_def_id = self.items[self.idx]; - let items_table = self.tcx.impl_or_trait_items.borrow(); - let item = items_table[&item_def_id].clone(); - self.idx += 1; - Some(item) - } else { - None - } - } -} - pub struct Ancestors<'a, 'tcx: 'a> { trait_def: &'a TraitDef<'tcx>, current_source: Option, @@ -358,104 +332,16 @@ impl NodeItem { } } -pub struct TypeDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for TypeDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct FnDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for FnDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - -pub struct ConstDefs<'a, 'tcx: 'a> { - // generally only invoked once or twice, so the box doesn't hurt - iter: Box>>> + 'a>, -} - -impl<'a, 'tcx> Iterator for ConstDefs<'a, 'tcx> { - type Item = NodeItem>>; - fn next(&mut self) -> Option { - self.iter.next() - } -} - impl<'a, 'gcx, 'tcx> Ancestors<'a, 'tcx> { - /// Search the items from the given ancestors, returning each type definition - /// with the given name. - pub fn type_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> TypeDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::TypeTraitItem(assoc_ty) = item { - if assoc_ty.name == name { - return Some(NodeItem { - node: node, - item: assoc_ty, - }); - } - } - None - }) - - }); - TypeDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each fn definition - /// with the given name. - pub fn fn_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> FnDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::MethodTraitItem(method) = item { - if method.name == name { - return Some(NodeItem { - node: node, - item: method, - }); - } - } - None - }) - - }); - FnDefs { iter: Box::new(iter) } - } - - /// Search the items from the given ancestors, returning each const - /// definition with the given name. - pub fn const_defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name) -> ConstDefs<'a, 'gcx> { - let iter = self.flat_map(move |node| { - node.items(tcx) - .filter_map(move |item| { - if let ty::ConstTraitItem(konst) = item { - if konst.name == name { - return Some(NodeItem { - node: node, - item: konst, - }); - } - } - None - }) - - }); - ConstDefs { iter: Box::new(iter) } + /// Search the items from the given ancestors, returning each definition + /// with the given name and the given kind. + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn defs(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, name: Name, kind: ty::AssociatedKind) + -> impl Iterator> + 'a { + self.flat_map(move |node| { + node.items(tcx).filter(move |item| item.kind == kind && item.name == name) + .map(move |item| NodeItem { node: node, item: item }) + }) } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 52830164d1d91..9346bbd30f9ce 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -477,8 +477,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut entries = 0; // Count number of methods and add them to the total offset. // Skip over associated types and constants. - for trait_item in &self.trait_items(trait_ref.def_id())[..] { - if let ty::MethodTraitItem(_) = *trait_item { + for trait_item in self.associated_items(trait_ref.def_id()) { + if trait_item.kind == ty::AssociatedKind::Method { entries += 1; } } @@ -495,17 +495,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // add them to the total offset. // Skip over associated types and constants. let mut entries = object.vtable_base; - for trait_item in &self.trait_items(object.upcast_trait_ref.def_id())[..] { - if trait_item.def_id() == method_def_id { + for trait_item in self.associated_items(object.upcast_trait_ref.def_id()) { + if trait_item.def_id == method_def_id { // The item with the ID we were given really ought to be a method. - assert!(match *trait_item { - ty::MethodTraitItem(_) => true, - _ => false - }); - + assert_eq!(trait_item.kind, ty::AssociatedKind::Method); return entries; } - if let ty::MethodTraitItem(_) = *trait_item { + if trait_item.kind == ty::AssociatedKind::Method { entries += 1; } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b19f935123519..60a48ba580a0d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -403,14 +403,10 @@ pub struct GlobalCtxt<'tcx> { pub tables: RefCell>, /// Maps from a trait item to the trait item "descriptor" - pub impl_or_trait_items: RefCell>>, + pub associated_items: RefCell>>, /// Maps from an impl/trait def-id to a list of the def-ids of its items - pub impl_or_trait_item_def_ids: RefCell>>, - - /// A cache for the trait_items() routine; note that the routine - /// itself pushes the `TraitItems` dependency node. - trait_items_cache: RefCell>>, + pub associated_item_def_ids: RefCell>>, pub impl_trait_refs: RefCell>>, pub trait_defs: RefCell>>, @@ -822,9 +818,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { tcache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), rcache: RefCell::new(FxHashMap()), tc_cache: RefCell::new(FxHashMap()), - impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - impl_or_trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), ty_param_defs: RefCell::new(NodeMap()), normalized_cache: RefCell::new(FxHashMap()), lang_items: lang_items, @@ -1539,15 +1534,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) } - pub fn trait_items(self, trait_did: DefId) -> Rc>> { - self.trait_items_cache.memoize(trait_did, || { - let def_ids = self.impl_or_trait_items(trait_did); - Rc::new(def_ids.iter() - .map(|&def_id| self.impl_or_trait_item(def_id)) - .collect()) - }) - } - /// Obtain the representation annotation for a struct definition. pub fn lookup_repr_hints(self, did: DefId) -> Rc> { self.repr_hint_cache.memoize(did, || { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index cad87081a93b4..43abb61e7fcd8 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -16,7 +16,7 @@ use ty::{self, Ty}; use std::cell::RefCell; use std::marker::PhantomData; use std::rc::Rc; -use syntax::{attr, ast}; +use syntax::attr; macro_rules! dep_map_ty { ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => { @@ -32,18 +32,16 @@ macro_rules! dep_map_ty { } } -dep_map_ty! { ImplOrTraitItems: ImplOrTraitItems(DefId) -> ty::ImplOrTraitItem<'tcx> } +dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem } dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { ImplOrTraitItemDefIds: ImplOrTraitItemDefIds(DefId) -> Rc> } +dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(DefId) -> Rc> } dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } -dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } -dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index fcf9b5ff2730c..1d260fd65feff 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -10,9 +10,8 @@ pub use self::Variance::*; pub use self::DtorKind::*; -pub use self::ImplOrTraitItemContainer::*; +pub use self::AssociatedItemContainer::*; pub use self::BorrowKind::*; -pub use self::ImplOrTraitItem::*; pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; @@ -135,12 +134,12 @@ impl DtorKind { } #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum ImplOrTraitItemContainer { +pub enum AssociatedItemContainer { TraitContainer(DefId), ImplContainer(DefId), } -impl ImplOrTraitItemContainer { +impl AssociatedItemContainer { pub fn id(&self) -> DefId { match *self { TraitContainer(id) => id, @@ -183,58 +182,34 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { } } -#[derive(Clone)] -pub enum ImplOrTraitItem<'tcx> { - ConstTraitItem(Rc>), - MethodTraitItem(Rc>), - TypeTraitItem(Rc>), -} - -impl<'tcx> ImplOrTraitItem<'tcx> { - pub fn def(&self) -> Def { - match *self { - ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), - MethodTraitItem(ref method) => Def::Method(method.def_id), - TypeTraitItem(ref ty) => Def::AssociatedTy(ty.def_id), - } - } - - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItem(ref associated_const) => associated_const.def_id, - MethodTraitItem(ref method) => method.def_id, - TypeTraitItem(ref associated_type) => associated_type.def_id, - } - } - - pub fn name(&self) -> Name { - match *self { - ConstTraitItem(ref associated_const) => associated_const.name, - MethodTraitItem(ref method) => method.name, - TypeTraitItem(ref associated_type) => associated_type.name, - } - } +#[derive(Copy, Clone, Debug)] +pub struct AssociatedItem { + pub def_id: DefId, + pub name: Name, + pub kind: AssociatedKind, + pub vis: Visibility, + pub defaultness: hir::Defaultness, + pub has_value: bool, + pub container: AssociatedItemContainer, - pub fn vis(&self) -> Visibility { - match *self { - ConstTraitItem(ref associated_const) => associated_const.vis, - MethodTraitItem(ref method) => method.vis, - TypeTraitItem(ref associated_type) => associated_type.vis, - } - } + /// Whether this is a method with an explicit self + /// as its first argument, allowing method calls. + pub method_has_self_argument: bool, +} - pub fn container(&self) -> ImplOrTraitItemContainer { - match *self { - ConstTraitItem(ref associated_const) => associated_const.container, - MethodTraitItem(ref method) => method.container, - TypeTraitItem(ref associated_type) => associated_type.container, - } - } +#[derive(Copy, Clone, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)] +pub enum AssociatedKind { + Const, + Method, + Type +} - pub fn as_opt_method(&self) -> Option>> { - match *self { - MethodTraitItem(ref m) => Some((*m).clone()), - _ => None, +impl AssociatedItem { + pub fn def(&self) -> Def { + match self.kind { + AssociatedKind::Const => Def::AssociatedConst(self.def_id), + AssociatedKind::Method => Def::Method(self.def_id), + AssociatedKind::Type => Def::AssociatedTy(self.def_id), } } } @@ -308,64 +283,6 @@ impl Visibility { } } -#[derive(Clone, Debug)] -pub struct Method<'tcx> { - pub name: Name, - pub generics: &'tcx Generics<'tcx>, - pub predicates: GenericPredicates<'tcx>, - pub fty: &'tcx BareFnTy<'tcx>, - pub explicit_self: ExplicitSelfCategory<'tcx>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub has_body: bool, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - -impl<'tcx> Method<'tcx> { - pub fn container_id(&self) -> DefId { - match self.container { - TraitContainer(id) => id, - ImplContainer(id) => id, - } - } -} - -impl<'tcx> PartialEq for Method<'tcx> { - #[inline] - fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id } -} - -impl<'tcx> Eq for Method<'tcx> {} - -impl<'tcx> Hash for Method<'tcx> { - #[inline] - fn hash(&self, s: &mut H) { - self.def_id.hash(s) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedConst<'tcx> { - pub name: Name, - pub ty: Ty<'tcx>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, - pub has_value: bool -} - -#[derive(Clone, Copy, Debug)] -pub struct AssociatedType<'tcx> { - pub name: Name, - pub ty: Option>, - pub vis: Visibility, - pub defaultness: hir::Defaultness, - pub def_id: DefId, - pub container: ImplOrTraitItemContainer, -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -1288,19 +1205,10 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { tcx.region_maps.item_extent(id)) } hir::ImplItemKind::Method(_, ref body) => { - let method_def_id = tcx.map.local_def_id(id); - match tcx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - tcx.construct_parameter_environment( - impl_item.span, - method_ty.def_id, - tcx.region_maps.call_site_extent(id, body.id)) - } - _ => { - bug!("ParameterEnvironment::for_item(): \ - got non-method item from impl method?!") - } - } + tcx.construct_parameter_environment( + impl_item.span, + tcx.map.local_def_id(id), + tcx.region_maps.call_site_extent(id, body.id)) } } } @@ -1319,27 +1227,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { // Use call-site for extent (unless this is a // trait method with no default; then fallback // to the method id). - let method_def_id = tcx.map.local_def_id(id); - match tcx.impl_or_trait_item(method_def_id) { - MethodTraitItem(ref method_ty) => { - let extent = if let Some(ref body) = *body { - // default impl: use call_site extent as free_id_outlive bound. - tcx.region_maps.call_site_extent(id, body.id) - } else { - // no default impl: use item extent as free_id_outlive bound. - tcx.region_maps.item_extent(id) - }; - tcx.construct_parameter_environment( - trait_item.span, - method_ty.def_id, - extent) - } - _ => { - bug!("ParameterEnvironment::for_item(): \ - got non-method item from provided \ - method?!") - } - } + let extent = if let Some(ref body) = *body { + // default impl: use call_site extent as free_id_outlive bound. + tcx.region_maps.call_site_extent(id, body.id) + } else { + // no default impl: use item extent as free_id_outlive bound. + tcx.region_maps.item_extent(id) + }; + tcx.construct_parameter_environment( + trait_item.span, + tcx.map.local_def_id(id), + extent) } } } @@ -2065,7 +1963,7 @@ impl LvaluePreference { } /// Helper for looking things up in the various maps that are populated during -/// typeck::collect (e.g., `tcx.impl_or_trait_items`, `tcx.tcache`, etc). All of +/// typeck::collect (e.g., `tcx.associated_items`, `tcx.tcache`, etc). All of /// these share the pattern that if the id is local, it should have been loaded /// into the map by the `typeck::collect` phase. If the def-id is external, /// then we have to go consult the crate loading code (and cache the result for @@ -2204,13 +2102,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn provided_trait_methods(self, id: DefId) -> Vec>> { - self.impl_or_trait_items(id).iter().filter_map(|&def_id| { - match self.impl_or_trait_item(def_id) { - MethodTraitItem(ref m) if m.has_body => Some(m.clone()), - _ => None - } - }).collect() + pub fn provided_trait_methods(self, id: DefId) -> Vec { + self.associated_items(id) + .filter(|item| item.kind == AssociatedKind::Method && item.has_value) + .collect() } pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { @@ -2243,17 +2138,105 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn impl_or_trait_item(self, id: DefId) -> ImplOrTraitItem<'gcx> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_items, - || self.sess.cstore.impl_or_trait_item(self.global_tcx(), id) - .expect("missing ImplOrTraitItem in metadata")) + pub fn associated_item(self, def_id: DefId) -> AssociatedItem { + self.associated_items.memoize(def_id, || { + if !def_id.is_local() { + return self.sess.cstore.associated_item(self.global_tcx(), def_id) + .expect("missing AssociatedItem in metadata"); + } + + let id = self.map.as_local_node_id(def_id).unwrap(); + let parent_id = self.map.get_parent(id); + let parent_def_id = self.map.local_def_id(parent_id); + match self.map.get(id) { + ast_map::NodeTraitItem(trait_item) => { + let (kind, has_self, has_value) = match trait_item.node { + hir::MethodTraitItem(ref sig, ref body) => { + (AssociatedKind::Method, sig.decl.get_self().is_some(), + body.is_some()) + } + hir::ConstTraitItem(_, ref value) => { + (AssociatedKind::Const, false, value.is_some()) + } + hir::TypeTraitItem(_, ref ty) => { + (AssociatedKind::Type, false, ty.is_some()) + } + }; + + AssociatedItem { + name: trait_item.name, + kind: kind, + vis: Visibility::from_hir(&hir::Inherited, id, self), + defaultness: hir::Defaultness::Default, + has_value: has_value, + def_id: def_id, + container: TraitContainer(parent_def_id), + method_has_self_argument: has_self + } + } + ast_map::NodeImplItem(impl_item) => { + let (kind, has_self) = match impl_item.node { + hir::ImplItemKind::Method(ref sig, _) => { + (AssociatedKind::Method, sig.decl.get_self().is_some()) + } + hir::ImplItemKind::Const(..) => (AssociatedKind::Const, false), + hir::ImplItemKind::Type(..) => (AssociatedKind::Type, false) + }; + + // Trait impl items are always public. + let public = hir::Public; + let parent_item = self.map.expect_item(parent_id); + let vis = if let hir::ItemImpl(.., Some(_), _, _) = parent_item.node { + &public + } else { + &impl_item.vis + }; + + AssociatedItem { + name: impl_item.name, + kind: kind, + vis: Visibility::from_hir(vis, id, self), + defaultness: impl_item.defaultness, + has_value: true, + def_id: def_id, + container: ImplContainer(parent_def_id), + method_has_self_argument: has_self + } + } + item => bug!("associated_item: {:?} not an associated item", item) + } + }) } - pub fn impl_or_trait_items(self, id: DefId) -> Rc> { - lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_item_def_ids, - || Rc::new(self.sess.cstore.impl_or_trait_items(id))) + pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { + self.associated_item_def_ids.memoize(def_id, || { + if !def_id.is_local() { + return Rc::new(self.sess.cstore.associated_item_def_ids(def_id)); + } + + let id = self.map.as_local_node_id(def_id).unwrap(); + let item = self.map.expect_item(id); + match item.node { + hir::ItemTrait(.., ref trait_items) => { + Rc::new(trait_items.iter().map(|trait_item| { + self.map.local_def_id(trait_item.id) + }).collect()) + } + hir::ItemImpl(.., ref impl_items) => { + Rc::new(impl_items.iter().map(|impl_item| { + self.map.local_def_id(impl_item.id) + }).collect()) + } + _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") + } + }) + } + + #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. + pub fn associated_items(self, def_id: DefId) + -> impl Iterator + 'a { + let def_ids = self.associated_item_def_ids(def_id); + (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) } /// Returns the trait-ref corresponding to a given impl, or None if it is @@ -2539,31 +2522,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL) } - /// Load primitive inherent implementations if necessary - pub fn populate_implementations_for_primitive_if_necessary(self, - primitive_def_id: DefId) { - if primitive_def_id.is_local() { - return - } - - // The primitive is not local, hence we are reading this out - // of metadata. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_primitive_impls.borrow().contains(&primitive_def_id) { - return - } - - debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", - primitive_def_id); - - let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id); - - // Store the implementation info. - self.impl_or_trait_item_def_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items)); - self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); - } - /// Populates the type context with all the inherent implementations for /// the given type if necessary. pub fn populate_inherent_implementations_for_type_if_necessary(self, @@ -2584,11 +2542,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { type_id); let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - for &impl_def_id in &inherent_impls { - // Store the implementation info. - let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); - self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); - } self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); self.populated_external_types.borrow_mut().insert(type_id); @@ -2617,23 +2570,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) { - let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); // Record the trait->implementation mapping. let parent = self.sess.cstore.impl_parent(impl_def_id).unwrap_or(trait_id); def.record_remote_impl(self, impl_def_id, trait_ref, parent); - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for &impl_item_def_id in &impl_items { - // load impl items eagerly for convenience - // FIXME: we may want to load these lazily - self.impl_or_trait_item(impl_item_def_id); - } - - // Store the implementation info. - self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); @@ -2679,17 +2620,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// ID of the impl that the method belongs to. Otherwise, return `None`. pub fn impl_of_method(self, def_id: DefId) -> Option { if def_id.krate != LOCAL_CRATE { - return self.sess.cstore.impl_or_trait_item(self.global_tcx(), def_id) + return self.sess.cstore.associated_item(self.global_tcx(), def_id) .and_then(|item| { - match item.container() { + match item.container { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), } }); } - match self.impl_or_trait_items.borrow().get(&def_id).cloned() { + match self.associated_items.borrow().get(&def_id).cloned() { Some(trait_item) => { - match trait_item.container() { + match trait_item.container { TraitContainer(_) => None, ImplContainer(def_id) => Some(def_id), } @@ -2705,9 +2646,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if def_id.krate != LOCAL_CRATE { return self.sess.cstore.trait_of_item(def_id); } - match self.impl_or_trait_items.borrow().get(&def_id) { - Some(impl_or_trait_item) => { - match impl_or_trait_item.container() { + match self.associated_items.borrow().get(&def_id) { + Some(associated_item) => { + match associated_item.container { TraitContainer(def_id) => Some(def_id), ImplContainer(_) => None } @@ -2716,30 +2657,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// If the given def ID describes an item belonging to a trait, (either a - /// default method or an implementation of a trait method), return the ID of - /// the method inside trait definition (this means that if the given def ID - /// is already that of the original trait method, then the return value is - /// the same). - /// Otherwise, return `None`. - pub fn trait_item_of_item(self, def_id: DefId) -> Option { - let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) { - Some(m) => m.clone(), - None => return None, - }; - match impl_or_trait_item.container() { - TraitContainer(_) => Some(impl_or_trait_item.def_id()), - ImplContainer(def_id) => { - self.trait_id_of_impl(def_id).and_then(|trait_did| { - let name = impl_or_trait_item.name(); - self.trait_items(trait_did).iter() - .find(|item| item.name() == name) - .map(|item| item.def_id()) - }) - } - } - } - /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { @@ -2856,15 +2773,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -/// The category of explicit self. -#[derive(Clone, Copy, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)] -pub enum ExplicitSelfCategory<'tcx> { - Static, - ByValue, - ByReference(&'tcx Region, hir::Mutability), - ByBox, -} - impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn with_freevars(self, fid: NodeId, f: F) -> T where F: FnOnce(&[hir::Freevar]) -> T, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 31304fb7b4993..01b44ced8e08e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -670,18 +670,6 @@ impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> { } } -impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "ImplOrTraitItem(")?; - match *self { - ty::ImplOrTraitItem::MethodTraitItem(ref i) => write!(f, "{:?}", i), - ty::ImplOrTraitItem::ConstTraitItem(ref i) => write!(f, "{:?}", i), - ty::ImplOrTraitItem::TypeTraitItem(ref i) => write!(f, "{:?}", i), - }?; - write!(f, ")") - } -} - impl<'tcx> fmt::Display for ty::FnSig<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "fn")?; @@ -995,20 +983,6 @@ impl fmt::Display for ty::InferTy { } } -impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - ty::ExplicitSelfCategory::Static => "static", - ty::ExplicitSelfCategory::ByValue => "self", - ty::ExplicitSelfCategory::ByReference(_, hir::MutMutable) => { - "&mut self" - } - ty::ExplicitSelfCategory::ByReference(_, hir::MutImmutable) => "&self", - ty::ExplicitSelfCategory::ByBox => "Box", - }) - } -} - impl fmt::Display for ty::ParamTy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 57a5400ecadf8..08b8f4c8941cc 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -1091,13 +1091,8 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let ac = tcx.impl_or_trait_items(impl_data.impl_def_id) - .iter().filter_map(|&def_id| { - match tcx.impl_or_trait_item(def_id) { - ty::ConstTraitItem(ic) => Some(ic), - _ => None - } - }).find(|ic| ic.name == ti.name); + let ac = tcx.associated_items(impl_data.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == ti.name); match ac { Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), None => match ti.node { diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index fea3de59520ca..28d45080284cd 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -29,10 +29,10 @@ pub enum MethodLateContext { pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext { let def_id = cx.tcx.map.local_def_id(id); - match cx.tcx.impl_or_trait_items.borrow().get(&def_id) { + match cx.tcx.associated_items.borrow().get(&def_id) { None => span_bug!(span, "missing method descriptor?!"), Some(item) => { - match item.container() { + match item.container { ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl, ty::ImplContainer(cid) => { match cx.tcx.impl_trait_ref(cid) { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 28dc71fd59bae..af05724d9f951 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -818,7 +818,7 @@ impl LateLintPass for UnconditionalRecursion { let method = match fn_kind { FnKind::ItemFn(..) => None, FnKind::Method(..) => { - cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method() + Some(cx.tcx.associated_item(cx.tcx.map.local_def_id(id))) } // closures can't recur, so they don't matter. FnKind::Closure(_) => return, @@ -937,7 +937,7 @@ impl LateLintPass for UnconditionalRecursion { // Check if the expression `id` performs a call to `method`. fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - method: &ty::Method, + method: &ty::AssociatedItem, id: ast::NodeId) -> bool { use rustc::ty::adjustment::*; @@ -986,14 +986,14 @@ impl LateLintPass for UnconditionalRecursion { // Check if the method call to the method with the ID `callee_id` // and instantiated with `callee_substs` refers to method `method`. fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - method: &ty::Method, + method: &ty::AssociatedItem, callee_id: DefId, callee_substs: &Substs<'tcx>, expr_id: ast::NodeId) -> bool { - let callee_item = tcx.impl_or_trait_item(callee_id); + let callee_item = tcx.associated_item(callee_id); - match callee_item.container() { + match callee_item.container { // This is an inherent method, so the `def_id` refers // directly to the method definition. ty::ImplContainer(_) => callee_id == method.def_id, @@ -1034,7 +1034,7 @@ impl LateLintPass for UnconditionalRecursion { let container = ty::ImplContainer(vtable_impl.impl_def_id); // It matches if it comes from the same impl, // and has the same method name. - container == method.container && callee_item.name() == method.name + container == method.container && callee_item.name == method.name } // There's no way to know if this call is diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index a618c98ff774c..18ce514c9c42d 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -144,7 +144,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn impl_or_trait_items(&self, def_id: DefId) -> Vec { + fn associated_item_def_ids(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; self.get_crate_data(def_id.krate) @@ -182,11 +182,11 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index) } - fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option> + fn associated_item<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> Option { self.dep_graph.read(DepNode::MetaData(def)); - self.get_crate_data(def.krate).get_impl_or_trait_item(def.index, tcx) + self.get_crate_data(def.krate).get_associated_item(def.index) } fn is_const_fn(&self, did: DefId) -> bool @@ -427,9 +427,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // the logic to do that already exists in `middle`. In order to // reuse that code, it needs to be able to look up the traits for // inlined items. - let ty_trait_item = tcx.impl_or_trait_item(def_id).clone(); + let ty_trait_item = tcx.associated_item(def_id).clone(); let trait_item_def_id = tcx.map.local_def_id(trait_item.id); - tcx.impl_or_trait_items.borrow_mut() + tcx.associated_items.borrow_mut() .insert(trait_item_def_id, ty_trait_item); } Some(&InlinedItem::ImplItem(_, ref impl_item)) => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 630b07744249b..7973cd880fe34 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -36,7 +36,6 @@ use std::borrow::Cow; use std::cell::Ref; use std::io; use std::mem; -use std::rc::Rc; use std::str; use std::u32; @@ -792,10 +791,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id).mir.map(|mir| mir.decode((self, tcx))) } - pub fn get_impl_or_trait_item(&self, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option> { + pub fn get_associated_item(&self, id: DefIndex) -> Option { let item = self.entry(id); let parent_and_name = || { let def_key = item.def_key.decode(self); @@ -806,52 +802,43 @@ impl<'a, 'tcx> CrateMetadata { Some(match item.kind { EntryKind::AssociatedConst(container) => { let (parent, name) = parent_and_name(); - ty::ConstTraitItem(Rc::new(ty::AssociatedConst { + ty::AssociatedItem { name: name, - ty: item.ty.unwrap().decode((self, tcx)), + kind: ty::AssociatedKind::Const, vis: item.visibility, defaultness: container.defaultness(), + has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), - has_value: container.has_body(), - })) + method_has_self_argument: false + } } EntryKind::Method(data) => { let (parent, name) = parent_and_name(); - let ity = item.ty.unwrap().decode((self, tcx)); - let fty = match ity.sty { - ty::TyFnDef(.., fty) => fty, - _ => { - bug!("the type {:?} of the method {:?} is not a function?", - ity, - name) - } - }; - let data = data.decode(self); - ty::MethodTraitItem(Rc::new(ty::Method { + ty::AssociatedItem { name: name, - generics: tcx.lookup_generics(self.local_def_id(id)), - predicates: item.predicates.unwrap().decode((self, tcx)), - fty: fty, - explicit_self: data.explicit_self.decode((self, tcx)), + kind: ty::AssociatedKind::Method, vis: item.visibility, defaultness: data.container.defaultness(), - has_body: data.container.has_body(), + has_value: data.container.has_value(), def_id: self.local_def_id(id), container: data.container.with_def_id(parent), - })) + method_has_self_argument: data.has_self + } } EntryKind::AssociatedType(container) => { let (parent, name) = parent_and_name(); - ty::TypeTraitItem(Rc::new(ty::AssociatedType { + ty::AssociatedItem { name: name, - ty: item.ty.map(|ty| ty.decode((self, tcx))), + kind: ty::AssociatedKind::Type, vis: item.visibility, defaultness: container.defaultness(), + has_value: container.has_value(), def_id: self.local_def_id(id), container: container.with_def_id(parent), - })) + method_has_self_argument: false + } } _ => return None, }) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index fb4fb50729628..2379e744c49e1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -457,19 +457,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let node_id = tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = tcx.map.expect_trait_item(node_id); - let trait_item = tcx.impl_or_trait_item(def_id); + let trait_item = tcx.associated_item(def_id); - let container = |has_body| if has_body { + let container = if trait_item.has_value { AssociatedContainer::TraitWithDefault } else { AssociatedContainer::TraitRequired }; - let kind = match trait_item { - ty::ConstTraitItem(ref associated_const) => { - EntryKind::AssociatedConst(container(associated_const.has_value)) - } - ty::MethodTraitItem(ref method_ty) => { + let kind = match trait_item.kind { + ty::AssociatedKind::Const => EntryKind::AssociatedConst(container), + ty::AssociatedKind::Method => { let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node { FnData { constness: hir::Constness::NotConst, @@ -478,30 +476,35 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { bug!() }; - let data = MethodData { + EntryKind::Method(self.lazy(&MethodData { fn_data: fn_data, - container: container(method_ty.has_body), - explicit_self: self.lazy(&method_ty.explicit_self), - }; - EntryKind::Method(self.lazy(&data)) + container: container, + has_self: trait_item.method_has_self_argument, + })) } - ty::TypeTraitItem(_) => EntryKind::AssociatedType(container(false)), + ty::AssociatedKind::Type => EntryKind::AssociatedType(container), }; Entry { kind: kind, - visibility: trait_item.vis().simplify(), + visibility: trait_item.vis.simplify(), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match trait_item { - ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), - ty::TypeTraitItem(ref associated_type) => { - associated_type.ty.map(|ty| self.lazy(&ty)) + ty: match trait_item.kind { + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => { + Some(self.encode_item_type(def_id)) + } + ty::AssociatedKind::Type => { + if trait_item.has_value { + Some(self.encode_item_type(def_id)) + } else { + None + } } }, inherent_impls: LazySeq::empty(), @@ -509,8 +512,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: if let ty::ConstTraitItem(_) = trait_item { - let trait_def_id = trait_item.container().id(); + ast: if trait_item.kind == ty::AssociatedKind::Const { + let trait_def_id = trait_item.container.id(); Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item))) } else { None @@ -522,17 +525,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { let node_id = self.tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.map.expect_impl_item(node_id); - let impl_item = self.tcx.impl_or_trait_item(def_id); - let impl_def_id = impl_item.container().id(); + let impl_item = self.tcx.associated_item(def_id); + let impl_def_id = impl_item.container.id(); - let container = match ast_item.defaultness { + let container = match impl_item.defaultness { hir::Defaultness::Default => AssociatedContainer::ImplDefault, hir::Defaultness::Final => AssociatedContainer::ImplFinal, }; - let kind = match impl_item { - ty::ConstTraitItem(_) => EntryKind::AssociatedConst(container), - ty::MethodTraitItem(ref method_ty) => { + let kind = match impl_item.kind { + ty::AssociatedKind::Const => EntryKind::AssociatedConst(container), + ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { FnData { constness: sig.constness, @@ -541,17 +544,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { bug!() }; - let data = MethodData { + EntryKind::Method(self.lazy(&MethodData { fn_data: fn_data, container: container, - explicit_self: self.lazy(&method_ty.explicit_self), - }; - EntryKind::Method(self.lazy(&data)) + has_self: impl_item.method_has_self_argument, + })) } - ty::TypeTraitItem(_) => EntryKind::AssociatedType(container), + ty::AssociatedKind::Type => EntryKind::AssociatedType(container) }; - let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item { + let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const { (true, true) } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { let generics = self.tcx.lookup_generics(def_id); @@ -565,20 +567,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Entry { kind: kind, - visibility: impl_item.vis().simplify(), + visibility: impl_item.vis.simplify(), def_key: self.encode_def_key(def_id), attributes: self.encode_attributes(&ast_item.attrs), children: LazySeq::empty(), stability: self.encode_stability(def_id), deprecation: self.encode_deprecation(def_id), - ty: match impl_item { - ty::ConstTraitItem(_) | - ty::MethodTraitItem(_) => Some(self.encode_item_type(def_id)), - ty::TypeTraitItem(ref associated_type) => { - associated_type.ty.map(|ty| self.lazy(&ty)) - } - }, + ty: Some(self.encode_item_type(def_id)), inherent_impls: LazySeq::empty(), variances: LazySeq::empty(), generics: Some(self.encode_generics(def_id)), @@ -758,7 +754,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemImpl(..) | hir::ItemTrait(..) => { - self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| { + self.lazy_seq(tcx.associated_item_def_ids(def_id).iter().map(|&def_id| { assert!(def_id.is_local()); def_id.index })) @@ -880,14 +876,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(def_id); } hir::ItemImpl(..) => { - for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + for &trait_item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, trait_item_def_id); } } hir::ItemTrait(..) => { - for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + for &item_def_id in &self.tcx.associated_item_def_ids(def_id)[..] { self.record(item_def_id, EncodeContext::encode_info_for_trait_item, item_def_id); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 3d1bd77d8bc28..ff2a764571025 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -245,7 +245,7 @@ pub enum EntryKind<'tcx> { Trait(Lazy>), Impl(Lazy>), DefaultImpl(Lazy>), - Method(Lazy>), + Method(Lazy), AssociatedType(AssociatedContainer), AssociatedConst(AssociatedContainer), } @@ -300,7 +300,7 @@ pub enum AssociatedContainer { } impl AssociatedContainer { - pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer { + pub fn with_def_id(&self, def_id: DefId) -> ty::AssociatedItemContainer { match *self { AssociatedContainer::TraitRequired | AssociatedContainer::TraitWithDefault => ty::TraitContainer(def_id), @@ -310,7 +310,7 @@ impl AssociatedContainer { } } - pub fn has_body(&self) -> bool { + pub fn has_value(&self) -> bool { match *self { AssociatedContainer::TraitRequired => false, @@ -332,10 +332,10 @@ impl AssociatedContainer { } #[derive(RustcEncodable, RustcDecodable)] -pub struct MethodData<'tcx> { +pub struct MethodData { pub fn_data: FnData, pub container: AssociatedContainer, - pub explicit_self: Lazy>, + pub has_self: bool, } #[derive(RustcEncodable, RustcDecodable)] diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 678db1e544cb0..ecc2d8fe050ad 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -147,20 +147,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { -> (Ty<'tcx>, Literal<'tcx>) { let method_name = token::intern(method_name); let substs = self.tcx.mk_substs_trait(self_ty, params); - for trait_item in self.tcx.trait_items(trait_def_id).iter() { - match *trait_item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => { - if method.name == method_name { - let method_ty = self.tcx.lookup_item_type(method.def_id); - let method_ty = method_ty.ty.subst(self.tcx, substs); - return (method_ty, Literal::Item { - def_id: method.def_id, - substs: substs, - }); - } - } - ty::ImplOrTraitItem::ConstTraitItem(..) | - ty::ImplOrTraitItem::TypeTraitItem(..) => {} + for item in self.tcx.associated_items(trait_def_id) { + if item.kind == ty::AssociatedKind::Method && item.name == method_name { + let method_ty = self.tcx.lookup_item_type(item.def_id); + let method_ty = method_ty.ty.subst(self.tcx, substs); + return (method_ty, Literal::Item { + def_id: item.def_id, + substs: substs, + }); } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f23539e88f78d..1ab99b822d08d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -542,7 +542,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node v.handle_const_fn_call(e, did, node_ty) } Some(Def::Method(did)) => { - match v.tcx.impl_or_trait_item(did).container() { + match v.tcx.associated_item(did).container { ty::ImplContainer(_) => { v.handle_const_fn_call(e, did, node_ty) } @@ -557,7 +557,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node } hir::ExprMethodCall(..) => { let method = v.tcx.tables().method_map[&method_call]; - let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() { + let is_const = match v.tcx.associated_item(method.def_id).container { ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty), ty::TraitContainer(_) => false }; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cbe2cd2628d29..dc7399e228908 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -399,7 +399,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a method is in scope. fn check_method(&mut self, span: Span, method_def_id: DefId) { - match self.tcx.impl_or_trait_item(method_def_id).container() { + match self.tcx.associated_item(method_def_id).container { // Trait methods are always all public. The only controlling factor // is whether the trait itself is accessible or not. ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1e998a2a4d5b0..cb8dd7250b496 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -456,7 +456,7 @@ impl<'b> Resolver<'b> { self.define(parent, name, TypeNS, (module, DUMMY_SP, vis)); // If this is a trait, add all the trait item names to the trait info. - let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); + let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id); for trait_item_def_id in trait_item_def_ids { let trait_item_name = self.session.cstore.def_key(trait_item_def_id) .disambiguated_data.data.get_opt_name() diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index db4788c3ceadb..148a24f1358c5 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -32,7 +32,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; -use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; +use rustc::ty::{self, TyCtxt, AssociatedItemContainer}; use std::collections::HashSet; use std::collections::hash_map::DefaultHasher; @@ -402,19 +402,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // with the right name. if !self.span.filter_generated(Some(method_data.span), span) { let container = - self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container(); + self.tcx.associated_item(self.tcx.map.local_def_id(id)).container; let mut trait_id; let mut decl_id = None; match container { - ImplOrTraitItemContainer::ImplContainer(id) => { + AssociatedItemContainer::ImplContainer(id) => { trait_id = self.tcx.trait_id_of_impl(id); match trait_id { Some(id) => { - for item in &**self.tcx.trait_items(id) { - if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { - if m.name == name { - decl_id = Some(m.def_id); + for item in self.tcx.associated_items(id) { + if item.kind == ty::AssociatedKind::Method { + if item.name == name { + decl_id = Some(item.def_id); break; } } @@ -429,7 +429,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } - ImplOrTraitItemContainer::TraitContainer(id) => { + AssociatedItemContainer::TraitContainer(id) => { trait_id = Some(id); } } @@ -916,11 +916,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // Modules or types in the path prefix. match self.tcx.expect_def(id) { Def::Method(did) => { - let ti = self.tcx.impl_or_trait_item(did); - if let ty::MethodTraitItem(m) = ti { - if m.explicit_self == ty::ExplicitSelfCategory::Static { - self.write_sub_path_trait_truncated(path); - } + let ti = self.tcx.associated_item(did); + if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument { + self.write_sub_path_trait_truncated(path); } } Def::Fn(..) | diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e1b67d211a333..fded34d2c856c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -313,7 +313,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { name: ast::Name, span: Span) -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, vis, docs) = + let (qualname, parent_scope, decl_id, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { @@ -323,12 +323,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&rustc::hir::print::ty_to_string(&ty)); let trait_id = self.tcx.trait_id_of_impl(impl_id); + let mut decl_id = None; if let Some(def_id) = trait_id { result.push_str(" as "); result.push_str(&self.tcx.item_path_str(def_id)); + self.tcx.associated_items(def_id) + .find(|item| item.name == name) + .map(|item| decl_id = Some(item.def_id)); } result.push_str(">"); - (result, trait_id, From::from(&item.vis), docs_for_attrs(&item.attrs)) + + (result, trait_id, decl_id, + From::from(&item.vis), + docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -351,7 +358,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { (format!("::{}", self.tcx.item_path_str(def_id)), - Some(def_id), + Some(def_id), None, From::from(&item.vis), docs_for_attrs(&item.attrs)) } @@ -373,15 +380,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let qualname = format!("{}::{}", qualname, name); - let def_id = self.tcx.map.local_def_id(id); - let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_def_id| { - if new_def_id != def_id { - Some(new_def_id) - } else { - None - } - }); - let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); Some(FunctionData { @@ -473,7 +471,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ast::ExprKind::MethodCall(..) => { let method_call = ty::MethodCall::expr(expr.id); let method_id = self.tcx.tables().method_map[&method_call].def_id; - let (def_id, decl_id) = match self.tcx.impl_or_trait_item(method_id).container() { + let (def_id, decl_id) = match self.tcx.associated_item(method_id).container { ty::ImplContainer(_) => (Some(method_id), None), ty::TraitContainer(_) => (None, Some(method_id)), }; @@ -535,21 +533,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_for_meth_name(path.span); filter!(self.span_utils, sub_span, path.span, None); let def_id = if decl_id.is_local() { - let ti = self.tcx.impl_or_trait_item(decl_id); - match ti.container() { - ty::TraitContainer(def_id) => { - self.tcx - .trait_items(def_id) - .iter() - .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr)) - .map(|mr| mr.def_id()) - } - ty::ImplContainer(def_id) => { - Some(*self.tcx.impl_or_trait_items(def_id).iter().find(|&&mr| { - self.tcx.impl_or_trait_item(mr).name() == ti.name() - }).unwrap()) - } - } + let ti = self.tcx.associated_item(decl_id); + self.tcx.associated_items(ti.container.id()) + .find(|item| item.name == ti.name && item.has_value) + .map(|item| item.def_id) } else { None }; @@ -582,20 +569,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool { - let def_id = mr.def_id(); - if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { - let trait_item = self.tcx.map.expect_trait_item(node_id); - if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node { - true - } else { - false - } - } else { - false - } - } - pub fn get_field_ref_data(&self, field_ref: &ast::Field, variant: ty::VariantDef, diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 548554af9727f..2c0ba36f3b412 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -844,17 +844,12 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, param_substs); if let Some(trait_def_id) = scx.tcx().trait_of_item(fn_def_id) { - match scx.tcx().impl_or_trait_item(fn_def_id) { - ty::MethodTraitItem(ref method) => { - debug!(" => trait method, attempting to find impl"); - do_static_trait_method_dispatch(scx, - method, - trait_def_id, - fn_substs, - param_substs) - } - _ => bug!() - } + debug!(" => trait method, attempting to find impl"); + do_static_trait_method_dispatch(scx, + &scx.tcx().associated_item(fn_def_id), + trait_def_id, + fn_substs, + param_substs) } else { debug!(" => regular function"); // The function is not part of an impl or trait, no dispatching @@ -866,7 +861,7 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Given a trait-method and substitution information, find out the actual // implementation of the trait method. fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - trait_method: &ty::Method, + trait_method: &ty::AssociatedItem, trait_id: DefId, callee_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) @@ -1187,7 +1182,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' continue; } - if !method.generics.types.is_empty() { + if !tcx.lookup_generics(method.def_id).types.is_empty() { continue; } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 3d0d889760943..b8d346b11c13f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -248,13 +248,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); if let traits::VtableImpl(vtable_impl) = vtable { let name = ccx.tcx().item_name(instance.def); - let ac = ccx.tcx().impl_or_trait_items(vtable_impl.impl_def_id) - .iter().filter_map(|&def_id| { - match ccx.tcx().impl_or_trait_item(def_id) { - ty::ConstTraitItem(ac) => Some(ac), - _ => None - } - }).find(|ic| ic.name == name); + let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id) + .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); if let Some(ac) = ac { instance = Instance::new(ac.def_id, vtable_impl.substs); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 57936f8a4b3be..513b4860d5e87 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -107,11 +107,6 @@ pub trait AstConv<'gcx, 'tcx> { fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId) -> Result>, ErrorReported>; - /// Returns true if the trait with id `trait_def_id` defines an - /// associated type with the name `name`. - fn trait_defines_associated_type_named(&self, trait_def_id: DefId, name: ast::Name) - -> bool; - /// Return an (optional) substitution to convert bound type parameters that /// are in scope into free ones. This function should only return Some /// within a fn body. @@ -831,6 +826,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { Some(self_ty)) } + fn trait_defines_associated_type_named(&self, + trait_def_id: DefId, + assoc_name: ast::Name) + -> bool + { + self.tcx().associated_items(trait_def_id).any(|item| { + item.kind == ty::AssociatedKind::Type && item.name == assoc_name + }) + } + fn ast_type_binding_to_poly_projection_predicate( &self, path_id: ast::NodeId, @@ -1144,20 +1149,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let mut associated_types = FxHashSet::default(); for tr in traits::supertraits(tcx, principal) { - if let Some(trait_id) = tcx.map.as_local_node_id(tr.def_id()) { - use collect::trait_associated_type_names; - - associated_types.extend(trait_associated_type_names(tcx, trait_id) - .map(|name| (tr.def_id(), name))) - } else { - let trait_items = tcx.impl_or_trait_items(tr.def_id()); - associated_types.extend(trait_items.iter().filter_map(|&def_id| { - match tcx.impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => Some(item.name), - _ => None - } - }).map(|name| (tr.def_id(), name))); - } + associated_types.extend(tcx.associated_items(tr.def_id()) + .filter(|item| item.kind == ty::AssociatedKind::Type) + .map(|item| (tr.def_id(), item.name))); } for projection_bound in &projection_bounds { @@ -1260,14 +1254,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if bounds.len() > 1 { let spans = bounds.iter().map(|b| { - self.tcx().impl_or_trait_items(b.def_id()).iter() - .find(|&&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name.as_str() == assoc_name, - _ => false - } + self.tcx().associated_items(b.def_id()).find(|item| { + item.kind == ty::AssociatedKind::Type && item.name.as_str() == assoc_name }) - .and_then(|&def_id| self.tcx().map.as_local_node_id(def_id)) + .and_then(|item| self.tcx().map.as_local_node_id(item.def_id)) .and_then(|node_id| self.tcx().map.opt_span(node_id)) }); @@ -1383,25 +1373,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_did = bound.0.def_id; let ty = self.projected_ty_from_poly_trait_ref(span, bound, assoc_name); - let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) { - // `ty::trait_items` used below requires information generated - // by type collection, which may be in progress at this point. - match tcx.map.expect_item(trait_id).node { - hir::ItemTrait(.., ref trait_items) => { - let item = trait_items.iter() - .find(|i| i.name == assoc_name) - .expect("missing associated type"); - tcx.map.local_def_id(item.id) - } - _ => bug!() - } - } else { - let trait_items = tcx.trait_items(trait_did); - let item = trait_items.iter().find(|i| i.name() == assoc_name); - item.expect("missing associated type").def_id() - }; - - (ty, Def::AssociatedTy(item_did)) + let item = tcx.associated_items(trait_did).find(|i| i.name == assoc_name); + (ty, Def::AssociatedTy(item.expect("missing associated type").def_id)) } fn qpath_to_ty(&self, @@ -1694,13 +1667,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); let anon_scope = rscope.anon_type_scope(); - let (bare_fn_ty, _) = - self.ty_of_method_or_bare_fn(bf.unsafety, - bf.abi, - None, - &bf.decl, - anon_scope, - anon_scope); + let bare_fn_ty = self.ty_of_method_or_bare_fn(bf.unsafety, + bf.abi, + None, + &bf.decl, + anon_scope, + anon_scope); // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not wellformed. @@ -1842,7 +1814,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { sig: &hir::MethodSig, untransformed_self_ty: Ty<'tcx>, anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) { + -> &'tcx ty::BareFnTy<'tcx> { self.ty_of_method_or_bare_fn(sig.unsafety, sig.abi, Some(untransformed_self_ty), @@ -1857,7 +1829,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, anon_scope: Option) -> &'tcx ty::BareFnTy<'tcx> { - self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope).0 + self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope) } fn ty_of_method_or_bare_fn(&self, @@ -1867,7 +1839,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, arg_anon_scope: Option, ret_anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) + -> &'tcx ty::BareFnTy<'tcx> { debug!("ty_of_method_or_bare_fn"); @@ -1880,13 +1852,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // lifetime elision, we can determine it in two ways. First (determined // here), if self is by-reference, then the implied output region is the // region of the self parameter. - let (self_ty, explicit_self_category) = match (opt_untransformed_self_ty, decl.get_self()) { + let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) { (Some(untransformed_self_ty), Some(explicit_self)) => { let self_type = self.determine_self_type(&rb, untransformed_self_ty, &explicit_self); - (Some(self_type.0), self_type.1) + (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type))) } - _ => (None, ty::ExplicitSelfCategory::Static), + _ => (None, None), }; // HACK(eddyb) replace the fake self type in the AST with the actual type. @@ -1901,8 +1873,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Second, if there was exactly one lifetime (either a substitution or a // reference) in the arguments, then any anonymous regions in the output // have that lifetime. - let implied_output_region = match explicit_self_category { - ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region), + let implied_output_region = match explicit_self { + Some(ExplicitSelf::ByReference(region, _)) => Ok(*region), _ => { // `pat_to_string` is expensive and // `find_implied_output_region` only needs its result when @@ -1928,7 +1900,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys); debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); - (self.tcx().mk_bare_fn(ty::BareFnTy { + self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: ty::Binder(ty::FnSig { @@ -1936,95 +1908,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { output: output_ty, variadic: decl.variadic }), - }), explicit_self_category) + }) } fn determine_self_type<'a>(&self, rscope: &RegionScope, untransformed_self_ty: Ty<'tcx>, explicit_self: &hir::ExplicitSelf) - -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>) + -> Ty<'tcx> { - return match explicit_self.node { - SelfKind::Value(..) => { - (untransformed_self_ty, ty::ExplicitSelfCategory::ByValue) - } + match explicit_self.node { + SelfKind::Value(..) => untransformed_self_ty, SelfKind::Region(ref lifetime, mutability) => { let region = self.opt_ast_region_to_region( rscope, explicit_self.span, lifetime); - (self.tcx().mk_ref(region, + self.tcx().mk_ref(region, ty::TypeAndMut { ty: untransformed_self_ty, mutbl: mutability - }), - ty::ExplicitSelfCategory::ByReference(region, mutability)) - } - SelfKind::Explicit(ref ast_type, _) => { - let explicit_type = self.ast_ty_to_ty(rscope, &ast_type); - - // We wish to (for now) categorize an explicit self - // declaration like `self: SomeType` into either `self`, - // `&self`, `&mut self`, or `Box`. We do this here - // by some simple pattern matching. A more precise check - // is done later in `check_method_self_type()`. - // - // Examples: - // - // ``` - // impl Foo for &T { - // // Legal declarations: - // fn method1(self: &&T); // ExplicitSelfCategory::ByReference - // fn method2(self: &T); // ExplicitSelfCategory::ByValue - // fn method3(self: Box<&T>); // ExplicitSelfCategory::ByBox - // - // // Invalid cases will be caught later by `check_method_self_type`: - // fn method_err1(self: &mut T); // ExplicitSelfCategory::ByReference - // } - // ``` - // - // To do the check we just count the number of "modifiers" - // on each type and compare them. If they are the same or - // the impl has more, we call it "by value". Otherwise, we - // look at the outermost modifier on the method decl and - // call it by-ref, by-box as appropriate. For method1, for - // example, the impl type has one modifier, but the method - // type has two, so we end up with - // ExplicitSelfCategory::ByReference. - - let impl_modifiers = count_modifiers(untransformed_self_ty); - let method_modifiers = count_modifiers(explicit_type); - - debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \ - explicit_type={:?} \ - modifiers=({},{})", - untransformed_self_ty, - explicit_type, - impl_modifiers, - method_modifiers); - - let category = if impl_modifiers >= method_modifiers { - ty::ExplicitSelfCategory::ByValue - } else { - match explicit_type.sty { - ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl), - ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox, - _ => ty::ExplicitSelfCategory::ByValue, - } - }; - - (explicit_type, category) - } - }; - - fn count_modifiers(ty: Ty) -> usize { - match ty.sty { - ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, - ty::TyBox(t) => count_modifiers(t) + 1, - _ => 0, + }) } + SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type) } } @@ -2334,3 +2241,64 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { vec } } + +pub enum ExplicitSelf<'tcx> { + ByValue, + ByReference(&'tcx ty::Region, hir::Mutability), + ByBox +} + +impl<'tcx> ExplicitSelf<'tcx> { + /// We wish to (for now) categorize an explicit self + /// declaration like `self: SomeType` into either `self`, + /// `&self`, `&mut self`, or `Box`. We do this here + /// by some simple pattern matching. A more precise check + /// is done later in `check_method_self_type()`. + /// + /// Examples: + /// + /// ``` + /// impl Foo for &T { + /// // Legal declarations: + /// fn method1(self: &&T); // ExplicitSelf::ByReference + /// fn method2(self: &T); // ExplicitSelf::ByValue + /// fn method3(self: Box<&T>); // ExplicitSelf::ByBox + /// + /// // Invalid cases will be caught later by `check_method_self_type`: + /// fn method_err1(self: &mut T); // ExplicitSelf::ByReference + /// } + /// ``` + /// + /// To do the check we just count the number of "modifiers" + /// on each type and compare them. If they are the same or + /// the impl has more, we call it "by value". Otherwise, we + /// look at the outermost modifier on the method decl and + /// call it by-ref, by-box as appropriate. For method1, for + /// example, the impl type has one modifier, but the method + /// type has two, so we end up with + /// ExplicitSelf::ByReference. + pub fn determine(untransformed_self_ty: Ty<'tcx>, + self_arg_ty: Ty<'tcx>) + -> ExplicitSelf<'tcx> { + fn count_modifiers(ty: Ty) -> usize { + match ty.sty { + ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1, + ty::TyBox(t) => count_modifiers(t) + 1, + _ => 0, + } + } + + let impl_modifiers = count_modifiers(untransformed_self_ty); + let method_modifiers = count_modifiers(self_arg_ty); + + if impl_modifiers >= method_modifiers { + ExplicitSelf::ByValue + } else { + match self_arg_ty.sty { + ty::TyRef(r, mt) => ExplicitSelf::ByReference(r, mt.mutbl), + ty::TyBox(_) => ExplicitSelf::ByBox, + _ => ExplicitSelf::ByValue, + } + } + } +} diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2cb719675ac48..ffde940b3f48a 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::hir; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::middle::free_region::FreeRegionMap; use rustc::ty; @@ -23,6 +24,7 @@ use syntax_pos::Span; use CrateCtxt; use super::assoc; use super::{Inherited, FnCtxt}; +use astconv::ExplicitSelf; /// Checks that a method from an impl conforms to the signature of /// the same method as declared in the trait. @@ -36,11 +38,11 @@ use super::{Inherited, FnCtxt}; /// - impl_trait_ref: the TraitRef corresponding to the trait implementation pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, impl_m_body_id: ast::NodeId, - trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>, trait_item_span: Option, old_broken_mode: bool) { debug!("compare_impl_method(impl_trait_ref={:?})", @@ -49,7 +51,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, if let Err(ErrorReported) = compare_self_type(ccx, impl_m, impl_m_span, - trait_m) { + trait_m, + impl_trait_ref) { return; } @@ -81,16 +84,16 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, impl_m_body_id: ast::NodeId, - trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>, + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>, old_broken_mode: bool) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let trait_to_impl_substs = &impl_trait_ref.substs; + let trait_to_impl_substs = impl_trait_ref.substs; // This code is best explained by example. Consider a trait: // @@ -165,18 +168,23 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Create mapping from trait to skolemized. let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx, - impl_m.container_id(), + impl_m.container.id(), trait_to_impl_substs.subst(tcx, impl_to_skol_substs)); debug!("compare_impl_method: trait_to_skol_substs={:?}", trait_to_skol_substs); + let impl_m_generics = tcx.lookup_generics(impl_m.def_id); + let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let impl_m_predicates = tcx.lookup_predicates(impl_m.def_id); + let trait_m_predicates = tcx.lookup_predicates(trait_m.def_id); + // Check region bounds. check_region_bounds_on_impl_method(ccx, impl_m_span, impl_m, - &trait_m.generics, - &impl_m.generics, + &trait_m_generics, + &impl_m_generics, trait_to_skol_substs, impl_to_skol_substs)?; @@ -185,7 +193,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // environment. We can't just use `impl_env.caller_bounds`, // however, because we want to replace all late-bound regions with // region variables. - let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap()); + let impl_predicates = tcx.lookup_predicates(impl_m_predicates.parent.unwrap()); let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs); debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds); @@ -198,7 +206,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // We then register the obligations from the impl_m and check to see // if all constraints hold. hybrid_preds.predicates - .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); + .extend(trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates); // Construct trait parameter environment and then shift it into the skolemized viewpoint. // The key step here is to update the caller_bounds's predicates to be @@ -219,7 +227,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut selcx = traits::SelectionContext::new(&infcx); - let impl_m_own_bounds = impl_m.predicates.instantiate_own(tcx, impl_to_skol_substs); + let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs); let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infer::HigherRankedType, &ty::Binder(impl_m_own_bounds.predicates)); @@ -260,10 +268,19 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let tcx = infcx.tcx; let origin = TypeOrigin::MethodCompatCheck(impl_m_span); + let m_fty = |method: &ty::AssociatedItem| { + match tcx.lookup_item_type(method.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + } + }; + let impl_m_fty = m_fty(impl_m); + let trait_m_fty = m_fty(trait_m); + let (impl_sig, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, infer::HigherRankedType, - &impl_m.fty.sig); + &impl_m_fty.sig); let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = @@ -273,15 +290,15 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_body_id, &impl_sig); let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: impl_m.fty.unsafety, - abi: impl_m.fty.abi, + unsafety: impl_m_fty.unsafety, + abi: impl_m_fty.abi, sig: ty::Binder(impl_sig.clone()), })); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.liberate_late_bound_regions( infcx.parameter_environment.free_id_outlive, - &trait_m.fty.sig); + &trait_m_fty.sig); let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = @@ -291,8 +308,8 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_body_id, &trait_sig); let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy { - unsafety: trait_m.fty.unsafety, - abi: trait_m.fty.abi, + unsafety: trait_m_fty.unsafety, + abi: trait_m_fty.abi, sig: ty::Binder(trait_sig.clone()), })); @@ -367,7 +384,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, trait_generics: &ty::Generics<'tcx>, impl_generics: &ty::Generics<'tcx>, trait_to_skol_substs: &Substs<'tcx>, @@ -413,9 +430,9 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, terr: &TypeError, origin: TypeOrigin, - impl_m: &ty::Method, + impl_m: &ty::AssociatedItem, impl_sig: ty::FnSig<'tcx>, - trait_m: &ty::Method, + trait_m: &ty::AssociatedItem, trait_sig: ty::FnSig<'tcx>) -> (Span, Option) { let tcx = infcx.tcx; @@ -505,9 +522,10 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a } fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, - trait_m: &ty::Method<'tcx>) + trait_m: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>) -> Result<(), ErrorReported> { let tcx = ccx.tcx; @@ -518,58 +536,75 @@ fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // that the error messages you get out of this code are a bit more // inscrutable, particularly for cases where one method has no // self. - match (&trait_m.explicit_self, &impl_m.explicit_self) { - (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {} - (&ty::ExplicitSelfCategory::Static, _) => { + + let self_string = |method: &ty::AssociatedItem| { + let untransformed_self_ty = match method.container { + ty::ImplContainer(_) => impl_trait_ref.self_ty(), + ty::TraitContainer(_) => tcx.mk_self_type() + }; + let method_ty = tcx.lookup_item_type(method.def_id).ty; + let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder(); + match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) { + ExplicitSelf::ByValue => "self".to_string(), + ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(), + ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_string(), + _ => format!("self: {}", self_arg_ty) + } + }; + + match (trait_m.method_has_self_argument, impl_m.method_has_self_argument) { + (false, false) | (true, true) => {} + + (false, true) => { + let self_descr = self_string(impl_m); let mut err = struct_span_err!(tcx.sess, impl_m_span, E0185, "method `{}` has a `{}` declaration in the impl, but \ not in the trait", trait_m.name, - impl_m.explicit_self); - err.span_label(impl_m_span, - &format!("`{}` used in impl", impl_m.explicit_self)); + self_descr); + err.span_label(impl_m_span, &format!("`{}` used in impl", self_descr)); if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, - &format!("trait declared without `{}`", impl_m.explicit_self)); + err.span_label(span, &format!("trait declared without `{}`", self_descr)); } err.emit(); return Err(ErrorReported); } - (_, &ty::ExplicitSelfCategory::Static) => { + + (true, false) => { + let self_descr = self_string(trait_m); let mut err = struct_span_err!(tcx.sess, impl_m_span, E0186, "method `{}` has a `{}` declaration in the trait, but \ not in the impl", trait_m.name, - trait_m.explicit_self); + self_descr); err.span_label(impl_m_span, - &format!("expected `{}` in impl", trait_m.explicit_self)); + &format!("expected `{}` in impl", self_descr)); if let Some(span) = tcx.map.span_if_local(trait_m.def_id) { - err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self)); + err.span_label(span, &format!("`{}` used in trait", self_descr)); } err.emit(); return Err(ErrorReported); } - _ => { - // Let the type checker catch other errors below - } } Ok(()) } fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, - trait_m: &ty::Method<'tcx>, + trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - let num_impl_m_type_params = impl_m.generics.types.len(); - let num_trait_m_type_params = trait_m.generics.types.len(); + let impl_m_generics = tcx.lookup_generics(impl_m.def_id); + let trait_m_generics = tcx.lookup_generics(trait_m.def_id); + let num_impl_m_type_params = impl_m_generics.types.len(); + let num_trait_m_type_params = trait_m_generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); let span = match tcx.map.expect_impl_item(impl_m_node_id).node { @@ -630,15 +665,23 @@ fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_m: &ty::Method<'tcx>, + impl_m: &ty::AssociatedItem, impl_m_span: Span, - trait_m: &ty::Method<'tcx>, + trait_m: &ty::AssociatedItem, trait_item_span: Option) -> Result<(), ErrorReported> { let tcx = ccx.tcx; - if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() { - let trait_number_args = trait_m.fty.sig.0.inputs.len(); - let impl_number_args = impl_m.fty.sig.0.inputs.len(); + let m_fty = |method: &ty::AssociatedItem| { + match tcx.lookup_item_type(method.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + } + }; + let impl_m_fty = m_fty(impl_m); + let trait_m_fty = m_fty(trait_m); + if impl_m_fty.sig.0.inputs.len() != trait_m_fty.sig.0.inputs.len() { + let trait_number_args = trait_m_fty.sig.0.inputs.len(); + let impl_number_args = impl_m_fty.sig.0.inputs.len(); let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id); let trait_span = if let Some(trait_id) = trait_m_node_id { match tcx.map.expect_trait_item(trait_id).node { @@ -708,10 +751,10 @@ fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - impl_c: &ty::AssociatedConst<'tcx>, + impl_c: &ty::AssociatedItem, impl_c_span: Span, - trait_c: &ty::AssociatedConst<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + trait_c: &ty::AssociatedItem, + impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); let tcx = ccx.tcx; @@ -723,7 +766,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // because we shouldn't really have to deal with lifetimes or // predicates. In fact some of this should probably be put into // shared functions because of DRY violations... - let trait_to_impl_substs = &impl_trait_ref.substs; + let trait_to_impl_substs = impl_trait_ref.substs; // Create a parameter environment that represents the implementation's // method. @@ -742,8 +785,8 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, trait_to_skol_substs); // Compute skolemized form of impl and trait const tys. - let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs); - let trait_ty = trait_c.ty.subst(tcx, trait_to_skol_substs); + let impl_ty = tcx.lookup_item_type(impl_c.def_id).ty.subst(tcx, impl_to_skol_substs); + let trait_ty = tcx.lookup_item_type(trait_c.def_id).ty.subst(tcx, trait_to_skol_substs); let mut origin = TypeOrigin::Misc(impl_c_span); let err = infcx.commit_if_ok(|_| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index d28eb85ebb49d..a06b3e70881a5 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -553,9 +553,9 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // attributes attached to the impl's generics. let dtor_method = adt_def.destructor() .expect("dtorck type without destructor impossible"); - let method = tcx.impl_or_trait_item(dtor_method); - let impl_id: DefId = method.container().id(); - let revised_ty = revise_self_ty(tcx, adt_def, impl_id, substs); + let method = tcx.associated_item(dtor_method); + let impl_def_id = method.container.id(); + let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs); return DropckKind::RevisedSelf(revised_ty); } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f88bb355d1270..3894a7a2097eb 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -37,16 +37,6 @@ impl<'a, 'gcx, 'tcx> Deref for ConfirmContext<'a, 'gcx, 'tcx> { } } -struct InstantiatedMethodSig<'tcx> { - /// Function signature of the method being invoked. The 0th - /// argument is the receiver. - method_sig: ty::FnSig<'tcx>, - - /// Generic bounds on the method's parameters which must be added - /// as pending obligations. - method_predicates: ty::InstantiatedPredicates<'tcx>, -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn confirm_method(&self, span: Span, @@ -98,31 +88,18 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { debug!("all_substs={:?}", all_substs); // Create the final signature for the method, replacing late-bound regions. - let InstantiatedMethodSig { method_sig, method_predicates } = - self.instantiate_method_sig(&pick, all_substs); - let method_self_ty = method_sig.inputs[0]; + let (method_ty, method_predicates) = self.instantiate_method_sig(&pick, all_substs); // Unify the (adjusted) self type with what the method expects. - self.unify_receivers(self_ty, method_self_ty); - - // Create the method type - let def_id = pick.item.def_id(); - let method_ty = pick.item.as_opt_method().unwrap(); - let fty = self.tcx.mk_fn_def(def_id, - all_substs, - self.tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(method_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); + self.unify_receivers(self_ty, method_ty.fn_sig().input(0).skip_binder()); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(fty, all_substs, &method_predicates); + self.add_obligations(method_ty, all_substs, &method_predicates); // Create the final `MethodCallee`. let callee = ty::MethodCallee { - def_id: def_id, - ty: fty, + def_id: pick.item.def_id, + ty: method_ty, substs: all_substs, }; @@ -193,7 +170,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { -> &'tcx Substs<'tcx> { match pick.kind { probe::InherentImplPick => { - let impl_def_id = pick.item.container().id(); + let impl_def_id = pick.item.container.id(); assert!(self.tcx.impl_trait_ref(impl_def_id).is_none(), "impl {:?} is not an inherent impl", impl_def_id); @@ -201,7 +178,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } probe::ObjectPick => { - let trait_def_id = pick.item.container().id(); + let trait_def_id = pick.item.container.id(); self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| { // The object data has no entry for the Self // Type. For the purposes of this method call, we @@ -244,7 +221,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } probe::TraitPick => { - let trait_def_id = pick.item.container().id(); + let trait_def_id = pick.item.container.id(); // Make a trait reference `$0 : Trait<$1...$n>` // consisting entirely of type variables. Later on in @@ -299,8 +276,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let num_supplied_types = supplied_method_types.len(); - let method = pick.item.as_opt_method().unwrap(); - let num_method_types = method.generics.types.len(); + let method_generics = self.tcx.lookup_generics(pick.item.def_id); + let num_method_types = method_generics.types.len(); if num_supplied_types > 0 && num_supplied_types != num_method_types { if num_method_types == 0 { @@ -332,18 +309,15 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // parameters from the type and those from the method. // // FIXME -- permit users to manually specify lifetimes - let supplied_start = substs.params().len() + method.generics.regions.len(); - Substs::for_item(self.tcx, - method.def_id, - |def, _| { + let supplied_start = substs.params().len() + method_generics.regions.len(); + Substs::for_item(self.tcx, pick.item.def_id, |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } - }, - |def, cur_substs| { + }, |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -376,7 +350,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_sig(&mut self, pick: &probe::Pick<'tcx>, all_substs: &'tcx Substs<'tcx>) - -> InstantiatedMethodSig<'tcx> { + -> (Ty<'tcx>, ty::InstantiatedPredicates<'tcx>) { debug!("instantiate_method_sig(pick={:?}, all_substs={:?})", pick, all_substs); @@ -384,36 +358,40 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Instantiate the bounds on the method with the // type/early-bound-regions substitutions performed. There can // be no late-bound regions appearing here. - let method_predicates = pick.item - .as_opt_method() - .unwrap() - .predicates - .instantiate(self.tcx, all_substs); - let method_predicates = self.normalize_associated_types_in(self.span, &method_predicates); + let def_id = pick.item.def_id; + let method_predicates = self.tcx.lookup_predicates(def_id) + .instantiate(self.tcx, all_substs); + let method_predicates = self.normalize_associated_types_in(self.span, + &method_predicates); debug!("method_predicates after subst = {:?}", method_predicates); + let fty = match self.tcx.lookup_item_type(def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. // // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.item - .as_opt_method() - .unwrap() - .fty - .sig); + let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig); debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig); debug!("type scheme substituted, method_sig={:?}", method_sig); - InstantiatedMethodSig { - method_sig: method_sig, - method_predicates: method_predicates, - } + let method_ty = self.tcx.mk_fn_def(def_id, all_substs, + self.tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(method_sig), + unsafety: fty.unsafety, + abi: fty.abi, + })); + + (method_ty, method_predicates) } fn add_obligations(&mut self, @@ -587,7 +565,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) { // Disallow calls to the method `drop` defined in the `Drop` trait. - match pick.item.container() { + match pick.item.container { ty::TraitContainer(trait_def_id) => { callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id) } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 2df562f9ade46..579a54fb5318d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -228,14 +228,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let method_item = self.impl_or_trait_item(trait_def_id, m_name).unwrap(); - let method_ty = method_item.as_opt_method().unwrap(); - assert_eq!(method_ty.generics.types.len(), 0); - assert_eq!(method_ty.generics.regions.len(), 0); + let method_item = self.associated_item(trait_def_id, m_name).unwrap(); + let def_id = method_item.def_id; + let generics = tcx.lookup_generics(def_id); + assert_eq!(generics.types.len(), 0); + assert_eq!(generics.regions.len(), 0); - debug!("lookup_in_trait_adjusted: method_item={:?} method_ty={:?}", - method_item, - method_ty); + debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -243,22 +242,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // NB: Instantiate late-bound regions first so that // `instantiate_type_scheme` can normalize associated types that // may reference those regions. - let fn_sig = - self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &method_ty.fty.sig) - .0; + let original_method_ty = tcx.lookup_item_type(def_id).ty; + let fty = match original_method_ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, + infer::FnCall, + &fty.sig).0; let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; - let def_id = method_item.def_id(); - let fty = tcx.mk_fn_def(def_id, - trait_ref.substs, - tcx.mk_bare_fn(ty::BareFnTy { - sig: ty::Binder(fn_sig), - unsafety: method_ty.fty.unsafety, - abi: method_ty.fty.abi.clone(), - })); - - debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", - fty, + let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, + tcx.mk_bare_fn(ty::BareFnTy { + sig: ty::Binder(fn_sig), + unsafety: fty.unsafety, + abi: fty.abi + })); + + debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", + method_ty, obligation); // Register obligations for the parameters. This will include the @@ -269,13 +271,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates); + let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs); assert!(!method_bounds.has_escaping_regions()); self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), &method_bounds); // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(fty, span, traits::MiscObligation); + self.register_wf_obligation(method_ty, span, traits::MiscObligation); // FIXME(#18653) -- Try to resolve obligations, giving us more // typing information, which can sometimes be needed to avoid @@ -283,61 +285,39 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); // Insert any adjustments needed (always an autoref of some mutability). - match self_expr { - None => {} - - Some(self_expr) => { - debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ - (self-id={}, autoderefs={}, unsize={}, explicit_self={:?})", - self_expr.id, - autoderefs, - unsize, - method_ty.explicit_self); - - let autoref = match method_ty.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - // Trait method is fn(self), no transformation needed. - assert!(!unsize); - None - } - - ty::ExplicitSelfCategory::ByReference(..) => { - // Trait method is fn(&self) or fn(&mut self), need an - // autoref. Pull the region etc out of the type of first argument. - match transformed_self_ty.sty { - ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ }) => { - Some(AutoBorrow::Ref(region, mutbl)) - } - - _ => { - span_bug!(span, - "trait method is &self but first arg is: {}", - transformed_self_ty); - } - } - } - - _ => { - span_bug!(span, - "unexpected explicit self type in operator method: {:?}", - method_ty.explicit_self); - } - }; - - self.write_adjustment(self_expr.id, Adjustment { - kind: Adjust::DerefRef { - autoderefs: autoderefs, - autoref: autoref, - unsize: unsize - }, - target: transformed_self_ty - }); - } + if let Some(self_expr) = self_expr { + debug!("lookup_in_trait_adjusted: inserting adjustment if needed \ + (self-id={}, autoderefs={}, unsize={}, fty={:?})", + self_expr.id, autoderefs, unsize, original_method_ty); + + let original_sig = original_method_ty.fn_sig(); + let autoref = match (&original_sig.input(0).skip_binder().sty, + &transformed_self_ty.sty) { + (&ty::TyRef(..), &ty::TyRef(region, ty::TypeAndMut { mutbl, ty: _ })) => { + // Trait method is fn(&self) or fn(&mut self), need an + // autoref. Pull the region etc out of the type of first argument. + Some(AutoBorrow::Ref(region, mutbl)) + } + _ => { + // Trait method is fn(self), no transformation needed. + assert!(!unsize); + None + } + }; + + self.write_adjustment(self_expr.id, Adjustment { + kind: Adjust::DerefRef { + autoderefs: autoderefs, + autoref: autoref, + unsize: unsize + }, + target: transformed_self_ty + }); } let callee = ty::MethodCallee { def_id: def_id, - ty: fty, + ty: method_ty, substs: trait_ref.substs, }; @@ -361,7 +341,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let def = pick.item.def(); if let probe::InherentImplPick = pick.kind { - if !pick.item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + if !pick.item.vis.is_accessible_from(self.body_id, &self.tcx.map) { let msg = format!("{} `{}` is private", def.kind_name(), &method_name.as_str()); self.tcx.sess.span_err(span, &msg); } @@ -371,14 +351,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - pub fn impl_or_trait_item(&self, - def_id: DefId, - item_name: ast::Name) - -> Option> { - self.tcx - .impl_or_trait_items(def_id) - .iter() - .map(|&did| self.tcx.impl_or_trait_item(did)) - .find(|m| m.name() == item_name) + pub fn associated_item(&self, def_id: DefId, item_name: ast::Name) + -> Option { + self.tcx.associated_items(def_id).find(|item| item.name == item_name) } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 54b1b6c6807db..7068b2dea7263 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -72,7 +72,7 @@ struct CandidateStep<'tcx> { #[derive(Debug)] struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, - item: ty::ImplOrTraitItem<'tcx>, + item: ty::AssociatedItem, kind: CandidateKind<'tcx>, import_id: Option, } @@ -95,7 +95,7 @@ enum CandidateKind<'tcx> { #[derive(Debug)] pub struct Pick<'tcx> { - pub item: ty::ImplOrTraitItem<'tcx>, + pub item: ty::AssociatedItem, pub kind: PickKind<'tcx>, pub import_id: Option, @@ -384,8 +384,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_inherent_impl_for_primitive(&mut self, lang_def_id: Option) { if let Some(impl_def_id) = lang_def_id { - self.tcx.populate_implementations_for_primitive_if_necessary(impl_def_id); - self.assemble_inherent_impl_probe(impl_def_id); } } @@ -409,7 +407,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - let item = match self.impl_or_trait_item(impl_def_id) { + let item = match self.associated_item(impl_def_id) { Some(m) => m, None => { return; @@ -421,7 +419,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return self.record_static_candidate(ImplSource(impl_def_id)); } - if !item.vis().is_accessible_from(self.body_id, &self.tcx.map) { + if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) { self.private_candidate = Some(item.def()); return; } @@ -512,17 +510,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let xform_self_ty = this.xform_self_ty(&item, trait_ref.self_ty(), trait_ref.substs); - if let Some(ref m) = item.as_opt_method() { - debug!("found match: trait_ref={:?} substs={:?} m={:?}", - trait_ref, - trait_ref.substs, - m); - assert_eq!(m.generics.parent_types as usize, - trait_ref.substs.types().count()); - assert_eq!(m.generics.parent_regions as usize, - trait_ref.substs.regions().count()); - } - // Because this trait derives from a where-clause, it // should not contain any inference variables or other // artifacts. This means it is safe to put into the @@ -544,13 +531,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn elaborate_bounds(&mut self, bounds: &[ty::PolyTraitRef<'tcx>], mut mk_cand: F) where F: for<'b> FnMut(&mut ProbeContext<'b, 'gcx, 'tcx>, ty::PolyTraitRef<'tcx>, - ty::ImplOrTraitItem<'tcx>) + ty::AssociatedItem) { debug!("elaborate_bounds(bounds={:?})", bounds); let tcx = self.tcx; for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { + let item = match self.associated_item(bound_trait_ref.def_id()) { Some(v) => v, None => { continue; @@ -601,9 +588,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { trait_def_id); // Check whether `trait_def_id` defines a method with suitable name: - let trait_items = self.tcx.trait_items(trait_def_id); - let maybe_item = trait_items.iter() - .find(|item| item.name() == self.item_name); + let maybe_item = self.tcx.associated_items(trait_def_id) + .find(|item| item.name == self.item_name); let item = match maybe_item { Some(i) => i, None => { @@ -612,7 +598,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { }; // Check whether `trait_def_id` defines a method with suitable name: - if !self.has_applicable_self(item) { + if !self.has_applicable_self(&item) { debug!("method has inapplicable self"); self.record_static_candidate(TraitSource(trait_def_id)); return Ok(()); @@ -631,7 +617,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_extension_candidates_for_trait_impls(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { let trait_def = self.tcx.lookup_trait_def(trait_def_id); // FIXME(arielb1): can we use for_each_relevant_impl here? @@ -700,7 +686,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_closure_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) + item: ty::AssociatedItem) -> Result<(), MethodError<'tcx>> { // Check if this is one of the Fn,FnMut,FnOnce traits. let tcx = self.tcx; @@ -765,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_projection_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { debug!("assemble_projection_candidates(\ trait_def_id={:?}, \ item={:?})", @@ -820,7 +806,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { fn assemble_where_clause_candidates(&mut self, trait_def_id: DefId, - item: ty::ImplOrTraitItem<'tcx>) { + item: ty::AssociatedItem) { debug!("assemble_where_clause_candidates(trait_def_id={:?})", trait_def_id); @@ -865,7 +851,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_extension_candidates_for_all_traits()?; let out_of_scope_traits = match self.pick_core() { - Some(Ok(p)) => vec![p.item.container().id()], + Some(Ok(p)) => vec![p.item.container.id()], Some(Err(MethodError::Ambiguity(v))) => { v.into_iter() .map(|source| { @@ -1065,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // don't have enough information to fully evaluate). let (impl_def_id, substs, ref_obligations) = match probe.kind { InherentImplCandidate(ref substs, ref ref_obligations) => { - (probe.item.container().id(), substs, ref_obligations) + (probe.item.container.id(), substs, ref_obligations) } ExtensionImplCandidate(impl_def_id, ref substs, ref ref_obligations) => { @@ -1128,12 +1114,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// use, so it's ok to just commit to "using the method from the trait Foo". fn collapse_candidates_to_trait_pick(&self, probes: &[&Candidate<'tcx>]) -> Option> { // Do all probes correspond to the same trait? - let container = probes[0].item.container(); + let container = probes[0].item.container; match container { ty::TraitContainer(_) => {} ty::ImplContainer(_) => return None, } - if probes[1..].iter().any(|p| p.item.container() != container) { + if probes[1..].iter().any(|p| p.item.container != container) { return None; } @@ -1150,19 +1136,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool { + fn has_applicable_self(&self, item: &ty::AssociatedItem) -> bool { // "fast track" -- check for usage of sugar - match *item { - ty::ImplOrTraitItem::MethodTraitItem(ref method) => { - match method.explicit_self { - ty::ExplicitSelfCategory::Static => self.mode == Mode::Path, - ty::ExplicitSelfCategory::ByValue | - ty::ExplicitSelfCategory::ByReference(..) | - ty::ExplicitSelfCategory::ByBox => true, - } - } - ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path, - _ => false, + match self.mode { + Mode::MethodCall => item.method_has_self_argument, + Mode::Path => true } // FIXME -- check for types that deref to `Self`, // like `Rc` and so on. @@ -1177,24 +1155,26 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn xform_self_ty(&self, - item: &ty::ImplOrTraitItem<'tcx>, + item: &ty::AssociatedItem, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { - match item.as_opt_method() { - Some(ref method) => self.xform_method_self_ty(method, impl_ty, substs), - None => impl_ty, + if item.kind == ty::AssociatedKind::Method && self.mode == Mode::MethodCall { + self.xform_method_self_ty(item.def_id, impl_ty, substs) + } else { + impl_ty } } fn xform_method_self_ty(&self, - method: &Rc>, + method: DefId, impl_ty: Ty<'tcx>, substs: &Substs<'tcx>) -> Ty<'tcx> { + let self_ty = self.tcx.lookup_item_type(method).ty.fn_sig().input(0); debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})", impl_ty, - method.fty.sig.0.inputs.get(0), + self_ty, substs); assert!(!substs.has_escaping_regions()); @@ -1204,26 +1184,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. - assert_eq!(substs.types().count(), - method.generics.parent_types as usize); - assert_eq!(substs.regions().count(), - method.generics.parent_regions as usize); - - if self.mode == Mode::Path { - return impl_ty; - } + let generics = self.tcx.lookup_generics(method); + assert_eq!(substs.types().count(), generics.parent_types as usize); + assert_eq!(substs.regions().count(), generics.parent_regions as usize); // Erase any late-bound regions from the method and substitute // in the values from the substitution. - let xform_self_ty = method.fty.sig.input(0); - let xform_self_ty = self.erase_late_bound_regions(&xform_self_ty); + let xform_self_ty = self.erase_late_bound_regions(&self_ty); - if method.generics.types.is_empty() && method.generics.regions.is_empty() { + if generics.types.is_empty() && generics.regions.is_empty() { xform_self_ty.subst(self.tcx, substs) } else { - let substs = Substs::for_item(self.tcx, - method.def_id, - |def, _| { + let substs = Substs::for_item(self.tcx, method, |def, _| { let i = def.index as usize; if i < substs.params().len() { substs.region_at(i) @@ -1232,8 +1204,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `impl_self_ty()` for an explanation. self.tcx.mk_region(ty::ReErased) } - }, - |def, cur_substs| { + }, |def, cur_substs| { let i = def.index as usize; if i < substs.params().len() { substs.type_at(i) @@ -1283,8 +1254,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { /// Find item with name `item_name` defined in impl/trait `def_id` /// and return it, or `None`, if no such item was defined there. - fn impl_or_trait_item(&self, def_id: DefId) -> Option> { - self.fcx.impl_or_trait_item(def_id, self.item_name) + fn associated_item(&self, def_id: DefId) -> Option { + self.fcx.associated_item(def_id, self.item_name) } } @@ -1317,11 +1288,11 @@ impl<'tcx> Candidate<'tcx> { fn to_source(&self) -> CandidateSource { match self.kind { - InherentImplCandidate(..) => ImplSource(self.item.container().id()), + InherentImplCandidate(..) => ImplSource(self.item.container.id()), ExtensionImplCandidate(def_id, ..) => ImplSource(def_id), ObjectCandidate | TraitCandidate | - WhereClauseCandidate(_) => TraitSource(self.item.container().id()), + WhereClauseCandidate(_) => TraitSource(self.item.container.id()), } } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 98d3957db7059..0cb8cf2a58886 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -89,20 +89,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.impl_or_trait_item(impl_did, item_name) + let item = self.associated_item(impl_did, item_name) .or_else(|| { - self.impl_or_trait_item(self.tcx - .impl_trait_ref(impl_did) - .unwrap() - .def_id, - - item_name) - }) - .unwrap(); - let note_span = self.tcx - .map - .span_if_local(item.def_id()) - .or_else(|| self.tcx.map.span_if_local(impl_did)); + self.associated_item( + self.tcx.impl_trait_ref(impl_did).unwrap().def_id, + + item_name + ) + }).unwrap(); + let note_span = self.tcx.map.span_if_local(item.def_id).or_else(|| { + self.tcx.map.span_if_local(impl_did) + }); let impl_ty = self.impl_self_ty(span, impl_did).ty; @@ -127,8 +124,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self.impl_or_trait_item(trait_did, item_name).unwrap(); - let item_span = self.tcx.map.def_id_span(item.def_id(), span); + let item = self.associated_item(trait_did, item_name).unwrap(); + let item_span = self.tcx.map.def_id_span(item.def_id, span); span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", @@ -334,8 +331,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - (type_is_local || info.def_id.is_local()) && - self.impl_or_trait_item(info.def_id, item_name).is_some() + (type_is_local || info.def_id.is_local()) + && self.associated_item(info.def_id, item_name).is_some() }) .collect::>(); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f7e05f4777ecc..0265e397ef6c4 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -760,7 +760,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { check_impl_items_against_trait(ccx, it.span, impl_def_id, - &impl_trait_ref, + impl_trait_ref, impl_items); let trait_def_id = impl_trait_ref.def_id; check_on_unimplemented(ccx, trait_def_id, it); @@ -942,21 +942,13 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let ancestors = trait_def.ancestors(impl_id); - let parent = match impl_item.node { - hir::ImplItemKind::Const(..) => { - ancestors.const_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - } - hir::ImplItemKind::Method(..) => { - ancestors.fn_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - - } - hir::ImplItemKind::Type(_) => { - ancestors.type_defs(tcx, impl_item.name).skip(1).next() - .map(|node_item| node_item.map(|parent| parent.defaultness)) - } + let kind = match impl_item.node { + hir::ImplItemKind::Const(..) => ty::AssociatedKind::Const, + hir::ImplItemKind::Method(..) => ty::AssociatedKind::Method, + hir::ImplItemKind::Type(_) => ty::AssociatedKind::Type }; + let parent = ancestors.defs(tcx, impl_item.name, kind).skip(1).next() + .map(|node_item| node_item.map(|parent| parent.defaultness)); if let Some(parent) = parent { if parent.item.is_final() { @@ -969,7 +961,7 @@ fn check_specialization_validity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_span: Span, impl_id: DefId, - impl_trait_ref: &ty::TraitRef<'tcx>, + impl_trait_ref: ty::TraitRef<'tcx>, impl_items: &[hir::ImplItem]) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` @@ -979,72 +971,61 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Locate trait definition and items let tcx = ccx.tcx; let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id); - let trait_items = tcx.trait_items(impl_trait_ref.def_id); let mut overridden_associated_type = None; // Check existing impl methods to see if they are both present in trait // and compatible with trait signature for impl_item in impl_items { - let ty_impl_item = tcx.impl_or_trait_item(tcx.map.local_def_id(impl_item.id)); - let ty_trait_item = trait_items.iter() - .find(|ac| ac.name() == ty_impl_item.name()); + let ty_impl_item = tcx.associated_item(tcx.map.local_def_id(impl_item.id)); + let ty_trait_item = tcx.associated_items(impl_trait_ref.def_id) + .find(|ac| ac.name == ty_impl_item.name); // Check that impl definition matches trait definition if let Some(ty_trait_item) = ty_trait_item { match impl_item.node { hir::ImplItemKind::Const(..) => { - let impl_const = match ty_impl_item { - ty::ConstTraitItem(ref cti) => cti, - _ => span_bug!(impl_item.span, "non-const impl-item for const") - }; - // Find associated const definition. - if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item { + if ty_trait_item.kind == ty::AssociatedKind::Const { compare_const_impl(ccx, - &impl_const, + &ty_impl_item, impl_item.span, - trait_const, - &impl_trait_ref); + &ty_trait_item, + impl_trait_ref); } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0323, "item `{}` is an associated const, \ which doesn't match its trait `{:?}`", - impl_const.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); // We can only get the spans from local trait definition // Same for E0324 and E0325 - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() } } hir::ImplItemKind::Method(_, ref body) => { - let impl_method = match ty_impl_item { - ty::MethodTraitItem(ref mti) => mti, - _ => span_bug!(impl_item.span, "non-method impl-item for method") - }; - - let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); - if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { + let trait_span = tcx.map.span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssociatedKind::Method { let err_count = tcx.sess.err_count(); compare_impl_method(ccx, - &impl_method, + &ty_impl_item, impl_item.span, body.id, - &trait_method, - &impl_trait_ref, + &ty_trait_item, + impl_trait_ref, trait_span, true); // start with old-broken-mode if err_count == tcx.sess.err_count() { // old broken mode did not report an error. Try with the new mode. compare_impl_method(ccx, - &impl_method, + &ty_impl_item, impl_item.span, body.id, - &trait_method, - &impl_trait_ref, + &ty_trait_item, + impl_trait_ref, trait_span, false); // use the new mode } @@ -1052,33 +1033,28 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ which doesn't match its trait `{:?}`", - impl_method.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() } } hir::ImplItemKind::Type(_) => { - let impl_type = match ty_impl_item { - ty::TypeTraitItem(ref tti) => tti, - _ => span_bug!(impl_item.span, "non-type impl-item for type") - }; - - if let &ty::TypeTraitItem(ref at) = ty_trait_item { - if let Some(_) = at.ty { + if ty_trait_item.kind == ty::AssociatedKind::Type { + if ty_trait_item.has_value { overridden_associated_type = Some(impl_item); } } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0325, "item `{}` is an associated type, \ which doesn't match its trait `{:?}`", - impl_type.name, + ty_impl_item.name, impl_trait_ref); err.span_label(impl_item.span, &format!("does not match trait")); - if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id()) { + if let Some(trait_span) = tcx.map.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, &format!("item in trait")); } err.emit() @@ -1091,70 +1067,55 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } // Check for missing items from trait - let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id); let mut missing_items = Vec::new(); let mut invalidated_items = Vec::new(); let associated_type_overridden = overridden_associated_type.is_some(); - for trait_item in trait_items.iter() { - let is_implemented; - let is_provided; - - match *trait_item { - ty::ConstTraitItem(ref associated_const) => { - is_provided = associated_const.has_value; - is_implemented = impl_items.iter().any(|ii| { - match ii.node { - hir::ImplItemKind::Const(..) => { - ii.name == associated_const.name - } - _ => false, - } - }); - } - ty::MethodTraitItem(ref trait_method) => { - is_provided = provided_methods.iter().any(|m| m.name == trait_method.name); - is_implemented = trait_def.ancestors(impl_id) - .fn_defs(tcx, trait_method.name) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - } - ty::TypeTraitItem(ref trait_assoc_ty) => { - is_provided = trait_assoc_ty.ty.is_some(); - is_implemented = trait_def.ancestors(impl_id) - .type_defs(tcx, trait_assoc_ty.name) - .next() - .map(|node_item| !node_item.node.is_from_trait()) - .unwrap_or(false); - } - } + for trait_item in tcx.associated_items(impl_trait_ref.def_id) { + let is_implemented = trait_def.ancestors(impl_id) + .defs(tcx, trait_item.name, trait_item.kind) + .next() + .map(|node_item| !node_item.node.is_from_trait()) + .unwrap_or(false); if !is_implemented { - if !is_provided { + if !trait_item.has_value { missing_items.push(trait_item); } else if associated_type_overridden { - invalidated_items.push(trait_item.name()); + invalidated_items.push(trait_item.name); } } } + let signature = |item: &ty::AssociatedItem| { + match item.kind { + ty::AssociatedKind::Method => { + format!("{}", tcx.lookup_item_type(item.def_id).ty.fn_sig().0) + } + ty::AssociatedKind::Type => format!("type {};", item.name.to_string()), + ty::AssociatedKind::Const => { + format!("const {}: {:?};", item.name.to_string(), + tcx.lookup_item_type(item.def_id).ty) + } + } + }; + if !missing_items.is_empty() { let mut err = struct_span_err!(tcx.sess, impl_span, E0046, "not all trait items implemented, missing: `{}`", missing_items.iter() - .map(|trait_item| trait_item.name().to_string()) + .map(|trait_item| trait_item.name.to_string()) .collect::>().join("`, `")); err.span_label(impl_span, &format!("missing `{}` in implementation", missing_items.iter() - .map(|trait_item| trait_item.name().to_string()) + .map(|trait_item| trait_item.name.to_string()) .collect::>().join("`, `"))); for trait_item in missing_items { - if let Some(span) = tcx.map.span_if_local(trait_item.def_id()) { - err.span_label(span, &format!("`{}` from trait", trait_item.name())); + if let Some(span) = tcx.map.span_if_local(trait_item.def_id) { + err.span_label(span, &format!("`{}` from trait", trait_item.name)); } else { err.note(&format!("`{}` from trait: `{}`", - trait_item.name(), - signature(trait_item))); + trait_item.name, + signature(&trait_item))); } } err.emit(); @@ -1172,14 +1133,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } } -fn signature<'a, 'tcx>(item: &ty::ImplOrTraitItem) -> String { - match *item { - ty::MethodTraitItem(ref item) => format!("{}", item.fty.sig.0), - ty::TypeTraitItem(ref item) => format!("type {};", item.name.to_string()), - ty::ConstTraitItem(ref item) => format!("const {}: {:?};", item.name.to_string(), item.ty), - } -} - /// Checks a constant with a given type. fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, @@ -1385,19 +1338,6 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Ok(r) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Name) - -> bool - { - self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name == assoc_name, - _ => false - } - }) - } - fn ty_infer(&self, _span: Span) -> Ty<'tcx> { self.next_ty_var() } @@ -1643,12 +1583,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// As `instantiate_type_scheme`, but for the bounds found in a /// generic type scheme. - fn instantiate_bounds(&self, - span: Span, - substs: &Substs<'tcx>, - bounds: &ty::GenericPredicates<'tcx>) - -> ty::InstantiatedPredicates<'tcx> - { + fn instantiate_bounds(&self, span: Span, def_id: DefId, substs: &Substs<'tcx>) + -> ty::InstantiatedPredicates<'tcx> { + let bounds = self.tcx.lookup_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); let result = self.normalize_associated_types_in(span, &result.predicates); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", @@ -3279,8 +3216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((variant, did, substs)) = variant { // Check bounds on type arguments used in the path. - let type_predicates = self.tcx.lookup_predicates(did); - let bounds = self.instantiate_bounds(path.span, substs, &type_predicates); + let bounds = self.instantiate_bounds(path.span, did, substs); let cause = traits::ObligationCause::new(path.span, self.body_id, traits::ItemObligation(did)); self.add_obligations_for_parameters(cause, &bounds); @@ -4149,7 +4085,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Case 3. Reference to a method or associated const. Def::Method(def_id) | Def::AssociatedConst(def_id) => { - let container = self.tcx.impl_or_trait_item(def_id).container(); + let container = self.tcx.associated_item(def_id).container; match container { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(self.ccx, span, trait_did) @@ -4290,13 +4226,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // The things we are substituting into the type should not contain // escaping late-bound regions, and nor should the base type scheme. let scheme = self.tcx.lookup_item_type(def.def_id()); - let type_predicates = self.tcx.lookup_predicates(def.def_id()); assert!(!substs.has_escaping_regions()); assert!(!scheme.ty.has_escaping_regions()); // Add all the obligations that are required, substituting and // normalized appropriately. - let bounds = self.instantiate_bounds(span, &substs, &type_predicates); + let bounds = self.instantiate_bounds(span, def.def_id(), &substs); self.add_obligations_for_parameters( traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def.def_id())), &bounds); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 741f327ac99e1..07415bab2f100 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use astconv::ExplicitSelf; use check::FnCtxt; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; + use hir::def_id::DefId; use middle::region::{CodeExtent}; use rustc::infer::TypeOrigin; @@ -156,8 +158,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } - hir::ItemTrait(.., ref items) => { - self.check_trait(item, items); + hir::ItemTrait(..) => { + self.check_trait(item); } _ => {} } @@ -172,32 +174,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let free_substs = &fcx.parameter_environment.free_substs; let free_id_outlive = fcx.parameter_environment.free_id_outlive; - let item = fcx.tcx.impl_or_trait_item(fcx.tcx.map.local_def_id(item_id)); + let item = fcx.tcx.associated_item(fcx.tcx.map.local_def_id(item_id)); - let (mut implied_bounds, self_ty) = match item.container() { + let (mut implied_bounds, self_ty) = match item.container { ty::TraitContainer(_) => (vec![], fcx.tcx.mk_self_type()), ty::ImplContainer(def_id) => (fcx.impl_implied_bounds(def_id, span), fcx.tcx.lookup_item_type(def_id).ty) }; - match item { - ty::ConstTraitItem(assoc_const) => { - let ty = fcx.instantiate_type_scheme(span, free_substs, &assoc_const.ty); + match item.kind { + ty::AssociatedKind::Const => { + let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } - ty::MethodTraitItem(method) => { - reject_shadowing_type_parameters(fcx.tcx, span, &method.generics); - let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); - this.check_fn_or_method(fcx, span, &method_ty, &predicates, + ty::AssociatedKind::Method => { + reject_shadowing_type_parameters(fcx.tcx, span, item.def_id); + let method_ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); + let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs); + let fty = match method_ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => bug!() + }; + this.check_fn_or_method(fcx, span, fty, &predicates, free_id_outlive, &mut implied_bounds); let sig_if_method = sig_if_method.expect("bad signature for method"); - this.check_method_receiver(fcx, sig_if_method, &method, + this.check_method_receiver(fcx, sig_if_method, &item, free_id_outlive, self_ty); } - ty::TypeTraitItem(assoc_type) => { - if let Some(ref ty) = assoc_type.ty { - let ty = fcx.instantiate_type_scheme(span, free_substs, ty); + ty::AssociatedKind::Type => { + if item.has_value { + let ty = fcx.tcx.lookup_item_type(item.def_id).ty; + let ty = fcx.instantiate_type_scheme(span, free_substs, &ty); fcx.register_wf_obligation(ty, span, code.clone()); } } @@ -248,19 +257,15 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } let free_substs = &fcx.parameter_environment.free_substs; - let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id)); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let def_id = fcx.tcx.map.local_def_id(item.id); + let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); vec![] // no implied bounds in a struct def'n }); } - fn check_auto_trait(&mut self, - trait_def_id: DefId, - items: &[hir::TraitItem], - span: Span) - { + fn check_auto_trait(&mut self, trait_def_id: DefId, span: Span) { // We want to ensure: // // 1) that there are no items contained within @@ -302,7 +307,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // extraneous predicates created by things like // an associated type inside the trait. let mut err = None; - if !items.is_empty() { + if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() { error_380(self.ccx, span); } else if has_ty_params { err = Some(struct_span_err!(self.tcx().sess, span, E0567, @@ -326,20 +331,16 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - fn check_trait(&mut self, - item: &hir::Item, - items: &[hir::TraitItem]) - { + fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx().map.local_def_id(item.id); if self.tcx().trait_has_default_impl(trait_def_id) { - self.check_auto_trait(trait_def_id, items, item.span); + self.check_auto_trait(trait_def_id, item.span); } self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; - let predicates = fcx.tcx.lookup_predicates(trait_def_id); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, trait_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); vec![] }); @@ -351,7 +352,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; - let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id)); + let def_id = fcx.tcx.map.local_def_id(item.id); + let type_scheme = fcx.tcx.lookup_item_type(def_id); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); let bare_fn_ty = match item_ty.sty { ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty, @@ -360,8 +362,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } }; - let predicates = fcx.tcx.lookup_predicates(fcx.tcx.map.local_def_id(item.id)); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs); let mut implied_bounds = vec![]; let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body.id); @@ -422,8 +423,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } - let predicates = fcx.tcx.lookup_predicates(item_def_id); - let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + let predicates = fcx.instantiate_bounds(item.span, item_def_id, free_substs); this.check_where_clauses(fcx, item.span, &predicates); fcx.impl_implied_bounds(fcx.tcx.map.local_def_id(item.id), item.span) @@ -476,35 +476,39 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_method_receiver<'fcx, 'tcx>(&mut self, fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, method_sig: &hir::MethodSig, - method: &ty::Method<'tcx>, + method: &ty::AssociatedItem, free_id_outlive: CodeExtent, self_ty: ty::Ty<'tcx>) { // check that the type of the method's receiver matches the // method's first parameter. - debug!("check_method_receiver({:?},cat={:?},self_ty={:?})", - method.name, method.explicit_self, self_ty); + debug!("check_method_receiver({:?}, self_ty={:?})", + method, self_ty); - let rcvr_ty = match method.explicit_self { - ty::ExplicitSelfCategory::Static => return, - ty::ExplicitSelfCategory::ByValue => self_ty, - ty::ExplicitSelfCategory::ByReference(region, mutability) => { - fcx.tcx.mk_ref(region, ty::TypeAndMut { - ty: self_ty, - mutbl: mutability - }) - } - ty::ExplicitSelfCategory::ByBox => fcx.tcx.mk_box(self_ty) - }; + if !method.method_has_self_argument { + return; + } let span = method_sig.decl.inputs[0].pat.span; let free_substs = &fcx.parameter_environment.free_substs; - let fty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); - let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig); + let method_ty = fcx.tcx.lookup_item_type(method.def_id).ty; + let fty = fcx.instantiate_type_scheme(span, free_substs, &method_ty); + let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.fn_sig()); debug!("check_method_receiver: sig={:?}", sig); + let self_arg_ty = sig.inputs[0]; + let rcvr_ty = match ExplicitSelf::determine(self_ty, self_arg_ty) { + ExplicitSelf::ByValue => self_ty, + ExplicitSelf::ByReference(region, mutbl) => { + fcx.tcx.mk_ref(region, ty::TypeAndMut { + ty: self_ty, + mutbl: mutbl + }) + } + ExplicitSelf::ByBox => fcx.tcx.mk_box(self_ty) + }; let rcvr_ty = fcx.instantiate_type_scheme(span, free_substs, &rcvr_ty); let rcvr_ty = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(rcvr_ty)); @@ -512,7 +516,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty); let origin = TypeOrigin::MethodReceiver(span); - fcx.demand_eqtype_with_origin(origin, rcvr_ty, sig.inputs[0]); + fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty); } fn check_variances_for_type_defn(&self, @@ -578,7 +582,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } } -fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, generics: &ty::Generics) { +fn reject_shadowing_type_parameters(tcx: TyCtxt, span: Span, def_id: DefId) { + let generics = tcx.lookup_generics(def_id); let parent = tcx.lookup_generics(generics.parent.unwrap()); let impl_params: FxHashMap<_, _> = parent.types .iter() diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 4a4dea5b514e5..90541539c1e23 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -38,8 +38,6 @@ use rustc::hir::intravisit; use rustc::hir::{Item, ItemImpl}; use rustc::hir; -use std::rc::Rc; - mod orphan; mod overlap; mod unsafety; @@ -113,8 +111,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // If there are no traits, then this implementation must have a // base type. - let impl_items = self.create_impl_from_item(item); - if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) { debug!("(checking implementation) adding impl for trait '{:?}', item '{}'", trait_ref, @@ -144,8 +140,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { self.add_inherent_impl(base_def_id, impl_did); } } - - tcx.impl_or_trait_item_def_ids.borrow_mut().insert(impl_did, Rc::new(impl_items)); } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { @@ -161,20 +155,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref); } - // Converts an implementation in the AST to a vector of items. - fn create_impl_from_item(&self, item: &Item) -> Vec { - match item.node { - ItemImpl(.., ref impl_items) => { - impl_items.iter() - .map(|impl_item| self.crate_context.tcx.map.local_def_id(impl_item.id)) - .collect() - } - _ => { - span_bug!(item.span, "can't convert a non-impl to an impl"); - } - } - } - // Destructors // @@ -187,10 +167,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { tcx.populate_implementations_for_trait_if_necessary(drop_trait); let drop_trait = tcx.lookup_trait_def(drop_trait); - let impl_items = tcx.impl_or_trait_item_def_ids.borrow(); - drop_trait.for_each_impl(tcx, |impl_did| { - let items = impl_items.get(&impl_did).unwrap(); + let items = tcx.associated_item_def_ids(impl_did); if items.is_empty() { // We'll error out later. For now, just don't ICE. return; diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 1bf140c21a5a5..b5aba512a66bd 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -48,25 +48,23 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { Value, } - fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> (ast::Name, Namespace) { - let item = tcx.impl_or_trait_item(def_id); - (item.name(), - match item { - ty::TypeTraitItem(..) => Namespace::Type, - ty::ConstTraitItem(..) => Namespace::Value, - ty::MethodTraitItem(..) => Namespace::Value, - }) - } + let name_and_namespace = |def_id| { + let item = self.tcx.associated_item(def_id); + (item.name, match item.kind { + ty::AssociatedKind::Type => Namespace::Type, + ty::AssociatedKind::Const | + ty::AssociatedKind::Method => Namespace::Value, + }) + }; - let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); + let impl_items1 = self.tcx.associated_item_def_ids(impl1); + let impl_items2 = self.tcx.associated_item_def_ids(impl2); - for &item1 in &impl_items[&impl1][..] { - let (name, namespace) = name_and_namespace(self.tcx, item1); + for &item1 in &impl_items1[..] { + let (name, namespace) = name_and_namespace(item1); - for &item2 in &impl_items[&impl2][..] { - if (name, namespace) == name_and_namespace(self.tcx, item2) { + for &item2 in &impl_items2[..] { + if (name, namespace) == name_and_namespace(item2) { let msg = format!("duplicate definitions with name `{}`", name); let node_id = self.tcx.map.as_local_node_id(item1).unwrap(); self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5c51877ae743e..d92a98485103c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -66,7 +66,7 @@ use middle::const_val::ConstVal; use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; -use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; +use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::util::IntTypeExt; use rscope::*; @@ -79,7 +79,6 @@ use rustc_const_math::ConstInt; use std::cell::RefCell; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::rc::Rc; use syntax::{abi, ast, attr}; use syntax::parse::token::keywords; @@ -351,24 +350,6 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { }) } - fn trait_defines_associated_type_named(&self, - trait_def_id: DefId, - assoc_name: ast::Name) - -> bool - { - if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) { - trait_associated_type_names(self.tcx(), trait_id) - .any(|name| name == assoc_name) - } else { - self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { - match self.tcx().impl_or_trait_item(def_id) { - ty::TypeTraitItem(ref item) => item.name == assoc_name, - _ => false - } - }) - } - } - fn get_free_substs(&self) -> Option<&Substs<'tcx>> { None } @@ -557,60 +538,6 @@ fn is_param<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, - id: ast::NodeId, - vis: &hir::Visibility, - sig: &hir::MethodSig, - defaultness: hir::Defaultness, - has_body: bool, - untransformed_rcvr_ty: Ty<'tcx>, - rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { - let def_id = ccx.tcx.map.local_def_id(id); - let ty_generics = generics_of_def_id(ccx, def_id); - - let ty_generic_predicates = - ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); - - let (fty, explicit_self_category) = { - let anon_scope = match container { - ImplContainer(_) => Some(AnonTypeScope::new(def_id)), - TraitContainer(_) => None - }; - AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - sig, untransformed_rcvr_ty, anon_scope) - }; - - let ty_method = ty::Method { - name: name, - generics: ty_generics, - predicates: ty_generic_predicates, - fty: fty, - explicit_self: explicit_self_category, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - has_body: has_body, - def_id: def_id, - container: container, - }; - - let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), - ccx.tcx.map.span(id), def_id); - let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty); - debug!("method {} (id {}) has type {:?}", - name, id, fty); - ccx.tcx.tcache.borrow_mut().insert(def_id, fty); - write_ty_to_tcx(ccx, id, fty); - ccx.tcx.predicates.borrow_mut().insert(def_id, ty_method.predicates.clone()); - - debug!("writing method type: def_id={:?} mty={:?}", - def_id, ty_method); - - ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id, - ty::MethodTraitItem(Rc::new(ty_method))); -} - fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_generics: &'tcx ty::Generics<'tcx>, struct_predicates: &ty::GenericPredicates<'tcx>, @@ -631,62 +558,65 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, struct_predicates.clone()); } +fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + container: AssociatedItemContainer, + id: ast::NodeId, + sig: &hir::MethodSig, + untransformed_rcvr_ty: Ty<'tcx>, + rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { + let def_id = ccx.tcx.map.local_def_id(id); + let ty_generics = generics_of_def_id(ccx, def_id); + + let ty_generic_predicates = + ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false); + + let anon_scope = match container { + ImplContainer(_) => Some(AnonTypeScope::new(def_id)), + TraitContainer(_) => None + }; + let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + sig, untransformed_rcvr_ty, anon_scope); + + let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), + ccx.tcx.map.span(id), def_id); + let fty = ccx.tcx.mk_fn_def(def_id, substs, fty); + ccx.tcx.tcache.borrow_mut().insert(def_id, fty); + write_ty_to_tcx(ccx, id, fty); + ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates); +} + fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, + container: AssociatedItemContainer, id: ast::NodeId, - vis: &hir::Visibility, - defaultness: hir::Defaultness, - ty: ty::Ty<'tcx>, - has_value: bool) + ty: ty::Ty<'tcx>) { let predicates = ty::GenericPredicates { parent: Some(container.id()), predicates: vec![] }; - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - predicates); + let def_id = ccx.tcx.map.local_def_id(id); + ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); + ccx.tcx.tcache.borrow_mut().insert(def_id, ty); write_ty_to_tcx(ccx, id, ty); - - let associated_const = Rc::new(ty::AssociatedConst { - name: name, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - def_id: ccx.tcx.map.local_def_id(id), - container: container, - ty: ty, - has_value: has_value - }); - ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const)); } fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, - container: ImplOrTraitItemContainer, - name: ast::Name, + container: AssociatedItemContainer, id: ast::NodeId, - vis: &hir::Visibility, - defaultness: hir::Defaultness, ty: Option>) { let predicates = ty::GenericPredicates { parent: Some(container.id()), predicates: vec![] }; - ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), - predicates); + let def_id = ccx.tcx.map.local_def_id(id); + ccx.tcx.predicates.borrow_mut().insert(def_id, predicates); - let associated_type = Rc::new(ty::AssociatedType { - name: name, - vis: ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness: defaultness, - ty: ty, - def_id: ccx.tcx.map.local_def_id(id), - container: container - }); - ccx.tcx.impl_or_trait_items.borrow_mut() - .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type)); + if let Some(ty) = ty { + ccx.tcx.tcache.borrow_mut().insert(def_id, ty); + write_ty_to_tcx(ccx, id, ty); + } } fn ensure_no_ty_param_bounds(ccx: &CrateCtxt, @@ -820,14 +750,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { generics: ty_generics, ty: ty, }); - // Trait-associated constants are always public. - let public = &hir::Public; - let visibility = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; convert_associated_const(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, - visibility, - impl_item.defaultness, - ty, true /* has_value */); + impl_item.id, ty); } } @@ -844,21 +768,14 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - convert_associated_type(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, &impl_item.vis, - impl_item.defaultness, Some(typ)); + convert_associated_type(ccx, ImplContainer(def_id), impl_item.id, Some(typ)); } } for impl_item in impl_items { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - // Trait methods are always public. - let public = &hir::Public; - let method_vis = if opt_trait_ref.is_some() { public } else { &impl_item.vis }; - convert_method(ccx, ImplContainer(def_id), - impl_item.name, impl_item.id, method_vis, - sig, impl_item.defaultness, true, selfty, + impl_item.id, sig, selfty, &ty_predicates); } } @@ -880,7 +797,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated constants. for trait_item in trait_items { - if let hir::ConstTraitItem(ref ty, ref default) = trait_item.node { + if let hir::ConstTraitItem(ref ty, _) = trait_item.node { let const_def_id = ccx.tcx.map.local_def_id(trait_item.id); let ty_generics = generics_of_def_id(ccx, const_def_id); let ty = ccx.icx(&trait_predicates) @@ -890,14 +807,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { generics: ty_generics, ty: ty, }); - convert_associated_const(ccx, - container, - trait_item.name, - trait_item.id, - &hir::Public, - hir::Defaultness::Default, - ty, - default.is_some()) + convert_associated_const(ccx, container, trait_item.id, ty) } } @@ -911,39 +821,21 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) }); - convert_associated_type(ccx, - container, - trait_item.name, - trait_item.id, - &hir::Public, - hir::Defaultness::Default, - typ); + convert_associated_type(ccx, container, trait_item.id, typ); } } // Convert all the methods for trait_item in trait_items { - if let hir::MethodTraitItem(ref sig, ref body) = trait_item.node { + if let hir::MethodTraitItem(ref sig, _) = trait_item.node { convert_method(ccx, container, - trait_item.name, trait_item.id, - &hir::Inherited, sig, - hir::Defaultness::Default, - body.is_some(), tcx.mk_self_type(), &trait_predicates); - } } - - // Add an entry mapping - let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { - ccx.tcx.map.local_def_id(trait_item.id) - }).collect()); - tcx.impl_or_trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - trait_item_def_ids); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { @@ -1308,28 +1200,6 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, tcx.intern_trait_def(trait_def) } -pub fn trait_associated_type_names<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_node_id: ast::NodeId) - -> impl Iterator + 'a -{ - let item = match tcx.map.get(trait_node_id) { - hir_map::NodeItem(item) => item, - _ => bug!("trait_node_id {} is not an item", trait_node_id) - }; - - let trait_items = match item.node { - hir::ItemTrait(.., ref trait_items) => trait_items, - _ => bug!("trait_node_id {} is not a trait", trait_node_id) - }; - - trait_items.iter().filter_map(|trait_item| { - match trait_item.node { - hir::TypeTraitItem(..) => Some(trait_item.name), - _ => None, - } - }) -} - fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) { let tcx = ccx.tcx; let trait_def = trait_def_of_item(ccx, it); @@ -2209,13 +2079,14 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters); let lifetimes_in_associated_types: FxHashSet<_> = impl_items.iter() - .map(|item| ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(item.id))) - .filter_map(|item| match item { - ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty, - ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None + .map(|item| ccx.tcx.map.local_def_id(item.id)) + .filter(|&def_id| { + let item = ccx.tcx.associated_item(def_id); + item.kind == ty::AssociatedKind::Type && item.has_value }) - .flat_map(|ty| ctp::parameters_for(&ty, true)) - .collect(); + .flat_map(|def_id| { + ctp::parameters_for(&ccx.tcx.lookup_item_type(def_id).ty, true) + }).collect(); for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() .zip(&ast_generics.lifetimes) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 1885b4276cc41..a2955169cbb81 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -163,7 +163,7 @@ pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) { pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Trait { let def = tcx.lookup_trait_def(did); - let trait_items = tcx.trait_items(did).clean(cx); + let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect(); let predicates = tcx.lookup_predicates(did); let generics = (def.generics, &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); @@ -307,7 +307,6 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { if !def_id.is_local() { - tcx.populate_implementations_for_primitive_if_necessary(def_id); build_impl(cx, tcx, def_id, &mut impls); } } @@ -367,21 +366,18 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } let predicates = tcx.lookup_predicates(did); - let trait_items = tcx.sess.cstore.impl_or_trait_items(did) - .iter() - .filter_map(|&did| { - match tcx.impl_or_trait_item(did) { - ty::ConstTraitItem(ref assoc_const) => { - let did = assoc_const.def_id; - let type_scheme = tcx.lookup_item_type(did); - let default = if assoc_const.has_value { + let trait_items = tcx.associated_items(did).filter_map(|item| { + match item.kind { + ty::AssociatedKind::Const => { + let type_scheme = tcx.lookup_item_type(item.def_id); + let default = if item.has_value { Some(pprust::expr_to_string( - lookup_const_by_id(tcx, did, None).unwrap().0)) + lookup_const_by_id(tcx, item.def_id, None).unwrap().0)) } else { None }; Some(clean::Item { - name: Some(assoc_const.name.clean(cx)), + name: Some(item.name.clean(cx)), inner: clean::AssociatedConstItem( type_scheme.ty.clean(cx), default, @@ -389,21 +385,21 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: tcx.lookup_stability(did).clean(cx), - deprecation: tcx.lookup_deprecation(did).clean(cx), - def_id: did + stability: tcx.lookup_stability(item.def_id).clean(cx), + deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), + def_id: item.def_id }) } - ty::MethodTraitItem(method) => { - if method.vis != ty::Visibility::Public && associated_trait.is_none() { + ty::AssociatedKind::Method => { + if item.vis != ty::Visibility::Public && associated_trait.is_none() { return None } - let mut item = method.clean(cx); - item.inner = match item.inner.clone() { + let mut cleaned = item.clean(cx); + cleaned.inner = match cleaned.inner.clone() { clean::TyMethodItem(clean::TyMethod { unsafety, decl, generics, abi }) => { - let constness = if tcx.sess.cstore.is_const_fn(did) { + let constness = if tcx.sess.cstore.is_const_fn(item.def_id) { hir::Constness::Const } else { hir::Constness::NotConst @@ -419,12 +415,11 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } _ => panic!("not a tymethod"), }; - Some(item) + Some(cleaned) } - ty::TypeTraitItem(ref assoc_ty) => { - let did = assoc_ty.def_id; + ty::AssociatedKind::Type => { let typedef = clean::Typedef { - type_: assoc_ty.ty.unwrap().clean(cx), + type_: tcx.lookup_item_type(item.def_id).ty.clean(cx), generics: clean::Generics { lifetimes: vec![], type_params: vec![], @@ -432,14 +427,14 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } }; Some(clean::Item { - name: Some(assoc_ty.name.clean(cx)), + name: Some(item.name.clean(cx)), inner: clean::TypedefItem(typedef, true), source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: tcx.lookup_stability(did).clean(cx), - deprecation: tcx.lookup_deprecation(did).clean(cx), - def_id: did + stability: tcx.lookup_stability(item.def_id).clean(cx), + deprecation: tcx.lookup_deprecation(item.def_id).clean(cx), + def_id: item.def_id }) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index df13e384d9615..9e29d191946b7 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1338,48 +1338,117 @@ impl Clean for hir::ImplItem { } } -impl<'tcx> Clean for ty::Method<'tcx> { +impl<'tcx> Clean for ty::AssociatedItem { fn clean(&self, cx: &DocContext) -> Item { - let generics = (self.generics, &self.predicates).clean(cx); - let mut decl = (self.def_id, &self.fty.sig).clean(cx); - match self.explicit_self { - ty::ExplicitSelfCategory::ByValue => { - decl.inputs.values[0].type_ = Infer; + let inner = match self.kind { + ty::AssociatedKind::Const => { + let ty = cx.tcx().lookup_item_type(self.def_id).ty; + AssociatedConstItem(ty.clean(cx), None) } - ty::ExplicitSelfCategory::ByReference(..) => { - match decl.inputs.values[0].type_ { - BorrowedRef{ref mut type_, ..} => **type_ = Infer, - _ => unreachable!(), + ty::AssociatedKind::Method => { + let generics = (cx.tcx().lookup_generics(self.def_id), + &cx.tcx().lookup_predicates(self.def_id)).clean(cx); + let fty = match cx.tcx().lookup_item_type(self.def_id).ty.sty { + ty::TyFnDef(_, _, f) => f, + _ => unreachable!() + }; + let mut decl = (self.def_id, &fty.sig).clean(cx); + + if self.method_has_self_argument { + let self_ty = match self.container { + ty::ImplContainer(def_id) => { + cx.tcx().lookup_item_type(def_id).ty + } + ty::TraitContainer(_) => cx.tcx().mk_self_type() + }; + let self_arg_ty = *fty.sig.input(0).skip_binder(); + if self_arg_ty == self_ty { + decl.inputs.values[0].type_ = Infer; + } else if let ty::TyRef(_, mt) = self_arg_ty.sty { + if mt.ty == self_ty { + match decl.inputs.values[0].type_ { + BorrowedRef{ref mut type_, ..} => **type_ = Infer, + _ => unreachable!(), + } + } + } + } + let provided = match self.container { + ty::ImplContainer(_) => false, + ty::TraitContainer(_) => self.has_value + }; + if provided { + MethodItem(Method { + unsafety: fty.unsafety, + generics: generics, + decl: decl, + abi: fty.abi, + + // trait methods canot (currently, at least) be const + constness: hir::Constness::NotConst, + }) + } else { + TyMethodItem(TyMethod { + unsafety: fty.unsafety, + generics: generics, + decl: decl, + abi: fty.abi, + }) } } - _ => {} - } - let provided = match self.container { - ty::ImplContainer(..) => false, - ty::TraitContainer(did) => { - cx.tcx().provided_trait_methods(did).iter().any(|m| { - m.def_id == self.def_id - }) + ty::AssociatedKind::Type => { + let my_name = self.name.clean(cx); + + let mut bounds = if let ty::TraitContainer(did) = self.container { + // When loading a cross-crate associated type, the bounds for this type + // are actually located on the trait/impl itself, so we need to load + // all of the generics from there and then look for bounds that are + // applied to this associated type in question. + let def = cx.tcx().lookup_trait_def(did); + let predicates = cx.tcx().lookup_predicates(did); + let generics = (def.generics, &predicates).clean(cx); + generics.where_predicates.iter().filter_map(|pred| { + let (name, self_type, trait_, bounds) = match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref name, ref self_type, ref trait_ }, + ref bounds + } => (name, self_type, trait_, bounds), + _ => return None, + }; + if *name != my_name { return None } + match **trait_ { + ResolvedPath { did, .. } if did == self.container.id() => {} + _ => return None, + } + match **self_type { + Generic(ref s) if *s == "Self" => {} + _ => return None, + } + Some(bounds) + }).flat_map(|i| i.iter().cloned()).collect::>() + } else { + vec![] + }; + + // Our Sized/?Sized bound didn't get handled when creating the generics + // because we didn't actually get our whole set of bounds until just now + // (some of them may have come from the trait). If we do have a sized + // bound, we remove it, and if we don't then we add the `?Sized` bound + // at the end. + match bounds.iter().position(|b| b.is_sized_bound(cx)) { + Some(i) => { bounds.remove(i); } + None => bounds.push(TyParamBound::maybe_sized(cx)), + } + + let ty = if self.has_value { + Some(cx.tcx().lookup_item_type(self.def_id).ty) + } else { + None + }; + + AssociatedTypeItem(bounds, ty.clean(cx)) } }; - let inner = if provided { - MethodItem(Method { - unsafety: self.fty.unsafety, - generics: generics, - decl: decl, - abi: self.fty.abi, - - // trait methods canot (currently, at least) be const - constness: hir::Constness::NotConst, - }) - } else { - TyMethodItem(TyMethod { - unsafety: self.fty.unsafety, - generics: generics, - decl: decl, - abi: self.fty.abi, - }) - }; Item { name: Some(self.name.clean(cx)), @@ -1394,16 +1463,6 @@ impl<'tcx> Clean for ty::Method<'tcx> { } } -impl<'tcx> Clean for ty::ImplOrTraitItem<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - match *self { - ty::ConstTraitItem(ref cti) => cti.clean(cx), - ty::MethodTraitItem(ref mti) => mti.clean(cx), - ty::TypeTraitItem(ref tti) => tti.clean(cx), - } - } -} - /// A trait reference, which may have higher ranked lifetimes. #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct PolyTrait { @@ -2884,79 +2943,6 @@ impl Clean for attr::Deprecation { } } -impl<'tcx> Clean for ty::AssociatedConst<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - Item { - source: DUMMY_SP.clean(cx), - name: Some(self.name.clean(cx)), - attrs: Vec::new(), - inner: AssociatedConstItem(self.ty.clean(cx), None), - visibility: None, - def_id: self.def_id, - stability: None, - deprecation: None, - } - } -} - -impl<'tcx> Clean for ty::AssociatedType<'tcx> { - fn clean(&self, cx: &DocContext) -> Item { - let my_name = self.name.clean(cx); - - let mut bounds = if let ty::TraitContainer(did) = self.container { - // When loading a cross-crate associated type, the bounds for this type - // are actually located on the trait/impl itself, so we need to load - // all of the generics from there and then look for bounds that are - // applied to this associated type in question. - let def = cx.tcx().lookup_trait_def(did); - let predicates = cx.tcx().lookup_predicates(did); - let generics = (def.generics, &predicates).clean(cx); - generics.where_predicates.iter().filter_map(|pred| { - let (name, self_type, trait_, bounds) = match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref name, ref self_type, ref trait_ }, - ref bounds - } => (name, self_type, trait_, bounds), - _ => return None, - }; - if *name != my_name { return None } - match **trait_ { - ResolvedPath { did, .. } if did == self.container.id() => {} - _ => return None, - } - match **self_type { - Generic(ref s) if *s == "Self" => {} - _ => return None, - } - Some(bounds) - }).flat_map(|i| i.iter().cloned()).collect::>() - } else { - vec![] - }; - - // Our Sized/?Sized bound didn't get handled when creating the generics - // because we didn't actually get our whole set of bounds until just now - // (some of them may have come from the trait). If we do have a sized - // bound, we remove it, and if we don't then we add the `?Sized` bound - // at the end. - match bounds.iter().position(|b| b.is_sized_bound(cx)) { - Some(i) => { bounds.remove(i); } - None => bounds.push(TyParamBound::maybe_sized(cx)), - } - - Item { - source: DUMMY_SP.clean(cx), - name: Some(self.name.clean(cx)), - attrs: inline::load_attrs(cx, cx.tcx(), self.def_id), - inner: AssociatedTypeItem(bounds, self.ty.clean(cx)), - visibility: self.vis.clean(cx), - def_id: self.def_id, - stability: cx.tcx().lookup_stability(self.def_id).clean(cx), - deprecation: cx.tcx().lookup_deprecation(self.def_id).clean(cx), - } - } -} - fn lang_struct(cx: &DocContext, did: Option, t: ty::Ty, name: &str, fallback: fn(Box) -> Type) -> Type {