@@ -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