Skip to content

Commit

Permalink
Auto merge of rust-lang#118968 - aliemjay:canon-static, r=<try>
Browse files Browse the repository at this point in the history
unify query canonicalization mode

Exclude from canonicalization only the static lifetimes that appear in the param env because of rust-lang#118965 . Any other occurrence can be canonicalized safely AFAICT.

r? `@lcnr`
  • Loading branch information
bors committed Dec 15, 2023
2 parents 96df494 + 707c4f9 commit 7e4f74f
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 75 deletions.
83 changes: 27 additions & 56 deletions compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,33 @@ impl<'tcx> InferCtxt<'tcx> {
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
self.canonicalize_query_with_mode(value, query_state, &CanonicalizeAllFreeRegions)
let (param_env, value) = value.into_parts();
let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
self.tcx,
param_env,
query_state,
|tcx, param_env, query_state| {
// FIXME(#118965): We don't canonicalize the static lifetimes that appear in the
// `param_env` beacause they are treated differently by trait selection.
Canonicalizer::canonicalize(
param_env,
None,
tcx,
&CanonicalizeFreeRegionsOtherThanStatic,
query_state,
)
},
);

Canonicalizer::canonicalize_with_base(
param_env,
value,
Some(self),
self.tcx,
&CanonicalizeAllFreeRegions,
query_state,
)
.unchecked_map(|(param_env, value)| param_env.and(value))
}

/// Canonicalizes a query *response* `V`. When we canonicalize a
Expand Down Expand Up @@ -96,61 +122,6 @@ impl<'tcx> InferCtxt<'tcx> {
&mut query_state,
)
}

/// A variant of `canonicalize_query` that does not
/// canonicalize `'static`. This is useful when
/// the query implementation can perform more efficient
/// handling of `'static` regions (e.g. trait evaluation).
pub fn canonicalize_query_keep_static<V>(
&self,
value: ty::ParamEnvAnd<'tcx, V>,
query_state: &mut OriginalQueryValues<'tcx>,
) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>>
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
self.canonicalize_query_with_mode(
value,
query_state,
&CanonicalizeFreeRegionsOtherThanStatic,
)
}

fn canonicalize_query_with_mode<V>(
&self,
value: ty::ParamEnvAnd<'tcx, V>,
query_state: &mut OriginalQueryValues<'tcx>,
canonicalize_region_mode: &dyn CanonicalizeMode,
) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>>
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
let (param_env, value) = value.into_parts();
let base = self.tcx.canonical_param_env_cache.get_or_insert(
self.tcx,
param_env,
query_state,
|tcx, param_env, query_state| {
Canonicalizer::canonicalize(
param_env,
None,
tcx,
&CanonicalizeFreeRegionsOtherThanStatic,
query_state,
)
},
);

Canonicalizer::canonicalize_with_base(
base,
value,
Some(self),
self.tcx,
canonicalize_region_mode,
query_state,
)
.unchecked_map(|(param_env, value)| param_env.and(value))
}
}

/// Controls how we canonicalize "free regions" that are not inference
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
assert!(!ty.has_non_region_infer());

let mut canonical_var_values = OriginalQueryValues::default();
let canonical_ty =
self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values);
let canonical_ty = self.canonicalize_query(param_env.and(ty), &mut canonical_var_values);
let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
return vec![];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,8 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
})
} else {
assert!(!self.intercrate);
let c_pred = self.canonicalize_query_keep_static(
param_env.and(obligation.predicate),
&mut _orig_values,
);
let c_pred =
self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
}
}
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_trait_selection/src/traits/query/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
let data = data.try_fold_with(self)?;

let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
// so we cannot canonicalize it.
let c_data = infcx
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
let c_data = infcx.canonicalize_query(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
let result = match kind {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
return Ok((result, None, vec![], Certainty::Proven));
}

// FIXME(#33684) -- We need to use
// `canonicalize_query_keep_static` here because of things
// like the subtype query, which go awry around
// `'static` otherwise.
let mut canonical_var_values = OriginalQueryValues::default();
let old_param_env = query_key.param_env;
let canonical_self =
infcx.canonicalize_query_keep_static(query_key, &mut canonical_var_values);
let canonical_self = infcx.canonicalize_query(query_key, &mut canonical_var_values);
let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?;

let InferOk { value, obligations } = infcx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: implementation of `Deserialize` is not general enough
LL | assert_deserialize_owned::<&'static str>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
|
= note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
= note: `&str` must implement `Deserialize<'0>`, for any lifetime `'0`...
= note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`

error: aborting due to 1 previous error
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ error: higher-ranked lifetime error
LL | v.t(|| {});
| ^^^^^
|
= note: could not prove `for<'a> &'a V: 'static`
= note: could not prove `for<'a> &'a V: 'b`

error: aborting due to 2 previous errors

2 changes: 1 addition & 1 deletion tests/ui/nll/issue-54302.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: implementation of `Deserialize` is not general enough
LL | assert_deserialize_owned::<&'static str>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Deserialize` is not general enough
|
= note: `&'static str` must implement `Deserialize<'0>`, for any lifetime `'0`...
= note: `&str` must implement `Deserialize<'0>`, for any lifetime `'0`...
= note: ...but `&str` actually implements `Deserialize<'1>`, for some specific lifetime `'1`

error: aborting due to 1 previous error
Expand Down

0 comments on commit 7e4f74f

Please sign in to comment.