Skip to content

Commit c944160

Browse files
committed
rustc: allow handling cycle errors gracefully in on-demand.
1 parent bfd642e commit c944160

File tree

8 files changed

+104
-54
lines changed

8 files changed

+104
-54
lines changed

src/librustc/dep_graph/dep_tracking_map.rs

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use hir::def_id::DefId;
1212
use rustc_data_structures::fx::FxHashMap;
1313
use std::cell::RefCell;
14+
use std::collections::hash_map::Entry;
1415
use std::ops::Index;
1516
use std::hash::Hash;
1617
use std::marker::PhantomData;
@@ -67,6 +68,11 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
6768
assert!(old_value.is_none());
6869
}
6970

71+
pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
72+
self.write(&k);
73+
self.map.entry(k)
74+
}
75+
7076
pub fn contains_key(&self, k: &M::Key) -> bool {
7177
self.read(k);
7278
self.map.contains_key(k)

src/librustc/ty/maps.rs

+70-30
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ use hir::def_id::{CrateNum, DefId};
1313
use middle::const_val::ConstVal;
1414
use mir;
1515
use ty::{self, Ty, TyCtxt};
16-
use util::common::MemoizationMap;
1716

1817
use rustc_data_structures::indexed_vec::IndexVec;
19-
use std::cell::RefCell;
18+
use std::cell::{RefCell, RefMut};
2019
use std::rc::Rc;
2120
use syntax_pos::{Span, DUMMY_SP};
2221

@@ -66,8 +65,13 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
6665
}
6766
}
6867

68+
pub struct CycleError<'a> {
69+
span: Span,
70+
cycle: RefMut<'a, [(Span, Query)]>
71+
}
72+
6973
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
70-
fn report_cycle(self, span: Span, cycle: &[(Span, Query)]) {
74+
pub fn report_cycle(self, CycleError { span, cycle }: CycleError) {
7175
assert!(!cycle.is_empty());
7276

7377
let mut err = struct_span_err!(self.sess, span, E0391,
@@ -88,24 +92,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
8892
err.emit();
8993
}
9094

91-
fn cycle_check<F, R>(self, span: Span, query: Query, compute: F) -> R
95+
fn cycle_check<F, R>(self, span: Span, query: Query, compute: F)
96+
-> Result<R, CycleError<'a>>
9297
where F: FnOnce() -> R
9398
{
9499
{
95100
let mut stack = self.maps.query_stack.borrow_mut();
96101
if let Some((i, _)) = stack.iter().enumerate().rev()
97102
.find(|&(_, &(_, ref q))| *q == query) {
98-
let cycle = &stack[i..];
99-
self.report_cycle(span, cycle);
100-
return R::from_cycle_error(self.global_tcx());
103+
return Err(CycleError {
104+
span: span,
105+
cycle: RefMut::map(stack, |stack| &mut stack[i..])
106+
});
101107
}
102108
stack.push((span, query));
103109
}
104110

105111
let result = compute();
106112

107113
self.maps.query_stack.borrow_mut().pop();
108-
result
114+
115+
Ok(result)
109116
}
110117
}
111118

@@ -140,7 +147,7 @@ macro_rules! define_maps {
140147
pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
141148
pub struct Maps<$tcx> {
142149
providers: IndexVec<CrateNum, Providers<$tcx>>,
143-
pub query_stack: RefCell<Vec<(Span, Query)>>,
150+
query_stack: RefCell<Vec<(Span, Query)>>,
144151
$($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
145152
}
146153

@@ -182,7 +189,60 @@ macro_rules! define_maps {
182189
$(impl<$tcx> DepTrackingMapConfig for queries::$name<$tcx> {
183190
type Key = $K;
184191
type Value = $V;
185-
fn to_dep_node(key: &$K) -> DepNode<DefId> { DepNode::$node(*key) }
192+
193+
#[allow(unused)]
194+
fn to_dep_node(key: &$K) -> DepNode<DefId> {
195+
use dep_graph::DepNode::*;
196+
197+
$node(*key)
198+
}
199+
}
200+
impl<'a, $tcx, 'lcx> queries::$name<$tcx> {
201+
fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
202+
mut span: Span,
203+
key: $K,
204+
f: F)
205+
-> Result<R, CycleError<'a>>
206+
where F: FnOnce(&$V) -> R
207+
{
208+
if let Some(result) = tcx.maps.$name.borrow().get(&key) {
209+
return Ok(f(result));
210+
}
211+
212+
// FIXME(eddyb) Get more valid Span's on queries.
213+
if span == DUMMY_SP {
214+
span = key.default_span(tcx);
215+
}
216+
217+
let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key));
218+
219+
let result = tcx.cycle_check(span, Query::$name(key), || {
220+
let provider = tcx.maps.providers[key.map_crate()].$name;
221+
provider(tcx.global_tcx(), key)
222+
})?;
223+
224+
Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
225+
}
226+
227+
pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
228+
-> Result<$V, CycleError<'a>> {
229+
Self::try_get_with(tcx, span, key, Clone::clone)
230+
}
231+
232+
$(#[$attr])*
233+
pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V {
234+
Self::try_get(tcx, span, key).unwrap_or_else(|e| {
235+
tcx.report_cycle(e);
236+
Value::from_cycle_error(tcx.global_tcx())
237+
})
238+
}
239+
240+
pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) {
241+
match Self::try_get_with(tcx, span, key, |_| ()) {
242+
Ok(()) => {}
243+
Err(e) => tcx.report_cycle(e)
244+
}
245+
}
186246
})*
187247

