Skip to content

Commit 930ca67

Browse files
committed
propagate ambiguity not evaluate
1 parent 74f87b0 commit 930ca67

4 files changed

Lines changed: 46 additions & 11 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
@@ -261,7 +261,7 @@ impl<'tcx> InferCtxt<'tcx> {
261261
&assumptions,
262262
);
263263
debug!(?constraint);
264-
let constraint = region_constraint::evaluate_solver_constraint(constraint);
264+
let constraint = region_constraint::propagate_ambiguity(constraint);
265265
debug!(?constraint);
266266

267267
// 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
@@ -1664,7 +1664,7 @@ where
16641664
let constraint = self.delegate.get_solver_region_constraint();
16651665
debug_assert_eq!(
16661666
constraint,
1667-
region_constraint::evaluate_solver_constraint(constraint.clone())
1667+
region_constraint::propagate_ambiguity(constraint.clone())
16681668
);
16691669
constraint
16701670
} 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());

compiler/rustc_type_ir/src/region_constraint.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -358,11 +358,10 @@ pub fn eagerly_handle_placeholders_in_universe<Infcx: InferCtxtLike<Interner = I
358358
let constraint = compute_new_region_constraints(infcx, constraint, u);
359359

360360
// 3. rewrite region outlives constraints (potentially to false/true)
361-
let constraint =
362-
pull_region_outlives_constraints_out_of_universe(infcx, constraint, u, &assumptions);
361+
let constraint = pull_region_outlives_constraints_out_of_universe(infcx, constraint, u, &assumptions);
363362

364-
// 4. actually evaluate the constraint to eagerly error on false
365-
evaluate_solver_constraint(constraint)
363+
// 4. force the constraint to ambiguous if it could be `false` in future reruns
364+
propagate_ambiguity(constraint)
366365
}
367366

368367
/// Filter our region constraints to not include constraints between region variables from `u` and
@@ -445,12 +444,48 @@ fn compute_new_region_constraints<Infcx: InferCtxtLike<Interner = I>, I: Interne
445444
)
446445
}
447446

448-
/// Evaluate ANDs and ORs to true/false/ambiguous based on whether their arguments are true/false/ambiguous
447+
/// Force the whole constraint to be ambiguous if it contains ambiguities which could
448+
/// have caused the constraint to be `false` if they had been `false` themselves.
449+
///
450+
/// For example if we have `'a: 'b AND ambig` it's possible that if we had more inference
451+
/// information we could have produced a better region constraint than `ambig`, and that
452+
/// constraint may then have gone on to be false, at which point we would have `'a: 'b AND false`
453+
/// causing the whole constraint to be `false`.
454+
///
455+
/// If we're not careful we can wind up returning `'a: 'b AND ambig` from passing trait solver
456+
/// goals and then upon rerunning wind up returning `NoSolution` which would be dubious :3
457+
///
458+
/// This is inherently conservative and this method should be called as little as possible as it
459+
/// can cause us to get ambiguities instead of `NoSolution` (for example if `'a: 'b` is `false`),
460+
/// which can affect coherence, candidate selection, etc.
461+
///
462+
/// FIXME(-Zassumptions-on-binders): this method should probably be trait-solver internal as it only
463+
/// matters at trait solver query boundaries. We currently call it in more than just that location
449464
#[instrument(level = "debug", ret)]
450-
pub fn evaluate_solver_constraint<I: Interner>(
465+
pub fn propagate_ambiguity<I: Interner>(
451466
constraint: CanonicalFormRegionConstraint<I>,
452467
) -> CanonicalFormRegionConstraint<I> {
453-
todo!("overhauled in future commit")
468+
if constraint.and_constraint.0.iter().any(|c| c.is_ambig()) {
469+
return CanonicalFormRegionConstraint::new_ambig();
470+
}
471+
472+
for and in constraint.or_constraint.0.iter() {
473+
// FIXME(-Zassumptions-on-binders): This is overly conservative. If we have:
474+
// `'a: 'b OR ambig` we don't necessarily want to propagate ambiguity here
475+
// as we might end up with `'a: 'b` being satisfied in which case we unncessarily
476+
// errored here.
477+
//
478+
// It's fine if the `ambig` wound up being `false` as that wouldn't cause a goal to
479+
// become `NoSolution`, it would instead result in us returning the `'a: 'b` constraint
480+
// by itself.
481+
//
482+
// `rust-lang/project-assumptions-on-binders#21`
483+
if and.0.iter().any(|c| c.is_ambig()) {
484+
return CanonicalFormRegionConstraint::new_ambig();
485+
}
486+
}
487+
488+
constraint
454489
}
455490

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

0 commit comments

Comments
 (0)