Skip to content

Commit

Permalink
Normalize opaque types when converting ParamEnv to Reveal::All
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron1011 committed Jun 13, 2020
1 parent 7c78a5f commit b8c6a11
Show file tree
Hide file tree
Showing 16 changed files with 148 additions and 85 deletions.
2 changes: 1 addition & 1 deletion src/librustc_middle/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl<'tcx> TyCtxt<'tcx> {
let substs = InternalSubsts::identity_for_item(self, def_id);
let instance = ty::Instance::new(def_id, substs);
let cid = GlobalId { instance, promoted: None };
let param_env = self.param_env(def_id).with_reveal_all();
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
self.const_eval_global_id(param_env, cid, None)
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_middle/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'tcx> ConstValue<'tcx> {
param_env: ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Option<u128> {
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
self.try_to_bits(size)
}

Expand Down
12 changes: 11 additions & 1 deletion src/librustc_middle/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,11 +766,17 @@ rustc_queries! {
/// type-checking etc, and it does not normalize specializable
/// associated types. This is almost always what you want,
/// unless you are doing MIR optimizations, in which case you
/// might want to use `reveal_all()` method to change modes.
query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
}

/// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode.
/// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
/// as this method is more efficient.
query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
}

/// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
Expand Down Expand Up @@ -1398,5 +1404,9 @@ rustc_queries! {
) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
}

query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
desc { "normalizing opaque types in {:?}", key }
}
}
}
4 changes: 2 additions & 2 deletions src/librustc_middle/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1903,7 +1903,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 };
Expand All @@ -1927,7 +1927,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 };
Expand Down
15 changes: 12 additions & 3 deletions src/librustc_middle/ty/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
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::*;
Expand Down Expand Up @@ -1605,8 +1605,16 @@ 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(self) -> Self {
ty::ParamEnv { reveal: Reveal::All, ..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(self, tcx: TyCtxt<'tcx>) -> Self {
if self.reveal == Reveal::All {
return self;
}

let new_bounds = tcx.normalize_opaque_types(self.caller_bounds);
ty::ParamEnv { reveal: Reveal::All, caller_bounds: new_bounds, ..self }
}

/// Returns this same environment but with no caller bounds.
Expand Down Expand Up @@ -2859,6 +2867,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,
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_middle/ty/query/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,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;

Expand Down
12 changes: 8 additions & 4 deletions src/librustc_middle/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2330,7 +2330,7 @@ impl<'tcx> Const<'tcx> {
ty: Ty<'tcx>,
) -> Option<u128> {
assert_eq!(self.ty, ty);
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
// if `ty` does not depend on generic parameters, use an empty param_env
self.eval(tcx, param_env).val.try_to_bits(size)
}
Expand All @@ -2342,12 +2342,16 @@ impl<'tcx> Const<'tcx> {
if let ConstKind::Unevaluated(did, substs, promoted) = self.val {
use crate::mir::interpret::ErrorHandled;

let param_env_and_substs = param_env.with_reveal_all().and(substs);

// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
// also does later, but we want to do it before checking for
// inference variables.
let param_env_and_substs = tcx.erase_regions(&param_env_and_substs);
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
// so that we don't try to invoke this query with
// any region variables.
let param_env_and_substs = tcx
.erase_regions(&param_env)
.with_reveal_all_normalized(tcx)
.and(tcx.erase_regions(&substs));

// HACK(eddyb) when the query key would contain inference variables,
// attempt using identity substs and `ParamEnv` instead, that will succeed
Expand Down
156 changes: 90 additions & 66 deletions src/librustc_middle/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1088,3 +1091,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 }
}
2 changes: 1 addition & 1 deletion src/librustc_mir/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
);
}
let patch = {
let param_env = tcx.param_env(def_id).with_reveal_all();
let param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut elaborator =
DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env };
let dropee = tcx.mk_place_deref(dropee_ptr);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
) -> ConstPropagator<'mir, 'tcx> {
let def_id = source.def_id();
let substs = &InternalSubsts::identity_for_item(tcx, def_id);
let param_env = tcx.param_env(def_id).with_reveal_all();
let param_env = tcx.param_env_reveal_all_normalized(def_id);

let span = tcx.def_span(def_id);
let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine::new(), ());
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/elaborate_drops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
debug!("elaborate_drops({:?} @ {:?})", src, body.span);

let def_id = src.def_id();
let param_env = tcx.param_env(src.def_id()).with_reveal_all();
let param_env = tcx.param_env_reveal_all_normalized(src.def_id());
let move_data = match MoveData::gather_moves(body, tcx, param_env) {
Ok(move_data) => move_data,
Err((move_data, _)) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl Inliner<'tcx> {

let mut callsites = VecDeque::new();

let param_env = self.tcx.param_env(self.source.def_id()).with_reveal_all();
let param_env = self.tcx.param_env_reveal_all_normalized(self.source.def_id());

// Only do inlining into fn bodies.
let id = self.tcx.hir().as_local_hir_id(self.source.def_id().expect_local());
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir_build/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {

// Use `Reveal::All` here because patterns are always monomorphic even if their function
// isn't.
let param_env_reveal_all = self.param_env.with_reveal_all();
let param_env_reveal_all = self.param_env.with_reveal_all_normalized(self.tcx);
let substs = self.tables.node_substs(id);
let instance = match ty::Instance::resolve(self.tcx, param_env_reveal_all, def_id, substs) {
Ok(Some(i)) => i,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_symbol_mangling/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
let key = self.tcx.def_key(impl_def_id);
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };

let mut param_env = self.tcx.param_env(impl_def_id).with_reveal_all();
let mut param_env = self.tcx.param_env_reveal_all_normalized(impl_def_id);
if !substs.is_empty() {
param_env = param_env.subst(self.tcx, substs);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn resolve_associated_item<'tcx>(
});

let substs = tcx.infer_ctxt().enter(|infcx| {
let param_env = param_env.with_reveal_all();
let param_env = param_env.with_reveal_all_normalized(tcx);
let substs = rcvr_substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
let substs = translate_substs(
&infcx,
Expand Down
Loading

0 comments on commit b8c6a11

Please sign in to comment.