Skip to content

Commit 12f6c50

Browse files
committedMar 27, 2017
Rollup merge of rust-lang#40683 - nikomatsakis:incr-comp-coerce-unsized-info, r=eddyb
on-demand-ify `custom_coerce_unsized_kind` and `inherent-impls` This "on-demand" task both checks for errors and computes the custom unsized kind, if any. This task is only defined on impls of `CoerceUnsized`; invoking it on any other kind of impl results in a bug. This is just to avoid having an `Option`, could easily be changed. r? @eddyb
2 parents 666bb19 + a29ae30 commit 12f6c50

File tree

17 files changed

+306
-220
lines changed

17 files changed

+306
-220
lines changed
 

‎src/librustc/dep_graph/dep_node.rs

-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ pub enum DepNode<D: Clone + Debug> {
7575
CoherenceCheckImpl(D),
7676
CoherenceOverlapCheck(D),
7777
CoherenceOverlapCheckSpecial(D),
78-
CoherenceOverlapInherentCheck(D),
7978
CoherenceOrphanCheck(D),
8079
Variance,
8180
WfCheck(D),
@@ -252,7 +251,6 @@ impl<D: Clone + Debug> DepNode<D> {
252251
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
253252
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
254253
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
255-
CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck),
256254
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
257255
WfCheck(ref d) => op(d).map(WfCheck),
258256
TypeckItemType(ref d) => op(d).map(TypeckItemType),

‎src/librustc/dep_graph/dep_tracking_map.rs

-15
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,6 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
8181
pub fn keys(&self) -> Vec<M::Key> {
8282
self.map.keys().cloned().collect()
8383
}
84-
85-
/// Append `elem` to the vector stored for `k`, creating a new vector if needed.
86-
/// This is considered a write to `k`.
87-
///
88-
/// NOTE: Caution is required when using this method. You should
89-
/// be sure that nobody is **reading from the vector** while you
90-
/// are writing to it. Eventually, it'd be nice to remove this.
91-
pub fn push<E: Clone>(&mut self, k: M::Key, elem: E)
92-
where M: DepTrackingMapConfig<Value=Vec<E>>
93-
{
94-
self.write(&k);
95-
self.map.entry(k)
96-
.or_insert(Vec::new())
97-
.push(elem);
98-
}
9984
}
10085

10186
impl<M: DepTrackingMapConfig> MemoizationMap for RefCell<DepTrackingMap<M>> {

‎src/librustc/middle/cstore.rs

-2
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,6 @@ pub trait CrateStore {
176176
fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
177177
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
178178
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
179-
fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>;
180179

181180
// trait info
182181
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
@@ -310,7 +309,6 @@ impl CrateStore for DummyCrateStore {
310309
{ bug!("item_generics_cloned") }
311310
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
312311
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
313-
fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![] }
314312

315313
// trait info
316314
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }

‎src/librustc/ty/adjustment.rs

+15
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,21 @@ pub enum AutoBorrow<'tcx> {
139139
RawPtr(hir::Mutability),
140140
}
141141

142+
/// Information for `CoerceUnsized` impls, storing information we
143+
/// have computed about the coercion.
144+
///
145+
/// This struct can be obtained via the `coerce_impl_info` query.
146+
/// Demanding this struct also has the side-effect of reporting errors
147+
/// for inappropriate impls.
148+
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
149+
pub struct CoerceUnsizedInfo {
150+
/// If this is a "custom coerce" impl, then what kind of custom
151+
/// coercion is it? This applies to impls of `CoerceUnsized` for
152+
/// structs, primarily, where we store a bit of info about which
153+
/// fields need to be coerced.
154+
pub custom_kind: Option<CustomCoerceUnsized>
155+
}
156+
142157
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
143158
pub enum CustomCoerceUnsized {
144159
/// Records the index of the field being coerced.

‎src/librustc/ty/maps.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
1313
use middle::const_val::ConstVal;
1414
use middle::privacy::AccessLevels;
1515
use mir;
16-
use ty::{self, Ty, TyCtxt};
16+
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
1717

1818
use rustc_data_structures::indexed_vec::IndexVec;
1919
use std::cell::{RefCell, RefMut};
@@ -177,9 +177,15 @@ impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> {
177177
}
178178
}
179179

