Skip to content

Commit ac9dfc3

Browse files
committed
Normalize opaque types when converting ParamEnv to Reveal::All
Fixes #65918
1 parent 8ad7bc3 commit ac9dfc3

File tree

15 files changed

+139
-82
lines changed

15 files changed

+139
-82
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
@@ -78,7 +78,7 @@ impl<'tcx> ConstValue<'tcx> {
7878
param_env: ParamEnv<'tcx>,
7979
ty: Ty<'tcx>,
8080
) -> Option<u128> {
81-
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
81+
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
8282
self.try_to_bits(size)
8383
}
8484

src/librustc_middle/query/mod.rs

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

871+
/// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode.
872+
/// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
873+
/// as this method is more efficient.
874+
query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
875+
desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
876+
}
877+
872878
/// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
873879
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
874880
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
@@ -1527,5 +1533,9 @@ rustc_queries! {
15271533
ty::Instance::new(key.value.0.to_def_id(), key.value.2),
15281534
}
15291535
}
1536+
1537+
query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
1538+
desc { "normalizing opaque types in {:?}", key }
1539+
}
15301540
}
15311541
}

src/librustc_middle/ty/layout.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
19211921
/// Computes the layout of a type. Note that this implicitly
19221922
/// executes in "reveal all" mode.
19231923
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
1924-
let param_env = self.param_env.with_reveal_all();
1924+
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
19251925
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
19261926
let layout = self.tcx.layout_raw(param_env.and(ty))?;
19271927
let layout = TyAndLayout { ty, layout };
@@ -1945,7 +1945,7 @@ impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
19451945
/// Computes the layout of a type. Note that this implicitly
19461946
/// executes in "reveal all" mode.
19471947
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
1948-
let param_env = self.param_env.with_reveal_all();
1948+
let param_env = self.param_env.with_reveal_all_normalized(*self.tcx);
19491949
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
19501950
let layout = self.tcx.layout_raw(param_env.and(ty))?;
19511951
let layout = TyAndLayout { ty, layout };

src/librustc_middle/ty/mod.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// ignore-tidy-filelength
2-
pub use self::fold::{TypeFoldable, TypeVisitor};
2+
pub use self::fold::{TypeFoldable, TypeFolder, TypeVisitor};
33
pub use self::AssocItemContainer::*;
44
pub use self::BorrowKind::*;
55
pub use self::IntVarValue::*;
@@ -1819,9 +1819,15 @@ impl<'tcx> ParamEnv<'tcx> {
18191819
/// the desired behavior during codegen and certain other special
18201820
/// contexts; normally though we want to use `Reveal::UserFacing`,
18211821
/// which is the default.
1822-
pub fn with_reveal_all(mut self) -> Self {
1823-
self.packed_data |= 1;
1824-
self
1822+
/// All opaque types in the caller_bounds of the `ParamEnv`
1823+
/// will be normalized to their underlying types.
1824+
/// See PR #65989 and issue #65918 for more details
1825+
pub fn with_reveal_all_normalized(mut self) -> Self {
1826+
if self.packed_data & 1 == 1 {
1827+
return self;
1828+
}
1829+
1830+
ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id)
18251831
}
18261832

18271833
/// Returns this same environment but with no caller bounds.
@@ -3067,6 +3073,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
30673073
context::provide(providers);
30683074
erase_regions::provide(providers);
30693075
layout::provide(providers);
3076+
util::provide(providers);
30703077
super::util::bug::provide(providers);
30713078
*providers = ty::query::Providers {
30723079
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
@@ -270,6 +270,17 @@ impl<'tcx> Key for Ty<'tcx> {
270270
}
271271
}
272272

273+
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
274+
type CacheSelector = DefaultCacheSelector;
275+
276+
fn query_crate(&self) -> CrateNum {
277+
LOCAL_CRATE
278+
}
279+
fn default_span(&self, _: TyCtxt<'_>) -> Span {
280+
DUMMY_SP
281+
}
282+
}
283+
273284
impl<'tcx> Key for ty::ParamEnv<'tcx> {
274285
type CacheSelector = DefaultCacheSelector;
275286

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.
@@ -1142,3 +1145,24 @@ pub fn needs_drop_components(
11421145

11431146
#[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)]
11441147
pub struct AlwaysRequiresDrop;
1148+
1149+
/// Normalizes all opaque types in the given value, replacing them
1150+
/// with their underlying types.
1151+
pub fn normalize_opaque_types(
1152+
tcx: TyCtxt<'tcx>,
1153+
val: &'tcx List<ty::Predicate<'tcx>>,
1154+
) -> &'tcx List<ty::Predicate<'tcx>> {
1155+
let mut visitor = OpaqueTypeExpander {
1156+
seen_opaque_tys: FxHashSet::default(),
1157+
expanded_cache: FxHashMap::default(),
1158+
primary_def_id: None,
1159+
found_recursion: false,
1160+
check_recursion: false,
1161+
tcx,
1162+
};
1163+
val.fold_with(&mut visitor)
1164+
}
1165+
1166+
pub fn provide(providers: &mut ty::query::Providers<'_>) {
1167+
*providers = ty::query::Providers { normalize_opaque_types, ..*providers }
1168+
}

src/librustc_mir/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
193193
);
194194
}
195195
let patch = {
196-
let param_env = tcx.param_env(def_id).with_reveal_all();
196+
let param_env = tcx.param_env_reveal_all_normalized(def_id);
197197
let mut elaborator =
198198
DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env };
199199
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
@@ -328,7 +328,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
328328
) -> ConstPropagator<'mir, 'tcx> {
329329
let def_id = source.def_id();
330330
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
331-
let param_env = tcx.param_env(def_id).with_reveal_all();
331+
let param_env = tcx.param_env_reveal_all_normalized(def_id);
332332

333333
let span = tcx.def_span(def_id);
334334
let can_const_prop = CanConstProp::check(body);

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
@@ -72,7 +72,7 @@ impl Inliner<'tcx> {
7272

7373
let mut callsites = VecDeque::new();
7474

75-
let param_env = self.tcx.param_env(self.source.def_id()).with_reveal_all();
75+
let param_env = self.tcx.param_env_reveal_all_normalized(self.source.def_id());
7676

7777
// Only do inlining into fn bodies.
7878
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
@@ -781,7 +781,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
781781

782782
// Use `Reveal::All` here because patterns are always monomorphic even if their function
783783
// isn't.
784-
let param_env_reveal_all = self.param_env.with_reveal_all();
784+
let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
785785
let substs = self.typeck_results.node_substs(id);
786786
let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
787787
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
@@ -137,7 +137,7 @@ fn resolve_associated_item<'tcx>(
137137
});
138138

139139
let substs = tcx.infer_ctxt().enter(|infcx| {
140-
let param_env = param_env.with_reveal_all();
140+
let param_env = param_env.with_reveal_all_normalized(tcx);
141141
let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
142142
let substs = translate_substs(
143143
&infcx,

src/librustc_ty/ty.rs

+5
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
276276
traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
277277
}
278278

279+
fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
280+
tcx.param_env(def_id).with_reveal_all_normalized(tcx)
281+
}
282+
279283
fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
280284
assert_eq!(crate_num, LOCAL_CRATE);
281285
tcx.sess.local_crate_disambiguator()
@@ -503,6 +507,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
503507
adt_sized_constraint,
504508
def_span,
505509
param_env,
510+
param_env_reveal_all_normalized,
506511
trait_of_item,
507512
crate_disambiguator,
508513
original_crate_name,

0 commit comments

Comments
 (0)