Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unused generic parameters of anonymous constants #33

Open
lcnr opened this issue Mar 23, 2022 · 0 comments
Open

Unused generic parameters of anonymous constants #33

lcnr opened this issue Mar 23, 2022 · 0 comments
Labels
A-generic-exprs Generic const expressions A-unification Unifying constants in the type system C-design-docs Category: This is part of our design documentation K-impl Document Kind: regarding implementation P-necessary Priority: will be needed at some point S-active

Comments

@lcnr
Copy link
Contributor

lcnr commented Mar 23, 2022

What is this

This is a design document for const generics. Any discussions about its content should be on zulip. The conclusions of these discussions should then be edited back into this issue. Please do not post any comments directly in this issue.

Content

This is one of the core issues wrt generic constants in the type system.
With feature(generic_const_exprs) we would like foo::<{ N + 3 }> to be valid code.
The current implementation gives anonymous constants all of the generics and where clauses of the parent item:

fn bar<const N: usize, T: Trait>() {
    foo::<{ N + 1 }>();
}

is desugared to

fn bar<const N: usize, T: Trait>() {
    const ANON_CONST<const N: usize, T: Trait>: usize = N + 1;
    foo::<ANON_CONST::<N, T>>();
}

This causes a lot of issues.

Forcing all type parameters to be invariant

struct Foo<'a, T, const N: usize> {
    field: [u8; N + 1],
    by_ref: &'a T,
}

is desugared to

const ANON_CONST<'a, T, const N: usize>: usize = N + 1;
struct Foo<'a, T, const N: usize> {
    field: [u8; ANON_CONST::<'a, T, N>],
    by_ref: &'a T,
}

Generic arguments of anonymous constants are forced to be invariant. This
causes 'a and T be invariant even though they aren't actually used.

Unsize coercions (#78369)

struct P<T: ?Sized>([u8; 1 + 4], T);

fn main() {
    let x: Box<P<[u8; 0]>> = Box::new(P(Default::default(), [0; 0]));
    let _: Box<P<[u8]>> = x;
}

This compiles on stable but fails to compile if we provide T to the anonymous constant 1 + 4 as
we now cannot unsize T anymore.

Self referential closures (#85665)

fn foo<F: FnOnce([u8; N - 1]), const N: usize>(_: F) {}

fn main() {
    foo(|arg: [u8; 5]| ());
}

The anonymous constant N - 1 has F as a generic parameter. This means that the function signature of F contains
F itself, causing an error.

How this might get fixed

As this is one of the core issues of const generics, we thought about quite a few potential solutions to this issue.

Completely replacing ty::ConstKind::Unevaluated

By never representing anonymous constants as ty::ConstKind::Unevaluated and instead directly converting them into some abstract
representation, we can avoid these issues, for example:

fn foo<F: FnOnce([u8; N - 1]), const N: usize>(_: F) {}
// We could represent `N - 1` as `ty::ConstKind::Expr(ty::Expr::Sub(N, 1))`,
// meaning that we don't mention `F` at all.

This means we directly embed the fully expanded AbstractConst directly as a variant of ty::ConstKind.

  • this has to happen incredibly early, can't really use typeck to get the abstract representation, add some special "mini typeck" which
    directly converts hir into the ty::ConstKind::Expr representation.
    • what if that mini typeck disagrees with the "correct typeck"
    • do we still want to typeck anon consts or do we only use the "mini typeck"
    • the "mini typeck" will only allow a fairly arbitrary and small subset
      • the more we allow, the higher our maintenance
      • will be fairly untested, so there could be a lot of bugs and bad diagnostics here
      • though, even when not using the mini typeck, we still have to restrict expressions which can
        be used in generic anonymous constants
    • the "mini typeck" can't be used for concrete anonymous constants
      • constants which don't explicitly mention a generic param keep getting typechecked without any generics in scope.
@lcnr lcnr added C-design-docs Category: This is part of our design documentation K-impl Document Kind: regarding implementation P-necessary Priority: will be needed at some point S-active A-generic-exprs Generic const expressions A-unification Unifying constants in the type system labels Mar 23, 2022
@rust-lang rust-lang locked and limited conversation to collaborators Mar 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A-generic-exprs Generic const expressions A-unification Unifying constants in the type system C-design-docs Category: This is part of our design documentation K-impl Document Kind: regarding implementation P-necessary Priority: will be needed at some point S-active
Projects
None yet
Development

No branches or pull requests

1 participant