Skip to content

Commit de35723

Browse files
committed
Auto merge of #123669 - oli-obk:eager_opaque_checks4, r=<try>
Avoid a scrape_region_constraints and instead register the region constraints directly Should fix the perf regression from #122077 (comment)
2 parents 86b603c + 28df1d3 commit de35723

File tree

3 files changed

+183
-145
lines changed

3 files changed

+183
-145
lines changed

compiler/rustc_infer/src/infer/canonical/query_response.rs

+139-84
Original file line numberDiff line numberDiff line change
@@ -248,64 +248,71 @@ impl<'tcx> InferCtxt<'tcx> {
248248
where
249249
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
250250
{
251-
let InferOk { value: result_args, mut obligations } = self
252-
.query_response_instantiation_guess(
253-
cause,
254-
param_env,
255-
original_values,
256-
query_response,
257-
)?;
251+
let result_args =
252+
self.query_response_instantiation_guess(cause, original_values, query_response);
253+
254+
let mut obligations = vec![];
255+
256+
// Carry all newly resolved opaque types to the caller's scope
257+
for &(opaque_type_key, hidden_ty) in &query_response.value.opaque_types {
258+
let opaque_type_key = instantiate_value(self.tcx, &result_args, opaque_type_key);
259+
let hidden_ty = instantiate_value(self.tcx, &result_args, hidden_ty);
260+
debug!(?opaque_type_key, ?hidden_ty, "constrain opaque type");
261+
// We can't use equate here, because the hidden type may have been an inference
262+
// variable that got constrained to the opaque type itself. In that case we want to ensure
263+
// any lifetime differences get recorded in `ouput_query_region_constraints` instead of
264+
// being registered in the `InferCtxt`.
265+
match hidden_ty.kind() {
266+
ty::Alias(ty::Opaque, alias_ty)
267+
if alias_ty.def_id == opaque_type_key.def_id.into() =>
268+
{
269+
assert_eq!(alias_ty.args.len(), opaque_type_key.args.len());
270+
for (key_arg, hidden_arg) in
271+
opaque_type_key.args.iter().zip(alias_ty.args.iter())
272+
{
273+
self.equate_generic_arg(
274+
key_arg,
275+
hidden_arg,
276+
output_query_region_constraints,
277+
ConstraintCategory::OpaqueType,
278+
&mut obligations,
279+
cause,
280+
param_env,
281+
)?;
282+
}
283+
}
284+
_ => {
285+
self.insert_hidden_type(
286+
opaque_type_key,
287+
cause,
288+
param_env,
289+
hidden_ty,
290+
&mut obligations,
291+
)?;
292+
}
293+
}
294+
}
258295

259296
// Compute `QueryOutlivesConstraint` values that unify each of
260297
// the original values `v_o` that was canonicalized into a
261298
// variable...
262299

263300
let constraint_category = cause.to_constraint_category();
264301

265-
for (index, original_value) in original_values.var_values.iter().enumerate() {
302+
for (index, &original_value) in original_values.var_values.iter().enumerate() {
266303
// ...with the value `v_r` of that variable from the query.
267304
let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| {
268305
v.var_values[BoundVar::new(index)]
269306
});
270-
match (original_value.unpack(), result_value.unpack()) {
271-
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
272-
if re1.is_erased() && re2.is_erased() =>
273-
{
274-
// No action needed.
275-
}
276-
277-
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
278-
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
279-
if v_o != v_r {
280-
output_query_region_constraints
281-
.outlives
282-
.push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
283-
output_query_region_constraints
284-
.outlives
285-
.push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
286-
}
287-
}
288-
289-
(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
290-
obligations.extend(
291-
self.at(&cause, param_env)
292-
.eq(DefineOpaqueTypes::Yes, v1, v2)?
293-
.into_obligations(),
294-
);
295-
}
296-
297-
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
298-
obligations.extend(
299-
self.at(&cause, param_env)
300-
.eq(DefineOpaqueTypes::Yes, v1, v2)?
301-
.into_obligations(),
302-
);
303-
}
304-
305-
_ => {
306-
bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value);
307-
}
308-
}
307+
self.equate_generic_arg(
308+
original_value,
309+
result_value,
310+
output_query_region_constraints,
311+
constraint_category,
312+
&mut obligations,
313+
cause,
314+
param_env,
315+
)?;
309316
}
310317

311318
// ...also include the other query region constraints from the query.
@@ -335,6 +342,57 @@ impl<'tcx> InferCtxt<'tcx> {
335342
Ok(InferOk { value: user_result, obligations })
336343
}
337344

