Skip to content

Commit b8b4f5f

Browse files
committed
only insert global predicates into the global cache once we've
completely proven them to be true
1 parent f291318 commit b8b4f5f

File tree

1 file changed

+27
-36
lines changed

1 file changed

+27
-36
lines changed

src/librustc/middle/traits/fulfill.rs

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ pub struct FulfillmentContext<'tcx> {
8686
// obligations (otherwise, it's easy to fail to walk to a
8787
// particular node-id).
8888
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
89-
90-
pub errors_will_be_reported: bool,
9189
}
9290

9391
#[derive(Clone)]
@@ -105,28 +103,11 @@ pub struct PendingPredicateObligation<'tcx> {
105103

106104
impl<'tcx> FulfillmentContext<'tcx> {
107105
/// Creates a new fulfillment context.
108-
///
109-
/// `errors_will_be_reported` indicates whether ALL errors that
110-
/// are generated by this fulfillment context will be reported to
111-
/// the end user. This is used to inform caching, because it
112-
/// allows us to conclude that traits that resolve successfully
113-
/// will in fact always resolve successfully (in particular, it
114-
/// guarantees that if some dependent obligation encounters a
115-
/// problem, compilation will be aborted). If you're not sure of
116-
/// the right value here, pass `false`, as that is the more
117-
/// conservative option.
118-
///
119-
/// FIXME -- a better option would be to hold back on modifying
120-
/// the global cache until we know that all dependent obligations
121-
/// are also satisfied. In that case, we could actually remove
122-
/// this boolean flag, and we'd also avoid the problem of squelching
123-
/// duplicate errors that occur across fns.
124-
pub fn new(errors_will_be_reported: bool) -> FulfillmentContext<'tcx> {
106+
pub fn new() -> FulfillmentContext<'tcx> {
125107
FulfillmentContext {
126108
duplicate_set: FulfilledPredicates::new(),
127109
predicates: ObligationForest::new(),
128110
region_obligations: NodeMap(),
129-
errors_will_be_reported: errors_will_be_reported,
130111
}
131112
}
132113

@@ -250,23 +231,27 @@ impl<'tcx> FulfillmentContext<'tcx> {
250231
tcx: &ty::ctxt<'tcx>,
251232
predicate: &ty::Predicate<'tcx>)
252233
-> bool {
253-
// This is a kind of dirty hack to allow us to avoid "rederiving"
254-
// things that we have already proven in other methods.
255-
//
256-
// The idea is that any predicate that doesn't involve type
257-
// parameters and which only involves the 'static region (and
258-
// no other regions) is universally solvable, since impls are global.
259-
//
260-
// This is particularly important since even if we have a
261-
// cache hit in the selection context, we still wind up
262-
// evaluating the 'nested obligations'. This cache lets us
263-
// skip those.
264-
265-
if self.errors_will_be_reported && predicate.is_global() {
266-
tcx.fulfilled_predicates.borrow_mut().is_duplicate_or_add(predicate)
267-
} else {
268-
self.duplicate_set.is_duplicate_or_add(predicate)
234+
// For "global" predicates -- that is, predicates that don't
235+
// involve type parameters, inference variables, or regions
236+
// other than 'static -- we can check the cache in the tcx,
237+
// which allows us to leverage work from other threads. Note
238+
// that we don't add anything to this cache yet (unlike the
239+
// local cache). This is because the tcx cache maintains the
240+
// invariant that it only contains things that have been
241+
// proven, and we have not yet proven that `predicate` holds.
242+
if predicate.is_global() && tcx.fulfilled_predicates.borrow().is_duplicate(predicate) {
243+
return true;
269244
}
245+
246+
// If `predicate` is not global, or not present in the tcx
247+
// cache, we can still check for it in our local cache and add
248+
// it if not present. Note that if we find this predicate in
249+
// the local cache we can stop immediately, without reporting
250+
// any errors, even though we don't know yet if it is
251+
// true. This is because, while we don't yet know if the
252+
// predicate holds, we know that this same fulfillment context
253+
// already is in the process of finding out.
254+
self.duplicate_set.is_duplicate_or_add(predicate)
270255
}
271256

272257
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
@@ -294,6 +279,12 @@ impl<'tcx> FulfillmentContext<'tcx> {
294279

295280
debug!("select_where_possible: outcome={:?}", outcome);
296281

282+
// these are obligations that were proven to be true.
283+
for pending_obligation in outcome.successful {
284+
let predicate = &pending_obligation.obligation.predicate;
285+
if predicate.is_global() {
286+
selcx.tcx().fulfilled_predicates.borrow_mut()
287+
.is_duplicate_or_add(predicate);
297288
}
298289
}
299290

0 commit comments

Comments
 (0)