Auto merge of #140553 - BoxyUwU:defer_type_system_ctfe, r=compiler-errors

Defer evaluating type system constants when they use infers or params

Split out of #137972, the parts necessary for associated const equality and min generic const args to make progress and have correct semantics around when CTFE is invoked. According to a [previous perf run](https://perf.rust-lang.org/compare.html?start=93257e2d20809d82d1bc0fcc1942480d1a66d7cd&end=01b4cbf0f47c3f782330db88fa5ba199bba1f8a2&stat=instructions:u) of adding the new `const_arg_kind` query we should expect minor regressions here.

I think this is acceptable as we should be able to remove this query relatively soon once mgca is more complete as we'll then be able to implement GCE in terms of mgca and rip out `GCEConst` at which point it's trivial to determine what kind of anon const we're dealing with (either it has generics and is a repeat expr hack, or it doesnt and is a normal anon const).

This should only affect unstable code as we handle repeat exprs specially and those are the only kinds of type system consts that are allowed to make use of generic parameters.

Fixes #133066
Fixes #133199
Fixes #136894
Fixes #137813

r? compiler-errors
This commit is contained in:
bors 2025-05-23 05:30:45 +00:00
commit 52bf0cf795
31 changed files with 552 additions and 195 deletions

View file

@ -88,6 +88,7 @@ pub(crate) fn provide(providers: &mut Providers) {
opaque_ty_origin,
rendered_precise_capturing_args,
const_param_default,
anon_const_kind,
..*providers
};
}
@ -1826,3 +1827,27 @@ fn const_param_default<'tcx>(
.lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args));
ty::EarlyBinder::bind(ct)
}
fn anon_const_kind<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ty::AnonConstKind {
let hir_id = tcx.local_def_id_to_hir_id(def);
let const_arg_id = tcx.parent_hir_id(hir_id);
match tcx.hir_node(const_arg_id) {
hir::Node::ConstArg(_) => {
if tcx.features().generic_const_exprs() {
ty::AnonConstKind::GCE
} else if tcx.features().min_generic_const_args() {
ty::AnonConstKind::MCG
} else if let hir::Node::Expr(hir::Expr {
kind: hir::ExprKind::Repeat(_, repeat_count),
..
}) = tcx.hir_node(tcx.parent_hir_id(const_arg_id))
&& repeat_count.hir_id == const_arg_id
{
ty::AnonConstKind::RepeatExprCount
} else {
ty::AnonConstKind::MCG
}
}
_ => ty::AnonConstKind::NonTypeSystem,
}
}

View file

