Skip to content

Commit 28df1d3

Browse files
committed
Avoid a scrape_region_constraints and instead register the region constraints directly
1 parent 592f251 commit 28df1d3

File tree

3 files changed

+122
-105
lines changed

3 files changed

+122
-105
lines changed

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

+78-44
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,50 @@ 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
@@ -381,25 +418,47 @@ impl<'tcx> InferCtxt<'tcx> {
381418
original_values, query_response,
382419
);
383420

384-
let mut value = self.query_response_instantiation_guess(
385-
cause,
386-
param_env,
387-
original_values,
388-
query_response,
389-
)?;
421+
let result_args =
422+
self.query_response_instantiation_guess(cause, original_values, query_response);
390423

391-
value.obligations.extend(
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+
}
449+
450+
obligations.extend(
392451
self.unify_query_response_instantiation_guess(
393452
cause,
394453
param_env,
395454
original_values,
396-
&value.value,
455+
&result_args,
397456
query_response,
398457
)?
399458
.into_obligations(),
400459
);
401460

402-
Ok(value)
461+
Ok(InferOk { value: result_args, obligations })
403462
}
404463

405464
/// Given the original values and the (canonicalized) result from
@@ -411,14 +470,13 @@ impl<'tcx> InferCtxt<'tcx> {
411470
/// will instantiate fresh inference variables for each canonical
412471
/// variable instead. Therefore, the result of this method must be
413472
/// properly unified
414-
#[instrument(level = "debug", skip(self, param_env))]
473+
#[instrument(level = "debug", skip(self))]
415474
fn query_response_instantiation_guess<R>(
416475
&self,
417476
cause: &ObligationCause<'tcx>,
418-
param_env: ty::ParamEnv<'tcx>,
419477
original_values: &OriginalQueryValues<'tcx>,
420478
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
421-
) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
479+
) -> CanonicalVarValues<'tcx>
422480
where
423481
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
424482
{
@@ -491,7 +549,7 @@ impl<'tcx> InferCtxt<'tcx> {
491549
// Create result arguments: if we found a value for a
492550
// given variable in the loop above, use that. Otherwise, use
493551
// a fresh inference variable.
494-
let result_args = CanonicalVarValues {
552+
CanonicalVarValues {
495553
var_values: self.tcx.mk_args_from_iter(
496554
query_response.variables.iter().enumerate().map(|(index, info)| {
497555
if info.universe() != ty::UniverseIndex::ROOT {
@@ -516,31 +574,7 @@ impl<'tcx> InferCtxt<'tcx> {
516574
}
517575
}),
518576
),
519-
};
520-
521-
let mut obligations = vec![];
522-
523-
// Carry all newly resolved opaque types to the caller's scope
524-
for &(a, b) in &query_response.value.opaque_types {
525-
let a = instantiate_value(self.tcx, &result_args, a);
526-
let b = instantiate_value(self.tcx, &result_args, b);
527-
debug!(?a, ?b, "constrain opaque type");
528-
// We use equate here instead of, for example, just registering the
529-
// opaque type's hidden value directly, because the hidden type may have been an inference
530-
// variable that got constrained to the opaque type itself. In that case we want to equate
531-
// the generic args of the opaque with the generic params of its hidden type version.
532-
obligations.extend(
533-
self.at(cause, param_env)
534-
.eq(
535-
DefineOpaqueTypes::Yes,
536-
Ty::new_opaque(self.tcx, a.def_id.to_def_id(), a.args),
537-
b,
538-
)?
539-
.obligations,
540-
);
541577
}
542-
543-
Ok(InferOk { value: result_args, obligations })
544578
}
545579

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

compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs

+43-60
Original file line numberDiff line numberDiff line change
@@ -159,70 +159,53 @@ where
159159
.0);
160160
}
161161

162-
let mut error_info = None;
163162
let mut region_constraints = QueryRegionConstraints::default();
164-
165-
// HACK(type_alias_impl_trait): When moving an opaque type to hidden type mapping from the query to the current inferctxt,
166-
// we sometimes end up with `Opaque<'a> = Opaque<'b>` instead of an actual hidden type. In that case we don't register a
167-
// hidden type but just equate the lifetimes. Thus we need to scrape the region constraints even though we're also manually
168-
// collecting region constraints via `region_constraints`.
169-
let (mut output, _) = scrape_region_constraints(
170-
infcx,
171-
|_ocx| {
172-
let (output, ei, mut obligations, _) =
173-
Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
174-
error_info = ei;
175-
176-
// Typically, instantiating NLL query results does not
177-
// create obligations. However, in some cases there
178-
// are unresolved type variables, and unify them *can*
179-
// create obligations. In that case, we have to go
180-
// fulfill them. We do this via a (recursive) query.
181-
while !obligations.is_empty() {
182-
trace!("{:#?}", obligations);
183-
let mut progress = false;
184-
for obligation in std::mem::take(&mut obligations) {
185-
let obligation = infcx.resolve_vars_if_possible(obligation);
186-
match ProvePredicate::fully_perform_into(
187-
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
188-
infcx,
189-
&mut region_constraints,
190-
span,
191-
) {
192-
Ok(((), _, new, certainty)) => {
193-
obligations.extend(new);
194-
progress = true;
195-
if let Certainty::Ambiguous = certainty {
196-
obligations.push(obligation);
197-
}
198-
}
199-
Err(_) => obligations.push(obligation),
163+
let (output, error_info, mut obligations, _) =
164+
Q::fully_perform_into(self, infcx, &mut region_constraints, span).map_err(|_| {
165+
infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}"))
166+
})?;
167+
168+
// Typically, instantiating NLL query results does not
169+
// create obligations. However, in some cases there
170+
// are unresolved type variables, and unify them *can*
171+
// create obligations. In that case, we have to go
172+
// fulfill them. We do this via a (recursive) query.
173+
while !obligations.is_empty() {
174+
trace!("{:#?}", obligations);
175+
let mut progress = false;
176+
for obligation in std::mem::take(&mut obligations) {
177+
let obligation = infcx.resolve_vars_if_possible(obligation);
178+
match ProvePredicate::fully_perform_into(
179+
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
180+
infcx,
181+
&mut region_constraints,
182+
span,
183+
) {
184+
Ok(((), _, new, certainty)) => {
185+
obligations.extend(new);
186+
progress = true;
187+
if let Certainty::Ambiguous = certainty {
188+
obligations.push(obligation);
200189
}
201190
}
202-
if !progress {
203-
infcx.dcx().span_bug(
204-
span,
205-
format!("ambiguity processing {obligations:?} from {self:?}"),
206-
);
207-
}
191+
Err(_) => obligations.push(obligation),
208192
}
209-
Ok(output)
210-
},
211-
"fully_perform",
212-
span,
213-
)?;
214-
output.error_info = error_info;
215-
if let Some(constraints) = output.constraints {
216-
region_constraints
217-
.member_constraints
218-
.extend(constraints.member_constraints.iter().cloned());
219-
region_constraints.outlives.extend(constraints.outlives.iter().cloned());
193+
}
194+
if !progress {
195+
infcx
196+
.dcx()
197+
.span_bug(span, format!("ambiguity processing {obligations:?} from {self:?}"));
198+
}
220199
}
221-
output.constraints = if region_constraints.is_empty() {
222-
None
223-
} else {
224-
Some(infcx.tcx.arena.alloc(region_constraints))
225-
};
226-
Ok(output)
200+
201+
Ok(TypeOpOutput {
202+
output,
203+
constraints: if region_constraints.is_empty() {
204+
None
205+
} else {
206+
Some(infcx.tcx.arena.alloc(region_constraints))
207+
},
208+
error_info,
209+
})
227210
}
228211
}

tests/ui/inference/issue-80409.no-compat.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: internal compiler error: error performing operation: fully_perform
1+
error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } }
22
--> $DIR/issue-80409.rs:49:30
33
|
44
LL | builder.state().on_entry(|_| {});

0 commit comments

Comments
 (0)