Skip to content

Commit ff0aa14

Browse files
committed
Auto merge of #65989 - Aaron1011:fix/normalize-param-env, r=<try>
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 ae1b871 + 10a5c93 commit ff0aa14

File tree

9 files changed

+158
-76
lines changed

9 files changed

+158
-76
lines changed

src/librustc/traits/specialize/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub fn find_associated_item<'tcx>(
130130
match ancestors.leaf_def(tcx, item.ident, item.kind) {
131131
Some(node_item) => {
132132
let substs = tcx.infer_ctxt().enter(|infcx| {
133-
let param_env = param_env.with_reveal_all();
133+
let param_env = param_env.with_reveal_all_normalized(tcx);
134134
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
135135
let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
136136
substs, node_item.node);

src/librustc/ty/layout.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1949,7 +1949,7 @@ impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
19491949
/// Computes the layout of a type. Note that this implicitly
19501950
/// executes in "reveal all" mode.
19511951
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
1952-
let param_env = self.param_env.with_reveal_all();
1952+
let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
19531953
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
19541954
let details = self.tcx.layout_raw(param_env.and(ty))?;
19551955
let layout = TyLayout {
@@ -1976,7 +1976,7 @@ impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
19761976
/// Computes the layout of a type. Note that this implicitly
19771977
/// executes in "reveal all" mode.
19781978
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
1979-
let param_env = self.param_env.with_reveal_all();
1979+
let param_env = self.param_env.with_reveal_all_normalized(*self.tcx);
19801980
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
19811981
let details = self.tcx.layout_raw(param_env.and(ty))?;
19821982
let layout = TyLayout {

src/librustc/ty/mod.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -1666,7 +1666,7 @@ impl<'tcx> ParamEnv<'tcx> {
16661666
/// environments like codegen or doing optimizations.
16671667
///
16681668
/// N.B., if you want to have predicates in scope, use `ParamEnv::new`,
1669-
/// or invoke `param_env.with_reveal_all()`.
1669+
/// or invoke `param_env.with_reveal_all_normalized()`.
16701670
#[inline]
16711671
pub fn reveal_all() -> Self {
16721672
Self::new(List::empty(), Reveal::All, None)
@@ -1688,8 +1688,14 @@ impl<'tcx> ParamEnv<'tcx> {
16881688
/// the desired behavior during codegen and certain other special
16891689
/// contexts; normally though we want to use `Reveal::UserFacing`,
16901690
/// which is the default.
1691-
pub fn with_reveal_all(self) -> Self {
1692-
ty::ParamEnv { reveal: Reveal::All, ..self }
1691+
///
1692+
/// All opaque types in the caller_bounds of the `ParamEnv`
1693+
/// will be normalized to their underlying types.
1694+
pub fn with_reveal_all_normalized(self, tcx: TyCtxt<'tcx>) -> Self {
1695+
let caller_bounds = tcx.normalize_impl_trait_types(
1696+
&self.caller_bounds
1697+
);
1698+
ty::ParamEnv { reveal: Reveal::All, caller_bounds, ..self }
16931699
}
16941700

16951701
/// Returns this same environment but with no caller bounds.

src/librustc/ty/sty.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2319,7 +2319,7 @@ impl<'tcx> Const<'tcx> {
23192319
ty: Ty<'tcx>,
23202320
) -> Option<u128> {
23212321
assert_eq!(self.ty, ty);
2322-
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
2322+
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
23232323
// if `ty` does not depend on generic parameters, use an empty param_env
23242324
self.eval(tcx, param_env).val.try_to_bits(size)
23252325
}
@@ -2331,7 +2331,7 @@ impl<'tcx> Const<'tcx> {
23312331
param_env: ParamEnv<'tcx>,
23322332
) -> &Const<'tcx> {
23332333
let try_const_eval = |did, param_env: ParamEnv<'tcx>, substs| {
2334-
let param_env_and_substs = param_env.with_reveal_all().and(substs);
2334+
let param_env_and_substs = param_env.with_reveal_all_normalized(tcx).and(substs);
23352335

23362336
// Avoid querying `tcx.const_eval(...)` with any e.g. inference vars.
23372337
if param_env_and_substs.has_local_value() {

src/librustc/ty/util.rs

+88-65
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::mir::interpret::{sign_extend, truncate};
88
use crate::ich::NodeIdHashingMode;
99
use crate::traits::{self, ObligationCause};
1010
use crate::ty::{self, DefIdTree, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
11+
use crate::ty::fold::TypeFolder;
1112
use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, GenericArgKind};
1213
use crate::ty::query::TyCtxtAt;
1314
use crate::ty::TyKind::*;
@@ -699,81 +700,32 @@ impl<'tcx> TyCtxt<'tcx> {
699700
}
700701
}
701702

703+
/// Normalizes all opaque types in the given value, replacing them
704+
/// with their underlying types.
705+
pub fn normalize_impl_trait_types<T: TypeFoldable<'tcx>>(self, val: &T) -> T {
706+
let mut visitor = OpaqueTypeExpander {
707+
seen_opaque_tys: FxHashSet::default(),
708+
expanded_cache: FxHashMap::default(),
709+
primary_def_id: None,
710+
found_recursion: false,
711+
check_recursion: false,
712+
tcx: self,
713+
};
714+
val.fold_with(&mut visitor)
715+
}
716+
702717
/// Expands the given impl trait type, stopping if the type is recursive.
703718
pub fn try_expand_impl_trait_type(
704719
self,
705720
def_id: DefId,
706721
substs: SubstsRef<'tcx>,
707722
) -> Result<Ty<'tcx>, Ty<'tcx>> {
708-
use crate::ty::fold::TypeFolder;
709-
710-
struct OpaqueTypeExpander<'tcx> {
711-
// Contains the DefIds of the opaque types that are currently being
712-
// expanded. When we expand an opaque type we insert the DefId of
713-
// that type, and when we finish expanding that type we remove the
714-
// its DefId.
715-
seen_opaque_tys: FxHashSet<DefId>,
716-
// Cache of all expansions we've seen so far. This is a critical
717-
// optimization for some large types produced by async fn trees.
718-
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
719-
primary_def_id: DefId,
720-
found_recursion: bool,
721-
tcx: TyCtxt<'tcx>,
722-
}
723-
724-
impl<'tcx> OpaqueTypeExpander<'tcx> {
725-
fn expand_opaque_ty(
726-
&mut self,
727-
def_id: DefId,
728-
substs: SubstsRef<'tcx>,
729-
) -> Option<Ty<'tcx>> {
730-
if self.found_recursion {
731-
return None;
732-
}
733-
let substs = substs.fold_with(self);
734-
if self.seen_opaque_tys.insert(def_id) {
735-
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
736-
Some(expanded_ty) => expanded_ty,
737-
None => {
738-
let generic_ty = self.tcx.type_of(def_id);
739-
let concrete_ty = generic_ty.subst(self.tcx, substs);
740-
let expanded_ty = self.fold_ty(concrete_ty);
741-
self.expanded_cache.insert((def_id, substs), expanded_ty);
742-
expanded_ty
743-
}
744-
};
745-
self.seen_opaque_tys.remove(&def_id);
746-
Some(expanded_ty)
747-
} else {
748-
// If another opaque type that we contain is recursive, then it
749-
// will report the error, so we don't have to.
750-
self.found_recursion = def_id == self.primary_def_id;
751-
None
752-
}
753-
}
754-
}
755-
756-
impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
757-
fn tcx(&self) -> TyCtxt<'tcx> {
758-
self.tcx
759-
}
760-
761-
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
762-
if let ty::Opaque(def_id, substs) = t.kind {
763-
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
764-
} else if t.has_projections() {
765-
t.super_fold_with(self)
766-
} else {
767-
t
768-
}
769-
}
770-
}
771-
772723
let mut visitor = OpaqueTypeExpander {
773724
seen_opaque_tys: FxHashSet::default(),
774725
expanded_cache: FxHashMap::default(),
775-
primary_def_id: def_id,
726+
primary_def_id: Some(def_id),
776727
found_recursion: false,
728+
check_recursion: true,
777729
tcx: self,
778730
};
779731
let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap();
@@ -785,6 +737,77 @@ impl<'tcx> TyCtxt<'tcx> {
785737
}
786738
}
787739

740+
/// Expands any nested opaque types, caching the expansion
741+
/// of each (DefId, SubstsRef) pair
742+
struct OpaqueTypeExpander<'tcx> {
743+
/// Contains the `DefId`s of the opaque types that are currently being
744+
/// expanded. When we expand an opaque type we insert the `DefId` of
745+
/// that type, and when we finish expanding that type we remove the
746+
/// its `DefId`.
747+
seen_opaque_tys: FxHashSet<DefId>,
748+
/// Cache of all expansions we've seen so far. This is a critical
749+
/// optimization for some large types produced by `async fn` trees.
750+
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
751+
primary_def_id: Option<DefId>,
752+
found_recursion: bool,
753+
/// Whether or not to check for recursive opaque types.
754+
/// This is `true` when we're explicitly checking for opaque type
755+
/// recursion, and 'false' otherwise to avoid unecessary work.
756+
check_recursion: bool,
757+
tcx: TyCtxt<'tcx>,
758+
}
759+
760+
impl<'tcx> OpaqueTypeExpander<'tcx> {
761+
fn expand_opaque_ty(
762+
&mut self,
763+
def_id: DefId,
764+
substs: SubstsRef<'tcx>,
765+
) -> Option<Ty<'tcx>> {
766+
if self.found_recursion {
767+
return None;
768+
}
769+
let substs = substs.fold_with(self);
770+
if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
771+
let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
772+
Some(expanded_ty) => expanded_ty,
773+
None => {
774+
let generic_ty = self.tcx.type_of(def_id);
775+
let concrete_ty = generic_ty.subst(self.tcx, substs);
776+
let expanded_ty = self.fold_ty(concrete_ty);
777+
self.expanded_cache.insert((def_id, substs), expanded_ty);
778+
expanded_ty
779+
}
780+
};
781+
if self.check_recursion {
782+
self.seen_opaque_tys.remove(&def_id);
783+
}
784+
Some(expanded_ty)
785+
} else {
786+
// If another opaque type that we contain is recursive, then it
787+
// will report the error, so we don't have to.
788+
self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
789+
None
790+
}
791+
}
792+
}
793+
794+
impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
795+
fn tcx(&self) -> TyCtxt<'tcx> {
796+
self.tcx
797+
}
798+
799+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
800+
if let ty::Opaque(def_id, substs) = t.kind {
801+
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
802+
} else if t.has_projections() {
803+
t.super_fold_with(self)
804+
} else {
805+
t
806+
}
807+
}
808+
}
809+
810+
788811
impl<'tcx> ty::TyS<'tcx> {
789812
/// Checks whether values of this type `T` are *moved* or *copied*
790813
/// when referenced -- this amounts to a check for whether `T:

src/librustc_codegen_utils/symbol_names/v0.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
264264
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
265265

266266
let mut param_env = self.tcx.param_env(impl_def_id)
267-
.with_reveal_all();
267+
.with_reveal_all_normalized(self.tcx);
268268
if !substs.is_empty() {
269269
param_env = param_env.subst(self.tcx, substs);
270270
}

src/librustc_mir/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ fn build_drop_shim<'tcx>(
221221
});
222222
}
223223
let patch = {
224-
let param_env = tcx.param_env(def_id).with_reveal_all();
224+
let param_env = tcx.param_env(def_id).with_reveal_all_normalized(tcx);
225225
let mut elaborator = DropShimElaborator {
226226
body: &body,
227227
patch: MirPatch::new(&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(src.def_id()).with_reveal_all_normalized(tcx);
2929
let move_data = match MoveData::gather_moves(body, tcx) {
3030
Ok(move_data) => move_data,
3131
Err(_) => bug!("No `move_errors` should be allowed in MIR borrowck"),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// run-pass
2+
3+
// Regression test for issue #65918 - checks that we do not
4+
// ICE when attempting to normalize a predicate containting
5+
// opaque types
6+
7+
#![feature(type_alias_impl_trait)]
8+
9+
use std::marker::PhantomData;
10+
11+
/* copied Index and TryFrom for convinience (and simplicity) */
12+
trait MyIndex<T> {
13+
type O;
14+
fn my_index(self) -> Self::O;
15+
}
16+
trait MyFrom<T>: Sized {
17+
type Error;
18+
fn my_from(value: T) -> Result<Self, Self::Error>;
19+
}
20+
21+
/* MCVE starts here */
22+
trait F {}
23+
impl F for () {}
24+
type DummyT<T> = impl F;
25+
fn _dummy_t<T>() -> DummyT<T> {}
26+
27+
struct Phantom1<T>(PhantomData<T>);
28+
struct Phantom2<T>(PhantomData<T>);
29+
struct Scope<T>(Phantom2<DummyT<T>>);
30+
31+
impl<T> Scope<T> {
32+
fn new() -> Self {
33+
Scope(Phantom2(PhantomData))
34+
}
35+
}
36+
37+
impl<T> MyFrom<Phantom2<T>> for Phantom1<T> {
38+
type Error = ();
39+
fn my_from(_: Phantom2<T>) -> Result<Self, Self::Error> {
40+
Ok(Phantom1(PhantomData))
41+
}
42+
}
43+
44+
impl<T: MyFrom<Phantom2<DummyT<U>>>, U> MyIndex<Phantom1<T>> for Scope<U> {
45+
type O = T;
46+
fn my_index(self) -> Self::O {
47+
MyFrom::my_from(self.0).ok().unwrap()
48+
}
49+
}
50+
51+
fn main() {
52+
let _pos: Phantom1<DummyT<()>> = Scope::new().my_index();
53+
}

0 commit comments

Comments
 (0)