diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 25faacadf3d0c..9a66972e65194 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -62,6 +62,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { opt_const_param_of: type_of::opt_const_param_of, type_of: type_of::type_of, + fully_revealed_type_of: type_of::fully_revealed_type_of, item_bounds: item_bounds::item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds, generics_of: generics_of::generics_of, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c29a645eb4a88..4c12205beb98d 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -7,7 +7,9 @@ use rustc_hir::{HirId, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; +use rustc_middle::ty::{ + self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, +}; use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; @@ -538,6 +540,35 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { } } +pub fn fully_revealed_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Ty<'tcx> { + let ty = tcx.type_of(def_id); + if ty.has_opaque_types() { ty.fold_with(&mut DeeperTypeFolder { tcx }) } else { ty } +} + +struct DeeperTypeFolder<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> TypeFolder<'tcx> for DeeperTypeFolder<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_opaque_types() { + return ty; + } + + let ty = ty.super_fold_with(self); + + if let ty::Opaque(def_id, substs) = *ty.kind() { + self.tcx.bound_fully_revealed_type_of(def_id).subst(self.tcx, substs) + } else { + ty + } + } +} + #[instrument(skip(tcx), level = "debug")] /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// laid for "higher-order pattern unification". diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c2eecd9e87a38..1c9f47c746818 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -587,6 +587,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> { self } + pub fn considering_regions(mut self, c: bool) -> Self { + self.considering_regions = c; + self + } + pub fn with_normalize_fn_sig_for_diagnostic( mut self, fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 00242e7eed775..f96fd1b12fec4 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -164,6 +164,21 @@ rustc_queries! { separate_provide_extern } + query fully_revealed_type_of(key: DefId) -> Ty<'tcx> { + desc { |tcx| + "fully {action} `{path}`", + action = { + use rustc_hir::def::DefKind; + match tcx.def_kind(key) { + DefKind::TyAlias => "expanding type alias", + DefKind::TraitAlias => "expanding trait alias", + _ => "computing type of", + } + }, + path = tcx.def_path_str(key), + } + } + query collect_trait_impl_trait_tys(key: DefId) -> Result<&'tcx FxHashMap>, ErrorGuaranteed> { @@ -1873,12 +1888,12 @@ rustc_queries! { /// Do not call this query directly: invoke `normalize` instead. query normalize_projection_ty( - goal: CanonicalProjectionGoal<'tcx> + key: CanonicalProjectionGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, > { - desc { "normalizing `{}`", goal.value.value } + desc { "normalizing `{}` {}", key.value.value.projection_ty, if key.value.value.considering_regions { "considering regions" } else { "modulo regions" } } remap_env_constness } diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index fb152b63f6344..417f81990ee59 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -78,7 +78,14 @@ pub mod type_op { } pub type CanonicalProjectionGoal<'tcx> = - Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>; + Canonical<'tcx, ty::ParamEnvAnd<'tcx, ProjectionGoal<'tcx>>>; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct ProjectionGoal<'tcx> { + pub projection_ty: ty::ProjectionTy<'tcx>, + pub considering_regions: bool, +} pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index ee13920d52edd..6955a8f5ce232 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -52,7 +52,7 @@ impl<'tcx> TyCtxt<'tcx> { let value = self.erase_regions(value); debug!(?value); - if !value.has_projections() { + if !value.needs_normalization(param_env.reveal()) { value } else { value.fold_with(&mut NormalizeAfterErasingRegionsFolder { tcx: self, param_env }) @@ -84,7 +84,7 @@ impl<'tcx> TyCtxt<'tcx> { let value = self.erase_regions(value); debug!(?value); - if !value.has_projections() { + if !value.needs_normalization(param_env.reveal()) { Ok(value) } else { let mut folder = TryNormalizeAfterErasingRegionsFolder::new(self, param_env); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f72e236eda133..dd047124f67fc 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -650,6 +650,10 @@ impl<'tcx> TyCtxt<'tcx> { ty::EarlyBinder(self.type_of(def_id)) } + pub fn bound_fully_revealed_type_of(self, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder(self.fully_revealed_type_of(def_id)) + } + pub fn bound_trait_impl_trait_tys( self, def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index f0e9f990a8115..c7b61b5981b6b 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -160,6 +160,19 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { fn still_further_specializable(&self) -> bool { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } + + fn needs_normalization(&self, reveal: ty::Reveal) -> bool { + match reveal { + ty::Reveal::UserFacing => { + self.has_type_flags(TypeFlags::HAS_TY_PROJECTION | TypeFlags::HAS_CT_PROJECTION) + } + ty::Reveal::All => self.has_type_flags( + TypeFlags::HAS_TY_PROJECTION + | TypeFlags::HAS_TY_OPAQUE + | TypeFlags::HAS_CT_PROJECTION, + ), + } + } } pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> { @@ -537,7 +550,7 @@ struct FoundFlags; // FIXME: Optimize for checking for infer flags struct HasTypeFlagsVisitor { - flags: ty::TypeFlags, + flags: TypeFlags, } impl std::fmt::Debug for HasTypeFlagsVisitor { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index a417e1440b9ee..798527d88572a 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -285,7 +285,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let infcx = self.selcx.infcx(); - if obligation.predicate.has_projections() { + if obligation.predicate.needs_normalization(obligation.param_env.reveal()) { let mut obligations = Vec::new(); let predicate = crate::traits::project::try_normalize_with_depth_to( &mut self.selcx, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index daee5dd8f02e6..0cb4ff3fd7d48 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -381,18 +381,6 @@ where result } -pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool { - match reveal { - Reveal::UserFacing => value - .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), - Reveal::All => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_OPAQUE - | ty::TypeFlags::HAS_CT_PROJECTION, - ), - } -} - struct AssocTypeNormalizer<'a, 'b, 'tcx> { selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -453,7 +441,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { value ); - if !needs_normalization(&value, self.param_env.reveal()) { + if !value.needs_normalization(self.param_env.reveal()) { value } else { value.fold_with(self) @@ -477,7 +465,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !needs_normalization(&ty, self.param_env.reveal()) { + if !ty.needs_normalization(self.param_env.reveal()) { return ty; } @@ -526,7 +514,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { } let substs = substs.fold_with(self); - let generic_ty = self.tcx().bound_type_of(def_id); + let generic_ty = self.tcx().bound_fully_revealed_type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.depth += 1; let folded_ty = self.fold_ty(concrete_ty); @@ -650,6 +638,10 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { if tcx.lazy_normalization() { constant } else { + if !constant.needs_normalization(self.param_env.reveal()) { + return constant; + } + let constant = constant.super_fold_with(self); debug!(?constant, ?self.param_env); with_replaced_escaping_bound_vars( @@ -663,7 +655,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { #[inline] fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + if p.allow_normalization() && p.needs_normalization(self.param_env.reveal()) { p.super_fold_with(self) } else { p @@ -1124,7 +1116,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_term = selcx.infcx().resolve_vars_if_possible(projected_term); - let mut result = if projected_term.has_projections() { + let mut result = if projected_term.needs_normalization(param_env.reveal()) { let mut normalizer = AssocTypeNormalizer::new( selcx, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 715f5be8e2f4b..95958e106ef78 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,7 +6,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::TypeErrCtxtExt; -use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::project::{BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -21,6 +21,7 @@ use std::ops::ControlFlow; use super::NoSolution; pub use rustc_middle::traits::query::NormalizationResult; +use rustc_middle::traits::query::ProjectionGoal; pub trait AtExt<'tcx> { fn normalize(&self, value: T) -> Result, NoSolution> @@ -53,7 +54,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { self.param_env, self.cause, ); - if !needs_normalization(&value, self.param_env.reveal()) { + if !value.needs_normalization(self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); } @@ -182,7 +183,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { #[instrument(level = "debug", skip(self))] fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { - if !needs_normalization(&ty, self.param_env.reveal()) { + if !ty.needs_normalization(self.param_env.reveal()) { return Ok(ty); } @@ -216,7 +217,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.infcx.err_ctxt().report_overflow_error(&obligation, true); } - let generic_ty = self.tcx().bound_type_of(def_id); + let generic_ty = self.tcx().bound_fully_revealed_type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.anon_depth += 1; if concrete_ty == ty { @@ -241,7 +242,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { // we don't need to replace them with placeholders (see branch below). let tcx = self.infcx.tcx; - let data = data.try_fold_with(self)?; + let data = ProjectionGoal { + projection_ty: data.try_fold_with(self)?, + considering_regions: self.infcx.considering_regions, + }; let mut orig_values = OriginalQueryValues::default(); // HACK(matthewjasper) `'static` is special-cased in selection, @@ -292,7 +296,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let infcx = self.infcx; let (data, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.try_fold_with(self)?; + let data = ProjectionGoal { + projection_ty: data.try_fold_with(self)?, + considering_regions: self.infcx.considering_regions, + }; let mut orig_values = OriginalQueryValues::default(); // HACK(matthewjasper) `'static` is special-cased in selection, @@ -353,6 +360,10 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { &mut self, constant: ty::Const<'tcx>, ) -> Result, Self::Error> { + if !constant.needs_normalization(self.param_env.reveal()) { + return Ok(constant); + } + let constant = constant.try_super_fold_with(self)?; debug!(?constant, ?self.param_env); Ok(crate::traits::project::with_replaced_escaping_bound_vars( @@ -368,7 +379,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { &mut self, p: ty::Predicate<'tcx>, ) -> Result, Self::Error> { - if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + if p.allow_normalization() && p.needs_normalization(self.param_env.reveal()) { p.try_super_fold_with(self) } else { Ok(p) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index e92ca7325d349..427c5c70316d3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -13,7 +13,11 @@ where type QueryResponse = T; fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option { - if !key.value.value.has_projections() { Some(key.value.value) } else { None } + if !key.value.value.needs_normalization(key.param_env.reveal()) { + Some(key.value.value) + } else { + None + } } fn perform_query( diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 2da64d73d34ac..e56099407738d 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,7 +1,9 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, FallibleTypeFolder, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable, +}; use rustc_trait_selection::traits::query::normalize::AtExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; use std::sync::atomic::Ordering; @@ -16,7 +18,23 @@ pub(crate) fn provide(p: &mut Providers) { .normalize_generic_arg_after_erasing_regions .fetch_add(1, Ordering::Relaxed); - try_normalize_after_erasing_regions(tcx, goal) + let ParamEnvAnd { param_env, value } = goal; + + match value.unpack() { + ty::GenericArgKind::Type(ty) => { + let ty = + ty.try_super_fold_with(&mut NormalizeDeeperFolder { tcx, param_env })?; + if let ty::Projection(..) | ty::Opaque(..) = ty.kind() { + Ok(try_normalize_after_erasing_regions(tcx, param_env, ty)?.into()) + } else { + Ok(ty.into()) + } + } + ty::GenericArgKind::Const(_) => { + try_normalize_after_erasing_regions(tcx, param_env, value) + } + ty::GenericArgKind::Lifetime(_) => unreachable!(), + } }, ..*p }; @@ -24,10 +42,10 @@ pub(crate) fn provide(p: &mut Providers) { fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>( tcx: TyCtxt<'tcx>, - goal: ParamEnvAnd<'tcx, T>, + param_env: ty::ParamEnv<'tcx>, + value: T, ) -> Result { - let ParamEnvAnd { param_env, value } = goal; - let infcx = tcx.infer_ctxt().build(); + let infcx = tcx.infer_ctxt().ignoring_regions().build(); let cause = ObligationCause::dummy(); match infcx.at(&cause, param_env).normalize(value) { Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => { @@ -52,6 +70,39 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + } } +struct NormalizeDeeperFolder<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> FallibleTypeFolder<'tcx> for NormalizeDeeperFolder<'tcx> { + type Error = NoSolution; + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { + if !ty.needs_normalization(self.param_env.reveal()) { + return Ok(ty); + } + + let ty = ty.try_super_fold_with(self)?; + if let ty::Projection(..) | ty::Opaque(..) = ty.kind() { + Ok(self + .tcx + .try_normalize_generic_arg_after_erasing_regions(self.param_env.and(ty.into()))? + .expect_ty()) + } else { + Ok(ty) + } + } + + fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result, Self::Error> { + try_normalize_after_erasing_regions(self.tcx, self.param_env, c) + } +} + fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool { match p.kind().skip_binder() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index e805eb4282119..1779f942b605c 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -20,16 +20,16 @@ fn normalize_projection_ty<'tcx>( debug!("normalize_provider(goal={:#?})", goal); tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed); - tcx.infer_ctxt().enter_canonical_trait_query( - &goal, - |ocx, ParamEnvAnd { param_env, value: goal }| { + tcx.infer_ctxt() + .considering_regions(goal.value.value.considering_regions) + .enter_canonical_trait_query(&goal, |ocx, ParamEnvAnd { param_env, value: goal }| { let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = vec![]; let answer = traits::normalize_projection_type( selcx, param_env, - goal, + goal.projection_ty, cause, 0, &mut obligations, @@ -39,6 +39,5 @@ fn normalize_projection_ty<'tcx>( // a type, but there is the possibility it could've been a const now. Maybe change // it to a Term later? Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() }) - }, - ) + }) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 52ba0eee97cd5..067fe227b4b40 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -431,9 +431,9 @@ fn layout_of_uncached<'tcx>( // Arrays and slices. ty::Array(element, mut count) => { - if count.has_projections() { + if count.needs_normalization(param_env.reveal()) { count = tcx.normalize_erasing_regions(param_env, count); - if count.has_projections() { + if count.needs_normalization(param_env.reveal()) { return Err(LayoutError::Unknown(ty)); } }