188248
pub struct Providers<$tcx> {
@@ -203,26 +263,6 @@ macro_rules! define_maps {
203263
Providers { $($name),* }
204264
}
205265
}
206-
207-
impl<'a, $tcx, 'lcx> Maps<$tcx> {
208-
$($(#[$attr])*
209-
pub fn $name(&self,
210-
tcx: TyCtxt<'a, $tcx, 'lcx>,
211-
mut span: Span,
212-
key: $K) -> $V {
213-
self.$name.memoize(key, || {
214-
// FIXME(eddyb) Get more valid Span's on queries.
215-
if span == DUMMY_SP {
216-
span = key.default_span(tcx);
217-
}
218-
219-
tcx.cycle_check(span, Query::$name(key), || {
220-
let provider = self.providers[key.map_crate()].$name;
221-
provider(tcx.global_tcx(), key)
222-
})
223-
})
224-
})*
225-
}
226266
}
227267
}
228268

src/librustc/ty/mod.rs

+17-15
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ pub use self::context::{Lift, TypeckTables};
7575

7676
pub use self::trait_def::{TraitDef, TraitFlags};
7777

78+
pub use self::maps::queries;
79+
7880
pub mod adjustment;
7981
pub mod cast;
8082
pub mod error;
@@ -1947,7 +1949,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
19471949
}
19481950

19491951
pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> {
1950-
self.maps.typeck_tables(self, DUMMY_SP, def_id)
1952+
queries::typeck_tables::get(self, DUMMY_SP, def_id)
19511953
}
19521954

19531955
pub fn expr_span(self, id: NodeId) -> Span {
@@ -2055,12 +2057,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
20552057
}
20562058

20572059
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
2058-
self.maps.custom_coerce_unsized_kind(self, DUMMY_SP, did)
2060+
queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
20592061
}
20602062

20612063
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
20622064
if !def_id.is_local() {
2063-
return self.maps.associated_item(self, DUMMY_SP, def_id);
2065+
return queries::associated_item::get(self, DUMMY_SP, def_id);
20642066
}
20652067

20662068
self.maps.associated_item.memoize(def_id, || {
@@ -2165,7 +2167,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
21652167

21662168
pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
21672169
if !def_id.is_local() {
2168-
return self.maps.associated_item_def_ids(self, DUMMY_SP, def_id);
2170+
return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id);
21692171
}
21702172

21712173
self.maps.associated_item_def_ids.memoize(def_id, || {
@@ -2200,7 +2202,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
22002202
/// Returns the trait-ref corresponding to a given impl, or None if it is
22012203
/// an inherent impl.
22022204
pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> {
2203-
self.maps.impl_trait_ref(self, DUMMY_SP, id)
2205+
queries::impl_trait_ref::get(self, DUMMY_SP, id)
22042206
}
22052207

22062208
// Returns `ty::VariantDef` if `def` refers to a struct,
@@ -2279,37 +2281,37 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
22792281
// If the given item is in an external crate, looks up its type and adds it to
22802282
// the type cache. Returns the type parameters and type.
22812283
pub fn item_type(self, did: DefId) -> Ty<'gcx> {
2282-
self.maps.ty(self, DUMMY_SP, did)
2284+
queries::ty::get(self, DUMMY_SP, did)
22832285
}
22842286

22852287
/// Given the did of a trait, returns its canonical trait ref.
22862288
pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef {
2287-
self.maps.trait_def(self, DUMMY_SP, did)
2289+
queries::trait_def::get(self, DUMMY_SP, did)
22882290
}
22892291

22902292
/// Given the did of an ADT, return a reference to its definition.
22912293
pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef {
2292-
self.maps.adt_def(self, DUMMY_SP, did)
2294+
queries::adt_def::get(self, DUMMY_SP, did)
22932295
}
22942296

22952297
/// Given the did of an item, returns its generics.
22962298
pub fn item_generics(self, did: DefId) -> &'gcx Generics {
2297-
self.maps.generics(self, DUMMY_SP, did)
2299+
queries::generics::get(self, DUMMY_SP, did)
22982300
}
22992301

23002302
/// Given the did of an item, returns its full set of predicates.
23012303
pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
2302-
self.maps.predicates(self, DUMMY_SP, did)
2304+
queries::predicates::get(self, DUMMY_SP, did)
23032305
}
23042306

23052307
/// Given the did of a trait, returns its superpredicates.
23062308
pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
2307-
self.maps.super_predicates(self, DUMMY_SP, did)
2309+
queries::super_predicates::get(self, DUMMY_SP, did)
23082310
}
23092311

