rustc_typeck: rework coherence to be almost completely on-demand.

This commit is contained in:
Eduard-Mihai Burtescu 2017-02-19 14:46:29 +02:00
parent 9890e0466d
commit c832e6f327
53 changed files with 836 additions and 682 deletions

View File

@ -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),

View File

@ -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),

View File

@ -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.

View File

@ -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 {

View File

@ -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),

View File

@ -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 }

View File

@ -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,

View File

@ -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()

View File

@ -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 =

View File

@ -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);

View File

@ -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;
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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,
}
}

View File

@ -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)
});

View File

@ -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

View File

@ -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)

View File

@ -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",

View File

@ -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 {:?}",

View File

@ -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() =>

View File

@ -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

View File

@ -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,
};

View File

@ -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());

View File

@ -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();

View File

@ -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);

View File

@ -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.

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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;
}
_ => {}

View File

@ -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

View File

@ -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
};

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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() {

View File

@ -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)
}
}
}

View File

@ -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>,

View 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 });
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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));
}
}
}
}
_ => {}
}

View File

@ -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);
}
_ => {}

View File

@ -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>,

View File

@ -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);
}

View File

@ -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) {

View File

@ -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() {
}

View File

@ -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() {

View File

@ -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 {}

View File

@ -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() {
}

View File

@ -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
|