180-
impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> {
180+
impl<'tcx> QueryDescription for queries::crate_inherent_impls<'tcx> {
181+
fn describe(_: TyCtxt, k: CrateNum) -> String {
182+
format!("all inherent impls defined in crate `{:?}`", k)
183+
}
184+
}
185+
186+
impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx> {
181187
fn describe(_: TyCtxt, _: CrateNum) -> String {
182-
format!("coherence checking all inherent impls")
188+
format!("check for overlap between inherent impls defined in this crate")
183189
}
184190
}
185191

@@ -375,7 +381,7 @@ define_maps! { <'tcx>
375381
/// Maps a DefId of a type to a list of its inherent impls.
376382
/// Contains implementations of methods that are inherent to a type.
377383
/// Methods in these implementations don't need to be exported.
378-
pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
384+
pub inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
379385

380386
/// Maps from the def-id of a function/method or const/static
381387
/// to its MIR. Mutation is done at an item granularity to
@@ -400,14 +406,22 @@ define_maps! { <'tcx>
400406
pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
401407

402408
/// Caches CoerceUnsized kinds for impls on custom types.
403-
pub custom_coerce_unsized_kind: ItemSignature(DefId)
404-
-> ty::adjustment::CustomCoerceUnsized,
409+
pub coerce_unsized_info: ItemSignature(DefId)
410+
-> ty::adjustment::CoerceUnsizedInfo,
405411

406412
pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
407413

408414
pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
409415

410-
pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (),
416+
/// Gets a complete map from all types to their inherent impls.
417+
/// Not meant to be used directly outside of coherence.
418+
/// (Defined only for LOCAL_CRATE)
419+
pub crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls,
420+
421+
/// Checks all types in the krate for overlap in their inherent impls. Reports errors.
422+
/// Not meant to be used directly outside of coherence.
423+
/// (Defined only for LOCAL_CRATE)
424+
pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
411425

412426
/// Results of evaluating monomorphic constants embedded in
413427
/// other items, such as enum variant explicit discriminants.
@@ -423,7 +437,7 @@ fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
423437
DepNode::CoherenceCheckTrait(def_id)
424438
}
425439

426-
fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
440+
fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
427441
DepNode::Coherence
428442
}
429443

‎src/librustc/ty/mod.rs

+16-31
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use ty::subst::{Subst, Substs};
3131
use ty::util::IntTypeExt;
3232
use ty::walk::TypeWalker;
3333
use util::common::MemoizationMap;
34-
use util::nodemap::{NodeSet, FxHashMap};
34+
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
3535

3636
use serialize::{self, Encodable, Encoder};
3737
use std::borrow::Cow;
@@ -2057,8 +2057,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
20572057
})
20582058
}
20592059

2060-
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
2061-
queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
2060+
pub fn coerce_unsized_info(self, did: DefId) -> adjustment::CoerceUnsizedInfo {
2061+
queries::coerce_unsized_info::get(self, DUMMY_SP, did)
20622062
}
20632063

20642064
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
@@ -2348,34 +2348,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
23482348
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
23492349
}
23502350

2351-
/// Populates the type context with all the inherent implementations for
2352-
/// the given type if necessary.
2353-
pub fn populate_inherent_implementations_for_type_if_necessary(self,
2354-
span: Span,
2355-
type_id: DefId) {
2356-
if type_id.is_local() {
2357-
// Make sure coherence of inherent impls ran already.
2358-
ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
2359-
return
2360-
}
2361-
2362-
// The type is not local, hence we are reading this out of
2363-
// metadata and don't need to track edges.
2364-
let _ignore = self.dep_graph.in_ignore();
2365-
2366-
if self.populated_external_types.borrow().contains(&type_id) {
2367-
return
2368-
}
2369-
2370-
debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}",
2371-
type_id);
2372-
2373-
let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id);
2374-
2375-
self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
2376-
self.populated_external_types.borrow_mut().insert(type_id);
2377-
}
2378-
23792351
/// Populates the type context with all the implementations for the given
23802352
/// trait if necessary.
23812353
pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) {
@@ -2640,3 +2612,16 @@ pub fn provide(providers: &mut ty::maps::Providers) {
26402612
..*providers
26412613
};
26422614
}
2615+
2616+
2617+
/// A map for the local crate mapping each type to a vector of its
2618+
/// inherent impls. This is not meant to be used outside of coherence;
2619+
/// rather, you should request the vector for a specific type via
2620+
/// `ty::queries::inherent_impls::get(def_id)` so as to minimize your
2621+
/// dependencies (constructing this map requires touching the entire
2622+
/// crate).
2623+
#[derive(Clone, Debug)]
2624+
pub struct CrateInherentImpls {
2625+
pub inherent_impls: DefIdMap<Rc<Vec<DefId>>>,
2626+
}
2627+