23102312
/// Given the did of an item, returns its MIR, borrowed immutably.
23112313
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
2312-
self.maps.mir(self, DUMMY_SP, did).borrow()
2314+
queries::mir::get(self, DUMMY_SP, did).borrow()
23132315
}
23142316

23152317
/// If `type_needs_drop` returns true, then `ty` is definitely
@@ -2361,7 +2363,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
23612363
}
23622364

23632365
pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
2364-
self.maps.variances(self, DUMMY_SP, item_id)
2366+
queries::variances::get(self, DUMMY_SP, item_id)
23652367
}
23662368

23672369
pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
@@ -2436,11 +2438,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
24362438
}
24372439

24382440
pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
2439-
self.maps.closure_kind(self, DUMMY_SP, def_id)
2441+
queries::closure_kind::get(self, DUMMY_SP, def_id)
24402442
}
24412443

24422444
pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
2443-
self.maps.closure_type(self, DUMMY_SP, def_id)
2445+
queries::closure_type::get(self, DUMMY_SP, def_id)
24442446
}
24452447

24462448
/// Given the def_id of an impl, return the def_id of the trait it implements.

src/librustc_metadata/cstore_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ macro_rules! provide {
4747
(<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => {
4848
pub fn provide<$lt>(providers: &mut Providers<$lt>) {
4949
$(fn $name<'a, $lt:$lt>($tcx: TyCtxt<'a, $lt, $lt>, $def_id: DefId)
50-
-> <ty::maps::queries::$name<$lt> as
50+
-> <ty::queries::$name<$lt> as
5151
DepTrackingMapConfig>::Value {
5252
assert!(!$def_id.is_local());
5353

src/librustc_metadata/encoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
264264
discr: variant.discr,
265265
evaluated_discr: match variant.discr {
266266
ty::VariantDiscr::Explicit(def_id) => {
267-
tcx.maps.monomorphic_const_eval(tcx, DUMMY_SP, def_id).ok()
267+
ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
268268
}
269269
ty::VariantDiscr::Relative(_) => None
270270
},

src/librustc_typeck/astconv.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
243243
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
244244
let default_needs_object_self = |p: &ty::TypeParameterDef| {
245245
if is_object && p.has_default {
246-
if tcx.maps.ty(tcx, span, p.def_id).has_self_ty() {
246+
if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() {
247247
// There is no suitable inference default for a type parameter
248248
// that references self, in an object type.
249249
return true;
@@ -310,7 +310,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
310310
tcx.types.err
311311
} else {
312312
// This is a default type parameter.
313-
tcx.maps.ty(tcx, span, def.def_id).subst_spanned(tcx, substs, Some(span))
313+
ty::queries::ty::get(tcx, span, def.def_id)
314+
.subst_spanned(tcx, substs, Some(span))
314315
}
315316
} else {
316317
// We've already errored above about the mismatch.
@@ -599,7 +600,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
599600
-> Ty<'tcx>
600601
{
601602
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
602-
self.tcx().maps.ty(self.tcx(), span, did).subst(self.tcx(), substs)
603+
ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs)
603604
}
604605

605606
/// Transform a PolyTraitRef into a PolyExistentialTraitRef by
@@ -985,7 +986,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
985986
assert_eq!(opt_self_ty, None);
986987
tcx.prohibit_type_params(&path.segments);
987988

988-
let ty = tcx.maps.ty(tcx, span, def_id);
989+
let ty = ty::queries::ty::get(tcx, span, def_id);
989990
if let Some(free_substs) = self.get_free_substs() {
990991
ty.subst(tcx, free_substs)
991992
} else {

src/librustc_typeck/collect.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
262262
def_id: DefId)
263263
-> ty::GenericPredicates<'tcx>
264264
{
265-
self.tcx.maps.type_param_predicates(self.tcx, span, (self.item_def_id, def_id))
265+
ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id))
266266
}
267267

268268
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
@@ -532,7 +532,7 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
532532
hir::ItemTrait(..) => {
533533
tcx.item_generics(def_id);
534534
tcx.lookup_trait_def(def_id);
535-
tcx.maps.super_predicates(tcx, it.span, def_id);
535+
ty::queries::super_predicates::get(tcx, it.span, def_id);
536536
tcx.item_predicates(def_id);
537537
},
538538
hir::ItemStruct(ref struct_def, _) |
@@ -836,7 +836,7 @@ fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
836836
// Now require that immediate supertraits are converted,
837837
// which will, in turn, reach indirect supertraits.
838838
for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
839-
tcx.maps.super_predicates(tcx, item.span, bound.def_id());
839+
ty::queries::super_predicates::get(tcx, item.span, bound.def_id());
840840
}
841841

842842
ty::GenericPredicates {

src/test/compile-fail/cycle-trait-default-type-trait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
trait Foo<X = Box<Foo>> {
1515
//~^ ERROR unsupported cyclic reference
16+
//~| ERROR unsupported cyclic reference
1617
}
1718

1819
fn main() { }

0 commit comments

Comments
 (0)