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