‎src/librustc_metadata/cstore_impl.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ provide! { <'tcx> tcx, def_id, cdata
8888
}
8989
associated_item => { cdata.get_associated_item(def_id.index) }
9090
impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
91-
custom_coerce_unsized_kind => {
92-
cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
93-
bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
91+
coerce_unsized_info => {
92+
cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
93+
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
9494
})
9595
}
9696
mir => {
@@ -109,6 +109,7 @@ provide! { <'tcx> tcx, def_id, cdata
109109
typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
110110
closure_kind => { cdata.closure_kind(def_id.index) }
111111
closure_type => { cdata.closure_ty(def_id.index, tcx) }
112+
inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
112113
}
113114

114115
impl CrateStore for cstore::CStore {
@@ -162,12 +163,6 @@ impl CrateStore for cstore::CStore {
162163
self.get_crate_data(did.krate).get_fn_arg_names(did.index)
163164
}
164165

165-
fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>
166-
{
167-
self.dep_graph.read(DepNode::MetaData(def_id));
168-
self.get_crate_data(def_id.krate).get_inherent_implementations_for_type(def_id.index)
169-
}
170-
171166
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>
172167
{
173168
if let Some(def_id) = filter {

‎src/librustc_metadata/decoder.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -643,10 +643,10 @@ impl<'a, 'tcx> CrateMetadata {
643643
self.get_impl_data(id).polarity
644644
}
645645

646-
pub fn get_custom_coerce_unsized_kind(&self,
647-
id: DefIndex)
648-
-> Option<ty::adjustment::CustomCoerceUnsized> {
649-
self.get_impl_data(id).coerce_unsized_kind
646+
pub fn get_coerce_unsized_info(&self,
647+
id: DefIndex)
648+
-> Option<ty::adjustment::CoerceUnsizedInfo> {
649+
self.get_impl_data(id).coerce_unsized_info
650650
}
651651

652652
pub fn get_impl_trait(&self,

‎src/librustc_metadata/encoder.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
693693
let data = ImplData {
694694
polarity: hir::ImplPolarity::Positive,
695695
parent_impl: None,
696-
coerce_unsized_kind: None,
696+
coerce_unsized_info: None,
697697
trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)),
698698
};
699699

@@ -713,13 +713,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
713713
None
714714
};
715715

716+
// if this is an impl of `CoerceUnsized`, create its
717+
// "unsized info", else just store None
718+
let coerce_unsized_info =
719+
trait_ref.and_then(|t| {
720+
if Some(t.def_id) == tcx.lang_items.coerce_unsized_trait() {
721+
Some(ty::queries::coerce_unsized_info::get(tcx, item.span, def_id))
722+
} else {
723+
None
724+
}
725+
});
726+
716727
let data = ImplData {
717728
polarity: polarity,
718729
parent_impl: parent,
719-
coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
720-
.borrow()
721-
.get(&def_id)
722-
.cloned(),
730+
coerce_unsized_info: coerce_unsized_info,
723731
trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)),
724732
};
725733

‎src/librustc_metadata/schema.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,9 @@ pub struct TraitData<'tcx> {
285285
pub struct ImplData<'tcx> {
286286
pub polarity: hir::ImplPolarity,
287287
pub parent_impl: Option<DefId>,
288-
pub coerce_unsized_kind: Option<ty::adjustment::CustomCoerceUnsized>,
288+
289+
/// This is `Some` only for impls of `CoerceUnsized`.
290+
pub coerce_unsized_info: Option<ty::adjustment::CoerceUnsizedInfo>,
289291
pub trait_ref: Option<Lazy<ty::TraitRef<'tcx>>>,
290292
}
291293

‎src/librustc_trans/monomorphize.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
287287

288288
match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
289289
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
290-
scx.tcx().custom_coerce_unsized_kind(impl_def_id)
290+
scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap()
291291
}
292292
vtable => {
293293
bug!("invalid CoerceUnsized vtable: {:?}", vtable);

‎src/librustc_typeck/check/method/probe.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -479,14 +479,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
479479
}
480480

