@@ -99,6 +99,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
99
99
previous call to `try_evaluate_added_goals!`"
100
100
) ;
101
101
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
+
102
109
// When normalizing, we've replaced the expected term with an unconstrained
103
110
// inference variable. This means that we dropped information which could
104
111
// have been important. We handle this by instead returning the nested goals
@@ -121,7 +128,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
121
128
} ;
122
129
123
130
let external_constraints =
124
- self . compute_external_query_constraints ( normalization_nested_goals) ? ;
131
+ self . compute_external_query_constraints ( certainty , normalization_nested_goals) ;
125
132
let ( var_values, mut external_constraints) =
126
133
( self . var_values , external_constraints) . fold_with ( & mut EagerResolver :: new ( self . infcx ) ) ;
127
134
// Remove any trivial region constraints once we've resolved regions
@@ -170,38 +177,45 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
170
177
#[ instrument( level = "trace" , skip( self ) , ret) ]
171
178
fn compute_external_query_constraints (
172
179
& self ,
180
+ certainty : Certainty ,
173
181
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
+ } ;
197
211
198
212
let mut opaque_types = self . infcx . clone_opaque_types_for_query_response ( ) ;
199
213
// Only return opaque type keys for newly-defined opaques
200
214
opaque_types. retain ( |( a, _) | {
201
215
self . predefined_opaques_in_body . opaque_types . iter ( ) . all ( |( pa, _) | pa != a)
202
216
} ) ;
203
217
204
- Ok ( ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } )
218
+ ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals }
205
219
}
206
220
207
221
/// After calling a canonical query, we apply the constraints returned
0 commit comments