Skip to content

Commit

Permalink
Auto merge of #54401 - nikomatsakis:issue-54302-hrtb-fail, r=<try>
Browse files Browse the repository at this point in the history
make evaluation track whether outlives relationships mattered

Previously, evaluation ignored outlives relationships. Since we using
evaluation to skip the "normal" trait selection (which enforces
outlives relationships) this led to incorrect results in some cases.

Fixes #54302

r? @arielb1
  • Loading branch information
bors committed Sep 25, 2018
2 parents ae36663 + 563ba10 commit 643b173
Show file tree
Hide file tree
Showing 9 changed files with 1,466 additions and 1,143 deletions.
2 changes: 1 addition & 1 deletion src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
!traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
}

/// Obtains the latest type of the given closure; this may be a
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,10 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone());

if data.is_global() && !data.has_late_bound_regions() {
if data.is_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if self.selcx.infcx().predicate_must_hold(&obligation) {
if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) {
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
data, obligation.recursion_depth);
return ProcessResult::Changed(vec![])
Expand Down
22 changes: 11 additions & 11 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,14 +564,14 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span)
-> bool
{
debug!("type_known_to_meet_bound(ty={:?}, bound={:?})",
pub fn type_known_to_meet_bound_modulo_regions<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span,
) -> bool {
debug!("type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
ty,
infcx.tcx.item_path_str(def_id));

Expand All @@ -586,7 +586,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
predicate: trait_ref.to_predicate(),
};

let result = infcx.predicate_must_hold(&obligation);
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
debug!("type_known_to_meet_ty={:?} bound={} => {:?}",
ty, infcx.tcx.item_path_str(def_id), result);

Expand All @@ -613,13 +613,13 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
// assume it is move; linear is always ok.
match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => {
debug!("type_known_to_meet_bound: ty={:?} bound={} success",
debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
infcx.tcx.item_path_str(def_id));
true
}
Err(e) => {
debug!("type_known_to_meet_bound: ty={:?} bound={} errors={:?}",
debug!("type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
ty,
infcx.tcx.item_path_str(def_id),
e);
Expand Down
19 changes: 17 additions & 2 deletions src/librustc/traits/query/evaluate_obligation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,26 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
/// Evaluates whether the predicate can be satisfied in the given
/// `ParamEnv`, and returns `false` if not certain. However, this is
/// not entirely accurate if inference variables are involved.
pub fn predicate_must_hold(
///
/// This version may conservatively fail when outlives obligations
/// are required.
pub fn predicate_must_hold_considering_regions(
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool {
self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk
self.evaluate_obligation(obligation).must_apply_considering_regions()
}

/// Evaluates whether the predicate can be satisfied in the given
/// `ParamEnv`, and returns `false` if not certain. However, this is
/// not entirely accurate if inference variables are involved.
///
/// This version ignores all outlives constraints.
pub fn predicate_must_hold_modulo_regions(
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool {
self.evaluate_obligation(obligation).must_apply_modulo_regions()
}

// Helper function that canonicalizes and runs the query, as well as handles
Expand Down
Loading

0 comments on commit 643b173

Please sign in to comment.