Skip to content

Commit fc27262

Browse files
committed
make ty and impl_trait_ref private
This requires copying out the cycle error to avoid a cyclic borrow. Is this a problem? Are there paths where we expect cycles to arise and not result in errors? (In such cases, we could add a faster way to test for cycle.)
1 parent 04e3a6e commit fc27262

File tree

2 files changed

+68
-30
lines changed

2 files changed

+68
-30
lines changed

src/librustc/ty/item_path.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,19 @@ use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1313
use ty::{self, Ty, TyCtxt};
1414
use syntax::ast;
1515
use syntax::symbol::Symbol;
16+
use syntax_pos::DUMMY_SP;
1617

1718
use std::cell::Cell;
1819

1920
thread_local! {
20-
static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false)
21+
static FORCE_ABSOLUTE: Cell<bool> = Cell::new(false);
22+
static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
2123
}
2224

23-
/// Enforces that item_path_str always returns an absolute path.
24-
/// This is useful when building symbols that contain types,
25-
/// where we want the crate name to be part of the symbol.
25+
/// Enforces that item_path_str always returns an absolute path and
26+
/// also enables "type-based" impl paths. This is used when building
27+
/// symbols that contain types, where we want the crate name to be
28+
/// part of the symbol.
2629
pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
2730
FORCE_ABSOLUTE.with(|force| {
2831
let old = force.get();
@@ -33,6 +36,20 @@ pub fn with_forced_absolute_paths<F: FnOnce() -> R, R>(f: F) -> R {
3336
})
3437
}
3538

39+
/// Force us to name impls with just the filename/line number. We
40+
/// normally try to use types. But at some points, notably while printing
41+
/// cycle errors, this can result in extra or suboptimal error output,
42+
/// so this variable disables that check.
43+
pub fn with_forced_impl_filename_line<F: FnOnce() -> R, R>(f: F) -> R {
44+
FORCE_IMPL_FILENAME_LINE.with(|force| {
45+
let old = force.get();
46+
force.set(true);
47+
let result = f();
48+
force.set(old);
49+
result
50+
})
51+
}
52+
3653
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
3754
/// Returns a string identifying this def-id. This string is
3855
/// suitable for user output. It is relative to the current crate
@@ -199,14 +216,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
199216
{
200217
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
201218

202-
let use_types = if !impl_def_id.is_local() {
203-
// always have full types available for extern crates
204-
true
205-
} else {
206-
// for local crates, check whether type info is
207-
// available; typeck might not have completed yet
208-
self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) &&
209-
self.maps.type_of.borrow().contains_key(&impl_def_id)
219+
// Always use types for non-local impls, where types are always
220+
// available, and filename/line-number is mostly uninteresting.
221+
let use_types = !impl_def_id.is_local() || {
222+
// Otherwise, use filename/line-number if forced.
223+
let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get());
224+
!force_no_types && {
225+
// Otherwise, use types if we can query them without inducing a cycle.
226+
ty::queries::impl_trait_ref::try_get(self, DUMMY_SP, impl_def_id).is_ok() &&
227+
ty::queries::type_of::try_get(self, DUMMY_SP, impl_def_id).is_ok()
228+
}
210229
};
211230

212231
if !use_types {

src/librustc/ty/maps.rs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ use middle::privacy::AccessLevels;
1616
use mir;
1717
use session::CompileResult;
1818
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
19+
use ty::item_path;
1920
use ty::subst::Substs;
2021
use util::nodemap::NodeSet;
2122

2223
use rustc_data_structures::indexed_vec::IndexVec;
2324
use std::cell::{RefCell, RefMut};
25+
use std::mem;
2426
use std::ops::Deref;
2527
use std::rc::Rc;
2628
use syntax_pos::{Span, DUMMY_SP};
@@ -138,24 +140,36 @@ pub struct CycleError<'a, 'tcx: 'a> {
138140

139141
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
140142
pub fn report_cycle(self, CycleError { span, cycle }: CycleError) {
141-
assert!(!cycle.is_empty());
142-
143-
let mut err = struct_span_err!(self.sess, span, E0391,
144-
"unsupported cyclic reference between types/traits detected");
145-
err.span_label(span, &format!("cyclic reference"));
146-
147-
err.span_note(cycle[0].0, &format!("the cycle begins when {}...",
148-
cycle[0].1.describe(self)));
149-
150-
for &(span, ref query) in &cycle[1..] {
151-
err.span_note(span, &format!("...which then requires {}...",
152-
query.describe(self)));
153-
}
143+
// Subtle: release the refcell lock before invoking `describe()`
144+
// below by dropping `cycle`.
145+
let stack = cycle.to_vec();
146+
mem::drop(cycle);
147+
148+
assert!(!stack.is_empty());
149+
150+
// Disable naming impls with types in this path, since that
151+
// sometimes cycles itself, leading to extra cycle errors.
152+
// (And cycle errors around impls tend to occur during the
153+
// collect/coherence phases anyhow.)
154+
item_path::with_forced_impl_filename_line(|| {
155+
let mut err =
156+
struct_span_err!(self.sess, span, E0391,
157+
"unsupported cyclic reference between types/traits detected");
158+
err.span_label(span, &format!("cyclic reference"));
159+
160+
err.span_note(stack[0].0, &format!("the cycle begins when {}...",
161+
stack[0].1.describe(self)));
162+
163+
for &(span, ref query) in &stack[1..] {
164+
err.span_note(span, &format!("...which then requires {}...",
165+
query.describe(self)));
166+
}
154167

155-
err.note(&format!("...which then again requires {}, completing the cycle.",
156-
cycle[0].1.describe(self)));
168+
err.note(&format!("...which then again requires {}, completing the cycle.",
169+
stack[0].1.describe(self)));
157170

158-
err.emit();
171+
err.emit();
172+
});
159173
}
160174

161175
fn cycle_check<F, R>(self, span: Span, query: Query<'gcx>, compute: F)
@@ -328,6 +342,11 @@ macro_rules! define_maps {
328342
-> Result<R, CycleError<'a, $tcx>>
329343
where F: FnOnce(&$V) -> R
330344
{
345+
debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})",
346+
stringify!($name),
347+
key,
348+
span);
349+
331350
if let Some(result) = tcx.maps.$name.borrow().get(&key) {
332351
return Ok(f(result));
333352
}
@@ -434,7 +453,7 @@ macro_rules! define_maps {
434453
// the driver creates (using several `rustc_*` crates).
435454
define_maps! { <'tcx>
436455
/// Records the type of every item.
437-
[pub] type_of: ItemSignature(DefId) -> Ty<'tcx>,
456+
[] type_of: ItemSignature(DefId) -> Ty<'tcx>,
438457

439458
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
440459
/// associated generics and predicates.
@@ -473,7 +492,7 @@ define_maps! { <'tcx>
473492
/// Maps from a trait item to the trait item "descriptor"
474493
[] associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
475494

476-
[pub] impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
495+
[] impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
477496
[] impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity,
478497

479498
/// Maps a DefId of a type to a list of its inherent impls.

0 commit comments

Comments
 (0)