# const generics general stuff idk ## Where do const expressions appear / come from * Types * Array `[T; C]` -- anonymous constants * Type parameter `S<{C}>` * Predicates * `where T: Foo<C>` * Definitions * `const N: Ty = C;` * Expressions * `const { expr }` -- inline constant * "basically" equivalent to `{const N: Ty = expr; N}` * except that it can refer to generic parameters from the surrounding scope * `N` (path that refers to a constant) * `[Expr; C]` * `N::<{C}>` * Grammar question * C = N | Literal | '{' Expr '}' ## Generics * Extend the set of generics with a const kind ## Const values * Known value = * Integer literals * Allocation ==> ValTree eventually * note that there are constants that can't be represented with a valtree, those values can appear in the values of statics or constant expressions that don't wind up in types * Generic parameter `N` / Placeholder `!C` * Unevaluated `D<Substs...>` * currently, the `Substs` can be 'lazy' * used because we don't know the set of parameters to start * Inference variable `?C` ### Examples hir -> ty happens [here](https://github.com/rust-lang/rust/blob/41301c3b2371365b753c2ad6a74528a38f3815ce/compiler/rustc_middle/src/ty/consts.rs#L39-L70) * `Foo<22>` -- the 22 is a integer literal * `impl<const N: usize> { ... Foo<N> ... }` -- [`ConstKind::Param`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/kind/enum.ConstKind.html#variant.Param) * `impl<const N: usize> { ... Foo<{N}> ... }` -- [`ConstKind::Param`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/kind/enum.ConstKind.html#variant.Param) * `... Foo<_> ...` anywhere where types can be inferred -- [`ConstKind::Infer`] but has feature gate and lcnr doesn't like the way it is implemented * `const N: usize = 22; ... Foo<{N}> ...` -- [`ConstKind::Unevaluated`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/consts/kind/enum.ConstKind.html#variant.Unevaluated) with the def-id of the parameter (the `{N}` in `Foo<{N}>`) * `Foo< ... >` -- as above for all other cases ## Inference rules Unifying two constants: * Known, Known ==> "just do it" * InfVar, InfVar ==> "just do it" * InfVar, Uneval ==> Map InfVar to Uneval * Uneval, Known | Uneval, Uneval ==> * `ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),` * @lcnr note: this is currently too lazy, so we need to change something here (cc https://rust-lang.zulipchat.com/#narrow/stream/260443-project-const-generics/topic/lazy.20norm.20recursive.20impls/near/223825249) ## ConstEquate ``` ConstEquate(C1, C2)? := ConstEval(C1)? == ConstEval(C2)? ``` code in trait system ### Unclear how to extend to generic computations ## ConstEval ``` ConstEval(C)? ==> KnownValue ``` code in [rustc_middle::mir::interpret::queries](https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/mir/interpret/queries.rs) * Known => done * InfVar => error * Uneval(DefId, Substs) => * get the MIR for DefId * evaluate it with Substs in scope * if this encounters: * placeholder: ## Niko talking random things ```rust const fn double(n: usize) -> usize { n * 2 } const fn square(n: usize) -> usize { n * n } fn main() { let mut x = [22; double(2)]; x = [22; square(2)]; } ``` ```rust impl<const C: usize> { double(C) == C * 2 // this has add'l stability implications: // // not just the return value of double(C) but the body // as well } ``` ## Cycle problems ### Variance computation * We were evaluating constants to compute variance of a type * We didn't need to, fixed ### Anonymous constants can reference themselves in predicate ```rust fn foo<T, const C: usize>() where T: PartialEq<[u8; C + 1]> // ^^^^^ anonymous constant generics(foo) = [T, C] predicates(foo) = [T: PartialEq<[u8; AC_0]>] generics(AC_0) = [T, C] predicates(AC_0) = [T: PartialEq<[u8; AC_0]>] // <-- cycle ``` ### Using associated consts in where bounds https://github.com/rust-lang/rust/issues/79356#issuecomment-772179196 ```rust #![feature(generic_const_exprs)] trait Foo where [(); Self::N]: { const N: usize; } ``` ### False inference variable cycles ```rust #![feature(generic_const_exprs)] #![allow(incomplete_features)] fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] { todo!() } fn main() { let mut arr = Default::default(); arr = bind(arr); //~ ERROR mismatched type } // Current solution: // * // * include a subset of predicates ``` ## Evaluatable `ConstEvaluatable(Unevaluated<'tcx, ()>)` ## Match ## Structural equality https://github.com/rust-lang/lang-team/issues/94