Skip to content
Open
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
8 changes: 5 additions & 3 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::const_eval::CheckAlignment;
use crate::interpret::{
CtfeValidationMode, GlobalId, Immediate, InternError, InternKind, InterpCx, InterpErrorKind,
InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ReturnContinuation, create_static_alloc,
intern_const_alloc_recursive, interp_ok, throw_exhaust,
ensure_monomorphic_enough, intern_const_alloc_recursive, interp_ok, throw_exhaust,
};
use crate::{CTRL_C_RECEIVED, diagnostics};

Expand Down Expand Up @@ -96,8 +96,10 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
body: &'tcx mir::Body<'tcx>,
) -> InterpResult<'tcx, R> {
let tcx = *ecx.tcx;
let layout = ecx
.layout_of(body.bound_return_ty(tcx).instantiate(tcx, cid.instance.args).skip_norm_wip())?;
let ty = body.bound_return_ty(tcx).instantiate(tcx, cid.instance.args).skip_norm_wip();
ensure_monomorphic_enough(ty)?;

let layout = ecx.layout_of(ty)?;
let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;

trace!(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {

sym::field_offset => {
let frt_ty = instance.args.type_at(0);
ensure_monomorphic_enough(ecx.tcx.tcx, frt_ty)?;
ensure_monomorphic_enough(frt_ty)?;

let (ty, variant, field) = if let ty::Adt(def, args) = frt_ty.kind()
&& let Some(FieldInfo { base, variant_idx, field_idx, .. }) =
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _) => {
// All reifications must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
ensure_monomorphic_enough(src.layout.ty)?;

// The src operand does not matter, just its type
match *src.layout.ty.kind() {
Expand Down Expand Up @@ -112,7 +112,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _) => {
// All reifications must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
ensure_monomorphic_enough(src.layout.ty)?;

// The src operand does not matter, just its type
match *src.layout.ty.kind() {
Expand Down Expand Up @@ -445,8 +445,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
_ => {
// Do not ICE if we are not monomorphic enough.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
ensure_monomorphic_enough(*self.tcx, cast_ty)?;
ensure_monomorphic_enough(src.layout.ty)?;
ensure_monomorphic_enough(cast_ty)?;

span_bug!(
self.cur_span(),
Expand Down Expand Up @@ -502,8 +502,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
_ => {
// Do not ICE if we are not monomorphic enough.
ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
ensure_monomorphic_enough(*self.tcx, cast_ty.ty)?;
ensure_monomorphic_enough(src.layout.ty)?;
ensure_monomorphic_enough(cast_ty.ty)?;

span_bug!(
self.cur_span(),
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,22 +186,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
match intrinsic_name {
sym::type_name => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
ensure_monomorphic_enough(tp_ty)?;
let (alloc_id, meta) = alloc_type_name(tcx, tp_ty);
let val = ConstValue::Slice { alloc_id, meta };
let val = self.const_val_to_op(val, dest.layout.ty, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::needs_drop => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
ensure_monomorphic_enough(tp_ty)?;
let val = ConstValue::from_bool(tp_ty.needs_drop(tcx, self.typing_env));
let val = self.const_val_to_op(val, tcx.types.bool, Some(dest.layout))?;
self.copy_op(&val, dest)?;
}
sym::type_id => {
let tp_ty = instance.args.type_at(0);
ensure_monomorphic_enough(tcx, tp_ty)?;
ensure_monomorphic_enough(tp_ty)?;
self.write_type_id(tp_ty, dest)?;
}
sym::type_id_eq => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (ty, dyn_ty) = self.tcx.erase_and_anonymize_regions((ty, dyn_ty));

// All vtables must be monomorphic, bail out otherwise.
ensure_monomorphic_enough(*self.tcx, ty)?;
ensure_monomorphic_enough(*self.tcx, dyn_ty)?;
ensure_monomorphic_enough(ty)?;
ensure_monomorphic_enough(dyn_ty)?;

let salt = M::get_global_alloc_salt(self, None);
let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/interpret/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>(
ty: Ty<'tcx>,
trait_ty: Ty<'tcx>,
) -> InterpResult<'tcx, (bool, &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>)> {
ensure_monomorphic_enough(ecx.tcx.tcx, ty)?;
ensure_monomorphic_enough(ecx.tcx.tcx, trait_ty)?;
ensure_monomorphic_enough(ty)?;
ensure_monomorphic_enough(trait_ty)?;

let ty::Dynamic(preds, _) = trait_ty.kind() else {
span_bug!(
Expand Down Expand Up @@ -50,7 +50,7 @@ pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>(
/// Checks whether a type contains generic parameters which must be instantiated.
///
/// In case it does, returns a `TooGeneric` const eval error.
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(_tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
pub(crate) fn ensure_monomorphic_enough<'tcx, T>(ty: T) -> InterpResult<'tcx>
where
T: TypeVisitable<TyCtxt<'tcx>>,
{
Expand Down
4 changes: 0 additions & 4 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use super::{
format_interp_error,
};
use crate::enter_trace_span;
use crate::interpret::ensure_monomorphic_enough;

// for the validation errors
#[rustfmt::skip]
Expand Down Expand Up @@ -1585,9 +1584,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx> {
trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty);

// We can't check validity if there are any generics left.
ensure_monomorphic_enough(*self.tcx, val.layout.ty)?;

@RalfJung RalfJung Jul 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% sure about removing this, but we don't have a test any more where it makes a difference so for how I'd prefer to avoid needless type traversals if we can. It anyway makes no sense to only check this once, we'd have to re-check every time we enter a struct as that can reveal new hidden generics (right?).

View changes since the review


// Run the visitor.
self.run_for_validation_mut(|ecx| {
let reset_padding = reset_provenance_and_padding && {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ impl<'tcx> Const<'tcx> {
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
tcx.const_eval_resolve(typing_env, uneval, span)
}
Const::Val(val, _) => Ok(val),
Const::Val(val, _ty) => Ok(val),
}
}

Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl<'tcx> ConstToPat<'tcx> {
// implemented as `type` consts (project-const-generics#76). At that point it'll
// become necessary to just use type system normalization for all const patterns
// but that's not yet possible.
let mut thir_pat = if alias_const.kind.is_type_const(self.tcx) {
let const_value = if alias_const.kind.is_type_const(self.tcx) {
let Ok(normalize) = self
.tcx
.try_normalize_erasing_regions(self.typing_env, Unnormalized::new_wip(self.c))
Expand All @@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> {
let err = self.tcx.dcx().create_err(CouldNotEvalConstPattern { span: self.span });
return self.mk_err(err, ty);
};
self.valtree_to_pat(value)
value
} else {
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
Expand Down Expand Up @@ -192,8 +192,10 @@ impl<'tcx> ConstToPat<'tcx> {
};

// Lower the valtree to a THIR pattern.
self.valtree_to_pat(ty::Value { ty, valtree })
ty::Value { ty, valtree }
};
debug_assert!(!const_value.ty.has_param());

@RalfJung RalfJung Jul 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems fairly clear that we want this property to hold here. However I have no idea how to ensure that it actually holds without checking it just above (which we currently don't do, but an earlier version of this PR did). OTOH at least our test suite also doesn't seem to have a counterexample to this...

View changes since the review

let mut thir_pat = self.valtree_to_pat(const_value);

if !thir_pat.references_error() {
// Always check for `PartialEq` if we had no other errors yet.
Expand Down
17 changes: 17 additions & 0 deletions tests/ui/pattern/generic-in-path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! Ensure we can deal with a pattern that depends on a generic in its path, but the
//! actual pattern value can be computed independent of the generic.
#[derive(PartialEq)]
pub struct Thing<const N: usize>;

impl<const N: usize> Thing<N> {
const A: Self = Thing;
}

fn broken<const N: usize>(x: Thing<N>) {
match x {
<Thing<N>>::A => {} //~ERROR: cannot depend on generic
_ => {}
}
}

fn main() {}
14 changes: 14 additions & 0 deletions tests/ui/pattern/generic-in-path.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error[E0158]: constant pattern cannot depend on generic parameters
--> $DIR/generic-in-path.rs:12:9
|
LL | impl<const N: usize> Thing<N> {
| -----------------------------
LL | const A: Self = Thing;
| ------------- constant defined here
...
LL | <Thing<N>>::A => {}
| ^^^^^^^^^^^^^ `const` depends on a generic parameter

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0158`.
Loading