Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lazily reveal opaque types during ctfe in typeck #102657

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ const NOTE_ON_UNDEFINED_BEHAVIOR_ERROR: &str = "The rules on what exactly is und
repository if you believe it should not be considered undefined behavior.";

// Returns a pointer to where the result lives
#[instrument(level = "debug", skip(ecx, body), fields(?param_env=ecx.param_env()), ret)]
fn eval_body_using_ecx<'mir, 'tcx>(
ecx: &mut CompileTimeEvalContext<'mir, 'tcx>,
cid: GlobalId<'tcx>,
body: &'mir mir::Body<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
let tcx = *ecx.tcx;
assert!(
cid.promoted.is_some()
Expand Down Expand Up @@ -78,7 +78,6 @@ fn eval_body_using_ecx<'mir, 'tcx>(
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
// we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway

debug!("eval_body_using_ecx done: {:?}", *ret);
Ok(ret)
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ fn create_mplace_from_layout<'tcx>(
ty: Ty<'tcx>,
) -> MPlaceTy<'tcx> {
let tcx = ecx.tcx;
let param_env = ecx.param_env;
let param_env = ecx.param_env();
let layout = tcx.layout_of(param_env.and(ty)).unwrap();
debug!(?layout);

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

let instance = ty::Instance::resolve_for_fn_ptr(
*self.tcx,
self.param_env,
self.param_env(),
def_id,
substs,
)
Expand Down Expand Up @@ -301,14 +301,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx> {
// A<Struct> -> A<Trait> conversion
let (src_pointee_ty, dest_pointee_ty) =
self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env);
self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env());

match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
(&ty::Array(_, length), &ty::Slice(_)) => {
let ptr = self.read_scalar(src)?;
// u64 cast is from usize to u64, which is always good
let val =
Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env()), self);
self.write_immediate(val, dest)
}
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
Expand Down
39 changes: 28 additions & 11 deletions compiler/rustc_const_eval/src/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
pub tcx: TyCtxtAt<'tcx>,

/// Bounds in scope for polymorphic evaluations.
pub(crate) param_env: ty::ParamEnv<'tcx>,
///
/// This has to be mutable as we may only lazily reveal opaque types.
pub(crate) param_env: Cell<ty::ParamEnv<'tcx>>,

/// The virtual memory system.
pub memory: Memory<'mir, 'tcx, M>,
Expand Down Expand Up @@ -298,7 +300,7 @@ where
M: Machine<'mir, 'tcx>,
{
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
self.param_env.get()
}
}

Expand Down Expand Up @@ -405,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
InterpCx {
machine,
tcx: tcx.at(root_span),
param_env,
param_env: Cell::new(param_env),
memory: Memory::new(),
recursion_limit: tcx.recursion_limit(),
}
Expand All @@ -418,6 +420,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.stack().last().map_or(self.tcx.span, |f| f.current_span())
}

#[inline(always)]
pub fn param_env(&self) -> ParamEnv<'tcx> {
self.param_env.get()
}

#[inline(always)]
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
M::stack(self)
Expand Down Expand Up @@ -465,7 +472,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

#[inline]
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
ty.is_freeze(self.tcx, self.param_env)
ty.is_freeze(self.tcx, self.param_env())
}

pub fn reveal_opaque_types_in_value<T: TypeFoldable<'tcx>>(&self, value: T) -> T {
let (param_env, value) = self.tcx.reveal_opaque_types_in_value(self.param_env.get(), value);
self.param_env.set(param_env);
value
}

