Skip to content

Commit e4309c2

Browse files
committed
Auto merge of #29209 - arielb1:exponential-evaluation, r=nmatsakis
This fixes an exponential worst-case and also provides an additional 1% perf improvement. r? @nikomatsakis
2 parents 68f8122 + 5982594 commit e4309c2

14 files changed

+530
-299
lines changed

src/librustc/middle/traits/mod.rs

+46-24
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub use self::object_safety::object_safety_violations;
4444
pub use self::object_safety::ObjectSafetyViolation;
4545
pub use self::object_safety::MethodViolationCode;
4646
pub use self::object_safety::is_vtable_safe_method;
47+
pub use self::select::EvaluationCache;
4748
pub use self::select::SelectionContext;
4849
pub use self::select::SelectionCache;
4950
pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
@@ -339,32 +340,53 @@ pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
339340
ty,
340341
bound);
341342

342-
let mut fulfill_cx = FulfillmentContext::new(false);
343-
344-
// We can use a dummy node-id here because we won't pay any mind
345-
// to region obligations that arise (there shouldn't really be any
346-
// anyhow).
347343
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
348-
349-
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
350-
351-
// Note: we only assume something is `Copy` if we can
352-
// *definitively* show that it implements `Copy`. Otherwise,
353-
// assume it is move; linear is always ok.
354-
match fulfill_cx.select_all_or_error(infcx) {
355-
Ok(()) => {
356-
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
357-
ty,
358-
bound);
359-
true
360-
}
361-
Err(e) => {
362-
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
363-
ty,
364-
bound,
365-
e);
366-
false
344+
let obligation =
345+
util::predicate_for_builtin_bound(infcx.tcx, cause, bound, 0, ty);
346+
let obligation = match obligation {
347+
Ok(o) => o,
348+
Err(..) => return false
349+
};
350+
let result = SelectionContext::new(infcx)
351+
.evaluate_obligation_conservatively(&obligation);
352+
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} => {:?}",
353+
ty, bound, result);
354+
355+
if result && (ty.has_infer_types() || ty.has_closure_types()) {
356+
// Because of inference "guessing", selection can sometimes claim
357+
// to succeed while the success requires a guess. To ensure
358+
// this function's result remains infallible, we must confirm
359+
// that guess. While imperfect, I believe this is sound.
360+
361+
let mut fulfill_cx = FulfillmentContext::new(false);
362+
363+
// We can use a dummy node-id here because we won't pay any mind
364+
// to region obligations that arise (there shouldn't really be any
365+
// anyhow).
366+
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
367+
368+
fulfill_cx.register_builtin_bound(infcx, ty, bound, cause);
369+
370+
// Note: we only assume something is `Copy` if we can
371+
// *definitively* show that it implements `Copy`. Otherwise,
372+
// assume it is move; linear is always ok.
373+
match fulfill_cx.select_all_or_error(infcx) {
374+
Ok(()) => {
375+
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
376+
ty,
377+
bound);
378+
true
379+
}
380+
Err(e) => {
381+
debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
382+
ty,
383+
bound,
384+
e);
385+
false
386+
}
367387
}
388+
} else {
389+
result
368390
}
369391
}
370392

0 commit comments

Comments
 (0)