rust-lang/rust · critical
expected subslice projection on fixed-size array
Error message
expected subslice projection on fixed-size array
What it means
In `PlaceTy::projection_ty`, handling a `Subslice { from, to, from_end: true }` projection on a `ty::Array(inner, size)` calls `size.try_to_target_usize(tcx)` and `.expect`s `Some`. rustc_middle throws this when an from-end subslice is applied to an array whose length constant is not a monomorphic `Const` evaluating to a concrete usize (i.e. a generic/abstract array size).
Source
Thrown at compiler/rustc_middle/src/mir/statement.rs:235
}
let answer = match *elem {
ProjectionElem::Deref => {
let ty = structurally_normalize(self.ty).builtin_deref(true).unwrap_or_else(|| {
bug!("deref projection of non-dereferenceable ty {:?}", self)
});
PlaceTy::from_ty(ty)
}
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
PlaceTy::from_ty(structurally_normalize(self.ty).builtin_index().unwrap())
}
ProjectionElem::Subslice { from, to, from_end } => {
PlaceTy::from_ty(match structurally_normalize(self.ty).kind() {
ty::Slice(..) => self.ty,
ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
ty::Array(inner, size) if from_end => {
let size = size
.try_to_target_usize(tcx)
.expect("expected subslice projection on fixed-size array");
let len = size - from - to;
Ty::new_array(tcx, *inner, len)
}
_ => bug!("cannot subslice non-array type: `{:?}`", self),
})
}
ProjectionElem::Downcast(_name, index) => {
PlaceTy { ty: self.ty, variant_index: Some(index) }
}
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(
structurally_normalize(self.ty),
self.variant_index,
f,
fty,
)),
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.View on GitHub (pinned to 22057b88b0)
Solutions
- Move the subslicing operation out of the generic context into a monomorphic call site so `N` is concrete when the projection is evaluated.
- Use a `&[T]` slice (or `array::AsSlice`) instead of subslicing `[T; N]` directly so the projection goes through the `ty::Slice` arm which doesn't need a concrete length.
- If writing/testing mir-opt, ensure subslice projections are only emitted after monomorphization, or guard `from_end` array subslices behind a concrete-length check.
- Report a rustc bug with the generic-array subslice repro if it occurs in stock code (this is supposed to be handled by monomorphization before projection).
Example fix
// before: generic from-end array subslice
fn tail<T, const N: usize>(a: [T; N]) -> &[T] { &a[1..] }
// panic: expected subslice projection on fixed-size array (N is generic)
// after
fn tail<T, const N: usize>(a: [T; N]) -> &[T] { a[1..].as_ref() } Defensive patterns
Strategy: type-guard
Validate before calling
// ProjectionElem::Subslice { from_end: true } on an Array requires the
// array length to be a concrete target-usize. Pre-check before projecting.
use rustc_middle::mir::PlaceTy;
use rustc_middle::ty::{self, Ty, TyCtxt};
fn array_supports_from_end_subslice<'tcx>(pty: &PlaceTy<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
if let ty::Array(_, len) = pty.ty.kind() {
len.try_to_target_usize(tcx).is_some() // concrete length resolvable
} else {
false // not an array at all
}
}
// Usage:
// if array_supports_from_end_subslice(&pty, tcx) {
// pty.projection_ty(tcx, ProjectionElem::Subslice { from, to, from_end: true })
// } else {
// // array length is generic/unknown: lower differently or reject
// } Type guard
// Narrow a PlaceTy to 'Array with a statically-known length'.
use rustc_middle::mir::PlaceTy;
use rustc_middle::ty::{self, TyCtxt};
fn as_fixed_array<'tcx>(pty: &PlaceTy<'tcx>, tcx: TyCtxt<'tcx>) -> Option<(ty::Ty<'tcx>, u64)> {
match pty.ty.kind() {
ty::Array(inner, len) => len.try_to_target_usize(tcx).map(|n| (*inner, n)),
_ => None,
}
} Prevention
- A Subslice projection with `from_end: true` is only valid when the base is a fixed-size array whose length is a monomorphic const; never emit it for `[T]` slices or arrays with a generic length.
- When lowering source-level `x[a..]` / `x[..b]` patterns onto arrays whose length depends on a generic const, defer or reject the pattern instead of emitting a from_end subslice.
- In any MIR transformation that introduces Subslice, compute the array length first and fail soft (not panic) when it isn't a concrete usize.
- Keep slices and arrays distinct in your mental model: slices use `ty::Slice(..)` (no length needed); only arrays hit this expect().
When it happens
Trigger: Triggered by MIR containing `&arr[from .. arr.len() - to]` (from_end subslice) where `arr` has type `[T; N]` with `N` still generic or otherwise not a concrete `usize` at the point of projection (e.g. evaluating MIR before monomorphization filled in `N`).
Common situations: Const generics code subslicing `[T; N]` inside a generic fn before monomorphization; mir-opt pass that re-orders subslice evaluation; nightly mir-level evaluation of generic array code; user code that depends on slice patterns of generic arrays in const context.
Related errors
- invalid terminator state
- destructed mir constant of adt without variant idx
- projecting to field of non-ADT {ty}
- range should be nonempty
- there must be provenance somewhere here
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/5c7644a72f61a750.json.
Report an issue: GitHub.