Skip to content

Commit b22bffa

Browse files
committed
propagate ambiguity not evaluate
1 parent 9bfb178 commit b22bffa

4 files changed

Lines changed: 45 additions & 12 deletions

File tree

compiler/rustc_infer/src/infer/outlives/obligations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl<'tcx> InferCtxt<'tcx> {
272272
&assumptions,
273273
);
274274
debug!(?constraint);
275-
let constraint = region_constraint::evaluate_solver_constraint(constraint);
275+
let constraint = region_constraint::propagate_ambiguity(constraint);
276276
debug!(?constraint);
277277

278278
// FIXME(-Zassumptions-on-binders): actually implement OR as an OR

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1667,7 +1667,7 @@ where
16671667
let constraint = self.delegate.get_solver_region_constraint();
16681668
debug_assert_eq!(
16691669
constraint,
1670-
region_constraint::evaluate_solver_constraint(constraint.clone())
1670+
region_constraint::propagate_ambiguity(constraint.clone())
16711671
);
16721672
constraint
16731673
} else {

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/solver_region_constraints.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_type_ir::outlives::{Component, push_outlives_components};
99
use rustc_type_ir::region_constraint::TransitiveRelationBuilder;
1010
use rustc_type_ir::region_constraint::{
1111
And, Assumptions, LeafRegionConstraint, Or, eagerly_handle_placeholders_in_universe,
12-
evaluate_solver_constraint,
12+
propagate_ambiguity,
1313
};
1414
use rustc_type_ir::{
1515
AliasTy, Binder, ClauseKind, InferCtxtLike, Interner, OutlivesClause, Region, TypeVisitable,
@@ -137,7 +137,7 @@ where
137137
.fold(constraint, |constraint, u| {
138138
eagerly_handle_placeholders_in_universe(&**self.delegate, constraint, u)
139139
});
140-
let constraint = evaluate_solver_constraint(constraint);
140+
let constraint = propagate_ambiguity(constraint);
141141

142142
debug!("final constraint={:?}", constraint);
143143
self.delegate.overwrite_solver_region_constraint(constraint.clone(), self.origin_span);

compiler/rustc_type_ir/src/region_constraint.rs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -466,8 +466,8 @@ pub fn eagerly_handle_placeholders_in_universe<Infcx: InferCtxtLike<Interner = I
466466
let constraint =
467467
pull_region_outlives_constraints_out_of_universe(infcx, constraint, u, &assumptions);
468468

469-
// 4. actually evaluate the constraint to eagerly error on false
470-
evaluate_solver_constraint(constraint)
469+
// 4. force the constraint to ambiguous if it could be `false` in future reruns
470+
propagate_ambiguity(constraint)
471471
}
472472

473473
/// Filter our region constraints to not include constraints between region variables from `u` and
@@ -551,15 +551,48 @@ fn compute_new_region_constraints<Infcx: InferCtxtLike<Interner = I>, I: Interne
551551
)
552552
}
553553

554-
/// Evaluate ANDs and ORs to true/false/ambiguous based on whether their arguments are true/false/ambiguous
554+
/// Force the whole constraint to be ambiguous if it contains ambiguities which could
555+
/// have caused the constraint to be `false` if they had been `false` themselves.
556+
///
557+
/// For example if we have `'a: 'b AND ambig` it's possible that if we had more inference
558+
/// information we could have produced a better region constraint than `ambig`, and that
559+
/// constraint may then have gone on to be false, at which point we would have `'a: 'b AND false`
560+
/// causing the whole constraint to be `false`.
561+
///
562+
/// If we're not careful we can wind up returning `'a: 'b AND ambig` from passing trait solver
563+
/// goals and then upon rerunning wind up returning `NoSolution` which would be dubious :3
564+
///
565+
/// This is inherently conservative and this method should be called as little as possible as it
566+
/// can cause us to get ambiguities instead of `NoSolution` (for example if `'a: 'b` is `false`),
567+
/// which can affect coherence, candidate selection, etc.
568+
///
569+
/// FIXME(-Zassumptions-on-binders): this method should probably be trait-solver internal as it only
570+
/// matters at trait solver query boundaries. We currently call it in more than just that location
555571
#[instrument(level = "debug", ret)]
556-
pub fn evaluate_solver_constraint<
557-
I: Interner,
558-
S: Clone + std::fmt::Debug + Eq + std::hash::Hash,
559-
>(
572+
pub fn propagate_ambiguity<I: Interner, S: Clone + std::fmt::Debug + Eq + std::hash::Hash>(
560573
constraint: RegionConstraint<I, S>,
561574
) -> RegionConstraint<I, S> {
562-
todo!("overhauled in future commit")
575+
if let Some(ambig) = constraint.and_constraint.0.iter().find(|c| c.is_ambig()) {
576+
return RegionConstraint::new_leaf(ambig.clone());
577+
}
578+
579+
for and in constraint.or_constraint.0.iter() {
580+
// FIXME(-Zassumptions-on-binders): This is overly conservative. If we have:
581+
// `'a: 'b OR ambig` we don't necessarily want to propagate ambiguity here
582+
// as we might end up with `'a: 'b` being satisfied in which case we unnecessarily
583+
// errored here.
584+
//
585+
// It's fine if the `ambig` wound up being `false` as that wouldn't cause a goal to
586+
// become `NoSolution`, it would instead result in us returning the `'a: 'b` constraint
587+
// by itself.
588+
//
589+
// `rust-lang/project-assumptions-on-binders#21`
590+
if let Some(ambig) = and.0.iter().find(|c| c.is_ambig()) {
591+
return RegionConstraint::new_leaf(ambig.clone());
592+
}
593+
}
594+
595+
constraint
563596
}
564597

565598
/// Handles converting region outlives constraints involving placeholders from `u` into OR constraints

0 commit comments

Comments
 (0)