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

Tracking Issue for inline const patterns (RFC 2920) #76001

Open
9 of 11 tasks
Tracked by #483
nikomatsakis opened this issue Aug 27, 2020 · 92 comments
Open
9 of 11 tasks
Tracked by #483

Tracking Issue for inline const patterns (RFC 2920) #76001

nikomatsakis opened this issue Aug 27, 2020 · 92 comments
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-inline_const_pat #![feature(inline_const_pat)] F-inline_const Inline constants (aka: const blocks, const expressions, anonymous constants) S-tracking-needs-summary Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Aug 27, 2020

This is a tracking issue for the RFC "Inline const expressions and patterns" (rust-lang/rfcs#2920).
Const expressions have been stabilized, but patterns have not
The feature gate for the issue is #![feature(inline_const_pat)].

This was originally a tracking issue for const blocks in both expression and pattern position. Inline const expressions have been stabilized in #104087 while patterns are still unstable.

About tracking issues

Tracking issues are used to record the overall progress of implementation.
They are also uses as hubs connecting to other relevant issues, e.g., bugs or open design questions.
A tracking issue is however not meant for large scale discussion, questions, or bug reports about a feature.
Instead, open a dedicated issue for the specific matter and add the relevant feature gate label.

Steps

Unresolved Questions

Implementation history

@nikomatsakis nikomatsakis added B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. T-lang Relevant to the language team, which will review and decide on the PR/issue. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) F-inline_const Inline constants (aka: const blocks, const expressions, anonymous constants) labels Aug 27, 2020
@jhpratt
Copy link
Member

jhpratt commented Aug 28, 2020

With regard to the lint, is there any semantic difference between the two? Intuitively I would expect them to behave identically (static lifetimes).

@RalfJung
Copy link
Member

They behave identically. The point of the lint is to have a single "idiomatic" form.

Naming: "inline const", "const block", or "anonymous const"?

The issue title calls it "const expressons" so maybe that should also be on the list.

I prefer "inline const" because it emphasizes that this is a totally separate body of code that is just written inline. That's much more like a closure than normal blocks.


