diff options
| author | Aaron Hill <aa1ronham@gmail.com> | 2020-04-11 00:50:02 -0400 |
|---|---|---|
| committer | Aaron Hill <aa1ronham@gmail.com> | 2020-07-22 00:57:43 -0400 |
| commit | ac9dfc3e7785c9bba96ebac4fd51726189e1bf91 (patch) | |
| tree | e7936b2679bf779ada0a87abd1a4436a2a02853c /src/librustc_middle/ty | |
| parent | 8ad7bc3f428300aee6764f6e23527e19eb235e81 (diff) | |
| download | rust-ac9dfc3e7785c9bba96ebac4fd51726189e1bf91.tar.gz rust-ac9dfc3e7785c9bba96ebac4fd51726189e1bf91.zip | |
Normalize opaque types when converting `ParamEnv` to `Reveal::All`
Fixes #65918
Diffstat (limited to 'src/librustc_middle/ty')
| -rw-r--r-- | src/librustc_middle/ty/layout.rs | 4 | ||||
| -rw-r--r-- | src/librustc_middle/ty/mod.rs | 15 | ||||
| -rw-r--r-- | src/librustc_middle/ty/query/keys.rs | 11 | ||||
| -rw-r--r-- | src/librustc_middle/ty/util.rs | 156 |
4 files changed, 114 insertions, 72 deletions
diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index cb937bf0112..06dd2eee505 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -1921,7 +1921,7 @@ impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - let param_env = self.param_env.with_reveal_all(); + let param_env = self.param_env.with_reveal_all_normalized(self.tcx); let ty = self.tcx.normalize_erasing_regions(param_env, ty); let layout = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyAndLayout { ty, layout }; @@ -1945,7 +1945,7 @@ impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout { - let param_env = self.param_env.with_reveal_all(); + let param_env = self.param_env.with_reveal_all_normalized(*self.tcx); let ty = self.tcx.normalize_erasing_regions(param_env, ty); let layout = self.tcx.layout_raw(param_env.and(ty))?; let layout = TyAndLayout { ty, layout }; diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 51a353c0132..ef0cf929dcd 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1,5 +1,5 @@ // ignore-tidy-filelength -pub use self::fold::{TypeFoldable, TypeVisitor}; +pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor}; pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; @@ -1819,9 +1819,15 @@ impl<'tcx> ParamEnv<'tcx> { /// the desired behavior during codegen and certain other special /// contexts; normally though we want to use `Reveal::UserFacing`, /// which is the default. - pub fn with_reveal_all(mut self) -> Self { - self.packed_data |= 1; - self + /// All opaque types in the caller_bounds of the `ParamEnv` + /// will be normalized to their underlying types. + /// See PR #65989 and issue #65918 for more details + pub fn with_reveal_all_normalized(mut self) -> Self { + if self.packed_data & 1 == 1 { + return self; + } + + ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id) } /// Returns this same environment but with no caller bounds. @@ -3067,6 +3073,7 @@ pub fn provide(providers: &mut ty::query::Providers) { context::provide(providers); erase_regions::provide(providers); layout::provide(providers); + util::provide(providers); super::util::bug::provide(providers); *providers = ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs index cb2b7a662cb..3f7a20bba2b 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/src/librustc_middle/ty/query/keys.rs @@ -270,6 +270,17 @@ impl<'tcx> Key for Ty<'tcx> { } } +impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for ty::ParamEnv<'tcx> { type CacheSelector = DefaultCacheSelector; diff --git a/src/librustc_middle/ty/util.rs b/src/librustc_middle/ty/util.rs index adba45facc9..35b684316fd 100644 --- a/src/librustc_middle/ty/util.rs +++ b/src/librustc_middle/ty/util.rs @@ -3,11 +3,12 @@ use crate::ich::NodeIdHashingMode; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::interpret::{sign_extend, truncate}; +use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::Float as _; use rustc_ast::ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -557,82 +558,84 @@ impl<'tcx> TyCtxt<'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Result<Ty<'tcx>, Ty<'tcx>> { - use crate::ty::fold::TypeFolder; - - struct OpaqueTypeExpander<'tcx> { - // Contains the DefIds of the opaque types that are currently being - // expanded. When we expand an opaque type we insert the DefId of - // that type, and when we finish expanding that type we remove the - // its DefId. - seen_opaque_tys: FxHashSet<DefId>, - // Cache of all expansions we've seen so far. This is a critical - // optimization for some large types produced by async fn trees. - expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, - primary_def_id: DefId, - found_recursion: bool, - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> OpaqueTypeExpander<'tcx> { - fn expand_opaque_ty( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Option<Ty<'tcx>> { - if self.found_recursion { - return None; - } - let substs = substs.fold_with(self); - if self.seen_opaque_tys.insert(def_id) { - let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { - Some(expanded_ty) => expanded_ty, - None => { - let generic_ty = self.tcx.type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx, substs); - let expanded_ty = self.fold_ty(concrete_ty); - self.expanded_cache.insert((def_id, substs), expanded_ty); - expanded_ty - } - }; - self.seen_opaque_tys.remove(&def_id); - Some(expanded_ty) - } else { - // If another opaque type that we contain is recursive, then it - // will report the error, so we don't have to. - self.found_recursion = def_id == self.primary_def_id; - None - } - } - } - - impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Opaque(def_id, substs) = t.kind { - self.expand_opaque_ty(def_id, substs).unwrap_or(t) - } else if t.has_opaque_types() { - t.super_fold_with(self) - } else { - t - } - } - } - let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), expanded_cache: FxHashMap::default(), - primary_def_id: def_id, + primary_def_id: Some(def_id), found_recursion: false, + check_recursion: true, tcx: self, }; + let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } } +struct OpaqueTypeExpander<'tcx> { + // Contains the DefIds of the opaque types that are currently being + // expanded. When we expand an opaque type we insert the DefId of + // that type, and when we finish expanding that type we remove the + // its DefId. + seen_opaque_tys: FxHashSet<DefId>, + // Cache of all expansions we've seen so far. This is a critical + // optimization for some large types produced by async fn trees. + expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>, + primary_def_id: Option<DefId>, + found_recursion: bool, + /// Whether or not to check for recursive opaque types. + /// This is `true` when we're explicitly checking for opaque type + /// recursion, and 'false' otherwise to avoid unecessary work. + check_recursion: bool, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> OpaqueTypeExpander<'tcx> { + fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> { + if self.found_recursion { + return None; + } + let substs = substs.fold_with(self); + if !self.check_recursion || self.seen_opaque_tys.insert(def_id) { + let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) { + Some(expanded_ty) => expanded_ty, + None => { + let generic_ty = self.tcx.type_of(def_id); + let concrete_ty = generic_ty.subst(self.tcx, substs); + let expanded_ty = self.fold_ty(concrete_ty); + self.expanded_cache.insert((def_id, substs), expanded_ty); + expanded_ty + } + }; + if self.check_recursion { + self.seen_opaque_tys.remove(&def_id); + } + Some(expanded_ty) + } else { + // If another opaque type that we contain is recursive, then it + // will report the error, so we don't have to. + self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap(); + None + } + } +} + +impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Opaque(def_id, substs) = t.kind { + self.expand_opaque_ty(def_id, substs).unwrap_or(t) + } else if t.has_opaque_types() { + t.super_fold_with(self) + } else { + t + } + } +} + impl<'tcx> ty::TyS<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. @@ -1142,3 +1145,24 @@ pub fn needs_drop_components( #[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)] pub struct AlwaysRequiresDrop; + +/// Normalizes all opaque types in the given value, replacing them +/// with their underlying types. +pub fn normalize_opaque_types( + tcx: TyCtxt<'tcx>, + val: &'tcx List<ty::Predicate<'tcx>>, +) -> &'tcx List<ty::Predicate<'tcx>> { + let mut visitor = OpaqueTypeExpander { + seen_opaque_tys: FxHashSet::default(), + expanded_cache: FxHashMap::default(), + primary_def_id: None, + found_recursion: false, + check_recursion: false, + tcx, + }; + val.fold_with(&mut visitor) +} + +pub fn provide(providers: &mut ty::query::Providers<'_>) { + *providers = ty::query::Providers { normalize_opaque_types, ..*providers } +} |