481481
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
482-
// Read the inherent implementation candidates for this type from the
483-
// metadata if necessary.
484-
self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id);
485-
486-
if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
487-
for &impl_def_id in impl_infos.iter() {
488-
self.assemble_inherent_impl_probe(impl_def_id);
489-
}
482+
let impl_def_ids = ty::queries::inherent_impls::get(self.tcx, self.span, def_id);
483+
for &impl_def_id in impl_def_ids.iter() {
484+
self.assemble_inherent_impl_probe(impl_def_id);
490485
}
491486
}
492487

‎src/librustc_typeck/coherence/builtin.rs

+31-15
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc::traits::{self, ObligationCause, Reveal};
1818
use rustc::ty::{self, Ty, TyCtxt};
1919
use rustc::ty::ParameterEnvironment;
2020
use rustc::ty::TypeFoldable;
21+
use rustc::ty::adjustment::CoerceUnsizedInfo;
2122
use rustc::ty::subst::Subst;
2223
use rustc::ty::util::CopyImplementationError;
2324
use rustc::infer;
@@ -159,28 +160,41 @@ fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
159160
}
160161

161162
fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
162-
coerce_unsized_trait: DefId,
163+
_: DefId,
163164
impl_did: DefId) {
164165
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
165166
impl_did);
166167

168+
// Just compute this for the side-effects, in particular reporting
169+
// errors; other parts of the code may demand it for the info of
170+
// course.
171+
if impl_did.is_local() {
172+
let span = tcx.def_span(impl_did);
173+
ty::queries::coerce_unsized_info::get(tcx, span, impl_did);
174+
}
175+
}
176+
177+
pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
178+
impl_did: DefId)
179+
-> CoerceUnsizedInfo {
180+
debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
181+
let coerce_unsized_trait = tcx.lang_items.coerce_unsized_trait().unwrap();
182+
167183
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
168184
Ok(id) => id,
169185
Err(err) => {
170186
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
171187
}
172188
};
173189

174-
let impl_node_id = if let Some(n) = tcx.hir.as_local_node_id(impl_did) {
175-
n
176-
} else {
177-
debug!("visit_implementation_of_coerce_unsized(): impl not \
178-
in this crate");
179-
return;
180-
};
190+
// this provider should only get invoked for local def-ids
191+
let impl_node_id = tcx.hir.as_local_node_id(impl_did).unwrap_or_else(|| {
192+
bug!("coerce_unsized_info: invoked for non-local def-id {:?}", impl_did)
193+
});
181194

182195
let source = tcx.item_type(impl_did);
183196
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
197+
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
184198
let target = trait_ref.substs.type_at(1);
185199
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
186200
source,
@@ -192,6 +206,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
192206
let target = target.subst(tcx, &param_env.free_substs);
193207
assert!(!source.has_escaping_regions());
194208

209+
let err_info = CoerceUnsizedInfo { custom_kind: None };
210+
195211
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
196212
source,
197213
target);
@@ -234,7 +250,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
234250
definition; expected {}, found {}",
235251
source_path,
236252
target_path);
237-
return;
253+
return err_info;
238254
}
239255

240256
let fields = &def_a.struct_variant().fields;
@@ -268,7 +284,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
268284
"the trait `CoerceUnsized` may only be implemented \
269285
for a coercion between structures with one field \
270286
being coerced, none found");
271-
return;
287+
return err_info;
272288
} else if diff_fields.len() > 1 {
273289
let item = tcx.hir.expect_item(impl_node_id);
274290
let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
@@ -295,7 +311,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
295311
.join(", ")));
296312
err.span_label(span, &format!("requires multiple coercions"));
297313
err.emit();
298-
return;
314+
return err_info;
299315
}
300316

301317
let (i, a, b) = diff_fields[0];
@@ -309,7 +325,7 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
309325
E0376,
310326
"the trait `CoerceUnsized` may only be implemented \
311327
for a coercion between structures");
312-
return;
328+
return err_info;
313329
}
314330
};
315331

@@ -331,8 +347,8 @@ fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
331347
.caller_bounds);
332348
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
333349

334-
if let Some(kind) = kind {
335-
tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind);
350+
CoerceUnsizedInfo {
351+
custom_kind: kind
336352
}
337-
});
353+
})
338354
}

‎src/librustc_typeck/coherence/inherent.rs renamed to ‎src/librustc_typeck/coherence/inherent_impls.rs

