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

Inline const expressions and patterns #2920

Merged
merged 19 commits into from
Aug 27, 2020

Conversation

ecstatic-morse
Copy link
Contributor

@ecstatic-morse ecstatic-morse commented May 4, 2020

Rendered

TL; DR: Allows users to request compile-time evaluation without requiring promotion or a named const.

fn foo() -> &'static i32 {
    &const { 
        let x = 4i32;
        x.pow(5)
    }
}

fn main() {
    match *x {
        0 ..= const { u32::MAX / 2 } => println!("low"),
        const { u32::MAX / 2 + 1 } ..= u32::MAX => println!("high"),
    }
}

This idea has been in the ether for a while now as a way to reduce dependence on promotion for evaluating simple expressions at compile-time. It was discussed most recently on Zulip.

Credit to @scottmcm, who discussed this with me on Zulip and was one of the people who discovered this idea. I believe both @RalfJung and @oli-obk have considered this as well.

text/0000-inline-const.md Outdated Show resolved Hide resolved
text/0000-inline-const.md Outdated Show resolved Hide resolved
@scottmcm scottmcm added the T-lang Relevant to the language team, which will review and decide on the RFC. label May 4, 2020
@scottmcm scottmcm self-assigned this May 4, 2020
@scottmcm
Copy link
Member

scottmcm commented May 4, 2020

Thanks for writing this up, @ecstatic-morse! The const-eval group's excellent promotion rules document you linked made me want this even more than I originally thought, as having a visible way to opt-in (and thus not need to worry about whether it is, isn't, or should be happening) seems so much better than trying to extend something that's already quite complicated.

@Lokathor
Copy link
Contributor

Lokathor commented May 4, 2020

prior art: Zig has a "comptime" mechanism, https://kristoff.it/blog/what-is-zig-comptime/

@petrochenkov petrochenkov mentioned this pull request May 4, 2020
@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented May 4, 2020

For the record, I am in favor of a single-expression, braceless variant like const 5. However, the grammar for the single-expression version is more complex than this one. If someone wants to look into this extension, I would very much appreciate it. Specifically, I'm worried about ambiguity in range patterns.

@scottmcm
Copy link
Member

scottmcm commented May 5, 2020

braceless variant like const 5

I feel somewhat strongly that for this RFC, const{} should just ape unsafe{} syntactically.

We can talk about const foo() and unsafe *pointer at another time.

(I would plausibly think otherwise if const { 4 } or const { u32::MAX } was actually necessary, but given that it needs at least an operator or function call before adding the block does anything, I'm just not that worried about the braces. I also don't expect this to be super-common.)

text/0000-inline-const.md Outdated Show resolved Hide resolved
`const` expressions inside a `const` or `static` is also an open question.

# Drawbacks
[drawbacks]: #drawbacks
Copy link
Member

@RalfJung RalfJung May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is a drawback or a complication, but I presume this would also work in generic contexts -- so we would be basically introducing generic consts with this RFC. Well, we already have consts in generic contexts with associated consts, but they don't work quite as well as other consts in terms of linting etc -- we have monomorphization-time errors because only then can we actually evaluate the const. The same would likely happen here, right?

fn aptr::<T>() -> &'static *mut T {
  const { &std::ptr::NonNull::dangling().as_ptr() }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is an excellent point. My initial thought was that we would indeed prevent inline constants from referring to generic parameters, just as constants currently do. If we allow this for inline constants, why not allow it for named constants as well? Are there backwards compatibility concerns?

Copy link
Contributor Author

@ecstatic-morse ecstatic-morse May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we accept this RFC without allowing inline constants to refer to in-scope generic parameters, there will be a narrow class of implicitly promotable expressions (e.g. std::ptr::null::<T>(), T::CONST + T::ANOTHER_CONST) that couldn't be written in const blocks. I don't expect a ton of code is depending on the promotability of expressions such as these, but it makes it more difficult to justify the deprecation of implicit promotion for all fn calls and arithmetic expressions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we accept this RFC without allowing inline constants to refer to in-scope generic parameters, there will be a narrow class of implicitly promotable expressions [...]

Exactly, that's why my gut feeling is we should allow generics.
We have to figure out better how to lint wrong CTFE in potentially generic consts -- maybe we can eagerly evaluate at least those that do not actually depend on a generic parameter -- but that seems like a concern to be figured out during implementation.

If we allow this for inline constants, why not allow it for named constants as well? Are there backwards compatibility concerns?

For once, we'd need syntax, which is not the case for inline consts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can backwards compatibly allow inline constants to refer to in-scope generic parameters in the future, I would like to separate that feature from the initial implementation. We would need both things before we considered deprecating the promotion of arithmetic expressions, but that doesn't mean they need to be spec'ed/implemented together.


It would also possible to separate out the parts of this RFC relating to patterns
so that they can be decided upon seperately. I think they are similar enough
that they are best considered as a unit, however.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that so far we do not do implicit promotion in patterns, I feel it makes sense to go baby steps here and start with inline consts (anonymous consts?) as expressions only to match the existing implicit promotion in expressions -- so IMO they should be made separate feature gates and stabilization considered separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, the overarching principles of this RFC should be:

  1. inline consts behave exactly the same as if you defined a named constant in the same scope.
  2. inline consts can be used anywhere you would use a named constant.

These rules of thumb help make this feature easy to reason about. Since you can already use named constants in patterns, I don't see any reason you shouldn't be allowed to use inline ones.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RFC describes inline consts as sugar for { const NAME := ...; NAME }; that expansion would not work in patterns as they are not expressions.

I feel like patterns and expressions are sufficiently different that there is no reason to tie them together like that. For expressions we have concrete cases and this has been floated for years; for patterns this is the first time I see it and frankly I find it syntactically rather awkward.

Copy link
Contributor Author

@ecstatic-morse ecstatic-morse May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RFC describes inline consts as sugar for { const NAME := ...; NAME }; that expansion would not work in patterns as they are not expressions.

This is not news to me. The RFC states explicitly that that analogy is only valid in expression context. The real desugaring is less elegant–define a new constant with a unique name in the same scope as the inline const and then refer to the newly defined constant–but operationally the same. I don't think it's too big of a stretch to go from one to the other.

The rest is a matter of opinion. I find the consistency argument compelling, and I don't think wanting to match on the result of a const fn is all that novel, although admittedly my examples aren't very convincing. Perhaps someone has a better example of code using one-off named constants in patterns that would benefit from this RFC?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest is a matter of opinion.

That is definitely so. :)
I am just asking that the RFC list arguments both way -- right now it lists your arguments but not mine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(From what I can see, the RFC still lists no arguments in favor of separating patterns.)

text/0000-inline-const.md Outdated Show resolved Hide resolved
In both the expression and pattern context, an inline `const` behaves exactly
as if the user had declared a uniquely identified `const` with the block's
contents as its initializer. For example, in expression context, writing
`const { ... }` is equivalent to writing:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is truly an equivalence, then these consts would not be able to access generics of the surrounding function. That's a fine first step, but implicit promotion can access those generics, so it would not be a full replacement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any implementation concerns with accessing generic parameters? I understand that that rules for items prevent it, but it would seem very odd for expressions to be unable to access generic parameters -- by analogy, you can reference generic parameters in an async{} even though you cannot reference them in a nested async fn.

I think this analogy would be reasonable in a guide-level intuition argument, but shouldn't be how it's actually defined.

text/0000-inline-const.md Outdated Show resolved Hide resolved
text/0000-inline-const.md Outdated Show resolved Hide resolved
@jonas-schievink jonas-schievink added A-const Proposals relating to const items A-const-eval Proposals relating to compile time evaluation (CTFE). labels May 5, 2020
@rfcbot
Copy link
Collaborator

rfcbot commented Jun 29, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot
Copy link
Collaborator

rfcbot commented Jul 9, 2020

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

The RFC will be merged soon.

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this RFC. and removed final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. labels Jul 9, 2020
@RalfJung
Copy link
Member

@nikomatsakis FCP "merge" is complete here. Any chance you could merge this? :D

@ecstatic-morse
Copy link
Contributor Author

@RalfJung raised an interesting question a while ago that I'm just now reading: Should the following code emit a const_err lint/error?

fn div() -> &'static i32 {
    const C: i32 = 0;
    if  C != 0 {
        const { &(42 / C) } // Does this emit `const_err`?
    } else {
        &0
    }
}

While it might be possible to skip const_err lints for anonymous consts that are not reached unconditionally, instead turning them into runtime panics, I think we should just make this a const_err for now. In this case, the condition is provably false at compile-time, so the user could expand the inline const to contain the if. If the condition depended on something runtime-only, it might be useful to have the code compile and only panic if the condition is hit, but this would break the analogy with uniquely named local constants.

I think we would be able to relax this rule at a later date if there was a compelling use-case, since always emitting const_err is maximally conservative. I haven't fully considered all the implications of this, however.

Does this match people's expectations?

@RalfJung
Copy link
Member

RalfJung commented Aug 14, 2020

If the condition depended on something runtime-only

How is that possible? It's a const, after all... EDIT: oh you said "condition", not the const.

Using an erroneous const causes a function to fail to compile, even when that use is inside an if false. That is deliberate, it was considered a soundness bug when the const was optimized away and function compilation succeeded. But this also means that making const {} blocks behave similarly is not necessarily forwards compatible with relaxing this later; people could start to rely on const {} failures causing hard errors for soundness.

OTOH, for promoteds, we do not make CTFE failure a hard error. In my opinion, we should only promote things that cannot fail to evaluate, thus side-stepping this problem.

So, my opinion is that it should be a hard error (not just a const_err lint) -- but once we guarantee this we cannot take it back easily.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Aug 27, 2020

Huzzah! The @rust-lang/lang team has decided to accept this RFC. You can follow along with development on the tracking issue, rust-lang/rust#76001.

GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request 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 pull request 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 pull request 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 pull request 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 pull request 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 pull request 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 pull request 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
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Apr 25, 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 #76001 (the tracking issue should *not* be closed as it needs to track inline const in pattern position). The initial implementation is done in #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. #89964). The inference is implemented in #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 #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: #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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const Proposals relating to const items A-const-eval Proposals relating to compile time evaluation (CTFE). disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this RFC. T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.