@ -104,19 +104,27 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
}
if in_param_ty {
// We do not allow generic parameters in anon consts if we are inside
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.features().generic_const_exprs() {
let parent_node = tcx.parent_hir_node(hir_id);
debug!(?parent_node);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
&& constant.hir_id == hir_id
{
// enum variant discriminants are not allowed to use any kind of generics
None
} else if let Some(param_id) = tcx.hir_opt_const_param_default_param_def_id(hir_id)
match tcx.anon_const_kind(def_id) {
// Stable: anon consts are not able to use any generic parameters...
ty::AnonConstKind::MCG => None,
// we provide generics to repeat expr counts as a backwards compatibility hack. #76200
ty::AnonConstKind::RepeatExprCount => Some(parent_did),
// Even GCE anon const should not be allowed to use generic parameters as it would be
// trivially forward declared uses once desugared. E.g. `const N: [u8; ANON::<N>]`.
//
// We could potentially mirror the hack done for defaults of generic parameters but
// this case just doesn't come up much compared to `const N: u32 = ...`. Long term the
// hack for defaulted parameters should be removed eventually anyway.
ty::AnonConstKind::GCE if in_param_ty => None,
// GCE anon consts as a default for a generic parameter should have their provided generics
// "truncated" up to whatever generic parameter this anon const is within the default of.
//
// FIXME(generic_const_exprs): This only handles `const N: usize = /*defid*/` but not type
// parameter defaults, e.g. `T = Foo</*defid*/>`.
ty::AnonConstKind::GCE
if let Some(param_id) =
tcx.hir_opt_const_param_default_param_def_id(hir_id) =>
{
// If the def_id we are calling generics_of on is an anon ct default i.e:
//
@ -160,36 +168,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions,
};
} else {
// HACK(eddyb) this provides the correct generics when
// `feature(generic_const_expressions)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
// `min_const_generics`.
}
ty::AnonConstKind::GCE => Some(parent_did),
// Field defaults are allowed to use generic parameters, e.g. `field: u32 = /*defid: N + 1*/`
ty::AnonConstKind::NonTypeSystem
if matches!(tcx.parent_hir_node(hir_id), Node::TyPat(_) | Node::Field(_)) =>
{
Some(parent_did)
}
} else {
let parent_node = tcx.parent_hir_node(hir_id);
let parent_node = match parent_node {
Node::ConstArg(ca) => tcx.parent_hir_node(ca.hir_id),
_ => parent_node,
};
match parent_node {
// HACK(eddyb) this provides the correct generics for repeat
// expressions' count (i.e. `N` in `[x; N]`), and explicit
// `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
// as they shouldn't be able to cause query cycle errors.
Node::Expr(Expr { kind: ExprKind::Repeat(_, ct), .. })
if ct.anon_const_hir_id() == Some(hir_id) =>
{
Some(parent_did)
}
Node::TyPat(_) => Some(parent_did),
// Field default values inherit the ADT's generics.
Node::Field(_) => Some(parent_did),
_ => None,
}
// Default to no generic parameters for other kinds of anon consts
ty::AnonConstKind::NonTypeSystem => None,
}
}
Node::ConstBlock(_)

View file