+76-107
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,82 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
//! The code in this module gathers up all of the inherent impls in
12+
//! the current crate and organizes them in a map. It winds up
13+
//! touching the whole crate and thus must be recomputed completely
14+
//! for any change, but it is very cheap to compute. In practice, most
15+
//! code in the compiler never *directly* requests this map. Instead,
16+
//! it requests the inherent impls specific to some type (via
17+
//! `ty::queries::inherent_impls::get(def_id)`). That value, however,
18+
//! is computed by selecting an idea from this table.
19+
1120
use rustc::dep_graph::DepNode;
12-
use rustc::hir::def_id::DefId;
21+
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
1322
use rustc::hir;
1423
use rustc::hir::itemlikevisit::ItemLikeVisitor;
15-
use rustc::lint;
16-
use rustc::traits::{self, Reveal};
17-
use rustc::ty::{self, TyCtxt};
24+
use rustc::ty::{self, CrateInherentImpls, TyCtxt};
25+
use rustc::util::nodemap::DefIdMap;
1826

27+
use std::rc::Rc;
1928
use syntax::ast;
20-
use syntax_pos::Span;
29+
use syntax_pos::{DUMMY_SP, Span};
30+
31+
/// On-demand query: yields a map containing all types mapped to their inherent impls.
32+
pub fn crate_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
33+
crate_num: CrateNum)
34+
-> CrateInherentImpls {
35+
assert_eq!(crate_num, LOCAL_CRATE);
36+
37+
let krate = tcx.hir.krate();
38+
let mut collect = InherentCollect {
39+
tcx,
40+
impls_map: CrateInherentImpls {
41+
inherent_impls: DefIdMap()
42+
}
43+
};
44+
krate.visit_all_item_likes(&mut collect);
45+
collect.impls_map
46+
}
47+
48+
/// On-demand query: yields a vector of the inherent impls for a specific type.
49+
pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
50+
ty_def_id: DefId)
51+
-> Rc<Vec<DefId>> {
52+
assert!(ty_def_id.is_local());
53+
54+
// NB. Until we adopt the red-green dep-tracking algorithm (see
55+
// [the plan] for details on that), we do some hackery here to get
56+
// the dependencies correct. Basically, we use a `with_ignore` to
57+
// read the result we want. If we didn't have the `with_ignore`,
58+
// we would wind up with a dependency on the entire crate, which
59+
// we don't want. Then we go and add dependencies on all the impls
60+
// in the result (which is what we wanted).
61+
//
62+
// The result is a graph with an edge from `Hir(I)` for every impl
63+
// `I` defined on some type `T` to `CoherentInherentImpls(T)`,
64+
// thus ensuring that if any of those impls change, the set of
65+
// inherent impls is considered dirty.
66+
//
67+
// [the plan]: https://github.com/rust-lang/rust-roadmap/issues/4
68+
69+
let result = tcx.dep_graph.with_ignore(|| {
70+
let crate_map = ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, ty_def_id.krate);
71+
match crate_map.inherent_impls.get(&ty_def_id) {
72+
Some(v) => v.clone(),
73+
None => Rc::new(vec![]),
74+
}
75+
});
76+
77+
for &impl_def_id in &result[..] {
78+
tcx.dep_graph.read(DepNode::Hir(impl_def_id));
79+
}
80+
81+
result
82+
}
2183

2284
struct InherentCollect<'a, 'tcx: 'a> {
23-
tcx: TyCtxt<'a, 'tcx, 'tcx>
85+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
86+
impls_map: CrateInherentImpls,
2487
}
2588

2689
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
@@ -209,25 +272,19 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
209272
}
210273