Also, is anyone up for implementing this? (I can't even mentor this I am afraid, this affects surface-level syntax and MIR building which is way outside what I know.^^)

@Lokathor
Copy link
Contributor

"const block" is clearly correct.

it matches "unsafe block" that way.

@RalfJung
Copy link
Member

That false parallel with "unsafe block" is exactly why it is not correct. An unsafe block inherits scope, execution environment, everything from its parent block. An inline const does not.

@ecstatic-morse
Copy link
Contributor

ecstatic-morse commented Aug 29, 2020

I'm happy to mentor, although by no means am I an expert on all the parts of the compiler you'll need to touch. There's already an AnonConst type in the AST and the HIR that should for the most part have the same rules as an inline const (e.g. no outside generic parameters), which should make the lowering part of this pretty easy.

If no one volunteers in the next few weeks, I'll try to set aside a day or two to implement this. However, I'm mostly in maintenance/review mode as far as Rust is concerned.

@workingjubilee
Copy link
Member

Does const { } differ from normal block expressions, however?
I think either "inline const" or "const expression" should be favored. Everyone's going to call it a constexpr anyways because of C++ user bleedover, and I don't think it's worth offering that much pushback this time. :^)

Hm... I need to fix my computer still. Guess I have a good reason today.

@memoryruins
Copy link
Contributor

memoryruins commented Sep 1, 2020

Does const { } differ from normal block expressions, however?

const {} does not inherit the same scopes as block expressions do.

Everyone's going to call it a constexpr anyways because of C++

It can be a useful comparison when introducing C++ users to Rust's const and const fn, yet I have not seen most users conflate them. Additionally, C++ does not have constexpr { ... }.

I don't think it's worth offering that much pushback this time.

There are no mentions of constexpr or C++ on this issue before or the RFC. I find it unproductive to label it as pushback from that. The concerns about naming are mentioned in the RFC https://rust-lang.github.io/rfcs/2920-inline-const.html and the comments.

@workingjubilee

This comment has been minimized.

@memoryruins

This comment has been minimized.

@spastorino
Copy link
Member

@ecstatic-morse I'd like to take this issue if it's not taken yet.

@ecstatic-morse
Copy link
Contributor

Go for it @spastorino!

@spastorino
Copy link
Member

I forgot to link this issue from the PR but the PR is now merged #77124

@camelid
Copy link
Member

camelid commented Oct 22, 2020

I would like to write the documentation.

@spastorino
Copy link
Member

I would like to write the documentation.

@camelid please once you have something up cc me so I can review.

bors added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
Stabilise inline_const

# Stabilisation Report

## Summary

This PR will stabilise `inline_const` feature in expression position. `inline_const_pat` is still unstable and will *not* be stabilised.

The feature will allow code like this:
```rust
foo(const { 1 + 1 })
```
which is roughly desugared into
```rust
struct Foo;
impl Foo {
    const FOO: i32 = 1 + 1;
}
foo(Foo::FOO)
```

This feature is from rust-lang/rfcs#2920 and is tracked in rust-lang#76001 (the tracking issue should *not* be closed as it needs to track inline const in pattern position). The initial implementation is done in rust-lang#77124.

## Difference from RFC

There are two major differences (enhancements) as implemented from the RFC. First thing is that the RFC says that the type of an inline const block inferred from the content *within* it, but we currently can infer the type using the information from outside the const block as well. This is a frequently requested feature to the initial implementation (e.g. rust-lang#89964). The inference is implemented in rust-lang#89561 and is done by treating inline const similar to a closure and therefore share inference context with its parent body.

This allows code like:
```rust
let v: Vec<i32> = const { Vec::new() };
```

Another enhancement that differs from the RFC is that we currently allow inline consts to reference generic parameters. This is implemented in rust-lang#96557.

This allows code like:
```rust
fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
    [const { None::<T> }; N]
}
```

This enhancement also makes inline const usable as static asserts:

```rust
fn require_zst<T>() {
    const { assert!(std::mem::size_of::<T>() == 0) }
}
```

## Documentation

Reference: rust-lang/reference#1295

## Unresolved issues

We still have a few issues that are not resolved, but I don't think it necessarily has to block stabilisation:
* expr fragment specifier issue: rust-lang#86730
* ~~`const {}` behaves similar to `async {}` but not to `{}` and `unsafe {}` (they are treated as `ExpressionWithoutBlock` rather than `ExpressionWithBlock`): https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/const.20blocks.20differ.20from.20normal.20and.20from.20unsafe.20blocks/near/290229453~~

## Tests

There are a few tests in https://github.com/rust-lang/rust/tree/master/src/test/ui/inline-const
bors added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
Stabilise inline_const

# Stabilisation Report

## Summary

This PR will stabilise `inline_const` feature in expression position. `inline_const_pat` is still unstable and will *not* be stabilised.

The feature will allow code like this:
```rust
foo(const { 1 + 1 })
```
which is roughly desugared into
```rust
struct Foo;
impl Foo {
    const FOO: i32 = 1 + 1;
}
foo(Foo::FOO)
```

This feature is from rust-lang/rfcs#2920 and is tracked in rust-lang#76001 (the tracking issue should *not* be closed as it needs to track inline const in pattern position). The initial implementation is done in rust-lang#77124.

## Difference from RFC

There are two major differences (enhancements) as implemented from the RFC. First thing is that the RFC says that the type of an inline const block inferred from the content *within* it, but we currently can infer the type using the information from outside the const block as well. This is a frequently requested feature to the initial implementation (e.g. rust-lang#89964). The inference is implemented in rust-lang#89561 and is done by treating inline const similar to a closure and therefore share inference context with its parent body.

This allows code like:
```rust
let v: Vec<i32> = const { Vec::new() };
```

Another enhancement that differs from the RFC is that we currently allow inline consts to reference generic parameters. This is implemented in rust-lang#96557.

This allows code like:
```rust
fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
    [const { None::<T> }; N]
}
```

This enhancement also makes inline const usable as static asserts:

```rust
fn require_zst<T>() {
    const { assert!(std::mem::size_of::<T>() == 0) }
}
```

## Documentation

Reference: rust-lang/reference#1295

## Unresolved issues

We still have a few issues that are not resolved, but I don't think it necessarily has to block stabilisation:
* expr fragment specifier issue: rust-lang#86730
* ~~`const {}` behaves similar to `async {}` but not to `{}` and `unsafe {}` (they are treated as `ExpressionWithoutBlock` rather than `ExpressionWithBlock`): https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/const.20blocks.20differ.20from.20normal.20and.20from.20unsafe.20blocks/near/290229453~~

## Tests

There are a few tests in https://github.com/rust-lang/rust/tree/master/src/test/ui/inline-const
bors added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
Stabilise inline_const

# Stabilisation Report

## Summary

This PR will stabilise `inline_const` feature in expression position. `inline_const_pat` is still unstable and will *not* be stabilised.

The feature will allow code like this:
```rust
foo(const { 1 + 1 })
```
which is roughly desugared into
```rust
struct Foo;
impl Foo {
    const FOO: i32 = 1 + 1;
}
foo(Foo::FOO)
```

This feature is from rust-lang/rfcs#2920 and is tracked in rust-lang#76001 (the tracking issue should *not* be closed as it needs to track inline const in pattern position). The initial implementation is done in rust-lang#77124.

## Difference from RFC

There are two major differences (enhancements) as implemented from the RFC. First thing is that the RFC says that the type of an inline const block inferred from the content *within* it, but we currently can infer the type using the information from outside the const block as well. This is a frequently requested feature to the initial implementation (e.g. rust-lang#89964). The inference is implemented in rust-lang#89561 and is done by treating inline const similar to a closure and therefore share inference context with its parent body.

This allows code like:
```rust
let v: Vec<i32> = const { Vec::new() };
```

Another enhancement that differs from the RFC is that we currently allow inline consts to reference generic parameters. This is implemented in rust-lang#96557.

This allows code like:
```rust
fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
    [const { None::<T> }; N]
}
```

This enhancement also makes inline const usable as static asserts:

```rust
fn require_zst<T>() {
    const { assert!(std::mem::size_of::<T>() == 0) }
}
```

## Documentation

Reference: rust-lang/reference#1295

## Unresolved issues

We still have a few issues that are not resolved, but I don't think it necessarily has to block stabilisation:
* expr fragment specifier issue: rust-lang#86730
* ~~`const {}` behaves similar to `async {}` but not to `{}` and `unsafe {}` (they are treated as `ExpressionWithoutBlock` rather than `ExpressionWithBlock`): https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/const.20blocks.20differ.20from.20normal.20and.20from.20unsafe.20blocks/near/290229453~~

## Tests

There are a few tests in https://github.com/rust-lang/rust/tree/master/src/test/ui/inline-const
bors added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
Stabilise inline_const

# Stabilisation Report

## Summary

This PR will stabilise `inline_const` feature in expression position. `inline_const_pat` is still unstable and will *not* be stabilised.

The feature will allow code like this:
```rust
foo(const { 1 + 1 })
```
which is roughly desugared into
```rust
struct Foo;
impl Foo {
    const FOO: i32 = 1 + 1;
}
foo(Foo::FOO)
```

This feature is from rust-lang/rfcs#2920 and is tracked in rust-lang#76001 (the tracking issue should *not* be closed as it needs to track inline const in pattern position). The initial implementation is done in rust-lang#77124.

## Difference from RFC

There are two major differences (enhancements) as implemented from the RFC. First thing is that the RFC says that the type of an inline const block inferred from the content *within* it, but we currently can infer the type using the information from outside the const block as well. This is a frequently requested feature to the initial implementation (e.g. rust-lang#89964). The inference is implemented in rust-lang#89561 and is done by treating inline const similar to a closure and therefore share inference context with its parent body.

This allows code like:
```rust
let v: Vec<i32> = const { Vec::new() };
```

Another enhancement that differs from the RFC is that we currently allow inline consts to reference generic parameters. This is implemented in rust-lang#96557.

This allows code like:
```rust
fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
    [const { None::<T> }; N]
}
```

This enhancement also makes inline const usable as static asserts:

```rust
fn require_zst<T>() {
    const { assert!(std::mem::size_of::<T>() == 0) }
}
```

## Documentation

Reference: rust-lang/reference#1295

## Unresolved issues

We still have a few issues that are not resolved, but I don't think it necessarily has to block stabilisation:
* expr fragment specifier issue: rust-lang#86730
* ~~`const {}` behaves similar to `async {}` but not to `{}` and `unsafe {}` (they are treated as `ExpressionWithoutBlock` rather than `ExpressionWithBlock`): https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/const.20blocks.20differ.20from.20normal.20and.20from.20unsafe.20blocks/near/290229453~~

## Tests

There are a few tests in https://github.com/rust-lang/rust/tree/master/src/test/ui/inline-const
@tgross35
Copy link
Contributor

Can this be closed with #104087?

@jhpratt
Copy link
Member

jhpratt commented Apr 24, 2024

@tgross35 patterns are still unstable, so no.

@lcnr lcnr changed the title Tracking Issue for inline const expressions and patterns (RFC 2920) Tracking Issue for inline const patterns (RFC 2920) Apr 24, 2024
@RalfJung
Copy link
Member

RalfJung commented May 3, 2024

What are the remaining blockers and other TODO items for inline const patterns?

@lolbinarycat
Copy link
Contributor

one thing i thing this is helpful for: allowing use withing patterns. this is expecially useful in the context of macros that expand into patterns.

for example, if we want to match against a variant of a certain enum, is it possible to expand to const { use Enum::*; $v }?

compiler-errors added a commit to compiler-errors/rust that referenced this issue Jun 24, 2024
Remove `MaybeUninit::uninit_array()` and replace it with inline const blocks.

\[This PR originally contained the changes in rust-lang#125995 too. See edit history for the original PR description.]

The documentation of `MaybeUninit::uninit_array()` says:

> Note: in a future Rust version this method may become unnecessary when Rust allows [inline const expressions](rust-lang#76001). The example below could then use `let mut buf = [const { MaybeUninit::<u8>::uninit() }; 32];`.

The PR adding it also said: <rust-lang#65580 (comment)>

> if it’s stabilized soon enough maybe it’s not worth having a standard library method that will be replaceable with `let buffer = [MaybeUninit::<T>::uninit(); $N];`

That time has come to pass — inline const expressions are stable — so `MaybeUninit::uninit_array()` is now unnecessary. The only remaining question is whether it is an important enough *convenience* to keep it around.

I believe it is net good to remove this function, on the principle that it is better to compose two orthogonal features (`MaybeUninit` and array construction) than to have a specific function for the specific combination, now that that is possible.
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jun 24, 2024
Rollup merge of rust-lang#125082 - kpreid:const-uninit, r=dtolnay

Remove `MaybeUninit::uninit_array()` and replace it with inline const blocks.

\[This PR originally contained the changes in rust-lang#125995 too. See edit history for the original PR description.]

The documentation of `MaybeUninit::uninit_array()` says:

> Note: in a future Rust version this method may become unnecessary when Rust allows [inline const expressions](rust-lang#76001). The example below could then use `let mut buf = [const { MaybeUninit::<u8>::uninit() }; 32];`.

The PR adding it also said: <rust-lang#65580 (comment)>

> if it’s stabilized soon enough maybe it’s not worth having a standard library method that will be replaceable with `let buffer = [MaybeUninit::<T>::uninit(); $N];`

That time has come to pass — inline const expressions are stable — so `MaybeUninit::uninit_array()` is now unnecessary. The only remaining question is whether it is an important enough *convenience* to keep it around.

I believe it is net good to remove this function, on the principle that it is better to compose two orthogonal features (`MaybeUninit` and array construction) than to have a specific function for the specific combination, now that that is possible.
@herabit
Copy link

herabit commented Nov 15, 2024

I have no clue how this whole "contributing to a major open source project" thing works, however, I'm curious about the progress of this feature.

It would make pattern matching with the newtype pattern (namely newtypes that have some invariant that must be upheld)
so much easier.

An example would be the ascii crate. As of now the crate does not currently expose any functionality for creating ASCII strings
at compile time, though for simplicity this will be overlooked as this would be trivial to add.

But let's say you're working with some format that must only work with ASCII strings, so you pull in the ascii crate. With this feature you could trivially match on keywords with something like:

macro_rules! ascii {
     ($e:expr) => {const {
           let x = $e;

           match ::ascii::AsciiStr::new_const(x) {
                  Some(x) => x,
                  None => panic!("not an ascii string"),
           }
    }};

}

fn is_keyword(s: &AsciiStr) -> bool {
       match s {
              ascii!("continue") => true,
              ascii!("break") => true,
              _ => false,
       }
}

This is just an example and there are many such cases where something like this would be really useful.

@TomerPelleg
Copy link

I would also like to support this feature, for a very simple use-case.

I would like to do something like:

fn main() {
    let x: usize = 0;
        match x {
            0 => println!("x is zero"),
            0+1 => println!("x is one"),
            _ => println!("x is neither 0 or 1")
        }
}

And this feature allows me to do (currently only at nightly):

fn main() {
    let x: usize = 0;
        match x {
            0 => println!("x is zero"),
            const{0+1}=> println!("x is one"),
            _ => println!("x is neither 0 or 1")
        }
}

By the way, will future versions allow the omitting the "const" keyword in cases where the pattern is a const expression (such as this example)?

@lcnr
Copy link
Contributor

lcnr commented Mar 14, 2025

feature(inline_const_pat) results in some quite non-trivial implementation challenges. We therefore intend to remove the implementation of this feature in #138492 until we're able to resolve them.

@Qix-
Copy link

Qix- commented Mar 14, 2025

Huge setback, then :/ This makes certain ergonomics of some of the code I'm working on much easier, and removing what little support is there means I'll have to resort to a proc macro.

Is there any way to keep what's there for now, even if things must be marked excessively with unstable features etc?

Zalathar added a commit to Zalathar/rust that referenced this issue Apr 1, 2025
remove `feature(inline_const_pat)`

Summarizing https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/remove.20feature.28inline_const_pat.29.20and.20shared.20borrowck.

With rust-lang/types-team#129 we will start to borrowck items together with their typeck parent. This is necessary to correctly support opaque types, blocking the new solver and TAIT/ATPIT stabilization with the old one. This means that we cannot really support `inline_const_pat` as they are implemented right now:

- we want to typeck inline consts together with their parent body to allow inference to flow both ways and to allow the const to refer to local regions of its parent.This means we also need to borrowck the inline const together with its parent as that's necessary to properly support opaque types
- we want the inline const pattern to participate in exhaustiveness checking
- to participate in exhaustiveness checking we need to evaluate it, which requires borrowck, which now relies on borrowck of the typeck root, which ends up checking exhaustiveness again. **This is a query cycle**.

There are 4 possible ways to handle this:
- stop typechecking inline const patterns together with their parent
  - causes inline const patterns to be different than inline const exprs
  - prevents bidirectional inference, we need to either fail to compile `if let const { 1 } = 1u32` or `if let const { 1u32 } = 1`
  - region inference for inline consts will be harder, it feels non-trivial to support inline consts referencing local regions from the parent fn
- inline consts no longer participate in exhaustiveness checking. Treat them like `pat if pat == const { .. }`  instead. We then only evaluate them after borrowck
  - difference between `const { 1 }`  and `const FOO: usize = 1; match x { FOO => () }`. This is confusing
  - do they carry their weight if they are now just equivalent to using an if-guard
- delay exhaustiveness checking until after borrowck
  - should be possible in theory, but is a quite involved change and may have some unexpected challenges
- remove this feature for now

I believe we should either delay exhaustiveness checking or remove the feature entirely. As moving exhaustiveness checking to after borrow checking is quite complex I think the right course of action is to fully remove the feature for now and to add it again once/if we've got that implementation figured out.

`const { .. }`-expressions remain stable. These seem to have been the main motivation for rust-lang/rfcs#2920.

r? types

cc `@rust-lang/types` `@rust-lang/lang` rust-lang#76001
Zalathar added a commit to Zalathar/rust that referenced this issue Apr 1, 2025
remove `feature(inline_const_pat)`

Summarizing https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/remove.20feature.28inline_const_pat.29.20and.20shared.20borrowck.

With rust-lang/types-team#129 we will start to borrowck items together with their typeck parent. This is necessary to correctly support opaque types, blocking the new solver and TAIT/ATPIT stabilization with the old one. This means that we cannot really support `inline_const_pat` as they are implemented right now:

- we want to typeck inline consts together with their parent body to allow inference to flow both ways and to allow the const to refer to local regions of its parent.This means we also need to borrowck the inline const together with its parent as that's necessary to properly support opaque types
- we want the inline const pattern to participate in exhaustiveness checking
- to participate in exhaustiveness checking we need to evaluate it, which requires borrowck, which now relies on borrowck of the typeck root, which ends up checking exhaustiveness again. **This is a query cycle**.

There are 4 possible ways to handle this:
- stop typechecking inline const patterns together with their parent
  - causes inline const patterns to be different than inline const exprs
  - prevents bidirectional inference, we need to either fail to compile `if let const { 1 } = 1u32` or `if let const { 1u32 } = 1`
  - region inference for inline consts will be harder, it feels non-trivial to support inline consts referencing local regions from the parent fn
- inline consts no longer participate in exhaustiveness checking. Treat them like `pat if pat == const { .. }`  instead. We then only evaluate them after borrowck
  - difference between `const { 1 }`  and `const FOO: usize = 1; match x { FOO => () }`. This is confusing
  - do they carry their weight if they are now just equivalent to using an if-guard
- delay exhaustiveness checking until after borrowck
  - should be possible in theory, but is a quite involved change and may have some unexpected challenges
- remove this feature for now

I believe we should either delay exhaustiveness checking or remove the feature entirely. As moving exhaustiveness checking to after borrow checking is quite complex I think the right course of action is to fully remove the feature for now and to add it again once/if we've got that implementation figured out.

`const { .. }`-expressions remain stable. These seem to have been the main motivation for rust-lang/rfcs#2920.

r? types

cc ``@rust-lang/types`` ``@rust-lang/lang`` rust-lang#76001
bors added a commit to rust-lang-ci/rust that referenced this issue Apr 1, 2025
remove `feature(inline_const_pat)`

Summarizing https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/remove.20feature.28inline_const_pat.29.20and.20shared.20borrowck.

With rust-lang/types-team#129 we will start to borrowck items together with their typeck parent. This is necessary to correctly support opaque types, blocking the new solver and TAIT/ATPIT stabilization with the old one. This means that we cannot really support `inline_const_pat` as they are implemented right now:

- we want to typeck inline consts together with their parent body to allow inference to flow both ways and to allow the const to refer to local regions of its parent.This means we also need to borrowck the inline const together with its parent as that's necessary to properly support opaque types
- we want the inline const pattern to participate in exhaustiveness checking
- to participate in exhaustiveness checking we need to evaluate it, which requires borrowck, which now relies on borrowck of the typeck root, which ends up checking exhaustiveness again. **This is a query cycle**.

There are 4 possible ways to handle this:
- stop typechecking inline const patterns together with their parent
  - causes inline const patterns to be different than inline const exprs
  - prevents bidirectional inference, we need to either fail to compile `if let const { 1 } = 1u32` or `if let const { 1u32 } = 1`
  - region inference for inline consts will be harder, it feels non-trivial to support inline consts referencing local regions from the parent fn
- inline consts no longer participate in exhaustiveness checking. Treat them like `pat if pat == const { .. }`  instead. We then only evaluate them after borrowck
  - difference between `const { 1 }`  and `const FOO: usize = 1; match x { FOO => () }`. This is confusing
  - do they carry their weight if they are now just equivalent to using an if-guard
- delay exhaustiveness checking until after borrowck
  - should be possible in theory, but is a quite involved change and may have some unexpected challenges
- remove this feature for now

I believe we should either delay exhaustiveness checking or remove the feature entirely. As moving exhaustiveness checking to after borrow checking is quite complex I think the right course of action is to fully remove the feature for now and to add it again once/if we've got that implementation figured out.

`const { .. }`-expressions remain stable. These seem to have been the main motivation for rust-lang/rfcs#2920.

r? types

cc `@rust-lang/types` `@rust-lang/lang` rust-lang#76001
@zeroflaw
Copy link

zeroflaw commented Apr 2, 2025

Anyone that is refactoring today, another way to get a const inline without the inline_const_pat feature is:

fn main() {
    let x: usize = 1;
    match x {
         0 => println!("x is zero"),
         const{0+1}=> println!("x is one"),
         _ => println!("x is neither 0 or 1")
    }
}

becomes:

fn main() {
    let x: usize = 1;
    match x {
         0 => println!("x is zero"),
         v if v == const{0+1}=> println!("x is one"),
         _ => println!("x is neither 0 or 1")
     }
}

The downside of the above is you can't "~const" PartialEq on a non-primitive type, like you could before. So you might need to implement a const_eq function so you can do:

v if v.const_eq(const { &Self::const_zero() }) => println!("x is zero"),

Hope this helps someone.

@Qix-
Copy link

Qix- commented Apr 3, 2025

The downside to that is that you cannot generalize that to an expression form.

const SOME_KEY = key!("...");

match SOME_KEY {
    key!("...") => { ... },
    key!("???") => { ... },
}

There's no way to write key!() in a way where that's usable in all expression contexts without this feature :|

@RalfJung
Copy link
Member

RalfJung commented Apr 3, 2025

The LHS of => is not an expression, it's a pattern. So what you are asking is for the same term to work both as a pattern and as an expression.

Yeah that does not work without const patterns, true.

github-actions bot pushed a commit to carolynzech/rust that referenced this issue Apr 3, 2025
remove `feature(inline_const_pat)`

Summarizing https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/remove.20feature.28inline_const_pat.29.20and.20shared.20borrowck.

With rust-lang/types-team#129 we will start to borrowck items together with their typeck parent. This is necessary to correctly support opaque types, blocking the new solver and TAIT/ATPIT stabilization with the old one. This means that we cannot really support `inline_const_pat` as they are implemented right now:

- we want to typeck inline consts together with their parent body to allow inference to flow both ways and to allow the const to refer to local regions of its parent.This means we also need to borrowck the inline const together with its parent as that's necessary to properly support opaque types
- we want the inline const pattern to participate in exhaustiveness checking
- to participate in exhaustiveness checking we need to evaluate it, which requires borrowck, which now relies on borrowck of the typeck root, which ends up checking exhaustiveness again. **This is a query cycle**.

There are 4 possible ways to handle this:
- stop typechecking inline const patterns together with their parent
  - causes inline const patterns to be different than inline const exprs
  - prevents bidirectional inference, we need to either fail to compile `if let const { 1 } = 1u32` or `if let const { 1u32 } = 1`
  - region inference for inline consts will be harder, it feels non-trivial to support inline consts referencing local regions from the parent fn
- inline consts no longer participate in exhaustiveness checking. Treat them like `pat if pat == const { .. }`  instead. We then only evaluate them after borrowck
  - difference between `const { 1 }`  and `const FOO: usize = 1; match x { FOO => () }`. This is confusing
  - do they carry their weight if they are now just equivalent to using an if-guard
- delay exhaustiveness checking until after borrowck
  - should be possible in theory, but is a quite involved change and may have some unexpected challenges
- remove this feature for now

I believe we should either delay exhaustiveness checking or remove the feature entirely. As moving exhaustiveness checking to after borrow checking is quite complex I think the right course of action is to fully remove the feature for now and to add it again once/if we've got that implementation figured out.

`const { .. }`-expressions remain stable. These seem to have been the main motivation for rust-lang/rfcs#2920.

r? types

cc `@rust-lang/types` `@rust-lang/lang` rust-lang#76001
flip1995 pushed a commit to flip1995/rust that referenced this issue Apr 3, 2025
remove `feature(inline_const_pat)`

Summarizing https://rust-lang.zulipchat.com/#narrow/channel/144729-t-types/topic/remove.20feature.28inline_const_pat.29.20and.20shared.20borrowck.

With rust-lang/types-team#129 we will start to borrowck items together with their typeck parent. This is necessary to correctly support opaque types, blocking the new solver and TAIT/ATPIT stabilization with the old one. This means that we cannot really support `inline_const_pat` as they are implemented right now:

- we want to typeck inline consts together with their parent body to allow inference to flow both ways and to allow the const to refer to local regions of its parent.This means we also need to borrowck the inline const together with its parent as that's necessary to properly support opaque types
- we want the inline const pattern to participate in exhaustiveness checking
- to participate in exhaustiveness checking we need to evaluate it, which requires borrowck, which now relies on borrowck of the typeck root, which ends up checking exhaustiveness again. **This is a query cycle**.

There are 4 possible ways to handle this:
- stop typechecking inline const patterns together with their parent
  - causes inline const patterns to be different than inline const exprs
  - prevents bidirectional inference, we need to either fail to compile `if let const { 1 } = 1u32` or `if let const { 1u32 } = 1`
  - region inference for inline consts will be harder, it feels non-trivial to support inline consts referencing local regions from the parent fn
- inline consts no longer participate in exhaustiveness checking. Treat them like `pat if pat == const { .. }`  instead. We then only evaluate them after borrowck
  - difference between `const { 1 }`  and `const FOO: usize = 1; match x { FOO => () }`. This is confusing
  - do they carry their weight if they are now just equivalent to using an if-guard
- delay exhaustiveness checking until after borrowck
  - should be possible in theory, but is a quite involved change and may have some unexpected challenges
- remove this feature for now

I believe we should either delay exhaustiveness checking or remove the feature entirely. As moving exhaustiveness checking to after borrow checking is quite complex I think the right course of action is to fully remove the feature for now and to add it again once/if we've got that implementation figured out.

`const { .. }`-expressions remain stable. These seem to have been the main motivation for rust-lang/rfcs#2920.

r? types

cc `@rust-lang/types` `@rust-lang/lang` rust-lang#76001
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-inline_const_pat #![feature(inline_const_pat)] F-inline_const Inline constants (aka: const blocks, const expressions, anonymous constants) S-tracking-needs-summary Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests