Skip to content

Commit 6e87bac

Browse files
committed
Auto merge of #65989 - Aaron1011:fix/normalize-param-env, r=nikomatsakis
Normalize all opaque types when converting ParamEnv to Reveal::All When we normalize a type using a ParamEnv with a reveal mode of RevealMode::All, we will normalize opaque types to their underlying types (e.g. `type MyOpaque = impl Foo` -> `StructThatImplsFoo`). However, the ParamEnv may still have predicates referring to the un-normalized opaque type (e.g. `<T as MyTrait<MyOpaque>>`). This can cause trait projection to fail, since a type containing normalized opaque types will not match up with the un-normalized type in the `ParamEnv`. To fix this, we now explicitly normalize all opaque types in caller_bounds of a `ParamEnv` when changing its mode to `RevealMode::All`. This ensures that all predicatse will refer to the underlying types of any opaque types involved, allowing them to be matched up properly during projection. To reflect the fact that normalization is occuring, `ParamEnv::with_reveal_all` is renamed to `ParamEnv::with_reveal_all_normalized` Fixes #65918
2 parents 62f9aa9 + 5e2e927 commit 6e87bac

File tree

19 files changed

+152
-89
lines changed

19 files changed

+152
-89
lines changed

Diff for: 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

Diff for: 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

Diff for: 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
}

Diff for: src/librustc_middle/ty/consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl<'tcx> Const<'tcx> {
158158
ty: Ty<'tcx>,
159159
) -> Option<u128> {
160160
assert_eq!(self.ty, ty);
161-
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
161+
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
162162
// if `ty` does not depend on generic parameters, use an empty param_env
163163
self.val.eval(tcx, param_env).try_to_bits(size)
164164
}

Diff for: src/librustc_middle/ty/consts/kind.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,16 @@ impl<'tcx> ConstKind<'tcx> {
9696
if let ConstKind::Unevaluated(def, substs, promoted) = self {
9797
use crate::mir::interpret::ErrorHandled;
9898

99-
let param_env_and_substs = param_env.with_reveal_all().and(substs);
100-
10199
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
102100
// also does later, but we want to do it before checking for
103101
// inference variables.
104-
let param_env_and_substs = tcx.erase_regions(&param_env_and_substs);
102+
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
103+
// so that we don't try to invoke this query with
104+
// any region variables.
105+
let param_env_and_substs = tcx
106+
.erase_regions(&param_env)
107+
.with_reveal_all_normalized(tcx)
108+
.and(tcx.erase_regions(&substs));
105109

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

Diff for: 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 };

Diff for: 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::*;
@@ -1874,9 +1874,15 @@ impl<'tcx> ParamEnv<'tcx> {
18741874
/// the desired behavior during codegen and certain other special
18751875
/// contexts; normally though we want to use `Reveal::UserFacing`,
18761876
/// which is the default.
1877-
pub fn with_reveal_all(mut self) -> Self {
1878-
self.packed_data |= 1;
1879-
self
1877+
/// All opaque types in the caller_bounds of the `ParamEnv`
1878+
/// will be normalized to their underlying types.
1879+
/// See PR #65989 and issue #65918 for more details
1880+
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
1881+
if self.packed_data & 1 == 1 {
1882+
return self;
1883+
}
1884+
1885+
ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id)
18801886
}
18811887

18821888
/// Returns this same environment but with no caller bounds.
@@ -3116,6 +3122,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
31163122
context::provide(providers);
31173123
erase_regions::provide(providers);
31183124
layout::provide(providers);
3125+
util::provide(providers);
31193126
super::util::bug::provide(providers);
31203127
*providers = ty::query::Providers {
31213128
trait_impls_of: trait_def::trait_impls_of_provider,

Diff for: 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

Diff for: 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+
}

Diff for: 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);

Diff for: 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);

Diff for: 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, _)) => {

Diff for: 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());

Diff for: src/librustc_mir/transform/validate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
189189
// Normalize projections and things like that.
190190
// FIXME: We need to reveal_all, as some optimizations change types in ways
191191
// that require unfolding opaque types.
192-
let param_env = self.param_env.with_reveal_all();
192+
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
193193
let src = self.tcx.normalize_erasing_regions(param_env, src);
194194
let dest = self.tcx.normalize_erasing_regions(param_env, dest);
195195

Diff for: src/librustc_mir_build/hair/pattern/mod.rs

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

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

0 commit comments

Comments
 (0)