211274
impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
212-
fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
275+
fn check_def_id(&mut self, item: &hir::Item, def_id: DefId) {
213276
if def_id.is_local() {
214277
// Add the implementation to the mapping from implementation to base
215278
// type def ID, if there is a base type for this implementation and
216279
// the implementation does not have any associated traits.
217280
let impl_def_id = self.tcx.hir.local_def_id(item.id);
281+
let mut rc_vec = self.impls_map.inherent_impls
282+
.entry(def_id)
283+
.or_insert_with(|| Rc::new(vec![]));
218284

219-
// Subtle: it'd be better to collect these into a local map
220-
// and then write the vector only once all items are known,
221-
// but that leads to degenerate dep-graphs. The problem is
222-
// that the write of that big vector winds up having reads
223-
// from *all* impls in the krate, since we've lost the
224-
// precision basically. This would be ok in the firewall
225-
// model so once we've made progess towards that we can modify
226-
// the strategy here. In the meantime, using `push` is ok
227-
// because we are doing this as a pre-pass before anyone
228-
// actually reads from `inherent_impls` -- and we know this is
229-
// true beacuse we hold the refcell lock.
230-
self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
285+
// At this point, there should not be any clones of the
286+
// `Rc`, so we can still safely push into it in place:
287+
Rc::get_mut(&mut rc_vec).unwrap().push(impl_def_id);
231288
} else {
232289
struct_span_err!(self.tcx.sess,
233290
item.span,
@@ -266,91 +323,3 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
266323
}
267324
}
268325

269-
struct InherentOverlapChecker<'a, 'tcx: 'a> {
270-
tcx: TyCtxt<'a, 'tcx, 'tcx>
271-
}
272-
273-
impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
274-
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
275-
#[derive(Copy, Clone, PartialEq)]
276-
enum Namespace {
277-
Type,
278-
Value,
279-
}
280-
281-
let name_and_namespace = |def_id| {
282-
let item = self.tcx.associated_item(def_id);
283-
(item.name, match item.kind {
284-
ty::AssociatedKind::Type => Namespace::Type,
285-
ty::AssociatedKind::Const |
286-
ty::AssociatedKind::Method => Namespace::Value,
287-
})
288-
};
289-
290-
let impl_items1 = self.tcx.associated_item_def_ids(impl1);
291-
let impl_items2 = self.tcx.associated_item_def_ids(impl2);
292-
293-
for &item1 in &impl_items1[..] {
294-
let (name, namespace) = name_and_namespace(item1);
295-
296-
for &item2 in &impl_items2[..] {
297-
if (name, namespace) == name_and_namespace(item2) {
298-
let msg = format!("duplicate definitions with name `{}`", name);
299-
let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
300-
self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
301-
node_id,
302-
self.tcx.span_of_impl(item1).unwrap(),
303-
msg);
304-
}
305-
}
306-
}
307-
}
308-
309-
fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
310-
let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
311-
312-
let inherent_impls = self.tcx.maps.inherent_impls.borrow();
313-
let impls = match inherent_impls.get(&ty_def_id) {
314-
Some(impls) => impls,
315-
None => return,
316-
};
317-
318-
for (i, &impl1_def_id) in impls.iter().enumerate() {
319-
for &impl2_def_id in &impls[(i + 1)..] {
320-
self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
321-
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
322-
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
323-
}
324-
});
325-
}
326-
}
327-
}
328-
}
329-
330-
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
331-
fn visit_item(&mut self, item: &'v hir::Item) {
332-
match item.node {
333-
hir::ItemEnum(..) |
334-
hir::ItemStruct(..) |
335-
hir::ItemTrait(..) |
336-
hir::ItemUnion(..) => {
337-
let type_def_id = self.tcx.hir.local_def_id(item.id);
338-
self.check_for_overlapping_inherent_impls(type_def_id);
339-
}
340-
_ => {}
341-
}
342-
}
343-
344-
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
345-
}
346-
347-
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
348-
}
349-
}
350-
351-
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
352-
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
353-
&mut InherentCollect { tcx });
354-
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
355-
&mut InherentOverlapChecker { tcx });
356-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
12+
use rustc::hir;
13+
use rustc::hir::itemlikevisit::ItemLikeVisitor;
14+
use rustc::lint;
15+
use rustc::traits::{self, Reveal};
16+
use rustc::ty::{self, TyCtxt};
17+
18+
use syntax_pos::DUMMY_SP;
19+
20+
pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
21+
crate_num: CrateNum) {
22+
assert_eq!(crate_num, LOCAL_CRATE);
23+
let krate = tcx.hir.krate();
24+
krate.visit_all_item_likes(&mut InherentOverlapChecker { tcx });
25+
}
26+
27+
struct InherentOverlapChecker<'a, 'tcx: 'a> {
28+
tcx: TyCtxt<'a, 'tcx, 'tcx>
29+
}
30+
31+
impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
32+
fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
33+
#[derive(Copy, Clone, PartialEq)]
34+
enum Namespace {
35+
Type,
36+
Value,
37+
}
38+
39+
let name_and_namespace = |def_id| {
40+
let item = self.tcx.associated_item(def_id);
41+
(item.name, match item.kind {
42+
ty::AssociatedKind::Type => Namespace::Type,
43+
ty::AssociatedKind::Const |
44+
ty::AssociatedKind::Method => Namespace::Value,
45+
})
46+
};
47+
48+
let impl_items1 = self.tcx.associated_item_def_ids(impl1);
49+
let impl_items2 = self.tcx.associated_item_def_ids(impl2);
50+
51+
for &item1 in &impl_items1[..] {
52+
let (name, namespace) = name_and_namespace(item1);
53+
54+
for &item2 in &impl_items2[..] {
55+
if (name, namespace) == name_and_namespace(item2) {
56+
let msg = format!("duplicate definitions with name `{}`", name);
57+
let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
58+
self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
59+
node_id,
60+
self.tcx.span_of_impl(item1).unwrap(),
61+
msg);
62+
}
63+
}
64+
}
65+
}
66+
67+
fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
68+
let impls = ty::queries::inherent_impls::get(self.tcx, DUMMY_SP, ty_def_id);
69+
70+
for (i, &impl1_def_id) in impls.iter().enumerate() {
71+
for &impl2_def_id in &impls[(i + 1)..] {
72+
self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
73+
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
74+
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
75+
}
76+
});
77+
}
78+
}
79+
}
80+
}
81+
82+
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
83+
fn visit_item(&mut self, item: &'v hir::Item) {
84+
match item.node {
85+
hir::ItemEnum(..) |
86+
hir::ItemStruct(..) |
87+
hir::ItemTrait(..) |
88+
hir::ItemUnion(..) => {
89+
let type_def_id = self.tcx.hir.local_def_id(item.id);
90+
self.check_for_overlapping_inherent_impls(type_def_id);
91+
}
92+
_ => {}
93+
}
94+
}
95+
96+
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
97+
}
98+
99+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
100+
}
101+
}
102+