345+
fn equate_generic_arg(
346+
&self,
347+
original_value: GenericArg<'tcx>,
348+
result_value: GenericArg<'tcx>,
349+
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
350+
constraint_category: ConstraintCategory<'tcx>,
351+
obligations: &mut Vec<Obligation<'tcx, ty::Predicate<'tcx>>>,
352+
cause: &ObligationCause<'tcx>,
353+
param_env: ty::ParamEnv<'tcx>,
354+
) -> Result<(), ty::error::TypeError<'tcx>> {
355+
Ok(match (original_value.unpack(), result_value.unpack()) {
356+
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
357+
if re1.is_erased() && re2.is_erased() =>
358+
{
359+
// No action needed.
360+
}
361+
362+
(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
363+
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
364+
if v_o != v_r {
365+
output_query_region_constraints
366+
.outlives
367+
.push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
368+
output_query_region_constraints
369+
.outlives
370+
.push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
371+
}
372+
}
373+
374+
(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
375+
obligations.extend(
376+
self.at(&cause, param_env)
377+
.eq(DefineOpaqueTypes::Yes, v1, v2)?
378+
.into_obligations(),
379+
);
380+
}
381+
382+
(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
383+
obligations.extend(
384+
self.at(&cause, param_env)
385+
.eq(DefineOpaqueTypes::Yes, v1, v2)?
386+
.into_obligations(),
387+
);
388+
}
389+
390+
_ => {
391+
bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value);
392+
}
393+
})
394+
}
395+
338396
/// Given the original values and the (canonicalized) result from
339397
/// computing a query, returns an instantiation that can be applied
340398
/// to the query result to convert the result back into the
@@ -360,25 +418,47 @@ impl<'tcx> InferCtxt<'tcx> {
360418
original_values, query_response,
361419
);
362420

363-
let mut value = self.query_response_instantiation_guess(
364-
cause,
365-
param_env,
366-
original_values,
367-
query_response,
368-
)?;
421+
let result_args =
422+
self.query_response_instantiation_guess(cause, original_values, query_response);
423+
424+
let mut obligations = vec![];
425+
426+
// Carry all newly resolved opaque types to the caller's scope
427+
for &(opaque_type_key, hidden_ty) in &query_response.value.opaque_types {
428+
let opaque_type_key = instantiate_value(self.tcx, &result_args, opaque_type_key);
429+
let hidden_ty = instantiate_value(self.tcx, &result_args, hidden_ty);
430+
debug!(?opaque_type_key, ?hidden_ty, "constrain opaque type");
431+
// We use equate here instead of, for example, just registering the
432+
// opaque type's hidden value directly, because the hidden type may have been an inference
433+
// variable that got constrained to the opaque type itself. In that case we want to equate
434+
// the generic args of the opaque with the generic params of its hidden type version.
435+
obligations.extend(
436+
self.at(cause, param_env)
437+
.eq(
438+
DefineOpaqueTypes::Yes,
439+
Ty::new_opaque(
440+
self.tcx,
441+
opaque_type_key.def_id.to_def_id(),
442+
opaque_type_key.args,
443+
),
444+
hidden_ty,
445+
)?
446+
.obligations,
447+
);
448+
}
369449

370-
value.obligations.extend(
450+
obligations.extend(
371451
self.unify_query_response_instantiation_guess(
372452
cause,
373453
param_env,
374454
original_values,
375-
&value.value,
455+
&result_args,
376456
query_response,
377457
)?
378458
.into_obligations(),
379459
);
380460

381-
Ok(value)
461+
Ok(InferOk { value: result_args, obligations })
382462
}
383463

384464
/// Given the original values and the (canonicalized) result from
@@ -390,14 +470,13 @@ impl<'tcx> InferCtxt<'tcx> {
390470
/// will instantiate fresh inference variables for each canonical
391471
/// variable instead. Therefore, the result of this method must be
392472
/// properly unified
393-
#[instrument(level = "debug", skip(self, param_env))]
473+
#[instrument(level = "debug", skip(self))]
394474
fn query_response_instantiation_guess<R>(
395475
&self,
396476
cause: &ObligationCause<'tcx>,
397-
param_env: ty::ParamEnv<'tcx>,
398477
original_values: &OriginalQueryValues<'tcx>,
399478
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
400-
) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
479+
) -> CanonicalVarValues<'tcx>
401480
where
402481
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
403482
{
@@ -470,7 +549,7 @@ impl<'tcx> InferCtxt<'tcx> {
470549
// Create result arguments: if we found a value for a
471550
// given variable in the loop above, use that. Otherwise, use
472551
// a fresh inference variable.
473-
let result_args = CanonicalVarValues {
552+
CanonicalVarValues {
474553
var_values: self.tcx.mk_args_from_iter(
475554
query_response.variables.iter().enumerate().map(|(index, info)| {
476555
if info.universe() != ty::UniverseIndex::ROOT {
@@ -495,31 +574,7 @@ impl<'tcx> InferCtxt<'tcx> {
495574
}
496575
}),
497576
),
498-
};
499-
500-
let mut obligations = vec![];
501-
502-
// Carry all newly resolved opaque types to the caller's scope
503-
for &(a, b) in &query_response.value.opaque_types {
504-
let a = instantiate_value(self.tcx, &result_args, a);
505-
let b = instantiate_value(self.tcx, &result_args, b);
506-
debug!(?a, ?b, "constrain opaque type");
507-
// We use equate here instead of, for example, just registering the
508-
// opaque type's hidden value directly, because the hidden type may have been an inference
509-
// variable that got constrained to the opaque type itself. In that case we want to equate
510-
// the generic args of the opaque with the generic params of its hidden type version.
511-
obligations.extend(
512-
self.at(cause, param_env)
513-
.eq(
514-
DefineOpaqueTypes::Yes,
515-
Ty::new_opaque(self.tcx, a.def_id.to_def_id(), a.args),
516-
b,
517-
)?
518-
.obligations,
519-
);
520577
}
521-
522-
Ok(InferOk { value: result_args, obligations })
523578
}
524579

525580
/// Given a "guess" at the values for the canonical variables in

0 commit comments

Comments
 (0)