Description
In order to make feature(generic_const_exprs)
not completely broken when used with feature(const_generics_defaults)
, #86580 was landed. From the description of the PR:
This PR doesn't handle the predicates of the const so
trait Foo<const N: usize> { const Assoc: usize; } pub struct Bar<const N: usize = { <()>::Assoc }> where (): Foo<N>;Resolves to
<() as Foo<N>>::Assoc
which can allow for using fwd declared params indirectly.trait Foo<const N: usize> {} struct Bar<const N: usize = { 2 + 3 }> where (): Foo<N>;This code also ICEs under this PR because instantiating the default's predicates causes an ICE as predicates_of contains predicates with fwd declared params
because of this these two features are still pretty incompatible with eachother. This issue tracks this as there have been a large volume of issues that are all about which makes looking through F-generic_const-exprs
issues harder than it needs to be.
It was previously attempted to fix this in #106847 but that was closed:
I don't feel super comfortable merging more hacks to make
generic_const_exprs
+const_generics_defaults
work in the presence of each other. #86580 alone was already rather hacky and I think this PR just makes it way too much to be reasonable. It's also unclear to me whether this is going to interfere with fixing some of the other issues we have with const generics and I don't want to make that any harder than necessary.
feature(generic_const_exprs)
is an incomplete feature (both literally and according to theincomplete_features
lint), having it in a broken state because we are not currently in a good position to properly fix this seems fine to me. Thanks for making the PR anyway but I expect this issue will stay open until we make a lot more progress ongeneric_const_exprs
😅
duplicate issues
When this is fixed the following should be revisited and checked to make sure everything works as intended:
Activity
C/#0
(Const { ty: (), val: Param(C/#0) }/0) out of range when substituting substs=[] #94846generic_const_exprs
& super trait #93182type parameter C/#1 (C/1) out of range when substituting, substs=[]
withgeneric_const_exprs
#105631generic_const_exprs
#106473substs
argument innominal_obligations
when const param defaults exist #106847peter-lyons-kehl commentedon Jan 17, 2023
Thank you for identifying this. And for any progress (hopefully).
Weeks of my proof-of-concept work on co-operative allocation in
library/alloc
depend on this. (I've referenced the old/duplicate of this issue in my commits; I'll reference this issue from new commits and rebase.)Minimizing this even more - even without any declared trait:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=971190f4162846600db09b2f4282f754
Update for ordinary Rust developers:
The above (ICE-triggering) example doesn't need feature
generic_const_exprs
- and without it, it does compile:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=73bf77d07827c62dfe19ac9486e22983
So, if you need expressions in
const
generic defaults, but not inwhere
bounds, there's a workaround:Do not use
generic_const_exprs
. If you do needgeneric_const_exprs
for other types, separate them into a separate crate, and make thatgeneric_const_exprs
-friendly crate consume/depend on the non-generic_const_exprs
crate.peter-lyons-kehl commentedon Feb 5, 2023
Hoping to help narrow this closer: This fails even if the
const
expression has no arithmetics, just type casting, and that type casting is in thestruct
's generic parameters' default value expression. The casting itself may not even be needed (in this example, castingusize
tousize
):Interestingly, if the
const
expression would normally require braces{...}
(for example, because of invoking a macro), this ICE is triggered before checking for missing braces:But, if there's no casting/transformation in the
const
generic param's default value (expression), then there's no ICE, and the checks for braces do get run:If the same value is NOT cast in the generic params' list from a default value (or if it has no default value), but it's cast when instantiating the generic type, it DOES compile:
However, if the
struct
's generic parameter list does have a default value BUT that expression does NOT involve casting/arithmetics (or any other transformations?), but the (generic param value) is cast in thewhere
bound itself instead, it DOES compile:The result type of the
const
generic parameter's default value (expression) is NOT checked (to be the same as thatconst
generic parameter's defined type) before the ICE happens:But, when there is no
where
bound, such an incorrectly typed of theconst
generic parameter's default value IS checked:peter-lyons-kehl commentedon Feb 5, 2023
What other combinations are worth checking (for someone not knowing deep
rustc
internals)? So that I can help this forward, please?1 remaining item
peter-lyons-kehl commentedon Feb 7, 2023
Still, while I'm narrowing this down from the "consumer's" point of view, and searching for workarounds, here are 2 examples.
#![feature(generic_const_exprs)]
itself. This code doesn't actually needgeneric_const_exprs
. But, if the feature is enabled, then this code has an ICE.unconstrained
#111419cannot convert ReFree to a region vid
#111433S/#1
(S/#1/1) out of range when instantiating, args=[A/#0] #121963