about summary refs log tree commit diff
path: root/src/librustc_middle/ty
diff options
context:
space:
mode:
authorAaron Hill <aa1ronham@gmail.com>2020-04-11 00:50:02 -0400
committerAaron Hill <aa1ronham@gmail.com>2020-07-22 00:57:43 -0400
commitac9dfc3e7785c9bba96ebac4fd51726189e1bf91 (patch)
treee7936b2679bf779ada0a87abd1a4436a2a02853c /src/librustc_middle/ty
parent8ad7bc3f428300aee6764f6e23527e19eb235e81 (diff)
downloadrust-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.rs4
-rw-r--r--src/librustc_middle/ty/mod.rs15
-rw-r--r--src/librustc_middle/ty/query/keys.rs11
-rw-r--r--src/librustc_middle/ty/util.rs156
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 }
+}