Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid a scrape_region_constraints and instead register the region constraints directly #123669

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 139 additions & 84 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,64 +248,71 @@ impl<'tcx> InferCtxt<'tcx> {
where
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
let InferOk { value: result_args, mut obligations } = self
.query_response_instantiation_guess(
cause,
param_env,
original_values,
query_response,
)?;
let result_args =
self.query_response_instantiation_guess(cause, original_values, query_response);

let mut obligations = vec![];

// Carry all newly resolved opaque types to the caller's scope
for &(opaque_type_key, hidden_ty) in &query_response.value.opaque_types {
let opaque_type_key = instantiate_value(self.tcx, &result_args, opaque_type_key);
let hidden_ty = instantiate_value(self.tcx, &result_args, hidden_ty);
debug!(?opaque_type_key, ?hidden_ty, "constrain opaque type");
// We can't use equate here, because the hidden type may have been an inference
// variable that got constrained to the opaque type itself. In that case we want to ensure
// any lifetime differences get recorded in `ouput_query_region_constraints` instead of
// being registered in the `InferCtxt`.
match hidden_ty.kind() {
ty::Alias(ty::Opaque, alias_ty)
if alias_ty.def_id == opaque_type_key.def_id.into() =>
{
assert_eq!(alias_ty.args.len(), opaque_type_key.args.len());
for (key_arg, hidden_arg) in
opaque_type_key.args.iter().zip(alias_ty.args.iter())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isnt taking into account variance is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, but that shouldn't matter here in practice, as all the args are either params or inference vars. Well, they should be. Unfortunately in the presence of erroneous code we may not have errored yet, as that only happens at the end of borrowck.

{
self.equate_generic_arg(
key_arg,
hidden_arg,
output_query_region_constraints,
ConstraintCategory::OpaqueType,
&mut obligations,
cause,
param_env,
)?;
}
}
_ => {
self.insert_hidden_type(
opaque_type_key,
cause,
param_env,
hidden_ty,
&mut obligations,
)?;
}
}
}

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

let constraint_category = cause.to_constraint_category();

for (index, original_value) in original_values.var_values.iter().enumerate() {
for (index, &original_value) in original_values.var_values.iter().enumerate() {
// ...with the value `v_r` of that variable from the query.
let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| {
v.var_values[BoundVar::new(index)]
});
match (original_value.unpack(), result_value.unpack()) {
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
if re1.is_erased() && re2.is_erased() =>
{
// No action needed.
}

(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
output_query_region_constraints
.outlives
.push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
output_query_region_constraints
.outlives
.push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
}
}

(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
obligations.extend(
self.at(&cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(),
);
}

(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
obligations.extend(
self.at(&cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(),
);
}

_ => {
bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value);
}
}
self.equate_generic_arg(
original_value,
result_value,
output_query_region_constraints,
constraint_category,
&mut obligations,
cause,
param_env,
)?;
}

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

fn equate_generic_arg(
&self,
original_value: GenericArg<'tcx>,
result_value: GenericArg<'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
constraint_category: ConstraintCategory<'tcx>,
obligations: &mut Vec<Obligation<'tcx, ty::Predicate<'tcx>>>,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Result<(), ty::error::TypeError<'tcx>> {
Ok(match (original_value.unpack(), result_value.unpack()) {
(GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
if re1.is_erased() && re2.is_erased() =>
{
// No action needed.
}

(GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => {
// To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`.
if v_o != v_r {
output_query_region_constraints
.outlives
.push((ty::OutlivesPredicate(v_o.into(), v_r), constraint_category));
output_query_region_constraints
.outlives
.push((ty::OutlivesPredicate(v_r.into(), v_o), constraint_category));
}
}

(GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => {
obligations.extend(
self.at(&cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(),
);
}

(GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => {
obligations.extend(
self.at(&cause, param_env)
.eq(DefineOpaqueTypes::Yes, v1, v2)?
.into_obligations(),
);
}

_ => {
bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value);
}
})
}

/// Given the original values and the (canonicalized) result from
/// computing a query, returns an instantiation that can be applied
/// to the query result to convert the result back into the
Expand All @@ -360,25 +418,47 @@ impl<'tcx> InferCtxt<'tcx> {
original_values, query_response,
);

let mut value = self.query_response_instantiation_guess(
cause,
param_env,
original_values,
query_response,
)?;
let result_args =
self.query_response_instantiation_guess(cause, original_values, query_response);

let mut obligations = vec![];

// Carry all newly resolved opaque types to the caller's scope
for &(opaque_type_key, hidden_ty) in &query_response.value.opaque_types {
let opaque_type_key = instantiate_value(self.tcx, &result_args, opaque_type_key);
let hidden_ty = instantiate_value(self.tcx, &result_args, hidden_ty);
debug!(?opaque_type_key, ?hidden_ty, "constrain opaque type");
// We use equate here instead of, for example, just registering the
// opaque type's hidden value directly, because the hidden type may have been an inference
// variable that got constrained to the opaque type itself. In that case we want to equate
// the generic args of the opaque with the generic params of its hidden type version.
obligations.extend(
self.at(cause, param_env)
.eq(
DefineOpaqueTypes::Yes,
Ty::new_opaque(
self.tcx,
opaque_type_key.def_id.to_def_id(),
opaque_type_key.args,
),
hidden_ty,
)?
.obligations,
);
}

value.obligations.extend(
obligations.extend(
self.unify_query_response_instantiation_guess(
cause,
param_env,
original_values,
&value.value,
&result_args,
query_response,
)?
.into_obligations(),
);

Ok(value)
Ok(InferOk { value: result_args, obligations })
}

/// Given the original values and the (canonicalized) result from
Expand All @@ -390,14 +470,13 @@ impl<'tcx> InferCtxt<'tcx> {
/// will instantiate fresh inference variables for each canonical
/// variable instead. Therefore, the result of this method must be
/// properly unified
#[instrument(level = "debug", skip(self, param_env))]
#[instrument(level = "debug", skip(self))]
fn query_response_instantiation_guess<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &OriginalQueryValues<'tcx>,
query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>,
) -> InferResult<'tcx, CanonicalVarValues<'tcx>>
) -> CanonicalVarValues<'tcx>
where
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
{
Expand Down Expand Up @@ -470,7 +549,7 @@ impl<'tcx> InferCtxt<'tcx> {
// Create result arguments: if we found a value for a
// given variable in the loop above, use that. Otherwise, use
// a fresh inference variable.
let result_args = CanonicalVarValues {
CanonicalVarValues {
var_values: self.tcx.mk_args_from_iter(
query_response.variables.iter().enumerate().map(|(index, info)| {
if info.universe() != ty::UniverseIndex::ROOT {
Expand All @@ -495,31 +574,7 @@ impl<'tcx> InferCtxt<'tcx> {
}
}),
),
};

let mut obligations = vec![];

// Carry all newly resolved opaque types to the caller's scope
for &(a, b) in &query_response.value.opaque_types {
let a = instantiate_value(self.tcx, &result_args, a);
let b = instantiate_value(self.tcx, &result_args, b);
debug!(?a, ?b, "constrain opaque type");
// We use equate here instead of, for example, just registering the
// opaque type's hidden value directly, because the hidden type may have been an inference
// variable that got constrained to the opaque type itself. In that case we want to equate
// the generic args of the opaque with the generic params of its hidden type version.
obligations.extend(
self.at(cause, param_env)
.eq(
DefineOpaqueTypes::Yes,
Ty::new_opaque(self.tcx, a.def_id.to_def_id(), a.args),
b,
)?
.obligations,
);
}

Ok(InferOk { value: result_args, obligations })
}

/// Given a "guess" at the values for the canonical variables in
Expand Down
Loading
Loading