mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 02:33:55 +00:00
rustc_typeck: rework coherence to be almost completely on-demand.
This commit is contained in:
parent
9890e0466d
commit
c832e6f327
@ -70,6 +70,7 @@ pub enum DepNode<D: Clone + Debug> {
|
||||
Resolve,
|
||||
EntryPoint,
|
||||
CheckEntryFn,
|
||||
CoherenceCheckTrait(D),
|
||||
CoherenceCheckImpl(D),
|
||||
CoherenceOverlapCheck(D),
|
||||
CoherenceOverlapCheckSpecial(D),
|
||||
@ -241,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||
MetaData(ref d) => op(d).map(MetaData),
|
||||
CollectItem(ref d) => op(d).map(CollectItem),
|
||||
CollectItemSig(ref d) => op(d).map(CollectItemSig),
|
||||
CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
|
||||
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
|
||||
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
|
||||
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
|
||||
|
@ -80,6 +80,9 @@ pub struct LoweringContext<'a> {
|
||||
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
||||
bodies: FxHashMap<hir::BodyId, hir::Body>,
|
||||
|
||||
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||
trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||
|
||||
loop_scopes: Vec<NodeId>,
|
||||
is_in_loop_condition: bool,
|
||||
|
||||
@ -116,6 +119,8 @@ pub fn lower_crate(sess: &Session,
|
||||
trait_items: BTreeMap::new(),
|
||||
impl_items: BTreeMap::new(),
|
||||
bodies: FxHashMap(),
|
||||
trait_impls: BTreeMap::new(),
|
||||
trait_default_impl: BTreeMap::new(),
|
||||
loop_scopes: Vec::new(),
|
||||
is_in_loop_condition: false,
|
||||
type_def_lifetime_params: DefIdMap(),
|
||||
@ -201,6 +206,8 @@ impl<'a> LoweringContext<'a> {
|
||||
trait_items: self.trait_items,
|
||||
impl_items: self.impl_items,
|
||||
bodies: self.bodies,
|
||||
trait_impls: self.trait_impls,
|
||||
trait_default_impl: self.trait_default_impl,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1089,14 +1096,27 @@ impl<'a> LoweringContext<'a> {
|
||||
hir::ItemUnion(vdata, self.lower_generics(generics))
|
||||
}
|
||||
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
|
||||
let trait_ref = self.lower_trait_ref(trait_ref);
|
||||
|
||||
if let Def::Trait(def_id) = trait_ref.path.def {
|
||||
self.trait_default_impl.insert(def_id, id);
|
||||
}
|
||||
|
||||
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
|
||||
self.lower_trait_ref(trait_ref))
|
||||
trait_ref)
|
||||
}
|
||||
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
|
||||
let new_impl_items = impl_items.iter()
|
||||
.map(|item| self.lower_impl_item_ref(item))
|
||||
.collect();
|
||||
let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
|
||||
|
||||
if let Some(ref trait_ref) = ifce {
|
||||
if let Def::Trait(def_id) = trait_ref.path.def {
|
||||
self.trait_impls.entry(def_id).or_insert(vec![]).push(id);
|
||||
}
|
||||
}
|
||||
|
||||
hir::ItemImpl(self.lower_unsafety(unsafety),
|
||||
self.lower_impl_polarity(polarity),
|
||||
self.lower_generics(generics),
|
||||
|
@ -461,6 +461,26 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
|
||||
self.dep_graph.read(DepNode::TraitImpls(trait_did));
|
||||
|
||||
// NB: intentionally bypass `self.forest.krate()` so that we
|
||||
// do not trigger a read of the whole krate here
|
||||
self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
|
||||
}
|
||||
|
||||
pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
|
||||
self.dep_graph.read(DepNode::TraitImpls(trait_did));
|
||||
|
||||
// NB: intentionally bypass `self.forest.krate()` so that we
|
||||
// do not trigger a read of the whole krate here
|
||||
self.forest.krate.trait_default_impl.get(&trait_did).cloned()
|
||||
}
|
||||
|
||||
pub fn trait_is_auto(&self, trait_did: DefId) -> bool {
|
||||
self.trait_default_impl(trait_did).is_some()
|
||||
}
|
||||
|
||||
/// Get the attributes on the krate. This is preferable to
|
||||
/// invoking `krate.attrs` because it registers a tighter
|
||||
/// dep-graph access.
|
||||
|
@ -410,6 +410,9 @@ pub struct Crate {
|
||||
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
|
||||
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
|
||||
pub bodies: FxHashMap<BodyId, Body>,
|
||||
|
||||
pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||
pub trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
|
@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||
evaluation_cache: traits::EvaluationCache::new(),
|
||||
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
||||
reported_trait_errors: RefCell::new(FxHashSet()),
|
||||
projection_mode: Reveal::NotSpecializable,
|
||||
projection_mode: Reveal::UserFacing,
|
||||
tainted_by_errors_flag: Cell::new(false),
|
||||
err_count_on_creation: self.sess.err_count(),
|
||||
obligations_in_snapshot: Cell::new(false),
|
||||
|
@ -191,7 +191,6 @@ pub trait CrateStore {
|
||||
|
||||
// flags
|
||||
fn is_const_fn(&self, did: DefId) -> bool;
|
||||
fn is_defaulted_trait(&self, did: DefId) -> bool;
|
||||
fn is_default_impl(&self, impl_did: DefId) -> bool;
|
||||
fn is_foreign_item(&self, did: DefId) -> bool;
|
||||
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
|
||||
@ -327,7 +326,6 @@ impl CrateStore for DummyCrateStore {
|
||||
|
||||
// flags
|
||||
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
|
||||
fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") }
|
||||
fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
|
||||
fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
|
||||
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
|
||||
|
@ -473,7 +473,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
|
||||
|
||||
tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let predicates = match fully_normalize(&infcx, cause,
|
||||
&infcx.parameter_environment.caller_bounds) {
|
||||
Ok(predicates) => predicates,
|
||||
|
@ -38,36 +38,6 @@ use util::common::FN_OUTPUT_NAME;
|
||||
/// more or less conservative.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Reveal {
|
||||
/// FIXME (#32205)
|
||||
/// At coherence-checking time, we're still constructing the
|
||||
/// specialization graph, and thus we only project
|
||||
/// non-`default` associated types that are defined directly in
|
||||
/// the applicable impl. (This behavior should be improved over
|
||||
/// time, to allow for successful projections modulo cycles
|
||||
/// between different impls).
|
||||
///
|
||||
/// Here's an example that will fail due to the restriction:
|
||||
///
|
||||
/// ```
|
||||
/// trait Assoc {
|
||||
/// type Output;
|
||||
/// }
|
||||
///
|
||||
/// impl<T> Assoc for T {
|
||||
/// type Output = bool;
|
||||
/// }
|
||||
///
|
||||
/// impl Assoc for u8 {} // <- inherits the non-default type from above
|
||||
///
|
||||
/// trait Foo {}
|
||||
/// impl Foo for u32 {}
|
||||
/// impl Foo for <u8 as Assoc>::Output {} // <- this projection will fail
|
||||
/// ```
|
||||
///
|
||||
/// The projection would succeed if `Output` had been defined
|
||||
/// directly in the impl for `u8`.
|
||||
ExactMatch,
|
||||
|
||||
/// At type-checking time, we refuse to project any associated
|
||||
/// type that is marked `default`. Non-`default` ("final") types
|
||||
/// are always projected. This is necessary in general for
|
||||
@ -90,7 +60,7 @@ pub enum Reveal {
|
||||
/// fn main() {
|
||||
/// let <() as Assoc>::Output = true;
|
||||
/// }
|
||||
NotSpecializable,
|
||||
UserFacing,
|
||||
|
||||
/// At trans time, all monomorphic projections will succeed.
|
||||
/// Also, `impl Trait` is normalized to the concrete type,
|
||||
@ -1347,8 +1317,9 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
|
||||
-> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
|
||||
{
|
||||
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
|
||||
let trait_def = selcx.tcx().lookup_trait_def(trait_def_id);
|
||||
|
||||
if selcx.projection_mode() == Reveal::ExactMatch {
|
||||
if !trait_def.is_complete(selcx.tcx()) {
|
||||
let impl_node = specialization_graph::Node::Impl(impl_def_id);
|
||||
for item in impl_node.items(selcx.tcx()) {
|
||||
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
|
||||
@ -1360,7 +1331,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
|
||||
}
|
||||
None
|
||||
} else {
|
||||
selcx.tcx().lookup_trait_def(trait_def_id)
|
||||
trait_def
|
||||
.ancestors(impl_def_id)
|
||||
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
|
||||
.next()
|
||||
|
@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
.subst(tcx, &penv.free_substs);
|
||||
|
||||
// Create a infcx, taking the predicates of impl1 as assumptions:
|
||||
let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| {
|
||||
let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
|
||||
// Normalize the trait reference. The WF rules ought to ensure
|
||||
// that this always succeeds.
|
||||
let impl1_trait_ref =
|
||||
|
@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children {
|
||||
let possible_sibling = *slot;
|
||||
|
||||
let tcx = tcx.global_tcx();
|
||||
let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
|
||||
let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
let overlap = traits::overlapping_impls(&infcx,
|
||||
possible_sibling,
|
||||
impl_def_id);
|
||||
|
@ -219,7 +219,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
res = res - TC::OwnsDtor;
|
||||
}
|
||||
|
||||
if def.has_dtor() {
|
||||
if def.has_dtor(tcx) {
|
||||
res = res | TC::OwnsDtor;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,15 @@ trait Key {
|
||||
fn default_span(&self, tcx: TyCtxt) -> Span;
|
||||
}
|
||||
|
||||
impl Key for CrateNum {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
*self
|
||||
}
|
||||
fn default_span(&self, _: TyCtxt) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for DefId {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
self.krate
|
||||
@ -42,6 +51,15 @@ impl Key for (DefId, DefId) {
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (CrateNum, DefId) {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
self.0
|
||||
}
|
||||
fn default_span(&self, tcx: TyCtxt) -> Span {
|
||||
self.1.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
trait Value<'tcx>: Sized {
|
||||
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
|
||||
}
|
||||
@ -141,6 +159,19 @@ impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> {
|
||||
fn describe(tcx: TyCtxt, (_, def_id): (CrateNum, DefId)) -> String {
|
||||
format!("coherence checking all impls of trait `{}`",
|
||||
tcx.item_path_str(def_id))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> {
|
||||
fn describe(_: TyCtxt, _: CrateNum) -> String {
|
||||
format!("coherence checking all inherent impls")
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_maps {
|
||||
(<$tcx:tt>
|
||||
$($(#[$attr:meta])*
|
||||
@ -238,6 +269,12 @@ macro_rules! define_maps {
|
||||
}
|
||||
|
||||
pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) {
|
||||
// FIXME(eddyb) Move away from using `DepTrackingMap`
|
||||
// so we don't have to explicitly ignore a false edge:
|
||||
// we can't observe a value dependency, only side-effects,
|
||||
// through `force`, and once everything has been updated,
|
||||
// perhaps only diagnostics, if those, will remain.
|
||||
let _ignore = tcx.dep_graph.in_ignore();
|
||||
match Self::try_get_with(tcx, span, key, |_| ()) {
|
||||
Ok(()) => {}
|
||||
Err(e) => tcx.report_cycle(e)
|
||||
@ -338,7 +375,19 @@ define_maps! { <'tcx>
|
||||
|
||||
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
|
||||
|
||||
pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
|
||||
|
||||
pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (),
|
||||
|
||||
/// Results of evaluating monomorphic constants embedded in
|
||||
/// other items, such as enum variant explicit discriminants.
|
||||
pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>
|
||||
}
|
||||
|
||||
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
|
||||
DepNode::CoherenceCheckTrait(def_id)
|
||||
}
|
||||
|
||||
fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
|
||||
DepNode::Coherence
|
||||
}
|
||||
|
@ -1301,6 +1301,7 @@ bitflags! {
|
||||
const IS_FUNDAMENTAL = 1 << 4,
|
||||
const IS_UNION = 1 << 5,
|
||||
const IS_BOX = 1 << 6,
|
||||
const IS_DTOR_VALID = 1 << 7,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1522,8 +1523,8 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
}
|
||||
|
||||
/// Returns whether this type has a destructor.
|
||||
pub fn has_dtor(&self) -> bool {
|
||||
self.destructor.get().is_some()
|
||||
pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||
self.destructor(tcx).is_some()
|
||||
}
|
||||
|
||||
/// Asserts this is a struct and returns the struct's unique
|
||||
@ -1578,12 +1579,36 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destructor(&self) -> Option<DefId> {
|
||||
self.destructor.get()
|
||||
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
|
||||
if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
|
||||
return self.destructor.get();
|
||||
}
|
||||
|
||||
let dtor = self.destructor_uncached(tcx);
|
||||
self.destructor.set(dtor);
|
||||
self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
|
||||
|
||||
dtor
|
||||
}
|
||||
|
||||
pub fn set_destructor(&self, dtor: DefId) {
|
||||
self.destructor.set(Some(dtor));
|
||||
fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
|
||||
let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
|
||||
def_id
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
|
||||
|
||||
let mut dtor = None;
|
||||
let ty = tcx.item_type(self.did);
|
||||
tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
|
||||
if let Some(item) = tcx.associated_items(def_id).next() {
|
||||
dtor = Some(item.def_id);
|
||||
}
|
||||
});
|
||||
|
||||
dtor
|
||||
}
|
||||
|
||||
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
@ -2367,23 +2392,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
|
||||
self.populate_implementations_for_trait_if_necessary(trait_def_id);
|
||||
|
||||
let def = self.lookup_trait_def(trait_def_id);
|
||||
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping.
|
||||
pub fn record_trait_has_default_impl(self, trait_def_id: DefId) {
|
||||
let def = self.lookup_trait_def(trait_def_id);
|
||||
def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
span: Span,
|
||||
type_id: DefId) {
|
||||
if type_id.is_local() {
|
||||
// Make sure coherence of inherent impls ran already.
|
||||
ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
|
||||
return
|
||||
}
|
||||
|
||||
@ -2416,16 +2436,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
let _ignore = self.dep_graph.in_ignore();
|
||||
|
||||
let def = self.lookup_trait_def(trait_id);
|
||||
if def.flags.get().intersects(TraitFlags::IMPLS_VALID) {
|
||||
if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
|
||||
|
||||
if self.sess.cstore.is_defaulted_trait(trait_id) {
|
||||
self.record_trait_has_default_impl(trait_id);
|
||||
}
|
||||
|
||||
for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) {
|
||||
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
|
||||
|
||||
@ -2434,7 +2450,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
|
||||
}
|
||||
|
||||
def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
|
||||
def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS);
|
||||
}
|
||||
|
||||
pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use dep_graph::DepNode;
|
||||
use hir::def_id::DefId;
|
||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use traits::{self, specialization_graph};
|
||||
use ty;
|
||||
use ty::fast_reject;
|
||||
@ -18,6 +18,9 @@ use std::cell::{Cell, RefCell};
|
||||
use hir;
|
||||
use util::nodemap::FxHashMap;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
/// A trait's definition with type information.
|
||||
pub struct TraitDef {
|
||||
pub def_id: DefId,
|
||||
@ -60,6 +63,11 @@ pub struct TraitDef {
|
||||
/// Various flags
|
||||
pub flags: Cell<TraitFlags>,
|
||||
|
||||
/// The number of impls we've added from the local crate.
|
||||
/// When this number matches up the list in the HIR map,
|
||||
/// we're done, and the specialization graph is correct.
|
||||
local_impl_count: Cell<usize>,
|
||||
|
||||
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
|
||||
/// recomputed all the time.
|
||||
pub def_path_hash: u64,
|
||||
@ -78,6 +86,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||
nonblanket_impls: RefCell::new(FxHashMap()),
|
||||
blanket_impls: RefCell::new(vec![]),
|
||||
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
|
||||
local_impl_count: Cell::new(0),
|
||||
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
|
||||
def_path_hash: def_path_hash,
|
||||
}
|
||||
@ -155,6 +164,13 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||
assert!(impl_def_id.is_local());
|
||||
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
|
||||
assert!(was_new);
|
||||
|
||||
self.local_impl_count.set(self.local_impl_count.get() + 1);
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping.
|
||||
pub fn record_has_default_impl(&self) {
|
||||
self.flags.set(self.flags.get() | TraitFlags::HAS_DEFAULT_IMPL);
|
||||
}
|
||||
|
||||
/// Records a trait-to-implementation mapping for a non-local impl.
|
||||
@ -194,10 +210,51 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||
specialization_graph::ancestors(self, of_impl)
|
||||
}
|
||||
|
||||
/// Whether the impl set and specialization graphs are complete.
|
||||
pub fn is_complete(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
|
||||
ty::queries::coherent_trait::try_get(tcx, DUMMY_SP, (LOCAL_CRATE, self.def_id)).is_ok()
|
||||
}
|
||||
|
||||
/// If any local impls haven't been added yet, returns
|
||||
/// Some(list of local impls for this trait).
|
||||
fn missing_local_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||
-> Option<&'gcx [ast::NodeId]> {
|
||||
if self.flags.get().intersects(TraitFlags::HAS_LOCAL_IMPLS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.is_complete(tcx) {
|
||||
self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
|
||||
return None;
|
||||
}
|
||||
|
||||
let impls = tcx.hir.trait_impls(self.def_id);
|
||||
assert!(self.local_impl_count.get() <= impls.len());
|
||||
if self.local_impl_count.get() == impls.len() {
|
||||
self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(impls)
|
||||
}
|
||||
|
||||
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
|
||||
self.read_trait_impls(tcx);
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
|
||||
|
||||
let local_impls = self.missing_local_impls(tcx);
|
||||
if let Some(impls) = local_impls {
|
||||
for &id in impls {
|
||||
f(tcx.hir.local_def_id(id));
|
||||
}
|
||||
}
|
||||
let mut f = |def_id: DefId| {
|
||||
if !(local_impls.is_some() && def_id.is_local()) {
|
||||
f(def_id);
|
||||
}
|
||||
};
|
||||
|
||||
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
@ -217,9 +274,20 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||
mut f: F)
|
||||
{
|
||||
self.read_trait_impls(tcx);
|
||||
|
||||
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
|
||||
|
||||
let local_impls = self.missing_local_impls(tcx);
|
||||
if let Some(impls) = local_impls {
|
||||
for &id in impls {
|
||||
f(tcx.hir.local_def_id(id));
|
||||
}
|
||||
}
|
||||
let mut f = |def_id: DefId| {
|
||||
if !(local_impls.is_some() && def_id.is_local()) {
|
||||
f(def_id);
|
||||
}
|
||||
};
|
||||
|
||||
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
@ -258,6 +326,7 @@ bitflags! {
|
||||
const HAS_DEFAULT_IMPL = 1 << 0,
|
||||
const IS_OBJECT_SAFE = 1 << 1,
|
||||
const OBJECT_SAFETY_VALID = 1 << 2,
|
||||
const IMPLS_VALID = 1 << 3,
|
||||
const HAS_REMOTE_IMPLS = 1 << 3,
|
||||
const HAS_LOCAL_IMPLS = 1 << 4,
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
|
||||
self_type: Ty<'tcx>, span: Span)
|
||||
-> Result<(), CopyImplementationError> {
|
||||
// FIXME: (@jroesch) float this code up
|
||||
tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
|
||||
let (adt, substs) = match self_type.sty {
|
||||
ty::TyAdt(adt, substs) => (adt, substs),
|
||||
_ => return Err(CopyImplementationError::NotAnAdt)
|
||||
@ -171,7 +171,7 @@ impl<'tcx> ParameterEnvironment<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if adt.has_dtor() {
|
||||
if adt.has_dtor(tcx) {
|
||||
return Err(CopyImplementationError::HasDestructor);
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// (This allows programs to make cyclic structures without
|
||||
/// resorting to unasfe means; see RFCs 769 and 1238).
|
||||
pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
|
||||
let dtor_method = match adt.destructor() {
|
||||
let dtor_method = match adt.destructor(self) {
|
||||
Some(dtor) => dtor,
|
||||
None => return false
|
||||
};
|
||||
@ -524,7 +524,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
let result =
|
||||
tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
|
||||
tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
|
||||
.enter(|infcx| {
|
||||
traits::type_known_to_meet_bound(&infcx, self, def_id, span)
|
||||
});
|
||||
|
@ -783,7 +783,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
}
|
||||
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
|
||||
match lp_base.to_type().sty {
|
||||
ty::TyAdt(def, _) if def.has_dtor() => {
|
||||
ty::TyAdt(def, _) if def.has_dtor(self.tcx()) => {
|
||||
// In the case where the owner implements drop, then
|
||||
// the path must be initialized to prevent a case of
|
||||
// partial reinitialization
|
||||
|
@ -177,7 +177,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
|
||||
match b.ty.sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
if def.has_dtor() {
|
||||
if def.has_dtor(bccx.tcx) {
|
||||
Some(cmt.clone())
|
||||
} else {
|
||||
check_and_get_illegal_move_origin(bccx, b)
|
||||
|
@ -150,7 +150,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
|
||||
Categorization::Downcast(ref b, _) |
|
||||
Categorization::Interior(ref b, mc::InteriorField(_)) => {
|
||||
match b.ty.sty {
|
||||
ty::TyAdt(def, _) if def.has_dtor() => {
|
||||
ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
|
||||
let mut err = struct_span_err!(bccx, move_from.span, E0509,
|
||||
"cannot move out of type `{}`, \
|
||||
which implements the `Drop` trait",
|
||||
|
@ -898,7 +898,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
if def.has_dtor() && !def.is_box() {
|
||||
if def.has_dtor(self.tcx) && !def.is_box() {
|
||||
self.tcx.sess.span_warn(
|
||||
c.source_info.span,
|
||||
&format!("dataflow bug??? moving out of type with dtor {:?}",
|
||||
|
@ -289,7 +289,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
||||
// error: can't move out of borrowed content
|
||||
ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
|
||||
// error: can't move out of struct with destructor
|
||||
ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() =>
|
||||
ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
|
||||
return Err(MovePathError::IllegalMove),
|
||||
// move out of union - always move the entire union
|
||||
ty::TyAdt(adt, _) if adt.is_union() =>
|
||||
|
@ -248,7 +248,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx
|
||||
lv, ty);
|
||||
true
|
||||
}
|
||||
ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => {
|
||||
ty::TyAdt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
|
||||
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
|
||||
lv, ty);
|
||||
true
|
||||
|
@ -516,7 +516,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||
///
|
||||
/// FIXME: this should be done by borrowck.
|
||||
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
|
||||
cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::NotSpecializable).enter(|infcx| {
|
||||
cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::UserFacing).enter(|infcx| {
|
||||
let mut checker = MutationChecker {
|
||||
cx: cx,
|
||||
};
|
||||
|
@ -922,7 +922,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
|
||||
trait_ref);
|
||||
|
||||
tcx.populate_implementations_for_trait_if_necessary(trait_id);
|
||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
|
@ -151,7 +151,7 @@ fn test_env<F>(source_string: &str,
|
||||
index,
|
||||
"test_crate",
|
||||
|tcx| {
|
||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
|
||||
body(Env { infcx: &infcx });
|
||||
let free_regions = FreeRegionMap::new();
|
||||
|
@ -1167,6 +1167,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
|
||||
trait_items: _,
|
||||
impl_items: _,
|
||||
bodies: _,
|
||||
|
||||
trait_impls: _,
|
||||
trait_default_impl: _,
|
||||
} = *krate;
|
||||
|
||||
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
|
||||
|
@ -523,7 +523,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
if def.has_dtor() {
|
||||
if def.has_dtor(cx.tcx) {
|
||||
return;
|
||||
}
|
||||
let parameter_environment = cx.tcx.empty_parameter_environment();
|
||||
@ -882,7 +882,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
|
||||
let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
|
||||
|
||||
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
|
||||
tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||
match selcx.select(&obligation) {
|
||||
// The method comes from a `T: Trait` bound.
|
||||
|
@ -203,12 +203,6 @@ impl CrateStore for cstore::CStore {
|
||||
self.get_crate_data(did.krate).is_const_fn(did.index)
|
||||
}
|
||||
|
||||
fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
|
||||
{
|
||||
self.dep_graph.read(DepNode::MetaData(trait_def_id));
|
||||
self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index)
|
||||
}
|
||||
|
||||
fn is_default_impl(&self, impl_did: DefId) -> bool {
|
||||
self.dep_graph.read(DepNode::MetaData(impl_did));
|
||||
self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
|
||||
|
@ -501,10 +501,16 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
_ => bug!(),
|
||||
};
|
||||
|
||||
ty::TraitDef::new(self.local_def_id(item_id),
|
||||
data.unsafety,
|
||||
data.paren_sugar,
|
||||
self.def_path(item_id).deterministic_hash(tcx))
|
||||
let def = ty::TraitDef::new(self.local_def_id(item_id),
|
||||
data.unsafety,
|
||||
data.paren_sugar,
|
||||
self.def_path(item_id).deterministic_hash(tcx));
|
||||
|
||||
if data.has_default_impl {
|
||||
def.record_has_default_impl();
|
||||
}
|
||||
|
||||
def
|
||||
}
|
||||
|
||||
fn get_variant(&self,
|
||||
@ -1027,13 +1033,6 @@ impl<'a, 'tcx> CrateMetadata {
|
||||
self.dllimport_foreign_items.contains(&id)
|
||||
}
|
||||
|
||||
pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
|
||||
match self.entry(trait_id).kind {
|
||||
EntryKind::Trait(data) => data.decode(self).has_default_impl,
|
||||
_ => bug!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
|
||||
match self.entry(impl_id).kind {
|
||||
EntryKind::DefaultImpl(_) => true,
|
||||
|
@ -96,7 +96,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
|
||||
};
|
||||
|
||||
let src = MirSource::from_node(tcx, id);
|
||||
tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
|
||||
let cx = Cx::new(&infcx, src);
|
||||
let mut mir = if let MirSource::Fn(id) = src {
|
||||
// fetch the fully liberated fn signature (that is, all bound
|
||||
|
@ -758,7 +758,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
|
||||
Rvalue::Aggregate(ref kind, _) => {
|
||||
if let AggregateKind::Adt(def, ..) = *kind {
|
||||
if def.has_dtor() {
|
||||
if def.has_dtor(self.tcx) {
|
||||
self.add(Qualif::NEEDS_DROP);
|
||||
self.deny_drop();
|
||||
}
|
||||
@ -1042,7 +1042,7 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
|
||||
// Statics must be Sync.
|
||||
if mode == Mode::Static {
|
||||
let ty = mir.return_ty;
|
||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
|
||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||
fulfillment_cx.register_bound(&infcx, ty,
|
||||
|
@ -699,7 +699,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
|
||||
return;
|
||||
}
|
||||
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
|
||||
tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let mut checker = TypeChecker::new(&infcx, src.item_id());
|
||||
{
|
||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||
|
@ -138,7 +138,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
|
||||
self.check_const_eval(&body.value);
|
||||
}
|
||||
|
||||
let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
|
||||
let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
|
||||
let param_env = infcx.parameter_environment.clone();
|
||||
let outer_penv = mem::replace(&mut self.param_env, param_env);
|
||||
euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
|
||||
@ -274,7 +274,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
|
||||
/// instead of producing errors.
|
||||
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
|
||||
match node_ty.sty {
|
||||
ty::TyAdt(def, _) if def.has_dtor() => {
|
||||
ty::TyAdt(def, _) if def.has_dtor(v.tcx) => {
|
||||
v.promotable = false;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -38,7 +38,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RvalueContext<'a, 'tcx> {
|
||||
|
||||
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
|
||||
let body = self.tcx.hir.body(body_id);
|
||||
self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
|
||||
self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
|
||||
let mut delegate = RvalueContextDelegate {
|
||||
tcx: infcx.tcx,
|
||||
param_env: &infcx.parameter_environment
|
||||
|
@ -754,7 +754,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
||||
// If the type implements Drop, also add a translation item for the
|
||||
// monomorphized Drop::drop() implementation.
|
||||
let destructor_did = match ty.sty {
|
||||
ty::TyAdt(def, _) => def.destructor(),
|
||||
ty::TyAdt(def, _) => def.destructor(scx.tcx()),
|
||||
_ => None
|
||||
};
|
||||
|
||||
|
@ -237,7 +237,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
|
||||
bcx.call(dtor, &[ptr.llval], None);
|
||||
bcx
|
||||
}
|
||||
ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => {
|
||||
ty::TyAdt(def, ..) if def.has_dtor(bcx.tcx()) && !skip_dtor => {
|
||||
let shallow_drop = def.is_union();
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
|
||||
traits::VtableImpl(data) => data,
|
||||
_ => bug!("dtor for {:?} is not an impl???", t)
|
||||
};
|
||||
let dtor_did = def.destructor().unwrap();
|
||||
let dtor_did = def.destructor(tcx).unwrap();
|
||||
let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
|
||||
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
|
||||
let llret;
|
||||
|
@ -224,7 +224,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
trait_param_env,
|
||||
normalize_cause.clone());
|
||||
|
||||
tcx.infer_ctxt(trait_param_env, Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let inh = Inherited::new(infcx);
|
||||
let infcx = &inh.infcx;
|
||||
let fulfillment_cx = &inh.fulfillment_cx;
|
||||
@ -730,7 +730,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>) {
|
||||
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||
|
||||
// The below is for the most part highly similar to the procedure
|
||||
|
@ -80,7 +80,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
||||
// check that the impl type can be made to match the trait type.
|
||||
|
||||
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
|
||||
tcx.infer_ctxt(impl_param_env, Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let tcx = infcx.tcx;
|
||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||
|
||||
@ -554,7 +554,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
||||
// Find the `impl<..> Drop for _` to inspect any
|
||||
// attributes attached to the impl's generics.
|
||||
let dtor_method = adt_def.destructor()
|
||||
let dtor_method = adt_def.destructor(tcx)
|
||||
.expect("dtorck type without destructor impossible");
|
||||
let method = tcx.associated_item(dtor_method);
|
||||
let impl_def_id = method.container.id();
|
||||
|
@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
|
||||
// Read the inherent implementation candidates for this type from the
|
||||
// metadata if necessary.
|
||||
self.tcx.populate_inherent_implementations_for_type_if_necessary(def_id);
|
||||
self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id);
|
||||
|
||||
if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
|
||||
for &impl_def_id in impl_infos.iter() {
|
||||
|
@ -477,7 +477,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
|
||||
let tables = ty::TypeckTables::empty();
|
||||
let param_env = ParameterEnvironment::for_item(tcx, id);
|
||||
InheritedBuilder {
|
||||
infcx: tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable)
|
||||
infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,47 +26,38 @@ use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::hir::{self, ItemImpl};
|
||||
|
||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
|
||||
check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
|
||||
check_trait(
|
||||
tcx,
|
||||
tcx.lang_items.coerce_unsized_trait(),
|
||||
visit_implementation_of_coerce_unsized);
|
||||
pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
|
||||
Checker { tcx, trait_def_id }
|
||||
.check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
|
||||
.check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
|
||||
.check(tcx.lang_items.coerce_unsized_trait(),
|
||||
visit_implementation_of_coerce_unsized);
|
||||
}
|
||||
|
||||
fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
trait_def_id: Option<DefId>,
|
||||
mut f: F)
|
||||
where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
|
||||
{
|
||||
if let Some(trait_def_id) = trait_def_id {
|
||||
let mut impls = vec![];
|
||||
tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
|
||||
impls.push(did);
|
||||
});
|
||||
impls.sort();
|
||||
for impl_def_id in impls {
|
||||
f(tcx, trait_def_id, impl_def_id);
|
||||
struct Checker<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
trait_def_id: DefId
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||
fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
|
||||
where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
|
||||
{
|
||||
if Some(self.trait_def_id) == trait_def_id {
|
||||
for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
|
||||
let impl_def_id = self.tcx.hir.local_def_id(impl_id);
|
||||
f(self.tcx, self.trait_def_id, impl_def_id);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_drop_did: DefId,
|
||||
impl_did: DefId) {
|
||||
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;
|
||||
}
|
||||
let method_def_id = items[0];
|
||||
|
||||
let self_type = tcx.item_type(impl_did);
|
||||
match self_type.sty {
|
||||
ty::TyAdt(type_def, _) => {
|
||||
type_def.set_destructor(method_def_id);
|
||||
}
|
||||
match tcx.item_type(impl_did).sty {
|
||||
ty::TyAdt(..) => {}
|
||||
_ => {
|
||||
// Destructors only work on nominal types.
|
||||
if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
|
||||
@ -205,7 +196,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
source,
|
||||
target);
|
||||
|
||||
tcx.infer_ctxt(param_env, Reveal::ExactMatch).enter(|infcx| {
|
||||
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
|
||||
let cause = ObligationCause::misc(span, impl_node_id);
|
||||
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
|
||||
mt_b: ty::TypeAndMut<'tcx>,
|
||||
|
356
src/librustc_typeck/coherence/inherent.rs
Normal file
356
src/librustc_typeck/coherence/inherent.rs
Normal file
@ -0,0 +1,356 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir;
|
||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc::lint;
|
||||
use rustc::traits::{self, Reveal};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
struct InherentCollect<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item) {
|
||||
let (unsafety, ty) = match item.node {
|
||||
hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
|
||||
_ => return
|
||||
};
|
||||
|
||||
match unsafety {
|
||||
hir::Unsafety::Normal => {
|
||||
// OK
|
||||
}
|
||||
hir::Unsafety::Unsafe => {
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0197,
|
||||
"inherent impls cannot be declared as unsafe");
|
||||
}
|
||||
}
|
||||
|
||||
let def_id = self.tcx.hir.local_def_id(item.id);
|
||||
let self_ty = self.tcx.item_type(def_id);
|
||||
match self_ty.sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
self.check_def_id(item, def.did);
|
||||
}
|
||||
ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
|
||||
self.check_def_id(item, data.principal().unwrap().def_id());
|
||||
}
|
||||
ty::TyChar => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.char_impl(),
|
||||
"char",
|
||||
"char",
|
||||
item.span);
|
||||
}
|
||||
ty::TyStr => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.str_impl(),
|
||||
"str",
|
||||
"str",
|
||||
item.span);
|
||||
}
|
||||
ty::TySlice(_) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.slice_impl(),
|
||||
"slice",
|
||||
"[T]",
|
||||
item.span);
|
||||
}
|
||||
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.const_ptr_impl(),
|
||||
"const_ptr",
|
||||
"*const T",
|
||||
item.span);
|
||||
}
|
||||
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.mut_ptr_impl(),
|
||||
"mut_ptr",
|
||||
"*mut T",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I8) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i8_impl(),
|
||||
"i8",
|
||||
"i8",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I16) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i16_impl(),
|
||||
"i16",
|
||||
"i16",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I32) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i32_impl(),
|
||||
"i32",
|
||||
"i32",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I64) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i64_impl(),
|
||||
"i64",
|
||||
"i64",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I128) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i128_impl(),
|
||||
"i128",
|
||||
"i128",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::Is) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.isize_impl(),
|
||||
"isize",
|
||||
"isize",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U8) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u8_impl(),
|
||||
"u8",
|
||||
"u8",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U16) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u16_impl(),
|
||||
"u16",
|
||||
"u16",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U32) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u32_impl(),
|
||||
"u32",
|
||||
"u32",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U64) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u64_impl(),
|
||||
"u64",
|
||||
"u64",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U128) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u128_impl(),
|
||||
"u128",
|
||||
"u128",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::Us) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.usize_impl(),
|
||||
"usize",
|
||||
"usize",
|
||||
item.span);
|
||||
}
|
||||
ty::TyFloat(ast::FloatTy::F32) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.f32_impl(),
|
||||
"f32",
|
||||
"f32",
|
||||
item.span);
|
||||
}
|
||||
ty::TyFloat(ast::FloatTy::F64) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.f64_impl(),
|
||||
"f64",
|
||||
"f64",
|
||||
item.span);
|
||||
}
|
||||
ty::TyError => {
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
ty.span,
|
||||
E0118,
|
||||
"no base type found for inherent implementation")
|
||||
.span_label(ty.span, &format!("impl requires a base type"))
|
||||
.note(&format!("either implement a trait on it or create a newtype \
|
||||
to wrap it instead"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
|
||||
fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
|
||||
if def_id.is_local() {
|
||||
// Add the implementation to the mapping from implementation to base
|
||||
// type def ID, if there is a base type for this implementation and
|
||||
// the implementation does not have any associated traits.
|
||||
let impl_def_id = self.tcx.hir.local_def_id(item.id);
|
||||
|
||||
// Subtle: it'd be better to collect these into a local map
|
||||
// and then write the vector only once all items are known,
|
||||
// but that leads to degenerate dep-graphs. The problem is
|
||||
// that the write of that big vector winds up having reads
|
||||
// from *all* impls in the krate, since we've lost the
|
||||
// precision basically. This would be ok in the firewall
|
||||
// model so once we've made progess towards that we can modify
|
||||
// the strategy here. In the meantime, using `push` is ok
|
||||
// because we are doing this as a pre-pass before anyone
|
||||
// actually reads from `inherent_impls` -- and we know this is
|
||||
// true beacuse we hold the refcell lock.
|
||||
self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
|
||||
} else {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0116,
|
||||
"cannot define inherent `impl` for a type outside of the crate \
|
||||
where the type is defined")
|
||||
.span_label(item.span,
|
||||
&format!("impl for type defined outside of crate."))
|
||||
.note("define and implement a trait or new type instead")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_primitive_impl(&self,
|
||||
impl_def_id: DefId,
|
||||
lang_def_id: Option<DefId>,
|
||||
lang: &str,
|
||||
ty: &str,
|
||||
span: Span) {
|
||||
match lang_def_id {
|
||||
Some(lang_def_id) if lang_def_id == impl_def_id => {
|
||||
// OK
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
span,
|
||||
E0390,
|
||||
"only a single inherent implementation marked with `#[lang = \
|
||||
\"{}\"]` is allowed for the `{}` primitive",
|
||||
lang,
|
||||
ty)
|
||||
.span_help(span, "consider using a trait to implement these methods")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InherentOverlapChecker<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
|
||||
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum Namespace {
|
||||
Type,
|
||||
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_items1 = self.tcx.associated_item_def_ids(impl1);
|
||||
let impl_items2 = self.tcx.associated_item_def_ids(impl2);
|
||||
|
||||
for &item1 in &impl_items1[..] {
|
||||
let (name, namespace) = name_and_namespace(item1);
|
||||
|
||||
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.hir.as_local_node_id(item1).unwrap();
|
||||
self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
|
||||
node_id,
|
||||
self.tcx.span_of_impl(item1).unwrap(),
|
||||
msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
|
||||
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
|
||||
|
||||
let inherent_impls = self.tcx.maps.inherent_impls.borrow();
|
||||
let impls = match inherent_impls.get(&ty_def_id) {
|
||||
Some(impls) => impls,
|
||||
None => return,
|
||||
};
|
||||
|
||||
for (i, &impl1_def_id) in impls.iter().enumerate() {
|
||||
for &impl2_def_id in &impls[(i + 1)..] {
|
||||
self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
|
||||
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
|
||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||
match item.node {
|
||||
hir::ItemEnum(..) |
|
||||
hir::ItemStruct(..) |
|
||||
hir::ItemTrait(..) |
|
||||
hir::ItemUnion(..) => {
|
||||
let type_def_id = self.tcx.hir.local_def_id(item.id);
|
||||
self.check_for_overlapping_inherent_impls(type_def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
|
||||
&mut InherentCollect { tcx });
|
||||
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
|
||||
&mut InherentOverlapChecker { tcx });
|
||||
}
|
@ -15,147 +15,73 @@
|
||||
// done by the orphan and overlap modules. Then we build up various
|
||||
// mappings. That mapping code resides here.
|
||||
|
||||
use dep_graph::DepTrackingMap;
|
||||
use hir::def_id::DefId;
|
||||
use rustc::ty::{self, maps, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::{Ty, TyBool, TyChar, TyError};
|
||||
use rustc::ty::{TyParam, TyRawPtr};
|
||||
use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
|
||||
use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
|
||||
use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr};
|
||||
use rustc::ty::{TyProjection, TyAnon};
|
||||
use syntax_pos::Span;
|
||||
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
||||
use rustc::ty::maps::Providers;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc::hir::{Item, ItemImpl};
|
||||
use rustc::hir;
|
||||
use std::cell::RefMut;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
mod builtin;
|
||||
mod inherent;
|
||||
mod orphan;
|
||||
mod overlap;
|
||||
mod unsafety;
|
||||
|
||||
struct CoherenceCollect<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
inherent_impls: RefMut<'a, DepTrackingMap<maps::queries::inherent_impls<'tcx>>>,
|
||||
}
|
||||
fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
|
||||
let impl_def_id = tcx.hir.local_def_id(node_id);
|
||||
|
||||
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
|
||||
fn visit_item(&mut self, item: &Item) {
|
||||
if let ItemImpl(..) = item.node {
|
||||
self.check_implementation(item)
|
||||
// If there are no traits, then this implementation must have a
|
||||
// base type.
|
||||
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
|
||||
debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
|
||||
trait_ref,
|
||||
tcx.item_path_str(impl_def_id));
|
||||
|
||||
// Skip impls where one of the self type is an error type.
|
||||
// This occurs with e.g. resolve failures (#30589).
|
||||
if trait_ref.references_error() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
|
||||
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
|
||||
let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
|
||||
trait_def.record_local_impl(tcx, impl_def_id, trait_ref);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
|
||||
fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
let inherent_impls = tcx.maps.inherent_impls.borrow_mut();
|
||||
let mut this = &mut CoherenceCollect { tcx, inherent_impls };
|
||||
|
||||
// Check implementations and traits. This populates the tables
|
||||
// containing the inherent methods and extension methods. It also
|
||||
// builds up the trait inheritance table.
|
||||
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, this);
|
||||
}
|
||||
|
||||
// Returns the def ID of the base type, if there is one.
|
||||
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
|
||||
match ty.sty {
|
||||
TyAdt(def, _) => Some(def.did),
|
||||
|
||||
TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
|
||||
|
||||
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
|
||||
TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
|
||||
TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
|
||||
|
||||
TyInfer(..) | TyClosure(..) | TyAnon(..) => {
|
||||
// `ty` comes from a user declaration so we should only expect types
|
||||
// that the user can type
|
||||
span_bug!(span,
|
||||
"coherence encountered unexpected type searching for base type: {}",
|
||||
ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_implementation(&mut self, item: &Item) {
|
||||
let tcx = self.tcx;
|
||||
let impl_did = tcx.hir.local_def_id(item.id);
|
||||
let self_type = tcx.item_type(impl_did);
|
||||
|
||||
// If there are no traits, then this implementation must have a
|
||||
// base type.
|
||||
|
||||
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
|
||||
debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
|
||||
trait_ref,
|
||||
item.name);
|
||||
|
||||
// Skip impls where one of the self type is an error type.
|
||||
// This occurs with e.g. resolve failures (#30589).
|
||||
if trait_ref.references_error() {
|
||||
return;
|
||||
}
|
||||
|
||||
enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
|
||||
self.add_trait_impl(trait_ref, impl_did);
|
||||
} else {
|
||||
// Skip inherent impls where the self type is an error
|
||||
// type. This occurs with e.g. resolve failures (#30589).
|
||||
if self_type.references_error() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the implementation to the mapping from implementation to base
|
||||
// type def ID, if there is a base type for this implementation and
|
||||
// the implementation does not have any associated traits.
|
||||
if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) {
|
||||
self.add_inherent_impl(base_def_id, impl_did);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_inherent_impl(&mut self, base_def_id: DefId, impl_def_id: DefId) {
|
||||
// Subtle: it'd be better to collect these into a local map
|
||||
// and then write the vector only once all items are known,
|
||||
// but that leads to degenerate dep-graphs. The problem is
|
||||
// that the write of that big vector winds up having reads
|
||||
// from *all* impls in the krate, since we've lost the
|
||||
// precision basically. This would be ok in the firewall
|
||||
// model so once we've made progess towards that we can modify
|
||||
// the strategy here. In the meantime, using `push` is ok
|
||||
// because we are doing this as a pre-pass before anyone
|
||||
// actually reads from `inherent_impls` -- and we know this is
|
||||
// true beacuse we hold the refcell lock.
|
||||
self.inherent_impls.push(base_def_id, impl_def_id);
|
||||
}
|
||||
|
||||
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
|
||||
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
|
||||
impl_trait_ref,
|
||||
impl_def_id);
|
||||
let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
|
||||
trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
|
||||
}
|
||||
}
|
||||
|
||||
fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
|
||||
if tcx.sess.features.borrow().unboxed_closures {
|
||||
// the feature gate allows all of them
|
||||
return;
|
||||
}
|
||||
fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
|
||||
let did = Some(trait_def_id);
|
||||
let li = &tcx.lang_items;
|
||||
|
||||
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
||||
if did == li.sized_trait() {
|
||||
let span = tcx.span_of_impl(impl_def_id).unwrap();
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0322,
|
||||
"explicit impls for the `Sized` trait are not permitted")
|
||||
.span_label(span, &format!("impl of 'Sized' not allowed"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
if did == li.unsize_trait() {
|
||||
let span = tcx.span_of_impl(impl_def_id).unwrap();
|
||||
span_err!(tcx.sess,
|
||||
span,
|
||||
E0328,
|
||||
"explicit impls for the `Unsize` trait are not permitted");
|
||||
return;
|
||||
}
|
||||
|
||||
if tcx.sess.features.borrow().unboxed_closures {
|
||||
// the feature gate allows all Fn traits
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_name = if did == li.fn_trait() {
|
||||
"Fn"
|
||||
} else if did == li.fn_mut_trait() {
|
||||
@ -166,7 +92,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
|
||||
return; // everything OK
|
||||
};
|
||||
let mut err = struct_span_err!(tcx.sess,
|
||||
sp,
|
||||
tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0183,
|
||||
"manual implementations of `{}` are experimental",
|
||||
trait_name);
|
||||
@ -175,12 +101,41 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
|
||||
err.emit();
|
||||
}
|
||||
|
||||
pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
CoherenceCollect::check(tcx);
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
coherent_trait,
|
||||
coherent_inherent_impls,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
||||
fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
(_, def_id): (CrateNum, DefId)) {
|
||||
tcx.populate_implementations_for_trait_if_necessary(def_id);
|
||||
|
||||
let impls = tcx.hir.trait_impls(def_id);
|
||||
for &impl_id in impls {
|
||||
check_impl(tcx, impl_id);
|
||||
}
|
||||
for &impl_id in impls {
|
||||
overlap::check_impl(tcx, impl_id);
|
||||
}
|
||||
builtin::check_trait(tcx, def_id);
|
||||
}
|
||||
|
||||
fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) {
|
||||
inherent::check(tcx);
|
||||
}
|
||||
|
||||
pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
let _task = tcx.dep_graph.in_task(DepNode::Coherence);
|
||||
for &trait_def_id in tcx.hir.krate().trait_impls.keys() {
|
||||
ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id));
|
||||
}
|
||||
|
||||
unsafety::check(tcx);
|
||||
orphan::check(tcx);
|
||||
overlap::check(tcx);
|
||||
builtin::check(tcx);
|
||||
overlap::check_default_impls(tcx);
|
||||
|
||||
ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
|
||||
}
|
||||
|
@ -11,11 +11,8 @@
|
||||
//! Orphan checker: every impl either implements a trait defined in this
|
||||
//! crate or pertains to a type defined in this crate.
|
||||
|
||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc::hir;
|
||||
@ -29,46 +26,6 @@ struct OrphanChecker<'cx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
|
||||
fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
|
||||
if def_id.krate != LOCAL_CRATE {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0116,
|
||||
"cannot define inherent `impl` for a type outside of the crate \
|
||||
where the type is defined")
|
||||
.span_label(item.span,
|
||||
&format!("impl for type defined outside of crate."))
|
||||
.note("define and implement a trait or new type instead")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn check_primitive_impl(&self,
|
||||
impl_def_id: DefId,
|
||||
lang_def_id: Option<DefId>,
|
||||
lang: &str,
|
||||
ty: &str,
|
||||
span: Span) {
|
||||
match lang_def_id {
|
||||
Some(lang_def_id) if lang_def_id == impl_def_id => {
|
||||
// OK
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
span,
|
||||
E0390,
|
||||
"only a single inherent implementation marked with `#[lang = \
|
||||
\"{}\"]` is allowed for the `{}` primitive",
|
||||
lang,
|
||||
ty)
|
||||
.span_help(span, "consider using a trait to implement these methods")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
/// Checks exactly one impl for orphan rules and other such
|
||||
/// restrictions. In this fn, it can happen that multiple errors
|
||||
@ -78,168 +35,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item) {
|
||||
let def_id = self.tcx.hir.local_def_id(item.id);
|
||||
match item.node {
|
||||
hir::ItemImpl(.., None, ref ty, _) => {
|
||||
// For inherent impls, self type must be a nominal type
|
||||
// defined in this crate.
|
||||
debug!("coherence2::orphan check: inherent impl {}",
|
||||
self.tcx.hir.node_to_string(item.id));
|
||||
let self_ty = self.tcx.item_type(def_id);
|
||||
match self_ty.sty {
|
||||
ty::TyAdt(def, _) => {
|
||||
self.check_def_id(item, def.did);
|
||||
}
|
||||
ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
|
||||
self.check_def_id(item, data.principal().unwrap().def_id());
|
||||
}
|
||||
ty::TyChar => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.char_impl(),
|
||||
"char",
|
||||
"char",
|
||||
item.span);
|
||||
}
|
||||
ty::TyStr => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.str_impl(),
|
||||
"str",
|
||||
"str",
|
||||
item.span);
|
||||
}
|
||||
ty::TySlice(_) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.slice_impl(),
|
||||
"slice",
|
||||
"[T]",
|
||||
item.span);
|
||||
}
|
||||
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.const_ptr_impl(),
|
||||
"const_ptr",
|
||||
"*const T",
|
||||
item.span);
|
||||
}
|
||||
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.mut_ptr_impl(),
|
||||
"mut_ptr",
|
||||
"*mut T",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I8) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i8_impl(),
|
||||
"i8",
|
||||
"i8",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I16) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i16_impl(),
|
||||
"i16",
|
||||
"i16",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I32) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i32_impl(),
|
||||
"i32",
|
||||
"i32",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I64) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i64_impl(),
|
||||
"i64",
|
||||
"i64",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::I128) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.i128_impl(),
|
||||
"i128",
|
||||
"i128",
|
||||
item.span);
|
||||
}
|
||||
ty::TyInt(ast::IntTy::Is) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.isize_impl(),
|
||||
"isize",
|
||||
"isize",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U8) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u8_impl(),
|
||||
"u8",
|
||||
"u8",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U16) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u16_impl(),
|
||||
"u16",
|
||||
"u16",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U32) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u32_impl(),
|
||||
"u32",
|
||||
"u32",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U64) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u64_impl(),
|
||||
"u64",
|
||||
"u64",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::U128) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.u128_impl(),
|
||||
"u128",
|
||||
"u128",
|
||||
item.span);
|
||||
}
|
||||
ty::TyUint(ast::UintTy::Us) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.usize_impl(),
|
||||
"usize",
|
||||
"usize",
|
||||
item.span);
|
||||
}
|
||||
ty::TyFloat(ast::FloatTy::F32) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.f32_impl(),
|
||||
"f32",
|
||||
"f32",
|
||||
item.span);
|
||||
}
|
||||
ty::TyFloat(ast::FloatTy::F64) => {
|
||||
self.check_primitive_impl(def_id,
|
||||
self.tcx.lang_items.f64_impl(),
|
||||
"f64",
|
||||
"f64",
|
||||
item.span);
|
||||
}
|
||||
ty::TyError => {
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
ty.span,
|
||||
E0118,
|
||||
"no base type found for inherent implementation")
|
||||
.span_label(ty.span, &format!("impl requires a base type"))
|
||||
.note(&format!("either implement a trait on it or create a newtype \
|
||||
to wrap it instead"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemImpl(.., Some(_), _, _) => {
|
||||
// "Trait" impl
|
||||
debug!("coherence2::orphan check: trait impl {}",
|
||||
@ -311,7 +106,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
trait_def_id,
|
||||
self.tcx.trait_has_default_impl(trait_def_id));
|
||||
if self.tcx.trait_has_default_impl(trait_def_id) &&
|
||||
trait_def_id.krate != LOCAL_CRATE {
|
||||
!trait_def_id.is_local() {
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let opt_self_def_id = match self_ty.sty {
|
||||
ty::TyAdt(self_def, _) => Some(self_def.did),
|
||||
@ -346,31 +141,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow *all* explicit impls of `Sized` and `Unsize` for now.
|
||||
if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0322,
|
||||
"explicit impls for the `Sized` trait are not permitted")
|
||||
.span_label(item.span, &format!("impl of 'Sized' not allowed"))
|
||||
.emit();
|
||||
return;
|
||||
}
|
||||
if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0328,
|
||||
"explicit impls for the `Unsize` trait are not permitted");
|
||||
return;
|
||||
}
|
||||
}
|
||||
hir::ItemDefaultImpl(_, ref item_trait_ref) => {
|
||||
// "Trait" impl
|
||||
debug!("coherence2::orphan check: default trait impl {}",
|
||||
self.tcx.hir.node_to_string(item.id));
|
||||
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
||||
if trait_ref.def_id.krate != LOCAL_CRATE {
|
||||
if !trait_ref.def_id.is_local() {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
item_trait_ref.path.span,
|
||||
E0318,
|
||||
|
@ -12,102 +12,101 @@
|
||||
//! same type. Likewise, no two inherent impls for a given type
|
||||
//! constructor provide a method with the same name.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc::traits::{self, Reveal};
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
||||
use syntax::ast;
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::hir;
|
||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
use util::nodemap::DefIdMap;
|
||||
use lint;
|
||||
|
||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
let mut overlap = OverlapChecker {
|
||||
tcx: tcx,
|
||||
default_impls: DefIdMap(),
|
||||
};
|
||||
pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
let mut overlap = OverlapChecker { tcx };
|
||||
|
||||
// this secondary walk specifically checks for some other cases,
|
||||
// like defaulted traits, for which additional overlap rules exist
|
||||
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
|
||||
}
|
||||
|
||||
struct OverlapChecker<'cx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
|
||||
let impl_def_id = tcx.hir.local_def_id(node_id);
|
||||
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
|
||||
// maps from a trait def-id to an impl id
|
||||
default_impls: DefIdMap<ast::NodeId>,
|
||||
if trait_ref.references_error() {
|
||||
debug!("coherence: skipping impl {:?} with error {:?}",
|
||||
impl_def_id, trait_ref);
|
||||
return
|
||||
}
|
||||
|
||||
let _task =
|
||||
tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
|
||||
|
||||
let def = tcx.lookup_trait_def(trait_def_id);
|
||||
|
||||
// attempt to insert into the specialization graph
|
||||
let insert_result = def.add_impl_for_specialization(tcx, impl_def_id);
|
||||
|
||||
// insertion failed due to overlap
|
||||
if let Err(overlap) = insert_result {
|
||||
let mut err = struct_span_err!(tcx.sess,
|
||||
tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0119,
|
||||
"conflicting implementations of trait `{}`{}:",
|
||||
overlap.trait_desc,
|
||||
overlap.self_desc.clone().map_or(String::new(),
|
||||
|ty| {
|
||||
format!(" for type `{}`", ty)
|
||||
}));
|
||||
|
||||
match tcx.span_of_impl(overlap.with_impl) {
|
||||
Ok(span) => {
|
||||
err.span_label(span, &format!("first implementation here"));
|
||||
err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
&format!("conflicting implementation{}",
|
||||
overlap.self_desc
|
||||
.map_or(String::new(),
|
||||
|ty| format!(" for `{}`", ty))));
|
||||
}
|
||||
Err(cname) => {
|
||||
err.note(&format!("conflicting implementation in crate `{}`", cname));
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
// check for overlap with the automatic `impl Trait for Trait`
|
||||
if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
|
||||
// This is something like impl Trait1 for Trait2. Illegal
|
||||
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
|
||||
|
||||
if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) {
|
||||
// This is an error, but it will be reported by wfcheck. Ignore it here.
|
||||
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
|
||||
} else {
|
||||
let mut supertrait_def_ids =
|
||||
traits::supertrait_def_ids(tcx,
|
||||
data.principal().unwrap().def_id());
|
||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||
span_err!(tcx.sess,
|
||||
tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0371,
|
||||
"the object type `{}` automatically \
|
||||
implements the trait `{}`",
|
||||
trait_ref.self_ty(),
|
||||
tcx.item_path_str(trait_def_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
||||
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum Namespace {
|
||||
Type,
|
||||
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_items1 = self.tcx.associated_item_def_ids(impl1);
|
||||
let impl_items2 = self.tcx.associated_item_def_ids(impl2);
|
||||
|
||||
for &item1 in &impl_items1[..] {
|
||||
let (name, namespace) = name_and_namespace(item1);
|
||||
|
||||
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.hir.as_local_node_id(item1).unwrap();
|
||||
self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
|
||||
node_id,
|
||||
self.tcx.span_of_impl(item1).unwrap(),
|
||||
msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
|
||||
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
|
||||
|
||||
let inherent_impls = self.tcx.maps.inherent_impls.borrow();
|
||||
let impls = match inherent_impls.get(&ty_def_id) {
|
||||
Some(impls) => impls,
|
||||
None => return,
|
||||
};
|
||||
|
||||
for (i, &impl1_def_id) in impls.iter().enumerate() {
|
||||
for &impl2_def_id in &impls[(i + 1)..] {
|
||||
self.tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
|
||||
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
|
||||
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
struct OverlapChecker<'cx, 'tcx: 'cx> {
|
||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||
match item.node {
|
||||
hir::ItemEnum(..) |
|
||||
hir::ItemStruct(..) |
|
||||
hir::ItemTrait(..) |
|
||||
hir::ItemUnion(..) => {
|
||||
let type_def_id = self.tcx.hir.local_def_id(item.id);
|
||||
self.check_for_overlapping_inherent_impls(type_def_id);
|
||||
}
|
||||
|
||||
hir::ItemDefaultImpl(..) => {
|
||||
// look for another default impl; note that due to the
|
||||
// general orphan/coherence rules, it must always be
|
||||
@ -115,8 +114,8 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
let impl_def_id = self.tcx.hir.local_def_id(item.id);
|
||||
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
|
||||
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
|
||||
if let Some(prev_id) = prev_default_impl {
|
||||
let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
|
||||
if prev_id != item.id {
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0521,
|
||||
@ -131,76 +130,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
hir::ItemImpl(.., Some(_), _, _) => {
|
||||
let impl_def_id = self.tcx.hir.local_def_id(item.id);
|
||||
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||
let trait_def_id = trait_ref.def_id;
|
||||
|
||||
if trait_ref.references_error() {
|
||||
debug!("coherence: skipping impl {:?} with error {:?}",
|
||||
impl_def_id, trait_ref);
|
||||
return
|
||||
}
|
||||
|
||||
let _task =
|
||||
self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
|
||||
|
||||
let def = self.tcx.lookup_trait_def(trait_def_id);
|
||||
|
||||
// attempt to insert into the specialization graph
|
||||
let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
|
||||
|
||||
// insertion failed due to overlap
|
||||
if let Err(overlap) = insert_result {
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
E0119,
|
||||
"conflicting implementations of trait `{}`{}:",
|
||||
overlap.trait_desc,
|
||||
overlap.self_desc.clone().map_or(String::new(),
|
||||
|ty| {
|
||||
format!(" for type `{}`", ty)
|
||||
}));
|
||||
|
||||
match self.tcx.span_of_impl(overlap.with_impl) {
|
||||
Ok(span) => {
|
||||
err.span_label(span, &format!("first implementation here"));
|
||||
err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||
&format!("conflicting implementation{}",
|
||||
overlap.self_desc
|
||||
.map_or(String::new(),
|
||||
|ty| format!(" for `{}`", ty))));
|
||||
}
|
||||
Err(cname) => {
|
||||
err.note(&format!("conflicting implementation in crate `{}`", cname));
|
||||
}
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
|
||||
// check for overlap with the automatic `impl Trait for Trait`
|
||||
if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
|
||||
// This is something like impl Trait1 for Trait2. Illegal
|
||||
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
|
||||
|
||||
if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) {
|
||||
// This is an error, but it will be reported by wfcheck. Ignore it here.
|
||||
// This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
|
||||
} else {
|
||||
let mut supertrait_def_ids =
|
||||
traits::supertrait_def_ids(self.tcx,
|
||||
data.principal().unwrap().def_id());
|
||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0371,
|
||||
"the object type `{}` automatically \
|
||||
implements the trait `{}`",
|
||||
trait_ref.self_ty(),
|
||||
self.tcx.item_path_str(trait_def_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -31,20 +31,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> {
|
||||
unsafety: hir::Unsafety,
|
||||
polarity: hir::ImplPolarity) {
|
||||
match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
|
||||
None => {
|
||||
// Inherent impl.
|
||||
match unsafety {
|
||||
hir::Unsafety::Normal => {
|
||||
// OK
|
||||
}
|
||||
hir::Unsafety::Unsafe => {
|
||||
span_err!(self.tcx.sess,
|
||||
item.span,
|
||||
E0197,
|
||||
"inherent impls cannot be declared as unsafe");
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
|
||||
Some(trait_ref) => {
|
||||
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
|
||||
@ -100,7 +87,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for UnsafetyChecker<'cx, 'tcx> {
|
||||
hir::ItemDefaultImpl(unsafety, _) => {
|
||||
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
|
||||
}
|
||||
hir::ItemImpl(unsafety, polarity, ref generics, ..) => {
|
||||
hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => {
|
||||
self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -519,9 +519,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
|
||||
convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
|
||||
},
|
||||
hir::ItemDefaultImpl(..) => {
|
||||
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
|
||||
tcx.record_trait_has_default_impl(trait_ref.def_id);
|
||||
}
|
||||
tcx.impl_trait_ref(def_id);
|
||||
}
|
||||
hir::ItemImpl(..) => {
|
||||
tcx.item_generics(def_id);
|
||||
@ -869,7 +867,13 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
|
||||
tcx.alloc_trait_def(ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash))
|
||||
let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash);
|
||||
|
||||
if tcx.hir.trait_is_auto(def_id) {
|
||||
def.record_has_default_impl();
|
||||
}
|
||||
|
||||
tcx.alloc_trait_def(def)
|
||||
}
|
||||
|
||||
fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
@ -155,7 +155,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>)
|
||||
-> bool {
|
||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
||||
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||
match infcx.eq_types(false, &cause, expected, actual) {
|
||||
Ok(InferOk { obligations, .. }) => {
|
||||
// FIXME(#32730) propagate obligations
|
||||
@ -287,6 +287,7 @@ fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
collect::provide(providers);
|
||||
coherence::provide(providers);
|
||||
check::provide(providers);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ use std::io;
|
||||
use std::iter::once;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax_pos::DUMMY_SP;
|
||||
use rustc::hir;
|
||||
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
@ -231,7 +232,7 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef {
|
||||
|
||||
pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
|
||||
let tcx = cx.tcx;
|
||||
tcx.populate_inherent_implementations_for_type_if_necessary(did);
|
||||
tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did);
|
||||
let mut impls = Vec::new();
|
||||
|
||||
if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
|
||||
|
@ -12,6 +12,8 @@ impl Drop for u32 {} //~ ERROR E0117
|
||||
//~^ NOTE impl doesn't use types inside crate
|
||||
//~| NOTE the impl does not reference any types defined in this crate
|
||||
//~| NOTE define and implement a trait or new type instead
|
||||
//~| ERROR the Drop trait may only be implemented on structures
|
||||
//~| implementing Drop requires a struct
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use trait_impl_conflict::Foo;
|
||||
|
||||
impl<A> Foo for A {
|
||||
//~^ ERROR type parameter `A` must be used as the type parameter for some local type
|
||||
//~| ERROR conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -13,9 +13,9 @@
|
||||
trait MyTrait {}
|
||||
|
||||
impl MyTrait for .. {}
|
||||
//~^ ERROR redundant default implementations of trait `MyTrait`
|
||||
|
||||
impl MyTrait for .. {}
|
||||
//~^ ERROR redundant default implementations of trait `MyTrait`
|
||||
|
||||
trait MySafeTrait {}
|
||||
|
||||
|
@ -27,14 +27,20 @@ impl Sized for TestE {} //~ ERROR E0322
|
||||
impl Sized for MyType {} //~ ERROR E0322
|
||||
//~^ impl of 'Sized' not allowed
|
||||
|
||||
impl Sized for (MyType, MyType) {} //~ ERROR E0117
|
||||
impl Sized for (MyType, MyType) {} //~ ERROR E0322
|
||||
//~^ impl of 'Sized' not allowed
|
||||
//~| ERROR E0117
|
||||
|
||||
impl Sized for &'static NotSync {} //~ ERROR E0322
|
||||
//~^ impl of 'Sized' not allowed
|
||||
|
||||
impl Sized for [MyType] {} //~ ERROR E0117
|
||||
impl Sized for [MyType] {} //~ ERROR E0322
|
||||
//~^ impl of 'Sized' not allowed
|
||||
//~| ERROR E0117
|
||||
|
||||
impl Sized for &'static [NotSync] {} //~ ERROR E0117
|
||||
impl Sized for &'static [NotSync] {} //~ ERROR E0322
|
||||
//~^ impl of 'Sized' not allowed
|
||||
//~| ERROR E0117
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -7,15 +7,6 @@ error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
15 | impl Copy for Foo { }
|
||||
| ^^^^
|
||||
|
||||
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
--> $DIR/E0204.rs:27:6
|
||||
|
|
||||
23 | Bar { x: Vec<u32> },
|
||||
| ----------- this field does not implement `Copy`
|
||||
...
|
||||
27 | impl Copy for EFoo { }
|
||||
| ^^^^
|
||||
|
||||
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
--> $DIR/E0204.rs:17:10
|
||||
|
|
||||
@ -25,6 +16,15 @@ error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
19 | ty: &'a mut bool,
|
||||
| ---------------- this field does not implement `Copy`
|
||||
|
||||
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
--> $DIR/E0204.rs:27:6
|
||||
|
|
||||
23 | Bar { x: Vec<u32> },
|
||||
| ----------- this field does not implement `Copy`
|
||||
...
|
||||
27 | impl Copy for EFoo { }
|
||||
| ^^^^
|
||||
|
||||
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||
--> $DIR/E0204.rs:29:10
|
||||
|
|
||||
|
Loading…
Reference in New Issue
Block a user