@ -425,6 +425,7 @@ provide! { tcx, def_id, other, cdata,
doc_link_traits_in_scope => {
tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(def_id.index))
}
anon_const_kind => { table }
}
pub(in crate::rmeta) fn provide(providers: &mut Providers) {

View file

@ -1569,6 +1569,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
<- tcx.explicit_implied_const_bounds(def_id).skip_binder());
}
}
if let DefKind::AnonConst = def_kind {
record!(self.tables.anon_const_kind[def_id] <- self.tcx.anon_const_kind(def_id));
}
if tcx.impl_method_has_trait_impl_trait_tys(def_id)
&& let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
{

View file

@ -480,6 +480,7 @@ define_tables! {
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
assumed_wf_types_for_rpitit: Table<DefIndex, LazyArray<(Ty<'static>, Span)>>,
opaque_ty_origin: Table<DefIndex, LazyValue<hir::OpaqueTyOrigin<DefId>>>,
anon_const_kind: Table<DefIndex, LazyValue<ty::AnonConstKind>>,
}
#[derive(TyEncodable, TyDecodable)]

View file

@ -316,6 +316,7 @@ trivial! {
rustc_middle::ty::Asyncness,
rustc_middle::ty::AsyncDestructor,
rustc_middle::ty::BoundVariableKind,
rustc_middle::ty::AnonConstKind,
rustc_middle::ty::DeducedParamAttrs,
rustc_middle::ty::Destructor,
rustc_middle::ty::fast_reject::SimplifiedType,

View file

@ -2592,6 +2592,11 @@ rustc_queries! {
desc { "estimating codegen size of `{}`", key }
cache_on_disk_if { true }
}
query anon_const_kind(def_id: DefId) -> ty::AnonConstKind {
desc { |tcx| "looking up anon const kind of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern
}
}
rustc_with_all_queries! { define_callbacks! }

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
use rustc_macros::HashStable;
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
@ -259,3 +259,16 @@ impl<'tcx> Const<'tcx> {
TypeWalker::new(self.into())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum AnonConstKind {
/// `feature(generic_const_exprs)` anon consts are allowed to use arbitrary generic parameters in scope
GCE,
/// stable `min_const_generics` anon consts are not allowed to use any generic parameters
MCG,
/// anon consts used as the length of a repeat expr are syntactically allowed to use generic parameters
/// but must not depend on the actual instantiation. See #76200 for more information
RepeatExprCount,
/// anon consts outside of the type system, e.g. enum discriminants
NonTypeSystem,
}

View file

@ -74,8 +74,8 @@ pub use self::closure::{
place_to_string_for_capture,
};
pub use self::consts::{
Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, ValTreeKind,
Value,
AnonConstKind, Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst,
ValTree, ValTreeKind, Value,
};
pub use self::context::{
CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt,

View file

@ -68,6 +68,7 @@ trivially_parameterized_over_tcx! {
ty::AsyncDestructor,
ty::AssocItemContainer,
ty::Asyncness,
ty::AnonConstKind,
ty::DeducedParamAttrs,
ty::Destructor,
ty::Generics,

View file

@ -540,10 +540,13 @@ pub fn try_evaluate_const<'tcx>(
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Expr(_) => Err(EvaluateConstErr::HasGenericsOrInfers),
ty::ConstKind::Unevaluated(uv) => {
let opt_anon_const_kind =
(tcx.def_kind(uv.def) == DefKind::AnonConst).then(|| tcx.anon_const_kind(uv.def));
// Postpone evaluation of constants that depend on generic parameters or
// inference variables.
//
// We use `TypingMode::PostAnalysis` here which is not *technically* correct
// We use `TypingMode::PostAnalysis` here which is not *technically* correct
// to be revealing opaque types here as borrowcheck has not run yet. However,
// CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
// typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
@ -551,65 +554,95 @@ pub fn try_evaluate_const<'tcx>(
//
// FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
// instead of having this logic here
let (args, typing_env) = if tcx.features().generic_const_exprs()
&& uv.has_non_region_infer()
{
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
match tcx.thir_abstract_const(uv.def) {
Ok(Some(ct)) => {
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
if let Err(e) = ct.error_reported() {
return Err(EvaluateConstErr::EvaluationFailure(e));
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
// If the anon const *does* actually use generic parameters or inference variables from
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
return Err(EvaluateConstErr::HasGenericsOrInfers);
} else {
let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args);
let typing_env = infcx
.typing_env(tcx.erase_regions(param_env))
.with_post_analysis_normalized(tcx);
(args, typing_env)
let (args, typing_env) = match opt_anon_const_kind {
// We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
// completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
// about if you have to consider gce whatsoever.
Some(ty::AnonConstKind::GCE) => {
if uv.has_non_region_infer() || uv.has_non_region_param() {
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
match tcx.thir_abstract_const(uv.def) {
Ok(Some(ct)) => {
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
if let Err(e) = ct.error_reported() {
return Err(EvaluateConstErr::EvaluationFailure(e));
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
// If the anon const *does* actually use generic parameters or inference variables from
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
return Err(EvaluateConstErr::HasGenericsOrInfers);
} else {
let args =
replace_param_and_infer_args_with_placeholder(tcx, uv.args);
let typing_env = infcx
.typing_env(tcx.erase_regions(param_env))
.with_post_analysis_normalized(tcx);
(args, typing_env)
}
}
Err(_) | Ok(None) => {
let args = GenericArgs::identity_for_item(tcx, uv.def);
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
(args, typing_env)
}
}
}
Err(_) | Ok(None) => {
let args = GenericArgs::identity_for_item(tcx, uv.def);
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
(args, typing_env)
} else {
let typing_env = infcx
.typing_env(tcx.erase_regions(param_env))
.with_post_analysis_normalized(tcx);
(uv.args, typing_env)
}
}
} else if tcx.def_kind(uv.def) == DefKind::AnonConst && uv.has_non_region_infer() {
// FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
//
// Diagnostics will sometimes replace the identity args of anon consts in
// array repeat expr counts with inference variables so we have to handle this
// even though it is not something we should ever actually encounter.
//
// Array repeat expr counts are allowed to syntactically use generic parameters
// but must not actually depend on them in order to evalaute successfully. This means
// that it is actually fine to evalaute them in their own environment rather than with
// the actually provided generic arguments.
tcx.dcx().delayed_bug(
"Encountered anon const with inference variable args but no error reported",
);
Some(ty::AnonConstKind::RepeatExprCount) => {
if uv.has_non_region_infer() {
// Diagnostics will sometimes replace the identity args of anon consts in
// array repeat expr counts with inference variables so we have to handle this
// even though it is not something we should ever actually encounter.
//
// Array repeat expr counts are allowed to syntactically use generic parameters
// but must not actually depend on them in order to evalaute successfully. This means
// that it is actually fine to evalaute them in their own environment rather than with
// the actually provided generic arguments.
tcx.dcx().delayed_bug("AnonConst with infer args but no error reported");
}
let args = GenericArgs::identity_for_item(tcx, uv.def);
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
(args, typing_env)
} else {
// FIXME: This codepath is reachable under `associated_const_equality` and in the
// future will be reachable by `min_generic_const_args`. We should handle inference
// variables and generic parameters properly instead of doing nothing.
let typing_env = infcx
.typing_env(tcx.erase_regions(param_env))
.with_post_analysis_normalized(tcx);
(uv.args, typing_env)
// The generic args of repeat expr counts under `min_const_generics` are not supposed to
// affect evaluation of the constant as this would make it a "truly" generic const arg.
// To prevent this we discard all the generic arguments and evalaute with identity args
// and in its own environment instead of the current environment we are normalizing in.
let args = GenericArgs::identity_for_item(tcx, uv.def);
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
(args, typing_env)
}
_ => {
// We are only dealing with "truly" generic/uninferred constants here:
// - GCEConsts have been handled separately
// - Repeat expr count back compat consts have also been handled separately
// So we are free to simply defer evaluation here.
//
// FIXME: This assumes that `args` are normalized which is not necessarily true
//
// Const patterns are converted to type system constants before being
// evaluated. However, we don't care about them here as pattern evaluation
// logic does not go through type system normalization. If it did this would
// be a backwards compatibility problem as we do not enforce "syntactic" non-
// usage of generic parameters like we do here.
if uv.args.has_non_region_param() || uv.args.has_non_region_infer() {
return Err(EvaluateConstErr::HasGenericsOrInfers);
}
let typing_env = infcx
.typing_env(tcx.erase_regions(param_env))
.with_post_analysis_normalized(tcx);
(uv.args, typing_env)
}
};
let uv = ty::UnevaluatedConst::new(uv.def, args);
let uv = ty::UnevaluatedConst::new(uv.def, args);
let erased_uv = tcx.erase_regions(uv);
use rustc_middle::mir::interpret::ErrorHandled;
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
Ok(Ok(val)) => Ok(ty::Const::new_value(

View file

@ -1,11 +0,0 @@
//@ known-bug: #133199
//@ aux-build: aux133199.rs
extern crate aux133199;
use aux133199::FixedBitSet;
fn main() {
FixedBitSet::<7>::new();
//~^ ERROR
}

View file

@ -1,8 +0,0 @@
//@ known-bug: #136894
#![feature(generic_const_exprs)]
#![crate_type = "lib"]
#![allow(incomplete_features, dead_code)]
struct X<T>([(); f::<T>()]) where [(); f::<T>()]:;
const fn f<T>() -> usize { panic!() }

View file

@ -1,18 +0,0 @@
//@ known-bug: #137813
trait AssocConst {
const A: u8;
}
impl<T> AssocConst for (T,) {
const A: u8 = 0;
}
trait Trait {}
impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
fn foo()
where
(): Trait,
{
}

View file

@ -0,0 +1,24 @@
#![feature(generic_arg_infer, associated_const_equality, generic_const_items)]
#![expect(incomplete_features)]
// Regression test for #133066 where we would try to evaluate `<() as Foo>::ASSOC<_>` even
// though it contained inference variables, which would cause ICEs.
trait Foo {
const ASSOC<const N: u32>: u32;
}
impl Foo for () {
const ASSOC<const N: u32>: u32 = N;
}
fn bar<const N: u32, T: Foo<ASSOC<N> = 10>>() {}
fn main() {
bar::<_, ()>();
//~^ ERROR: type mismatch resolving `<() as Foo>::ASSOC<_> == 10`
// FIXME(mgca):
// FIXME(associated_const_equality):
// This ought to start compiling once const items are aliases rather than bodies
}

View file

@ -0,0 +1,17 @@
error[E0271]: type mismatch resolving `<() as Foo>::ASSOC<_> == 10`
--> $DIR/equality_bound_with_infer.rs:18:14
|
LL | bar::<_, ()>();
| ^^ expected `10`, found `<() as Foo>::ASSOC::<_>`
|
= note: expected constant `10`
found constant `<() as Foo>::ASSOC::<_>`
note: required by a bound in `bar`
--> $DIR/equality_bound_with_infer.rs:15:29
|
LL | fn bar<const N: u32, T: Foo<ASSOC<N> = 10>>() {}
| ^^^^^^^^^^^^^ required by this bound in `bar`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0271`.

View file

@ -0,0 +1,26 @@
// regression test for #137813 where we would assume all constants in the type system
// cannot contain inference variables, even though associated const equality syntax
// was still lowered without the feature gate enabled.
trait AssocConst {
const A: u8;
}
impl<T> AssocConst for (T,) {
const A: u8 = 0;
}
trait Trait {}
impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
//~^ ERROR associated const equality is incomplete
//~| ERROR the type parameter `U` is not constrained by the impl trait
fn foo()
where
(): Trait,
//~^ ERROR type mismatch resolving
{
}
fn main() {}

View file

@ -0,0 +1,39 @@
error[E0658]: associated const equality is incomplete
--> $DIR/unconstrained_impl_param.rs:15:45
|
LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
| ^^^^^^^^^
|
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained_impl_param.rs:15:6
|
LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
| ^ unconstrained type parameter
error[E0271]: type mismatch resolving `<(_,) as AssocConst>::A == 0`
--> $DIR/unconstrained_impl_param.rs:21:5
|
LL | (): Trait,
| ^^^^^^^^^ expected `0`, found `<(_,) as AssocConst>::A`
|
= note: expected constant `0`
found constant `<(_,) as AssocConst>::A`
note: required for `()` to implement `Trait`
--> $DIR/unconstrained_impl_param.rs:15:9
|
LL | impl<U> Trait for () where (U,): AssocConst<A = { 0 }> {}
| ^^^^^ ^^ --------- unsatisfied trait bound introduced here
= help: see issue #48214
help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
|
LL + #![feature(trivial_bounds)]
|
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0207, E0271, E0658.
For more information about an error, try `rustc --explain E0207`.

View file

@ -1,9 +1,9 @@
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
pub struct FixedBitSet<const N: usize>;
pub struct Foo<const N: usize>;
impl<const N: usize> FixedBitSet<N>
impl<const N: usize> Foo<N>
where
[u8; N.div_ceil(8)]: Sized,
{

View file

@ -0,0 +1,10 @@
//@ check-pass
//@ aux-build: cross-crate-2.rs
extern crate cross_crate_2;
use cross_crate_2::Foo;
fn main() {
Foo::<7>::new();
}

View file

@ -1,5 +1,5 @@
error: generic parameters may not be used in const operations
--> $DIR/dependence_lint.rs:14:32
--> $DIR/dependence_lint.rs:15:32
|
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
| ^ cannot perform const operation using `T`
@ -8,7 +8,7 @@ LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
= help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
error: generic parameters may not be used in const operations
--> $DIR/dependence_lint.rs:21:37
--> $DIR/dependence_lint.rs:22:37
|
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
| ^ cannot perform const operation using `T`
@ -27,7 +27,7 @@ LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_
= note: `#[warn(const_evaluatable_unchecked)]` on by default
warning: cannot use constants which depend on generic parameters in types
--> $DIR/dependence_lint.rs:17:9
--> $DIR/dependence_lint.rs:18:9
|
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -9,8 +9,19 @@ help: try adding a `where` bound
LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
| ++++++++++++++++++++++++++++++++
error: unconstrained generic constant
--> $DIR/dependence_lint.rs:10:5
|
LL | [0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try adding a `where` bound
|
LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
| ++++++++++++++++++++++++++++++++
error: overly complex generic constant
--> $DIR/dependence_lint.rs:17:9
--> $DIR/dependence_lint.rs:18:9
|
LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error with gce
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
@ -18,7 +29,7 @@ LL | [0; if false { size_of::<T>() } else { 3 }]; // lint on stable, error w
= help: consider moving this anonymous constant into a `const` function
error: unconstrained generic constant
--> $DIR/dependence_lint.rs:14:12
--> $DIR/dependence_lint.rs:15:12
|
LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -29,12 +40,12 @@ LL | fn foo<T>() where [(); size_of::<*mut T>()]: {
| ++++++++++++++++++++++++++++++++
error: overly complex generic constant
--> $DIR/dependence_lint.rs:21:17
--> $DIR/dependence_lint.rs:22:17
|
LL | let _: [u8; if true { size_of::<T>() } else { 3 }]; // error on stable, error with gce
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants
|
= help: consider moving this anonymous constant into a `const` function
error: aborting due to 4 previous errors
error: aborting due to 5 previous errors

View file

@ -9,7 +9,8 @@ use std::mem::size_of;
fn foo<T>() {
[0; size_of::<*mut T>()]; // lint on stable, error with `generic_const_exprs`
//[gce]~^ ERROR unconstrained
//[full]~^^ WARNING cannot use constants
//[gce]~| ERROR unconstrained generic constant
//[full]~^^^ WARNING cannot use constants
//[full]~| WARNING this was previously accepted
let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce
//[full]~^ ERROR generic parameters may not be used

View file

@ -2,10 +2,10 @@ error[E0308]: mismatched types
--> $DIR/different-fn.rs:10:5
|
LL | [0; size_of::<Foo<T>>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `0`
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
|
= note: expected constant `size_of::<T>()`
found constant `0`
found constant `size_of::<Foo<T>>()`
error: unconstrained generic constant
--> $DIR/different-fn.rs:10:9

View file

@ -0,0 +1,16 @@
//@ check-pass
// regression test for #136894.
// I (BoxyUwU) don't know what the underlying cause was here
#![feature(generic_const_exprs)]
#![crate_type = "lib"]
#![allow(incomplete_features, dead_code)]
struct X<T>([(); f::<T>()])
where
[(); f::<T>()]:;
const fn f<T>() -> usize {
panic!()
}

View file

@ -25,7 +25,9 @@ impl<T: Copy> DataHolder<T> {
}
<IsCopy<T>>::VALUE
} as usize] = []; //~ ERROR unconstrained generic constant
} as usize] = [];
//~^ ERROR unconstrained generic constant
//~^^ ERROR mismatched types
}
fn main() {}

View file

@ -59,5 +59,49 @@ LL + <IsCopy<T>>::VALUE
LL ~ } as usize]: = [];
|
error: aborting due to 2 previous errors
error[E0308]: mismatched types
--> $DIR/issue-71202.rs:28:19
|
LL | } as usize] = [];
| ^^ expected `1 - {
trait NotCopy {
const VALUE: bool = false;
}
impl<__Type: ?Sized> NotCopy for __Type {}
struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
impl<__Type> IsCopy<__Type>
where
__Type: Sized + Copy,
{
const VALUE: bool = true;
}
<IsCopy<T>>::VALUE
} as usize`, found `0`
|
= note: expected constant `1 - {
trait NotCopy {
const VALUE: bool = false;
}
impl<__Type: ?Sized> NotCopy for __Type {}
struct IsCopy<__Type: ?Sized>(PhantomData<__Type>);
impl<__Type> IsCopy<__Type>
where
__Type: Sized + Copy,
{
const VALUE: bool = true;
}
<IsCopy<T>>::VALUE
} as usize`
found constant `0`
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -3,10 +3,6 @@
trait TensorDimension {
const DIM: usize;
//~^ ERROR cycle detected when resolving instance
//~| ERROR cycle detected when resolving instance
// FIXME Given the current state of the compiler its expected that we cycle here,
// but the cycle is still wrong.
const ISSCALAR: bool = Self::DIM == 0;
fn is_scalar(&self) -> bool {
Self::ISSCALAR
@ -49,6 +45,7 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorDimension for LazyUpdim<'a, T
impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T::DIM }, DIM> {
fn size(&self) -> [usize; DIM] {
//~^ ERROR: method not compatible with trait
self.size
}
}
@ -56,12 +53,17 @@ impl<'a, T: Broadcastable, const DIM: usize> TensorSize for LazyUpdim<'a, T, { T
impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> {
type Element = T::Element;
fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
//~^ ERROR: method not compatible with trait
assert!(DIM >= T::DIM);
if !self.inbounds(index) {
//~^ ERROR: unconstrained generic constant
//~| ERROR: mismatched types
return None;
}
let size = self.size();
//~^ ERROR: unconstrained generic constant
let newindex: [usize; T::DIM] = Default::default();
//~^ ERROR: the trait bound
self.reference.bget(newindex)
}
}
@ -82,6 +84,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> TensorSi
fn size(&self) -> [usize; DIM] {
//~^ ERROR: method not compatible with trait
self.reference.size()
//~^ ERROR: unconstrained generic constant
//~| ERROR: mismatched types
}
}
@ -92,6 +96,8 @@ impl<'a, R, T: Broadcastable, F: Fn(T::Element) -> R, const DIM: usize> Broadcas
fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
//~^ ERROR: method not compatible with trait
self.reference.bget(index).map(&self.closure)
//~^ ERROR: unconstrained generic constant
//~| ERROR: mismatched types
}
}
@ -100,12 +106,14 @@ impl<T> TensorDimension for Vec<T> {
}
impl<T> TensorSize for Vec<T> {
fn size(&self) -> [usize; 1] {
//~^ ERROR: method not compatible with trait
[self.len()]
}
}
impl<T: Clone> Broadcastable for Vec<T> {
type Element = T;
fn bget(&self, index: [usize; 1]) -> Option<T> {
//~^ ERROR: method not compatible with trait
self.get(index[0]).cloned()
}
}

View file

@ -1,43 +1,5 @@
error[E0391]: cycle detected when resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`
--> $DIR/issue-83765.rs:5:5
|
LL | const DIM: usize;
| ^^^^^^^^^^^^^^^^
|
note: ...which requires computing candidate for `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>`...
--> $DIR/issue-83765.rs:4:1
|
LL | trait TensorDimension {
| ^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle
note: cycle used when checking assoc item `<impl at $DIR/issue-83765.rs:50:1: 50:94>::size` is compatible with trait definition
--> $DIR/issue-83765.rs:51:5
|
LL | fn size(&self) -> [usize; DIM] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0391]: cycle detected when resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`
--> $DIR/issue-83765.rs:5:5
|
LL | const DIM: usize;
| ^^^^^^^^^^^^^^^^
|
note: ...which requires computing candidate for `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>`...
--> $DIR/issue-83765.rs:4:1
|
LL | trait TensorDimension {
| ^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle
note: cycle used when checking assoc item `<impl at $DIR/issue-83765.rs:56:1: 56:97>::bget` is compatible with trait definition
--> $DIR/issue-83765.rs:58:5
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:82:5
--> $DIR/issue-83765.rs:47:5
|
LL | fn size(&self) -> [usize; DIM] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
@ -46,7 +8,7 @@ LL | fn size(&self) -> [usize; DIM] {
found constant `DIM`
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:92:5
--> $DIR/issue-83765.rs:55:5
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
@ -54,7 +16,145 @@ LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
= note: expected constant `Self::DIM`
found constant `DIM`
error: aborting due to 4 previous errors
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:84:5
|
LL | fn size(&self) -> [usize; DIM] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected constant `Self::DIM`
found constant `DIM`
Some errors have detailed explanations: E0308, E0391.
For more information about an error, try `rustc --explain E0308`.
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:96:5
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected constant `Self::DIM`
found constant `DIM`
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:108:5
|
LL | fn size(&self) -> [usize; 1] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1`
|
= note: expected constant `Self::DIM`
found constant `1`
error[E0308]: method not compatible with trait
--> $DIR/issue-83765.rs:115:5
|
LL | fn bget(&self, index: [usize; 1]) -> Option<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Self::DIM`, found `1`
|
= note: expected constant `Self::DIM`
found constant `1`
error: unconstrained generic constant
--> $DIR/issue-83765.rs:58:13
|
LL | if !self.inbounds(index) {
| ^^^^
|
note: required by a bound in `TensorSize::inbounds`
--> $DIR/issue-83765.rs:14:39
|
LL | fn inbounds(&self, index: [usize; Self::DIM]) -> bool {
| ^^^^^^^^^ required by this bound in `TensorSize::inbounds`
help: try adding a `where` bound
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> where [(); Self::DIM]: {
| ++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-83765.rs:58:27
|
LL | if !self.inbounds(index) {
| ^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected constant `Self::DIM`
found constant `DIM`
error: unconstrained generic constant
--> $DIR/issue-83765.rs:63:25
|
LL | let size = self.size();
| ^^^^
|
note: required by a bound in `TensorSize::size`
--> $DIR/issue-83765.rs:13:31
|
LL | fn size(&self) -> [usize; Self::DIM];
| ^^^^^^^^^ required by this bound in `TensorSize::size`
help: try adding a `where` bound
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> where [(); Self::DIM]: {
| ++++++++++++++++++++++
error[E0277]: the trait bound `[usize; T::DIM]: Default` is not satisfied
--> $DIR/issue-83765.rs:65:41
|
LL | let newindex: [usize; T::DIM] = Default::default();
| ^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[usize; T::DIM]`
|
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> where [usize; T::DIM]: Default {
| ++++++++++++++++++++++++++++++
error: unconstrained generic constant
--> $DIR/issue-83765.rs:86:24
|
LL | self.reference.size()
| ^^^^
|
note: required by a bound in `TensorSize::size`
--> $DIR/issue-83765.rs:13:31
|
LL | fn size(&self) -> [usize; Self::DIM];
| ^^^^^^^^^ required by this bound in `TensorSize::size`
help: try adding a `where` bound
|
LL | fn size(&self) -> [usize; DIM] where [(); Self::DIM]: {
| ++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-83765.rs:86:9
|
LL | self.reference.size()
| ^^^^^^^^^^^^^^^^^^^^^ expected `DIM`, found `Self::DIM`
|
= note: expected constant `DIM`
found constant `Self::DIM`
error: unconstrained generic constant
--> $DIR/issue-83765.rs:98:9
|
LL | self.reference.bget(index).map(&self.closure)
| ^^^^^^^^^^^^^^
|
note: required by a bound in `Broadcastable::bget`
--> $DIR/issue-83765.rs:21:35
|
LL | fn bget(&self, index: [usize; Self::DIM]) -> Option<Self::Element>;
| ^^^^^^^^^ required by this bound in `Broadcastable::bget`
help: try adding a `where` bound
|
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> where [(); Self::DIM]: {
| ++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/issue-83765.rs:98:29
|
LL | self.reference.bget(index).map(&self.closure)
| ^^^^^ expected `Self::DIM`, found `DIM`
|
= note: expected constant `Self::DIM`
found constant `DIM`
error: aborting due to 14 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.

View file

@ -0,0 +1,19 @@
//@ check-pass
// Tests that const patterns that use generic parameters are
// allowed if we are still able to evaluate them.
trait Trait { const ASSOC: usize; }
impl<T> Trait for T {
const ASSOC: usize = 10;
}
fn foo<T>(a: usize) {
match a {
<T as Trait>::ASSOC => (),
_ => (),
}
}
fn main() {}

View file

@ -62,6 +62,11 @@ LL | / fn foo() -> Bar
LL | | where
LL | | Bar: Send,
| |______________^
note: ...which requires computing revealed normalized predicates of `foo::{constant#0}`...
--> $DIR/in-where-clause.rs:13:9
|
LL | [0; 1 + 2]
| ^^^^^
= note: ...which requires revealing opaque types in `[Binder { value: TraitPredicate(<Bar as core::marker::Send>, polarity:Positive), bound_vars: [] }]`...
note: ...which requires computing type of `Bar::{opaque#0}`...
--> $DIR/in-where-clause.rs:5:12