rustc_typeck: rework coherence to be almost completely on-demand.
This commit is contained in:
parent
9890e0466d
commit
c832e6f327
53 changed files with 836 additions and 682 deletions
|
@ -70,6 +70,7 @@ pub enum DepNode<D: Clone + Debug> {
|
||||||
Resolve,
|
Resolve,
|
||||||
EntryPoint,
|
EntryPoint,
|
||||||
CheckEntryFn,
|
CheckEntryFn,
|
||||||
|
CoherenceCheckTrait(D),
|
||||||
CoherenceCheckImpl(D),
|
CoherenceCheckImpl(D),
|
||||||
CoherenceOverlapCheck(D),
|
CoherenceOverlapCheck(D),
|
||||||
CoherenceOverlapCheckSpecial(D),
|
CoherenceOverlapCheckSpecial(D),
|
||||||
|
@ -241,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
||||||
MetaData(ref d) => op(d).map(MetaData),
|
MetaData(ref d) => op(d).map(MetaData),
|
||||||
CollectItem(ref d) => op(d).map(CollectItem),
|
CollectItem(ref d) => op(d).map(CollectItem),
|
||||||
CollectItemSig(ref d) => op(d).map(CollectItemSig),
|
CollectItemSig(ref d) => op(d).map(CollectItemSig),
|
||||||
|
CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
|
||||||
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
|
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
|
||||||
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
|
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
|
||||||
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
|
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
|
||||||
|
|
|
@ -80,6 +80,9 @@ pub struct LoweringContext<'a> {
|
||||||
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
|
||||||
bodies: FxHashMap<hir::BodyId, hir::Body>,
|
bodies: FxHashMap<hir::BodyId, hir::Body>,
|
||||||
|
|
||||||
|
trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||||
|
trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||||
|
|
||||||
loop_scopes: Vec<NodeId>,
|
loop_scopes: Vec<NodeId>,
|
||||||
is_in_loop_condition: bool,
|
is_in_loop_condition: bool,
|
||||||
|
|
||||||
|
@ -116,6 +119,8 @@ pub fn lower_crate(sess: &Session,
|
||||||
trait_items: BTreeMap::new(),
|
trait_items: BTreeMap::new(),
|
||||||
impl_items: BTreeMap::new(),
|
impl_items: BTreeMap::new(),
|
||||||
bodies: FxHashMap(),
|
bodies: FxHashMap(),
|
||||||
|
trait_impls: BTreeMap::new(),
|
||||||
|
trait_default_impl: BTreeMap::new(),
|
||||||
loop_scopes: Vec::new(),
|
loop_scopes: Vec::new(),
|
||||||
is_in_loop_condition: false,
|
is_in_loop_condition: false,
|
||||||
type_def_lifetime_params: DefIdMap(),
|
type_def_lifetime_params: DefIdMap(),
|
||||||
|
@ -201,6 +206,8 @@ impl<'a> LoweringContext<'a> {
|
||||||
trait_items: self.trait_items,
|
trait_items: self.trait_items,
|
||||||
impl_items: self.impl_items,
|
impl_items: self.impl_items,
|
||||||
bodies: self.bodies,
|
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))
|
hir::ItemUnion(vdata, self.lower_generics(generics))
|
||||||
}
|
}
|
||||||
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
|
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),
|
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) => {
|
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
|
||||||
let new_impl_items = impl_items.iter()
|
let new_impl_items = impl_items.iter()
|
||||||
.map(|item| self.lower_impl_item_ref(item))
|
.map(|item| self.lower_impl_item_ref(item))
|
||||||
.collect();
|
.collect();
|
||||||
let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
|
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),
|
hir::ItemImpl(self.lower_unsafety(unsafety),
|
||||||
self.lower_impl_polarity(polarity),
|
self.lower_impl_polarity(polarity),
|
||||||
self.lower_generics(generics),
|
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
|
/// Get the attributes on the krate. This is preferable to
|
||||||
/// invoking `krate.attrs` because it registers a tighter
|
/// invoking `krate.attrs` because it registers a tighter
|
||||||
/// dep-graph access.
|
/// dep-graph access.
|
||||||
|
|
|
@ -410,6 +410,9 @@ pub struct Crate {
|
||||||
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
|
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
|
||||||
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
|
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
|
||||||
pub bodies: FxHashMap<BodyId, Body>,
|
pub bodies: FxHashMap<BodyId, Body>,
|
||||||
|
|
||||||
|
pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
|
||||||
|
pub trait_default_impl: BTreeMap<DefId, NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Crate {
|
impl Crate {
|
||||||
|
|
|
@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
|
||||||
evaluation_cache: traits::EvaluationCache::new(),
|
evaluation_cache: traits::EvaluationCache::new(),
|
||||||
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
projection_cache: RefCell::new(traits::ProjectionCache::new()),
|
||||||
reported_trait_errors: RefCell::new(FxHashSet()),
|
reported_trait_errors: RefCell::new(FxHashSet()),
|
||||||
projection_mode: Reveal::NotSpecializable,
|
projection_mode: Reveal::UserFacing,
|
||||||
tainted_by_errors_flag: Cell::new(false),
|
tainted_by_errors_flag: Cell::new(false),
|
||||||
err_count_on_creation: self.sess.err_count(),
|
err_count_on_creation: self.sess.err_count(),
|
||||||
obligations_in_snapshot: Cell::new(false),
|
obligations_in_snapshot: Cell::new(false),
|
||||||
|
|
|
@ -191,7 +191,6 @@ pub trait CrateStore {
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
fn is_const_fn(&self, did: DefId) -> bool;
|
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_default_impl(&self, impl_did: DefId) -> bool;
|
||||||
fn is_foreign_item(&self, did: DefId) -> bool;
|
fn is_foreign_item(&self, did: DefId) -> bool;
|
||||||
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
|
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
|
||||||
|
@ -327,7 +326,6 @@ impl CrateStore for DummyCrateStore {
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
|
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_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_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
|
||||||
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
|
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);
|
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,
|
let predicates = match fully_normalize(&infcx, cause,
|
||||||
&infcx.parameter_environment.caller_bounds) {
|
&infcx.parameter_environment.caller_bounds) {
|
||||||
Ok(predicates) => predicates,
|
Ok(predicates) => predicates,
|
||||||
|
|
|
@ -38,36 +38,6 @@ use util::common::FN_OUTPUT_NAME;
|
||||||
/// more or less conservative.
|
/// more or less conservative.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum Reveal {
|
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
|
/// At type-checking time, we refuse to project any associated
|
||||||
/// type that is marked `default`. Non-`default` ("final") types
|
/// type that is marked `default`. Non-`default` ("final") types
|
||||||
/// are always projected. This is necessary in general for
|
/// are always projected. This is necessary in general for
|
||||||
|
@ -90,7 +60,7 @@ pub enum Reveal {
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let <() as Assoc>::Output = true;
|
/// let <() as Assoc>::Output = true;
|
||||||
/// }
|
/// }
|
||||||
NotSpecializable,
|
UserFacing,
|
||||||
|
|
||||||
/// At trans time, all monomorphic projections will succeed.
|
/// At trans time, all monomorphic projections will succeed.
|
||||||
/// Also, `impl Trait` is normalized to the concrete type,
|
/// 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>>
|
-> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
|
||||||
{
|
{
|
||||||
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
|
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);
|
let impl_node = specialization_graph::Node::Impl(impl_def_id);
|
||||||
for item in impl_node.items(selcx.tcx()) {
|
for item in impl_node.items(selcx.tcx()) {
|
||||||
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
|
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
|
||||||
|
@ -1360,7 +1331,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
selcx.tcx().lookup_trait_def(trait_def_id)
|
trait_def
|
||||||
.ancestors(impl_def_id)
|
.ancestors(impl_def_id)
|
||||||
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
|
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
|
||||||
.next()
|
.next()
|
||||||
|
|
|
@ -189,7 +189,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
.subst(tcx, &penv.free_substs);
|
.subst(tcx, &penv.free_substs);
|
||||||
|
|
||||||
// Create a infcx, taking the predicates of impl1 as assumptions:
|
// 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
|
// Normalize the trait reference. The WF rules ought to ensure
|
||||||
// that this always succeeds.
|
// that this always succeeds.
|
||||||
let impl1_trait_ref =
|
let impl1_trait_ref =
|
||||||
|
|
|
@ -108,7 +108,7 @@ impl<'a, 'gcx, 'tcx> Children {
|
||||||
let possible_sibling = *slot;
|
let possible_sibling = *slot;
|
||||||
|
|
||||||
let tcx = tcx.global_tcx();
|
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,
|
let overlap = traits::overlapping_impls(&infcx,
|
||||||
possible_sibling,
|
possible_sibling,
|
||||||
impl_def_id);
|
impl_def_id);
|
||||||
|
|
|
@ -219,7 +219,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||||
res = res - TC::OwnsDtor;
|
res = res - TC::OwnsDtor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if def.has_dtor() {
|
if def.has_dtor(tcx) {
|
||||||
res = res | TC::OwnsDtor;
|
res = res | TC::OwnsDtor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,15 @@ trait Key {
|
||||||
fn default_span(&self, tcx: TyCtxt) -> Span;
|
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 {
|
impl Key for DefId {
|
||||||
fn map_crate(&self) -> CrateNum {
|
fn map_crate(&self) -> CrateNum {
|
||||||
self.krate
|
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 {
|
trait Value<'tcx>: Sized {
|
||||||
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
|
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 {
|
macro_rules! define_maps {
|
||||||
(<$tcx:tt>
|
(<$tcx:tt>
|
||||||
$($(#[$attr:meta])*
|
$($(#[$attr:meta])*
|
||||||
|
@ -238,6 +269,12 @@ macro_rules! define_maps {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) {
|
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, |_| ()) {
|
match Self::try_get_with(tcx, span, key, |_| ()) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => tcx.report_cycle(e)
|
Err(e) => tcx.report_cycle(e)
|
||||||
|
@ -338,7 +375,19 @@ define_maps! { <'tcx>
|
||||||
|
|
||||||
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'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
|
/// Results of evaluating monomorphic constants embedded in
|
||||||
/// other items, such as enum variant explicit discriminants.
|
/// other items, such as enum variant explicit discriminants.
|
||||||
pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal, ()>
|
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_FUNDAMENTAL = 1 << 4,
|
||||||
const IS_UNION = 1 << 5,
|
const IS_UNION = 1 << 5,
|
||||||
const IS_BOX = 1 << 6,
|
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.
|
/// Returns whether this type has a destructor.
|
||||||
pub fn has_dtor(&self) -> bool {
|
pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||||
self.destructor.get().is_some()
|
self.destructor(tcx).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts this is a struct and returns the struct's unique
|
/// 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> {
|
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
|
||||||
self.destructor.get()
|
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) {
|
fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
|
||||||
self.destructor.set(Some(dtor));
|
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>)
|
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 {
|
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);
|
let def = self.lookup_trait_def(trait_def_id);
|
||||||
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
|
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
|
/// Populates the type context with all the inherent implementations for
|
||||||
/// the given type if necessary.
|
/// the given type if necessary.
|
||||||
pub fn populate_inherent_implementations_for_type_if_necessary(self,
|
pub fn populate_inherent_implementations_for_type_if_necessary(self,
|
||||||
|
span: Span,
|
||||||
type_id: DefId) {
|
type_id: DefId) {
|
||||||
if type_id.is_local() {
|
if type_id.is_local() {
|
||||||
|
// Make sure coherence of inherent impls ran already.
|
||||||
|
ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2416,16 +2436,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
let _ignore = self.dep_graph.in_ignore();
|
let _ignore = self.dep_graph.in_ignore();
|
||||||
|
|
||||||
let def = self.lookup_trait_def(trait_id);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
|
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)) {
|
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();
|
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.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 {
|
pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use dep_graph::DepNode;
|
use dep_graph::DepNode;
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use traits::{self, specialization_graph};
|
use traits::{self, specialization_graph};
|
||||||
use ty;
|
use ty;
|
||||||
use ty::fast_reject;
|
use ty::fast_reject;
|
||||||
|
@ -18,6 +18,9 @@ use std::cell::{Cell, RefCell};
|
||||||
use hir;
|
use hir;
|
||||||
use util::nodemap::FxHashMap;
|
use util::nodemap::FxHashMap;
|
||||||
|
|
||||||
|
use syntax::ast;
|
||||||
|
use syntax_pos::DUMMY_SP;
|
||||||
|
|
||||||
/// A trait's definition with type information.
|
/// A trait's definition with type information.
|
||||||
pub struct TraitDef {
|
pub struct TraitDef {
|
||||||
pub def_id: DefId,
|
pub def_id: DefId,
|
||||||
|
@ -60,6 +63,11 @@ pub struct TraitDef {
|
||||||
/// Various flags
|
/// Various flags
|
||||||
pub flags: Cell<TraitFlags>,
|
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
|
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
|
||||||
/// recomputed all the time.
|
/// recomputed all the time.
|
||||||
pub def_path_hash: u64,
|
pub def_path_hash: u64,
|
||||||
|
@ -78,6 +86,7 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||||
nonblanket_impls: RefCell::new(FxHashMap()),
|
nonblanket_impls: RefCell::new(FxHashMap()),
|
||||||
blanket_impls: RefCell::new(vec![]),
|
blanket_impls: RefCell::new(vec![]),
|
||||||
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
|
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
|
||||||
|
local_impl_count: Cell::new(0),
|
||||||
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
|
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
|
||||||
def_path_hash: def_path_hash,
|
def_path_hash: def_path_hash,
|
||||||
}
|
}
|
||||||
|
@ -155,6 +164,13 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||||
assert!(impl_def_id.is_local());
|
assert!(impl_def_id.is_local());
|
||||||
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
|
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
|
||||||
assert!(was_new);
|
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.
|
/// 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)
|
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) {
|
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
|
||||||
self.read_trait_impls(tcx);
|
self.read_trait_impls(tcx);
|
||||||
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
|
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() {
|
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||||
f(impl_def_id);
|
f(impl_def_id);
|
||||||
}
|
}
|
||||||
|
@ -217,9 +274,20 @@ impl<'a, 'gcx, 'tcx> TraitDef {
|
||||||
mut f: F)
|
mut f: F)
|
||||||
{
|
{
|
||||||
self.read_trait_impls(tcx);
|
self.read_trait_impls(tcx);
|
||||||
|
|
||||||
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
|
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() {
|
for &impl_def_id in self.blanket_impls.borrow().iter() {
|
||||||
f(impl_def_id);
|
f(impl_def_id);
|
||||||
}
|
}
|
||||||
|
@ -258,6 +326,7 @@ bitflags! {
|
||||||
const HAS_DEFAULT_IMPL = 1 << 0,
|
const HAS_DEFAULT_IMPL = 1 << 0,
|
||||||
const IS_OBJECT_SAFE = 1 << 1,
|
const IS_OBJECT_SAFE = 1 << 1,
|
||||||
const OBJECT_SAFETY_VALID = 1 << 2,
|
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)
|
self_type: Ty<'tcx>, span: Span)
|
||||||
-> Result<(), CopyImplementationError> {
|
-> Result<(), CopyImplementationError> {
|
||||||
// FIXME: (@jroesch) float this code up
|
// 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 {
|
let (adt, substs) = match self_type.sty {
|
||||||
ty::TyAdt(adt, substs) => (adt, substs),
|
ty::TyAdt(adt, substs) => (adt, substs),
|
||||||
_ => return Err(CopyImplementationError::NotAnAdt)
|
_ => 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);
|
return Err(CopyImplementationError::HasDestructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// (This allows programs to make cyclic structures without
|
/// (This allows programs to make cyclic structures without
|
||||||
/// resorting to unasfe means; see RFCs 769 and 1238).
|
/// resorting to unasfe means; see RFCs 769 and 1238).
|
||||||
pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
|
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,
|
Some(dtor) => dtor,
|
||||||
None => return false
|
None => return false
|
||||||
};
|
};
|
||||||
|
@ -524,7 +524,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result =
|
let result =
|
||||||
tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
|
tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
|
||||||
.enter(|infcx| {
|
.enter(|infcx| {
|
||||||
traits::type_known_to_meet_bound(&infcx, self, def_id, span)
|
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(_))) => {
|
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
|
||||||
match lp_base.to_type().sty {
|
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
|
// In the case where the owner implements drop, then
|
||||||
// the path must be initialized to prevent a case of
|
// the path must be initialized to prevent a case of
|
||||||
// partial reinitialization
|
// 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, _)) => {
|
Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
|
||||||
match b.ty.sty {
|
match b.ty.sty {
|
||||||
ty::TyAdt(def, _) => {
|
ty::TyAdt(def, _) => {
|
||||||
if def.has_dtor() {
|
if def.has_dtor(bccx.tcx) {
|
||||||
Some(cmt.clone())
|
Some(cmt.clone())
|
||||||
} else {
|
} else {
|
||||||
check_and_get_illegal_move_origin(bccx, b)
|
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::Downcast(ref b, _) |
|
||||||
Categorization::Interior(ref b, mc::InteriorField(_)) => {
|
Categorization::Interior(ref b, mc::InteriorField(_)) => {
|
||||||
match b.ty.sty {
|
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,
|
let mut err = struct_span_err!(bccx, move_from.span, E0509,
|
||||||
"cannot move out of type `{}`, \
|
"cannot move out of type `{}`, \
|
||||||
which implements the `Drop` trait",
|
which implements the `Drop` trait",
|
||||||
|
|
|
@ -898,7 +898,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||||
|
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::TyAdt(def, _) => {
|
ty::TyAdt(def, _) => {
|
||||||
if def.has_dtor() && !def.is_box() {
|
if def.has_dtor(self.tcx) && !def.is_box() {
|
||||||
self.tcx.sess.span_warn(
|
self.tcx.sess.span_warn(
|
||||||
c.source_info.span,
|
c.source_info.span,
|
||||||
&format!("dataflow bug??? moving out of type with dtor {:?}",
|
&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
|
// error: can't move out of borrowed content
|
||||||
ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
|
ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
|
||||||
// error: can't move out of struct with destructor
|
// 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),
|
return Err(MovePathError::IllegalMove),
|
||||||
// move out of union - always move the entire union
|
// move out of union - always move the entire union
|
||||||
ty::TyAdt(adt, _) if adt.is_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);
|
lv, ty);
|
||||||
true
|
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",
|
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
|
||||||
lv, ty);
|
lv, ty);
|
||||||
true
|
true
|
||||||
|
|
|
@ -516,7 +516,7 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
|
||||||
///
|
///
|
||||||
/// FIXME: this should be done by borrowck.
|
/// FIXME: this should be done by borrowck.
|
||||||
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
|
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 {
|
let mut checker = MutationChecker {
|
||||||
cx: cx,
|
cx: cx,
|
||||||
};
|
};
|
||||||
|
|
|
@ -922,7 +922,7 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
|
||||||
trait_ref);
|
trait_ref);
|
||||||
|
|
||||||
tcx.populate_implementations_for_trait_if_necessary(trait_id);
|
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 mut selcx = traits::SelectionContext::new(&infcx);
|
||||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||||
trait_ref.to_poly_trait_predicate());
|
trait_ref.to_poly_trait_predicate());
|
||||||
|
|
|
@ -151,7 +151,7 @@ fn test_env<F>(source_string: &str,
|
||||||
index,
|
index,
|
||||||
"test_crate",
|
"test_crate",
|
||||||
|tcx| {
|
|tcx| {
|
||||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||||
|
|
||||||
body(Env { infcx: &infcx });
|
body(Env { infcx: &infcx });
|
||||||
let free_regions = FreeRegionMap::new();
|
let free_regions = FreeRegionMap::new();
|
||||||
|
|
|
@ -1167,6 +1167,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
|
||||||
trait_items: _,
|
trait_items: _,
|
||||||
impl_items: _,
|
impl_items: _,
|
||||||
bodies: _,
|
bodies: _,
|
||||||
|
|
||||||
|
trait_impls: _,
|
||||||
|
trait_default_impl: _,
|
||||||
} = *krate;
|
} = *krate;
|
||||||
|
|
||||||
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
|
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
|
||||||
|
|
|
@ -523,7 +523,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
if def.has_dtor() {
|
if def.has_dtor(cx.tcx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let parameter_environment = cx.tcx.empty_parameter_environment();
|
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 node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
|
||||||
|
|
||||||
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
|
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);
|
let mut selcx = traits::SelectionContext::new(&infcx);
|
||||||
match selcx.select(&obligation) {
|
match selcx.select(&obligation) {
|
||||||
// The method comes from a `T: Trait` bound.
|
// 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)
|
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 {
|
fn is_default_impl(&self, impl_did: DefId) -> bool {
|
||||||
self.dep_graph.read(DepNode::MetaData(impl_did));
|
self.dep_graph.read(DepNode::MetaData(impl_did));
|
||||||
self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
|
self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
|
||||||
|
|
|
@ -501,10 +501,16 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ty::TraitDef::new(self.local_def_id(item_id),
|
let def = ty::TraitDef::new(self.local_def_id(item_id),
|
||||||
data.unsafety,
|
data.unsafety,
|
||||||
data.paren_sugar,
|
data.paren_sugar,
|
||||||
self.def_path(item_id).deterministic_hash(tcx))
|
self.def_path(item_id).deterministic_hash(tcx));
|
||||||
|
|
||||||
|
if data.has_default_impl {
|
||||||
|
def.record_has_default_impl();
|
||||||
|
}
|
||||||
|
|
||||||
|
def
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_variant(&self,
|
fn get_variant(&self,
|
||||||
|
@ -1027,13 +1033,6 @@ impl<'a, 'tcx> CrateMetadata {
|
||||||
self.dllimport_foreign_items.contains(&id)
|
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 {
|
pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
|
||||||
match self.entry(impl_id).kind {
|
match self.entry(impl_id).kind {
|
||||||
EntryKind::DefaultImpl(_) => true,
|
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);
|
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 cx = Cx::new(&infcx, src);
|
||||||
let mut mir = if let MirSource::Fn(id) = src {
|
let mut mir = if let MirSource::Fn(id) = src {
|
||||||
// fetch the fully liberated fn signature (that is, all bound
|
// 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, _) => {
|
Rvalue::Aggregate(ref kind, _) => {
|
||||||
if let AggregateKind::Adt(def, ..) = *kind {
|
if let AggregateKind::Adt(def, ..) = *kind {
|
||||||
if def.has_dtor() {
|
if def.has_dtor(self.tcx) {
|
||||||
self.add(Qualif::NEEDS_DROP);
|
self.add(Qualif::NEEDS_DROP);
|
||||||
self.deny_drop();
|
self.deny_drop();
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1042,7 @@ impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
|
||||||
// Statics must be Sync.
|
// Statics must be Sync.
|
||||||
if mode == Mode::Static {
|
if mode == Mode::Static {
|
||||||
let ty = mir.return_ty;
|
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 cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
|
||||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||||
fulfillment_cx.register_bound(&infcx, ty,
|
fulfillment_cx.register_bound(&infcx, ty,
|
||||||
|
|
|
@ -699,7 +699,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
|
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 checker = TypeChecker::new(&infcx, src.item_id());
|
||||||
{
|
{
|
||||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
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);
|
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 param_env = infcx.parameter_environment.clone();
|
||||||
let outer_penv = mem::replace(&mut self.param_env, param_env);
|
let outer_penv = mem::replace(&mut self.param_env, param_env);
|
||||||
euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
|
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.
|
/// instead of producing errors.
|
||||||
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
|
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
|
||||||
match node_ty.sty {
|
match node_ty.sty {
|
||||||
ty::TyAdt(def, _) if def.has_dtor() => {
|
ty::TyAdt(def, _) if def.has_dtor(v.tcx) => {
|
||||||
v.promotable = false;
|
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) {
|
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
|
||||||
let body = self.tcx.hir.body(body_id);
|
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 {
|
let mut delegate = RvalueContextDelegate {
|
||||||
tcx: infcx.tcx,
|
tcx: infcx.tcx,
|
||||||
param_env: &infcx.parameter_environment
|
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
|
// If the type implements Drop, also add a translation item for the
|
||||||
// monomorphized Drop::drop() implementation.
|
// monomorphized Drop::drop() implementation.
|
||||||
let destructor_did = match ty.sty {
|
let destructor_did = match ty.sty {
|
||||||
ty::TyAdt(def, _) => def.destructor(),
|
ty::TyAdt(def, _) => def.destructor(scx.tcx()),
|
||||||
_ => None
|
_ => 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.call(dtor, &[ptr.llval], None);
|
||||||
bcx
|
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 shallow_drop = def.is_union();
|
||||||
let tcx = bcx.tcx();
|
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,
|
traits::VtableImpl(data) => data,
|
||||||
_ => bug!("dtor for {:?} is not an impl???", t)
|
_ => 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 callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
|
||||||
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
|
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
|
||||||
let llret;
|
let llret;
|
||||||
|
|
|
@ -224,7 +224,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
trait_param_env,
|
trait_param_env,
|
||||||
normalize_cause.clone());
|
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 inh = Inherited::new(infcx);
|
||||||
let infcx = &inh.infcx;
|
let infcx = &inh.infcx;
|
||||||
let fulfillment_cx = &inh.fulfillment_cx;
|
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>) {
|
impl_trait_ref: ty::TraitRef<'tcx>) {
|
||||||
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
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();
|
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||||
|
|
||||||
// The below is for the most part highly similar to the procedure
|
// 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.
|
// 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);
|
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 tcx = infcx.tcx;
|
||||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
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
|
// Find the `impl<..> Drop for _` to inspect any
|
||||||
// attributes attached to the impl's generics.
|
// 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");
|
.expect("dtorck type without destructor impossible");
|
||||||
let method = tcx.associated_item(dtor_method);
|
let method = tcx.associated_item(dtor_method);
|
||||||
let impl_def_id = method.container.id();
|
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) {
|
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
|
||||||
// Read the inherent implementation candidates for this type from the
|
// Read the inherent implementation candidates for this type from the
|
||||||
// metadata if necessary.
|
// 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) {
|
if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
|
||||||
for &impl_def_id in impl_infos.iter() {
|
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 tables = ty::TypeckTables::empty();
|
||||||
let param_env = ParameterEnvironment::for_item(tcx, id);
|
let param_env = ParameterEnvironment::for_item(tcx, id);
|
||||||
InheritedBuilder {
|
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::map as hir_map;
|
||||||
use rustc::hir::{self, ItemImpl};
|
use rustc::hir::{self, ItemImpl};
|
||||||
|
|
||||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
|
||||||
check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
|
Checker { tcx, trait_def_id }
|
||||||
check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
|
.check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
|
||||||
check_trait(
|
.check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
|
||||||
tcx,
|
.check(tcx.lang_items.coerce_unsized_trait(),
|
||||||
tcx.lang_items.coerce_unsized_trait(),
|
visit_implementation_of_coerce_unsized);
|
||||||
visit_implementation_of_coerce_unsized);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
struct Checker<'a, 'tcx: 'a> {
|
||||||
trait_def_id: Option<DefId>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
mut f: F)
|
trait_def_id: DefId
|
||||||
where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
|
}
|
||||||
{
|
|
||||||
if let Some(trait_def_id) = trait_def_id {
|
impl<'a, 'tcx> Checker<'a, 'tcx> {
|
||||||
let mut impls = vec![];
|
fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
|
||||||
tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
|
where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
|
||||||
impls.push(did);
|
{
|
||||||
});
|
if Some(self.trait_def_id) == trait_def_id {
|
||||||
impls.sort();
|
for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
|
||||||
for impl_def_id in impls {
|
let impl_def_id = self.tcx.hir.local_def_id(impl_id);
|
||||||
f(tcx, trait_def_id, impl_def_id);
|
f(self.tcx, self.trait_def_id, impl_def_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
_drop_did: DefId,
|
_drop_did: DefId,
|
||||||
impl_did: DefId) {
|
impl_did: DefId) {
|
||||||
let items = tcx.associated_item_def_ids(impl_did);
|
match tcx.item_type(impl_did).sty {
|
||||||
if items.is_empty() {
|
ty::TyAdt(..) => {}
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
// Destructors only work on nominal types.
|
// Destructors only work on nominal types.
|
||||||
if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
|
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,
|
source,
|
||||||
target);
|
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 cause = ObligationCause::misc(span, impl_node_id);
|
||||||
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
|
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
|
||||||
mt_b: 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
|
// done by the orphan and overlap modules. Then we build up various
|
||||||
// mappings. That mapping code resides here.
|
// mappings. That mapping code resides here.
|
||||||
|
|
||||||
use dep_graph::DepTrackingMap;
|
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
use hir::def_id::DefId;
|
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use rustc::ty::{self, maps, TyCtxt, TypeFoldable};
|
use rustc::ty::maps::Providers;
|
||||||
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 rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc::hir::{Item, ItemImpl};
|
use syntax::ast;
|
||||||
use rustc::hir;
|
use syntax_pos::DUMMY_SP;
|
||||||
use std::cell::RefMut;
|
|
||||||
|
|
||||||
mod builtin;
|
mod builtin;
|
||||||
|
mod inherent;
|
||||||
mod orphan;
|
mod orphan;
|
||||||
mod overlap;
|
mod overlap;
|
||||||
mod unsafety;
|
mod unsafety;
|
||||||
|
|
||||||
struct CoherenceCollect<'a, 'tcx: 'a> {
|
fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
let impl_def_id = tcx.hir.local_def_id(node_id);
|
||||||
inherent_impls: RefMut<'a, DepTrackingMap<maps::queries::inherent_impls<'tcx>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
|
// If there are no traits, then this implementation must have a
|
||||||
fn visit_item(&mut self, item: &Item) {
|
// base type.
|
||||||
if let ItemImpl(..) = item.node {
|
|
||||||
self.check_implementation(item)
|
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) {
|
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);
|
||||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
|
fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
let did = Some(trait_def_id);
|
let did = Some(trait_def_id);
|
||||||
let li = &tcx.lang_items;
|
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() {
|
let trait_name = if did == li.fn_trait() {
|
||||||
"Fn"
|
"Fn"
|
||||||
} else if did == li.fn_mut_trait() {
|
} 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
|
return; // everything OK
|
||||||
};
|
};
|
||||||
let mut err = struct_span_err!(tcx.sess,
|
let mut err = struct_span_err!(tcx.sess,
|
||||||
sp,
|
tcx.span_of_impl(impl_def_id).unwrap(),
|
||||||
E0183,
|
E0183,
|
||||||
"manual implementations of `{}` are experimental",
|
"manual implementations of `{}` are experimental",
|
||||||
trait_name);
|
trait_name);
|
||||||
|
@ -175,12 +101,41 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
CoherenceCollect::check(tcx);
|
*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);
|
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);
|
unsafety::check(tcx);
|
||||||
orphan::check(tcx);
|
orphan::check(tcx);
|
||||||
overlap::check(tcx);
|
overlap::check_default_impls(tcx);
|
||||||
builtin::check(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
|
//! Orphan checker: every impl either implements a trait defined in this
|
||||||
//! crate or pertains to a type defined in this crate.
|
//! crate or pertains to a type defined in this crate.
|
||||||
|
|
||||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use syntax::ast;
|
|
||||||
use syntax_pos::Span;
|
|
||||||
use rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
@ -29,46 +26,6 @@ struct OrphanChecker<'cx, 'tcx: 'cx> {
|
||||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
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> {
|
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||||
/// Checks exactly one impl for orphan rules and other such
|
/// Checks exactly one impl for orphan rules and other such
|
||||||
/// restrictions. In this fn, it can happen that multiple errors
|
/// 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) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
let def_id = self.tcx.hir.local_def_id(item.id);
|
let def_id = self.tcx.hir.local_def_id(item.id);
|
||||||
match item.node {
|
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(_), _, _) => {
|
hir::ItemImpl(.., Some(_), _, _) => {
|
||||||
// "Trait" impl
|
// "Trait" impl
|
||||||
debug!("coherence2::orphan check: 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,
|
trait_def_id,
|
||||||
self.tcx.trait_has_default_impl(trait_def_id));
|
self.tcx.trait_has_default_impl(trait_def_id));
|
||||||
if 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 self_ty = trait_ref.self_ty();
|
||||||
let opt_self_def_id = match self_ty.sty {
|
let opt_self_def_id = match self_ty.sty {
|
||||||
ty::TyAdt(self_def, _) => Some(self_def.did),
|
ty::TyAdt(self_def, _) => Some(self_def.did),
|
||||||
|
@ -346,31 +141,13 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
|
||||||
return;
|
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) => {
|
hir::ItemDefaultImpl(_, ref item_trait_ref) => {
|
||||||
// "Trait" impl
|
// "Trait" impl
|
||||||
debug!("coherence2::orphan check: default trait impl {}",
|
debug!("coherence2::orphan check: default trait impl {}",
|
||||||
self.tcx.hir.node_to_string(item.id));
|
self.tcx.hir.node_to_string(item.id));
|
||||||
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
|
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,
|
struct_span_err!(self.tcx.sess,
|
||||||
item_trait_ref.path.span,
|
item_trait_ref.path.span,
|
||||||
E0318,
|
E0318,
|
||||||
|
|
|
@ -12,102 +12,101 @@
|
||||||
//! same type. Likewise, no two inherent impls for a given type
|
//! same type. Likewise, no two inherent impls for a given type
|
||||||
//! constructor provide a method with the same name.
|
//! constructor provide a method with the same name.
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use rustc::traits;
|
||||||
use rustc::traits::{self, Reveal};
|
|
||||||
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
use rustc::ty::{self, TyCtxt, TypeFoldable};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use rustc::dep_graph::DepNode;
|
use rustc::dep_graph::DepNode;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
use util::nodemap::DefIdMap;
|
|
||||||
use lint;
|
|
||||||
|
|
||||||
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||||
let mut overlap = OverlapChecker {
|
let mut overlap = OverlapChecker { tcx };
|
||||||
tcx: tcx,
|
|
||||||
default_impls: DefIdMap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// this secondary walk specifically checks for some other cases,
|
// this secondary walk specifically checks for some other cases,
|
||||||
// like defaulted traits, for which additional overlap rules exist
|
// like defaulted traits, for which additional overlap rules exist
|
||||||
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
|
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OverlapChecker<'cx, 'tcx: 'cx> {
|
pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
|
||||||
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
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
|
if trait_ref.references_error() {
|
||||||
default_impls: DefIdMap<ast::NodeId>,
|
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> {
|
struct OverlapChecker<'cx, 'tcx: 'cx> {
|
||||||
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
|
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
|
||||||
#[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)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
|
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &'v hir::Item) {
|
fn visit_item(&mut self, item: &'v hir::Item) {
|
||||||
match item.node {
|
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(..) => {
|
hir::ItemDefaultImpl(..) => {
|
||||||
// look for another default impl; note that due to the
|
// look for another default impl; note that due to the
|
||||||
// general orphan/coherence rules, it must always be
|
// 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 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_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
|
||||||
|
|
||||||
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
|
let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
|
||||||
if let Some(prev_id) = prev_default_impl {
|
if prev_id != item.id {
|
||||||
let mut err = struct_span_err!(self.tcx.sess,
|
let mut err = struct_span_err!(self.tcx.sess,
|
||||||
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
self.tcx.span_of_impl(impl_def_id).unwrap(),
|
||||||
E0521,
|
E0521,
|
||||||
|
@ -131,76 +130,6 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ItemImpl(.., Some(_), _, _) => {
|
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,
|
unsafety: hir::Unsafety,
|
||||||
polarity: hir::ImplPolarity) {
|
polarity: hir::ImplPolarity) {
|
||||||
match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
|
match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
|
||||||
None => {
|
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(trait_ref) => {
|
Some(trait_ref) => {
|
||||||
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
|
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, _) => {
|
hir::ItemDefaultImpl(unsafety, _) => {
|
||||||
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
|
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);
|
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);
|
convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
|
||||||
},
|
},
|
||||||
hir::ItemDefaultImpl(..) => {
|
hir::ItemDefaultImpl(..) => {
|
||||||
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
|
tcx.impl_trait_ref(def_id);
|
||||||
tcx.record_trait_has_default_impl(trait_ref.def_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
hir::ItemImpl(..) => {
|
hir::ItemImpl(..) => {
|
||||||
tcx.item_generics(def_id);
|
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);
|
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>,
|
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>,
|
expected: Ty<'tcx>,
|
||||||
actual: Ty<'tcx>)
|
actual: Ty<'tcx>)
|
||||||
-> bool {
|
-> bool {
|
||||||
tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
|
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
|
||||||
match infcx.eq_types(false, &cause, expected, actual) {
|
match infcx.eq_types(false, &cause, expected, actual) {
|
||||||
Ok(InferOk { obligations, .. }) => {
|
Ok(InferOk { obligations, .. }) => {
|
||||||
// FIXME(#32730) propagate 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) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
collect::provide(providers);
|
collect::provide(providers);
|
||||||
|
coherence::provide(providers);
|
||||||
check::provide(providers);
|
check::provide(providers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use std::io;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
use syntax_pos::DUMMY_SP;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
|
|
||||||
use rustc::hir::def::{Def, CtorKind};
|
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> {
|
pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
|
||||||
let tcx = cx.tcx;
|
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();
|
let mut impls = Vec::new();
|
||||||
|
|
||||||
if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
|
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 impl doesn't use types inside crate
|
||||||
//~| NOTE the impl does not reference any types defined in this crate
|
//~| NOTE the impl does not reference any types defined in this crate
|
||||||
//~| NOTE define and implement a trait or new type instead
|
//~| 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() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use trait_impl_conflict::Foo;
|
||||||
|
|
||||||
impl<A> Foo for A {
|
impl<A> Foo for A {
|
||||||
//~^ ERROR type parameter `A` must be used as the type parameter for some local type
|
//~^ 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() {
|
fn main() {
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
trait MyTrait {}
|
trait MyTrait {}
|
||||||
|
|
||||||
impl MyTrait for .. {}
|
impl MyTrait for .. {}
|
||||||
|
//~^ ERROR redundant default implementations of trait `MyTrait`
|
||||||
|
|
||||||
impl MyTrait for .. {}
|
impl MyTrait for .. {}
|
||||||
//~^ ERROR redundant default implementations of trait `MyTrait`
|
|
||||||
|
|
||||||
trait MySafeTrait {}
|
trait MySafeTrait {}
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,20 @@ impl Sized for TestE {} //~ ERROR E0322
|
||||||
impl Sized for MyType {} //~ ERROR E0322
|
impl Sized for MyType {} //~ ERROR E0322
|
||||||
//~^ impl of 'Sized' not allowed
|
//~^ 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 Sized for &'static NotSync {} //~ ERROR E0322
|
||||||
//~^ impl of 'Sized' not allowed
|
//~^ 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() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,6 @@ error[E0204]: the trait `Copy` may not be implemented for this type
|
||||||
15 | impl Copy for Foo { }
|
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
|
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||||
--> $DIR/E0204.rs:17:10
|
--> $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,
|
19 | ty: &'a mut bool,
|
||||||
| ---------------- this field does not implement `Copy`
|
| ---------------- 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
|
error[E0204]: the trait `Copy` may not be implemented for this type
|
||||||
--> $DIR/E0204.rs:29:10
|
--> $DIR/E0204.rs:29:10
|
||||||
|
|
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue