@@ -99,6 +99,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
9999
100100        ) ; 
101101
102+         // We only check for leaks from universes which were entered inside 
103+         // of the query. 
104+         self . infcx . leak_check ( self . max_input_universe ,  None ) . map_err ( |e| { 
105+             trace ! ( ?e,  "failed the leak check" ) ; 
106+             NoSolution 
107+         } ) ?; 
108+ 
102109        // When normalizing, we've replaced the expected term with an unconstrained 
103110        // inference variable. This means that we dropped information which could 
104111        // have been important. We handle this by instead returning the nested goals 
@@ -121,7 +128,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
121128        } ; 
122129
123130        let  external_constraints =
124-             self . compute_external_query_constraints ( normalization_nested_goals) ? ; 
131+             self . compute_external_query_constraints ( certainty ,   normalization_nested_goals) ; 
125132        let  ( var_values,  mut  external_constraints)  =
126133            ( self . var_values ,  external_constraints) . fold_with ( & mut  EagerResolver :: new ( self . infcx ) ) ; 
127134        // Remove any trivial region constraints once we've resolved regions 
@@ -170,38 +177,45 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
170177#[ instrument( level = "trace" ,  skip( self ) ,  ret) ]  
171178    fn  compute_external_query_constraints ( 
172179        & self , 
180+         certainty :  Certainty , 
173181        normalization_nested_goals :  NestedNormalizationGoals < ' tcx > , 
174-     )  -> Result < ExternalConstraintsData < ' tcx > ,  NoSolution >  { 
175-         // We only check for leaks from universes which were entered inside 
176-         // of the query. 
177-         self . infcx . leak_check ( self . max_input_universe ,  None ) . map_err ( |e| { 
178-             trace ! ( ?e,  "failed the leak check" ) ; 
179-             NoSolution 
180-         } ) ?; 
181- 
182-         // Cannot use `take_registered_region_obligations` as we may compute the response 
183-         // inside of a `probe` whenever we have multiple choices inside of the solver. 
184-         let  region_obligations = self . infcx . inner . borrow ( ) . region_obligations ( ) . to_owned ( ) ; 
185-         let  mut  region_constraints = self . infcx . with_region_constraints ( |region_constraints| { 
186-             make_query_region_constraints ( 
187-                 self . tcx ( ) , 
188-                 region_obligations
189-                     . iter ( ) 
190-                     . map ( |r_o| ( r_o. sup_type ,  r_o. sub_region ,  r_o. origin . to_constraint_category ( ) ) ) , 
191-                 region_constraints, 
192-             ) 
193-         } ) ; 
194- 
195-         let  mut  seen = FxHashSet :: default ( ) ; 
196-         region_constraints. outlives . retain ( |outlives| seen. insert ( * outlives) ) ; 
182+     )  -> ExternalConstraintsData < ' tcx >  { 
183+         // We only return region constraints once the certainty is `Yes`. This 
184+         // is necessary as we may drop nested goals on ambiguity, which may result 
185+         // in unconstrained inference variables in the region constraints. It also 
186+         // prevents us from emitting duplicate region constraints, avoiding some 
187+         // unnecessary work. This slightly weakens the leak check in case it uses 
188+         // region constraints from an ambiguous nested goal. This is tested in both 
189+         // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and 
190+         // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. 
191+         let  region_constraints = if  certainty == Certainty :: Yes  { 
192+             // Cannot use `take_registered_region_obligations` as we may compute the response 
193+             // inside of a `probe` whenever we have multiple choices inside of the solver. 
194+             let  region_obligations = self . infcx . inner . borrow ( ) . region_obligations ( ) . to_owned ( ) ; 
195+             let  mut  region_constraints = self . infcx . with_region_constraints ( |region_constraints| { 
196+                 make_query_region_constraints ( 
197+                     self . tcx ( ) , 
198+                     region_obligations. iter ( ) . map ( |r_o| { 
199+                         ( r_o. sup_type ,  r_o. sub_region ,  r_o. origin . to_constraint_category ( ) ) 
200+                     } ) , 
201+                     region_constraints, 
202+                 ) 
203+             } ) ; 
204+ 
205+             let  mut  seen = FxHashSet :: default ( ) ; 
206+             region_constraints. outlives . retain ( |outlives| seen. insert ( * outlives) ) ; 
207+             region_constraints
208+         }  else  { 
209+             Default :: default ( ) 
210+         } ; 
197211
198212        let  mut  opaque_types = self . infcx . clone_opaque_types_for_query_response ( ) ; 
199213        // Only return opaque type keys for newly-defined opaques 
200214        opaque_types. retain ( |( a,  _) | { 
201215            self . predefined_opaques_in_body . opaque_types . iter ( ) . all ( |( pa,  _) | pa != a) 
202216        } ) ; 
203217
204-         Ok ( ExternalConstraintsData  {  region_constraints,  opaque_types,  normalization_nested_goals } ) 
218+         ExternalConstraintsData  {  region_constraints,  opaque_types,  normalization_nested_goals } 
205219    } 
206220
207221    /// After calling a canonical query, we apply the constraints returned 
0 commit comments