Rollup merge of #109171 - oli-obk:normalization_cleanup, r=compiler-errors
Some cleanups in our normalization logic Changed a match to be exhaustive and deduplicated some code. r? ```@compiler-errors``` this pulls out the uncontroversial part of https://github.com/rust-lang/rust/pull/108860
This commit is contained in:
commit
113e815b36
2 changed files with 48 additions and 77 deletions
|
@ -468,6 +468,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (kind, data) = match *ty.kind() {
|
||||||
|
ty::Alias(kind, alias_ty) => (kind, alias_ty),
|
||||||
|
_ => return ty.super_fold_with(self),
|
||||||
|
};
|
||||||
|
|
||||||
// We try to be a little clever here as a performance optimization in
|
// We try to be a little clever here as a performance optimization in
|
||||||
// cases where there are nested projections under binders.
|
// cases where there are nested projections under binders.
|
||||||
// For example:
|
// For example:
|
||||||
|
@ -491,13 +496,11 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
// replace bound vars if the current type is a `Projection` and we need
|
// replace bound vars if the current type is a `Projection` and we need
|
||||||
// to make sure we don't forget to fold the substs regardless.
|
// to make sure we don't forget to fold the substs regardless.
|
||||||
|
|
||||||
match *ty.kind() {
|
match kind {
|
||||||
// This is really important. While we *can* handle this, this has
|
// This is really important. While we *can* handle this, this has
|
||||||
// severe performance implications for large opaque types with
|
// severe performance implications for large opaque types with
|
||||||
// late-bound regions. See `issue-88862` benchmark.
|
// late-bound regions. See `issue-88862` benchmark.
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
|
ty::Opaque if !data.substs.has_escaping_bound_vars() => {
|
||||||
if !substs.has_escaping_bound_vars() =>
|
|
||||||
{
|
|
||||||
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
||||||
match self.param_env.reveal() {
|
match self.param_env.reveal() {
|
||||||
Reveal::UserFacing => ty.super_fold_with(self),
|
Reveal::UserFacing => ty.super_fold_with(self),
|
||||||
|
@ -513,8 +516,8 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let substs = substs.fold_with(self);
|
let substs = data.substs.fold_with(self);
|
||||||
let generic_ty = self.interner().type_of(def_id);
|
let generic_ty = self.interner().type_of(data.def_id);
|
||||||
let concrete_ty = generic_ty.subst(self.interner(), substs);
|
let concrete_ty = generic_ty.subst(self.interner(), substs);
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
let folded_ty = self.fold_ty(concrete_ty);
|
let folded_ty = self.fold_ty(concrete_ty);
|
||||||
|
@ -523,8 +526,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty::Opaque => ty.super_fold_with(self),
|
||||||
|
|
||||||
ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
|
ty::Projection if !data.has_escaping_bound_vars() => {
|
||||||
// This branch is *mostly* just an optimization: when we don't
|
// This branch is *mostly* just an optimization: when we don't
|
||||||
// have escaping bound vars, we don't need to replace them with
|
// have escaping bound vars, we don't need to replace them with
|
||||||
// placeholders (see branch below). *Also*, we know that we can
|
// placeholders (see branch below). *Also*, we know that we can
|
||||||
|
@ -563,7 +567,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
normalized_ty.ty().unwrap()
|
normalized_ty.ty().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Alias(ty::Projection, data) => {
|
ty::Projection => {
|
||||||
// If there are escaping bound vars, we temporarily replace the
|
// If there are escaping bound vars, we temporarily replace the
|
||||||
// bound vars with placeholders. Note though, that in the case
|
// bound vars with placeholders. Note though, that in the case
|
||||||
// that we still can't project for whatever reason (e.g. self
|
// that we still can't project for whatever reason (e.g. self
|
||||||
|
@ -612,8 +616,6 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
|
||||||
);
|
);
|
||||||
normalized_ty
|
normalized_ty
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => ty.super_fold_with(self),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,23 +197,30 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||||
return Ok(*ty);
|
return Ok(*ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (kind, data) = match *ty.kind() {
|
||||||
|
ty::Alias(kind, data) => (kind, data),
|
||||||
|
_ => {
|
||||||
|
let res = ty.try_super_fold_with(self)?;
|
||||||
|
self.cache.insert(ty, res);
|
||||||
|
return Ok(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// See note in `rustc_trait_selection::traits::project` about why we
|
// See note in `rustc_trait_selection::traits::project` about why we
|
||||||
// wait to fold the substs.
|
// wait to fold the substs.
|
||||||
|
|
||||||
// Wrap this in a closure so we don't accidentally return from the outer function
|
// Wrap this in a closure so we don't accidentally return from the outer function
|
||||||
let res = match *ty.kind() {
|
let res = match kind {
|
||||||
// This is really important. While we *can* handle this, this has
|
// This is really important. While we *can* handle this, this has
|
||||||
// severe performance implications for large opaque types with
|
// severe performance implications for large opaque types with
|
||||||
// late-bound regions. See `issue-88862` benchmark.
|
// late-bound regions. See `issue-88862` benchmark.
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. })
|
ty::Opaque if !data.substs.has_escaping_bound_vars() => {
|
||||||
if !substs.has_escaping_bound_vars() =>
|
|
||||||
{
|
|
||||||
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
// Only normalize `impl Trait` outside of type inference, usually in codegen.
|
||||||
match self.param_env.reveal() {
|
match self.param_env.reveal() {
|
||||||
Reveal::UserFacing => ty.try_super_fold_with(self)?,
|
Reveal::UserFacing => ty.try_super_fold_with(self)?,
|
||||||
|
|
||||||
Reveal::All => {
|
Reveal::All => {
|
||||||
let substs = substs.try_fold_with(self)?;
|
let substs = data.substs.try_fold_with(self)?;
|
||||||
let recursion_limit = self.interner().recursion_limit();
|
let recursion_limit = self.interner().recursion_limit();
|
||||||
if !recursion_limit.value_within_limit(self.anon_depth) {
|
if !recursion_limit.value_within_limit(self.anon_depth) {
|
||||||
// A closure or generator may have itself as in its upvars.
|
// A closure or generator may have itself as in its upvars.
|
||||||
|
@ -228,7 +235,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||||
return ty.try_super_fold_with(self);
|
return ty.try_super_fold_with(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
let generic_ty = self.interner().type_of(def_id);
|
let generic_ty = self.interner().type_of(data.def_id);
|
||||||
let concrete_ty = generic_ty.subst(self.interner(), substs);
|
let concrete_ty = generic_ty.subst(self.interner(), substs);
|
||||||
self.anon_depth += 1;
|
self.anon_depth += 1;
|
||||||
if concrete_ty == ty {
|
if concrete_ty == ty {
|
||||||
|
@ -248,62 +255,22 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Alias(ty::Projection, data) if !data.has_escaping_bound_vars() => {
|
ty::Opaque => ty.try_super_fold_with(self)?,
|
||||||
// This branch is just an optimization: when we don't have escaping bound vars,
|
|
||||||
// we don't need to replace them with placeholders (see branch below).
|
|
||||||
|
|
||||||
let tcx = self.infcx.tcx;
|
ty::Projection => {
|
||||||
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 = self
|
|
||||||
.infcx
|
|
||||||
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
|
|
||||||
debug!("QueryNormalizer: c_data = {:#?}", c_data);
|
|
||||||
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
|
|
||||||
let result = tcx.normalize_projection_ty(c_data)?;
|
|
||||||
// We don't expect ambiguity.
|
|
||||||
if result.is_ambiguous() {
|
|
||||||
// Rustdoc normalizes possibly not well-formed types, so only
|
|
||||||
// treat this as a bug if we're not in rustdoc.
|
|
||||||
if !tcx.sess.opts.actually_rustdoc {
|
|
||||||
tcx.sess.delay_span_bug(
|
|
||||||
DUMMY_SP,
|
|
||||||
format!("unexpected ambiguity: {:?} {:?}", c_data, result),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Err(NoSolution);
|
|
||||||
}
|
|
||||||
let InferOk { value: result, obligations } =
|
|
||||||
self.infcx.instantiate_query_response_and_region_obligations(
|
|
||||||
self.cause,
|
|
||||||
self.param_env,
|
|
||||||
&orig_values,
|
|
||||||
result,
|
|
||||||
)?;
|
|
||||||
debug!("QueryNormalizer: result = {:#?}", result);
|
|
||||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
|
||||||
self.obligations.extend(obligations);
|
|
||||||
|
|
||||||
let res = result.normalized_ty;
|
|
||||||
// `tcx.normalize_projection_ty` may normalize to a type that still has
|
|
||||||
// unevaluated consts, so keep normalizing here if that's the case.
|
|
||||||
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
|
|
||||||
res.try_super_fold_with(self)?
|
|
||||||
} else {
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::Alias(ty::Projection, data) => {
|
|
||||||
// See note in `rustc_trait_selection::traits::project`
|
// See note in `rustc_trait_selection::traits::project`
|
||||||
|
|
||||||
let tcx = self.infcx.tcx;
|
let tcx = self.infcx.tcx;
|
||||||
let infcx = self.infcx;
|
let infcx = self.infcx;
|
||||||
let (data, mapped_regions, mapped_types, mapped_consts) =
|
// Just an optimization: When we don't have escaping bound vars,
|
||||||
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
// we don't need to replace them with placeholders.
|
||||||
|
let (data, maps) = if data.has_escaping_bound_vars() {
|
||||||
|
let (data, mapped_regions, mapped_types, mapped_consts) =
|
||||||
|
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
|
||||||
|
(data, Some((mapped_regions, mapped_types, mapped_consts)))
|
||||||
|
} else {
|
||||||
|
(data, None)
|
||||||
|
};
|
||||||
let data = data.try_fold_with(self)?;
|
let data = data.try_fold_with(self)?;
|
||||||
|
|
||||||
let mut orig_values = OriginalQueryValues::default();
|
let mut orig_values = OriginalQueryValues::default();
|
||||||
|
@ -337,14 +304,18 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||||
debug!("QueryNormalizer: result = {:#?}", result);
|
debug!("QueryNormalizer: result = {:#?}", result);
|
||||||
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
debug!("QueryNormalizer: obligations = {:#?}", obligations);
|
||||||
self.obligations.extend(obligations);
|
self.obligations.extend(obligations);
|
||||||
let res = PlaceholderReplacer::replace_placeholders(
|
let res = if let Some((mapped_regions, mapped_types, mapped_consts)) = maps {
|
||||||
infcx,
|
PlaceholderReplacer::replace_placeholders(
|
||||||
mapped_regions,
|
infcx,
|
||||||
mapped_types,
|
mapped_regions,
|
||||||
mapped_consts,
|
mapped_types,
|
||||||
&self.universes,
|
mapped_consts,
|
||||||
result.normalized_ty,
|
&self.universes,
|
||||||
);
|
result.normalized_ty,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
result.normalized_ty
|
||||||
|
};
|
||||||
// `tcx.normalize_projection_ty` may normalize to a type that still has
|
// `tcx.normalize_projection_ty` may normalize to a type that still has
|
||||||
// unevaluated consts, so keep normalizing here if that's the case.
|
// unevaluated consts, so keep normalizing here if that's the case.
|
||||||
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
|
if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
|
||||||
|
@ -353,8 +324,6 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => ty.try_super_fold_with(self)?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cache.insert(ty, res);
|
self.cache.insert(ty, res);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue