Skip to content

Commit b8c6a11

Browse files
committed
Normalize opaque types when converting ParamEnv to Reveal::All
Fixes rust-lang#65918
1 parent 7c78a5f commit b8c6a11

File tree

16 files changed

+148
-85
lines changed

16 files changed

+148
-85
lines changed

src/librustc_middle/mir/interpret/queries.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl<'tcx> TyCtxt<'tcx> {
1818
let substs = InternalSubsts::identity_for_item(self, def_id);
1919
let instance = ty::Instance::new(def_id, substs);
2020
let cid = GlobalId { instance, promoted: None };
21-
let param_env = self.param_env(def_id).with_reveal_all();
21+
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
2222
self.const_eval_global_id(param_env, cid, None)
2323
}
2424

src/librustc_middle/mir/interpret/value.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl<'tcx> ConstValue<'tcx> {
6666
param_env: ParamEnv<'tcx>,
6767
ty: Ty<'tcx>,
6868
) -> Option<u128> {
69-
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
69+
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
7070
self.try_to_bits(size)
7171
}
7272

src/librustc_middle/query/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -766,11 +766,17 @@ rustc_queries! {
766766
/// type-checking etc, and it does not normalize specializable
767767
/// associated types. This is almost always what you want,
768768
/// unless you are doing MIR optimizations, in which case you
769-
/// might want to use `reveal_all()` method to change modes.
770769
query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
771770
desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
772771
}
773772

773+
/// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode.
774+
/// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
775+
/// as this method is more efficient.
776+
query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
777+
desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
778+
}
779+
774780
/// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
775781
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
776782
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
@@ -1398,5 +1404,9 @@ rustc_queries! {
13981404
) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
13991405
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
14001406
}
1407+
1408+
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
1409+
desc { "normalizing opaque types in {:?}", key }
1410+
}
14011411
}
14021412
}

src/librustc_middle/ty/layout.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,7 @@ impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
19031903
/// Computes the layout of a type. Note that this implicitly
19041904
/// executes in "reveal all" mode.
19051905
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
1906-
let param_env = self.param_env.with_reveal_all();
1906+
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
19071907
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
19081908
let layout = self.tcx.layout_raw(param_env.and(ty))?;
19091909
let layout = TyAndLayout { ty, layout };
@@ -1927,7 +1927,7 @@ impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
19271927
/// Computes the layout of a type. Note that this implicitly
19281928
/// executes in "reveal all" mode.
19291929
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
1930-
let param_env = self.param_env.with_reveal_all();
1930+
let param_env = self.param_env.with_reveal_all_normalized(*self.tcx);
19311931
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
19321932
let layout = self.tcx.layout_raw(param_env.and(ty))?;
19331933
let layout = TyAndLayout { ty, layout };

src/librustc_middle/ty/mod.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub use self::fold::{TypeFoldable, TypeVisitor};
1+
pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor};
22
pub use self::AssocItemContainer::*;
33
pub use self::BorrowKind::*;
44
pub use self::IntVarValue::*;
@@ -1605,8 +1605,16 @@ impl<'tcx> ParamEnv<'tcx> {
16051605
/// the desired behavior during codegen and certain other special
16061606
/// contexts; normally though we want to use `Reveal::UserFacing`,
16071607
/// which is the default.
1608-
pub fn with_reveal_all(self) -> Self {
1609-
ty::ParamEnv { reveal: Reveal::All, ..self }
1608+
/// All opaque types in the caller_bounds of the `ParamEnv`
1609+
/// will be normalized to their underlying types.
1610+
/// See PR #65989 and issue #65918 for more details
1611+
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
1612+
if self.reveal == Reveal::All {
1613+
return self;
1614+
}
1615+
1616+
let new_bounds = tcx.normalize_opaque_types(self.caller_bounds);
1617+
ty::ParamEnv { reveal: Reveal::All, caller_bounds: new_bounds, ..self }
16101618
}
16111619

16121620
/// Returns this same environment but with no caller bounds.
@@ -2859,6 +2867,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
28592867
context::provide(providers);
28602868
erase_regions::provide(providers);
28612869
layout::provide(providers);
2870+
util::provide(providers);
28622871
super::util::bug::provide(providers);
28632872
*providers = ty::query::Providers {
28642873
trait_impls_of: trait_def::trait_impls_of_provider,

src/librustc_middle/ty/query/keys.rs

+11
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,17 @@ impl<'tcx> Key for Ty<'tcx> {
237237
}
238238
}
239239

240+
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
241+
type CacheSelector = DefaultCacheSelector;
242+
243+
fn query_crate(&self) -> CrateNum {
244+
LOCAL_CRATE
245+
}
246+
fn default_span(&self, _: TyCtxt<'_>) -> Span {
247+
DUMMY_SP
248+
}
249+
}
250+
240251
impl<'tcx> Key for ty::ParamEnv<'tcx> {
241252
type CacheSelector = DefaultCacheSelector;
242253

src/librustc_middle/ty/sty.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -2330,7 +2330,7 @@ impl<'tcx> Const<'tcx> {
23302330
ty: Ty<'tcx>,
23312331
) -> Option<u128> {
23322332
assert_eq!(self.ty, ty);
2333-
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
2333+
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
23342334
// if `ty` does not depend on generic parameters, use an empty param_env
23352335
self.eval(tcx, param_env).val.try_to_bits(size)
23362336
}
@@ -2342,12 +2342,16 @@ impl<'tcx> Const<'tcx> {
23422342
if let ConstKind::Unevaluated(did, substs, promoted) = self.val {
23432343
use crate::mir::interpret::ErrorHandled;
23442344

2345-
let param_env_and_substs = param_env.with_reveal_all().and(substs);
2346-
23472345
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
23482346
// also does later, but we want to do it before checking for
23492347
// inference variables.
2350-
let param_env_and_substs = tcx.erase_regions(&param_env_and_substs);
2348+
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
2349+
// so that we don't try to invoke this query with
2350+
// any region variables.
2351+
let param_env_and_substs = tcx
2352+
.erase_regions(&param_env)
2353+
.with_reveal_all_normalized(tcx)
2354+
.and(tcx.erase_regions(&substs));
23512355

23522356
// HACK(eddyb) when the query key would contain inference variables,
23532357
// attempt using identity substs and `ParamEnv` instead, that will succeed

src/librustc_middle/ty/util.rs

+90-66
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
use crate::ich::NodeIdHashingMode;
44
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
55
use crate::mir::interpret::{sign_extend, truncate};
6+
use crate::ty::fold::TypeFolder;
67
use crate::ty::layout::IntegerExt;
78
use crate::ty::query::TyCtxtAt;
89
use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
910
use crate::ty::TyKind::*;
10-
use crate::ty::{self, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable};
11+
use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable};
1112
use rustc_apfloat::Float as _;
1213
use rustc_ast::ast;
1314
use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@@ -557,82 +558,84 @@ impl<'tcx> TyCtxt<'tcx> {
557558
def_id: DefId,
558559
substs: SubstsRef<'tcx>,
559560
) -> Result<Ty<'tcx>, Ty<'tcx>> {
560-
use crate::ty::fold::TypeFolder;
561-
562-
struct OpaqueTypeExpander<'tcx> {
563-
// Contains the DefIds of the opaque types that are currently being
564-
// expanded. When we expand an opaque type we insert the DefId of
565-
// that type, and when we finish expanding that type we remove the
566-
// its DefId.
567-
seen_opaque_tys: FxHashSet<DefId>,
568-
// Cache of all expansions we've seen so far. This is a critical
569-
// optimization for some large types produced by async fn trees.
570-
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
571-
primary_def_id: DefId,
572-
found_recursion: bool,
573-
tcx: TyCtxt<'tcx>,
574-
}
575-
576-
impl<'tcx> OpaqueTypeExpander<'tcx> {
577-
fn expand_opaque_ty(
578-
&mut self,
579-
def_id: DefId,
580-
substs: SubstsRef<'tcx>,
581-
) -> Option<Ty<'tcx>> {
582-
if self.found_recursion {
583-
return None;
584-
}
585-
let substs = substs.fold_with(self);
586-
if self.seen_opaque_tys.insert(def_id) {
587-
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
588-
Some(expanded_ty) => expanded_ty,
589-
None => {
590-
let generic_ty = self.tcx.type_of(def_id);
591-
let concrete_ty = generic_ty.subst(self.tcx, substs);
592-
let expanded_ty = self.fold_ty(concrete_ty);
593-
self.expanded_cache.insert((def_id, substs), expanded_ty);
594-
expanded_ty
595-
}
596-
};
597-
self.seen_opaque_tys.remove(&def_id);
598-
Some(expanded_ty)
599-
} else {
600-
// If another opaque type that we contain is recursive, then it
601-
// will report the error, so we don't have to.
602-
self.found_recursion = def_id == self.primary_def_id;
603-
None
604-
}
605-
}
606-
}
607-
608-
impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
609-
fn tcx(&self) -> TyCtxt<'tcx> {
610-
self.tcx
611-
}
612-
613-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
614-
if let ty::Opaque(def_id, substs) = t.kind {
615-
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
616-
} else if t.has_opaque_types() {
617-
t.super_fold_with(self)
618-
} else {
619-
t
620-
}
621-
}
622-
}
623-
624561
let mut visitor = OpaqueTypeExpander {
625562
seen_opaque_tys: FxHashSet::default(),
626563
expanded_cache: FxHashMap::default(),
627-
primary_def_id: def_id,
564+
primary_def_id: Some(def_id),
628565
found_recursion: false,
566+
check_recursion: true,
629567
tcx: self,
630568
};
569+
631570
let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap();
632571
if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
633572
}
634573
}
635574

575+
struct OpaqueTypeExpander<'tcx> {
576+
// Contains the DefIds of the opaque types that are currently being
577+
// expanded. When we expand an opaque type we insert the DefId of
578+
// that type, and when we finish expanding that type we remove the
579+
// its DefId.
580+
seen_opaque_tys: FxHashSet<DefId>,
581+
// Cache of all expansions we've seen so far. This is a critical
582+
// optimization for some large types produced by async fn trees.
583+
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
584+
primary_def_id: Option<DefId>,
585+
found_recursion: bool,
586+
/// Whether or not to check for recursive opaque types.
587+
/// This is `true` when we're explicitly checking for opaque type
588+
/// recursion, and 'false' otherwise to avoid unecessary work.
589+
check_recursion: bool,
590+
tcx: TyCtxt<'tcx>,
591+
}
592+
593+
impl<'tcx> OpaqueTypeExpander<'tcx> {
594+
fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> {
595+
if self.found_recursion {
596+
return None;
597+
}
598+
let substs = substs.fold_with(self);
599+
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
600+
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
601+
Some(expanded_ty) => expanded_ty,
602+
None => {
603+
let generic_ty = self.tcx.type_of(def_id);
604+
let concrete_ty = generic_ty.subst(self.tcx, substs);
605+
let expanded_ty = self.fold_ty(concrete_ty);
606+
self.expanded_cache.insert((def_id, substs), expanded_ty);
607+
expanded_ty
608+
}
609+
};
610+
if self.check_recursion {
611+
self.seen_opaque_tys.remove(&def_id);
612+
}
613+
Some(expanded_ty)
614+
} else {
615+
// If another opaque type that we contain is recursive, then it
616+
// will report the error, so we don't have to.
617+
self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
618+
None
619+
}
620+
}
621+
}
622+
623+
impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
624+
fn tcx(&self) -> TyCtxt<'tcx> {
625+
self.tcx
626+
}
627+
628+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
629+
if let ty::Opaque(def_id, substs) = t.kind {
630+
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
631+
} else if t.has_opaque_types() {
632+
t.super_fold_with(self)
633+
} else {
634+
t
635+
}
636+
}
637+
}
638+
636639
impl<'tcx> ty::TyS<'tcx> {
637640
/// Returns the maximum value for the given numeric type (including `char`s)
638641
/// or returns `None` if the type is not numeric.
@@ -1088,3 +1091,24 @@ pub fn needs_drop_components(
10881091

10891092
#[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)]
10901093
pub struct AlwaysRequiresDrop;
1094+
1095+
/// Normalizes all opaque types in the given value, replacing them
1096+
/// with their underlying types.
1097+
pub fn normalize_opaque_types(
1098+
tcx: TyCtxt<'tcx>,
1099+
val: &'tcx List<ty::Predicate<'tcx>>,
1100+
) -> &'tcx List<ty::Predicate<'tcx>> {
1101+
let mut visitor = OpaqueTypeExpander {
1102+
seen_opaque_tys: FxHashSet::default(),
1103+
expanded_cache: FxHashMap::default(),
1104+
primary_def_id: None,
1105+
found_recursion: false,
1106+
check_recursion: false,
1107+
tcx,
1108+
};
1109+
val.fold_with(&mut visitor)
1110+
}
1111+
1112+
pub fn provide(providers: &mut ty::query::Providers<'_>) {
1113+
*providers = ty::query::Providers { normalize_opaque_types, ..*providers }
1114+
}

src/librustc_mir/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
203203
);
204204
}
205205
let patch = {
206-
let param_env = tcx.param_env(def_id).with_reveal_all();
206+
let param_env = tcx.param_env_reveal_all_normalized(def_id);
207207
let mut elaborator =
208208
DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env };
209209
let dropee = tcx.mk_place_deref(dropee_ptr);

src/librustc_mir/transform/const_prop.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
310310
) -> ConstPropagator<'mir, 'tcx> {
311311
let def_id = source.def_id();
312312
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
313-
let param_env = tcx.param_env(def_id).with_reveal_all();
313+
let param_env = tcx.param_env_reveal_all_normalized(def_id);
314314

315315
let span = tcx.def_span(def_id);
316316
let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine::new(), ());

src/librustc_mir/transform/elaborate_drops.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
2525
debug!("elaborate_drops({:?} @ {:?})", src, body.span);
2626

2727
let def_id = src.def_id();
28-
let param_env = tcx.param_env(src.def_id()).with_reveal_all();
28+
let param_env = tcx.param_env_reveal_all_normalized(src.def_id());
2929
let move_data = match MoveData::gather_moves(body, tcx, param_env) {
3030
Ok(move_data) => move_data,
3131
Err((move_data, _)) => {

src/librustc_mir/transform/inline.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl Inliner<'tcx> {
6666

6767
let mut callsites = VecDeque::new();
6868

69-
let param_env = self.tcx.param_env(self.source.def_id()).with_reveal_all();
69+
let param_env = self.tcx.param_env_reveal_all_normalized(self.source.def_id());
7070

7171
// Only do inlining into fn bodies.
7272
let id = self.tcx.hir().as_local_hir_id(self.source.def_id().expect_local());

src/librustc_mir_build/hair/pattern/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
778778

779779
// Use `Reveal::All` here because patterns are always monomorphic even if their function
780780
// isn't.
781-
let param_env_reveal_all = self.param_env.with_reveal_all();
781+
let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
782782
let substs = self.tables.node_substs(id);
783783
let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
784784
Ok(Some(i)) => i,

src/librustc_symbol_mangling/v0.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
271271
let key = self.tcx.def_key(impl_def_id);
272272
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
273273

274-
let mut param_env = self.tcx.param_env(impl_def_id).with_reveal_all();
274+
let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
275275
if !substs.is_empty() {
276276
param_env = param_env.subst(self.tcx, substs);
277277
}

src/librustc_ty/instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ fn resolve_associated_item<'tcx>(
102102
});
103103

104104
let substs = tcx.infer_ctxt().enter(|infcx| {
105-
let param_env = param_env.with_reveal_all();
105+
let param_env = param_env.with_reveal_all_normalized(tcx);
106106
let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
107107
let substs = translate_substs(
108108
&infcx,

0 commit comments

Comments
 (0)