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 · 86 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 · 86 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.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 1, 2024
…t-pat, r=compiler-errors

`#![feature(inline_const_pat)]` is no longer incomplete

Now that borrow checking and safety checking is implemented for inline constant patterns, the incomplete feature status is not necessary. Stabilizing this feature requires more testing and has some of the same unresolved questions as inline constants.

cc rust-lang#76001
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 1, 2024
…t-pat, r=compiler-errors

`#![feature(inline_const_pat)]` is no longer incomplete

Now that borrow checking and safety checking is implemented for inline constant patterns, the incomplete feature status is not necessary. Stabilizing this feature requires more testing and has some of the same unresolved questions as inline constants.

cc rust-lang#76001
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Feb 4, 2024
…t-pat, r=compiler-errors

`#![feature(inline_const_pat)]` is no longer incomplete

Now that borrow checking and safety checking is implemented for inline constant patterns, the incomplete feature status is not necessary. Stabilizing this feature requires more testing and has some of the same unresolved questions as inline constants.

cc rust-lang#76001
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Feb 5, 2024
Rollup merge of rust-lang#120547 - matthewjasper:complete-inline-const-pat, r=compiler-errors

`#![feature(inline_const_pat)]` is no longer incomplete

Now that borrow checking and safety checking is implemented for inline constant patterns, the incomplete feature status is not necessary. Stabilizing this feature requires more testing and has some of the same unresolved questions as inline constants.

cc rust-lang#76001
@CAD97
Copy link
Contributor

CAD97 commented Mar 24, 2024

Something I hope we can consider before stabilization (and don't think has been mentioned prior): should we reserve/disallow const blocks as an if's test expression? Potential rationale for doing so:

  • if const { … } is a natural way to spell a const_eval_select (if we decide that const fn are allowed to have inconsistent behavior between consteval and runtime1).
  • C++20 has constexpr if and std::is_constant_evaluated, but if constexpr (std::is_constant_evaluated()) is unusefully always true, leading to the introduction of if consteval in C++23.
    • Allowing if const { … } { … } opens Rust up to the same potential pitfall if we introduce such a const fn.
  • const if … { … } is a natural way to spell a condition which guarantees the primary body is only required to be WF when the condition is true, but it'd be quite unfortunate if both const if … { … } and if const { … } { … } can write the "same" thing with subtly different behavior.
    • Critically, not only for the purpose of post-mono consteval errors, but also for feature(generic_const_exprs) style usage in pre-mono where clauses.
    • (Avoiding this is why I typically use static if as the syntax bikeshed color for this functionality.)
  • Writing if (const { … }) { … } instead isn't that much of an ask, and even is perhaps desirable for the same reason match match is generally considered undesirable.

I entirely don't mind not reserving/disallowing the syntax; I just want some confidence lang is aware of potential future extension around this.

Footnotes

  1. Which AIUI will essentially be required if we want to make floating point math const safe.

@RalfJung
Copy link
Member

RalfJung commented Mar 25, 2024

So basically you are saying if const should be considered a magic keyword sequence and not just that composition of if and const? And this would interact e.g. with our guarantee of which other constants in the function body are guaranteed to evaluate? That'll surely be "interesting" for MIR consumers tying to figure out which constants they have to evaluate and which they must not evaluate...

It also seems potentially problematic for macros, where if I write if macro!(...) then depending on what the macro does, behavior is extremely different.

OTOH if it can be made to work, I do see the appeal of if const.

A prototype intrinsic for this would look more like const_eval_select, let's call it const_mono_select(b, f1, f2): it would take a bool (required to be a constant) and two functions, and monomorphize only one of them. (This would need a special representation in mentioned_items to ensure the monomorphization set remains opt-level independent. I have no clue how reachability is supposed to deal with this)

Allowing if const { … } { … } opens Rust up to the same potential pitfall if we introduce such a const fn.

I would say that "pitfall" is the only sensible behavior. if const { const_eval_select(...) } should obviously pick the "const" branch for the select, the "runtime" branch can't even be run inside a const.

if const for monomorphization control is a very different feature from const_eval_select/is_constant_evaluated. So if anything this seems to me to be an argument against making if const suitable for monomorphization control? I am honestly not even sure what you are suggesting we do here. There are two fundamentally different features here, const_eval_select and const_mono_select.

Which AIUI will essentially be required if we want to make floating point math const safe

It's a bit more subtle than that due to non-determinism. Floats do not provide a way that code can reliably test for compiletime vs runtime evaluation.

@nbdd0121
Copy link
Contributor

nbdd0121 commented Mar 25, 2024

That'll surely be "interesting" for MIR consumers tying to figure out which constants they have to evaluate and which they must not evaluate...

That sounds like the implementation detail of rust-lang/rfcs#3582 or #85836? If we have any construct that allows us to do a partial mono we will have the same issue.

It also seems potentially problematic for macros, where if I write if macro!(...) then depending on what the macro does, behavior is extremely different.

I think the argument is to only reserve, syntactically, if const ..., not if (const ...), or if macro_expands_to_const!(...) .

There's already precedent in the standard library where in std::thread_local, const { ... } is treated as a special construct as an initialising expression.

@RalfJung
Copy link
Member

That sounds like the implementation detail of rust-lang/rfcs#3582

Yes. That RFC has the risk of being a major pain for all future MIR work. But that's probably off-topic here.

or #85836?

No, that's just about doing less codegen, but not about evaluating fewer consts during monomorphization.

GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this issue Apr 22, 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 22, 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
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.

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