‎src/librustc_typeck/coherence/mod.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ use syntax::ast;
2424
use syntax_pos::DUMMY_SP;
2525

2626
mod builtin;
27-
mod inherent;
27+
mod inherent_impls;
28+
mod inherent_impls_overlap;
2829
mod orphan;
2930
mod overlap;
3031
mod unsafety;
@@ -102,9 +103,16 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
102103
}
103104

104105
pub fn provide(providers: &mut Providers) {
106+
use self::builtin::coerce_unsized_info;
107+
use self::inherent_impls::{crate_inherent_impls, inherent_impls};
108+
use self::inherent_impls_overlap::crate_inherent_impls_overlap_check;
109+
105110
*providers = Providers {
106111
coherent_trait,
107-
coherent_inherent_impls,
112+
crate_inherent_impls,
113+
inherent_impls,
114+
crate_inherent_impls_overlap_check,
115+
coerce_unsized_info,
108116
..*providers
109117
};
110118
}
@@ -123,10 +131,6 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
123131
builtin::check_trait(tcx, def_id);
124132
}
125133

126-
fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) {
127-
inherent::check(tcx);
128-
}
129-
130134
pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
131135
let _task = tcx.dep_graph.in_task(DepNode::Coherence);
132136
for &trait_def_id in tcx.hir.krate().trait_impls.keys() {
@@ -137,5 +141,7 @@ pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
137141
orphan::check(tcx);
138142
overlap::check_default_impls(tcx);
139143

140-
ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
144+
// these queries are executed for side-effects (error reporting):
145+
ty::queries::crate_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
146+
ty::queries::crate_inherent_impls_overlap_check::get(tcx, DUMMY_SP, LOCAL_CRATE);
141147
}

‎src/librustdoc/clean/inline.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,12 @@ fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef {
232232

233233
pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
234234
let tcx = cx.tcx;
235-
tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did);
236235
let mut impls = Vec::new();
237236

238-
if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
239-
for &did in i.iter() {
240-
build_impl(cx, did, &mut impls);
241-
}
237+
for &did in ty::queries::inherent_impls::get(tcx, DUMMY_SP, did).iter() {
238+
build_impl(cx, did, &mut impls);
242239
}
240+
243241
// If this is the first time we've inlined something from another crate, then
244242
// we inline *all* impls from all the crates into this crate. Note that there's
245243
// currently no way for us to filter this based on type, and we likely need

0 commit comments

Comments
 (0)
Please sign in to comment.