pub fn load_mir(
Expand Down Expand Up @@ -505,7 +518,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> Result<T, InterpError<'tcx>> {
frame
.instance
.try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
.try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env(), value)
.map(|value| {
let (param_env, value) =
self.tcx.reveal_opaque_types_in_value(self.param_env.get(), value);
self.param_env.set(param_env);
value
})
.map_err(|e| {
self.tcx.sess.delay_span_bug(
self.cur_span(),
Expand All @@ -517,15 +536,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}

/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
#[instrument(level = "trace", skip(self), fields(param_env = ?self.param_env), ret)]
pub(super) fn resolve(
&self,
def: ty::WithOptConstParam<DefId>,
substs: SubstsRef<'tcx>,
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def, substs);
trace!("param_env: {:#?}", self.param_env);
trace!("substs: {:#?}", substs);
match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) {
match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env(), def, substs) {
Ok(Some(instance)) => Ok(instance),
Ok(None) => throw_inval!(TooGeneric),

Expand All @@ -545,7 +562,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// have to support that case (mostly by skipping all caching).
match frame.locals.get(local).and_then(|state| state.layout.get()) {
None => {
let layout = from_known_layout(self.tcx, self.param_env, layout, || {
let layout = from_known_layout(self.tcx, self.param_env(), layout, || {
let local_ty = frame.body.local_decls[local].ty;
let local_ty =
self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?;
Expand Down Expand Up @@ -914,7 +931,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let param_env = if self.tcx.is_static(gid.instance.def_id()) {
ty::ParamEnv::reveal_all()
} else {
self.param_env
self.param_env()
};
let param_env = param_env.with_const();
// Use a precise span for better cycle errors.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
if let InternMode::Static(mutability) = mode {
// For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
// no interior mutability.
let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env));
let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env.get()));
// For statics, allocation mutability is the combination of place mutability and
// type mutability.
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
Expand Down Expand Up @@ -243,7 +243,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
assert_eq!(mplace.layout.ty, referenced_ty);
// Handle trait object vtables.
if let ty::Dynamic(..) =
tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind()
tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env()).kind()
{
let ptr = mplace.meta.unwrap_meta().to_pointer(&tcx)?;
if let Some(alloc_id) = ptr.provenance {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => bug!(),
};
let val =
self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
self.tcx.const_eval_global_id(self.param_env(), gid, Some(self.tcx.span))?;
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
self.copy_op(&val, dest, /*allow_transmute*/ false)?;
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
debug_assert!(
mir_assign_valid_types(
*self.tcx,
self.param_env,
self.param_env(),
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty
)?)?,
Expand Down Expand Up @@ -570,7 +570,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let cid = GlobalId { instance, promoted: None };
let _valtree = self
.tcx
.eval_to_valtree(self.param_env.and(cid))?
.eval_to_valtree(self.param_env().and(cid))?
.unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"));

Ok(self.eval_to_allocation(cid)?.into())
Expand Down Expand Up @@ -606,7 +606,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Scalar::Int(int) => Scalar::Int(int),
})
};
let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
let layout = from_known_layout(self.tcx, self.param_env(), layout, || self.layout_of(ty))?;
let op = match val_val {
ConstValue::ByRef { alloc, offset } => {
let id = self.tcx.create_memory_alloc(alloc);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ where
debug_assert!(
mir_assign_valid_types(
*self.tcx,
self.param_env,
self.param_env(),
self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty
)?)?,
Expand Down Expand Up @@ -626,7 +626,7 @@ where
// We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast.
let layout_compat =
mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout);
mir_assign_valid_types(*self.tcx, self.param_env(), src.layout, dest.layout);
if !allow_transmute && !layout_compat {
span_bug!(
self.cur_span(),
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx);
let fn_sig =
self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder);
self.tcx.normalize_erasing_late_bound_regions(self.param_env(), fn_sig_binder);
let extra_args = &args[fn_sig.inputs().len()..];
let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty));

Expand All @@ -86,6 +86,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::FnDef(def_id, substs) => {
let instance =
self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?;
let instance = self.reveal_opaque_types_in_value(instance);
(
FnVal::Instance(instance),
self.fn_abi_of_instance(instance, extra_args)?,
Expand Down Expand Up @@ -563,7 +564,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Obtain the underlying trait we are working on.
let receiver_tail = self
.tcx
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env());
let ty::Dynamic(data, ..) = receiver_tail.kind() else {
span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail)
};
Expand Down Expand Up @@ -599,7 +600,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

let concrete_method = Instance::resolve_for_vtable(
tcx,
self.param_env,
self.param_env(),
def_id,
instance.substs.rebase_onto(tcx, trait_def_id, concrete_trait_ref.substs),
)
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ where
T: TypeVisitable<'tcx>,
{
debug!("ensure_monomorphic_enough: ty={:?}", ty);
if !ty.needs_subst() {
if !(ty.needs_subst() || ty.has_opaque_types()) {
return Ok(());
}

Expand All @@ -31,7 +31,7 @@ where
}

match *ty.kind() {
ty::Param(_) => ControlFlow::Break(FoundParam),
ty::Param(_) | ty::Opaque(..) => ControlFlow::Break(FoundParam),
ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, ..)
| ty::FnDef(def_id, substs) => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
meta: MemPlaceMeta<M::Provenance>,
pointee: TyAndLayout<'tcx>,
) -> InterpResult<'tcx> {
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env());
match tail.kind() {
ty::Dynamic(..) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
Expand Down Expand Up @@ -726,7 +726,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
) -> InterpResult<'tcx> {
// Special check preventing `UnsafeCell` inside unions in the inner part of constants.
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) {
if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) {
if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env()) {
throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
}
}
Expand Down
Loading