-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Stabilize feature(generic_arg_infer)
#141610
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
base: master
Are you sure you want to change the base?
Conversation
Some changes occurred in src/tools/clippy cc @rust-lang/clippy HIR ty lowering was modified cc @fmease |
This comment has been minimized.
This comment has been minimized.
077c8ba
to
081d24a
Compare
This PR changes a file inside |
This comment has been minimized.
This comment has been minimized.
Hi @rust-lang/lang I'm proposing we stabilize the Explicitly inferred const arguments: Stabilization reportGeneral designWe now allow users to write fn foo() -> [u8; 2] {
// Previously `_` here was unstable, now its stable
[1; _]
}
fn make_array<const N: usize>() -> [u8; N] {
loop {}
}
fn bar() {
// Previously `_` here was unstable, now its stable
let _: [u8; 5] = make_array::<_>();
} Inferring const arguments implicitly has always been possible since the original stabilization of const generics. What is being proposed for stabilization is the ability to explicitly infer a generic argument, instead of implicitly inferring all generic arguments by eliding the entire set. Inference of explicitly inferred const arguments is handled the same way as elided generic arguments and generally the same as how inference of type arguments is handled. Defaulted const generic parameters are not taken into account for fallback of inferred const arguments, this is the same as how defaulted type parameters work. Array repeat expressions ( The types team believes that the current implementation of type inference for repeat expresions with inferred counts is maintainable and sound. Information about the exact details of how type inference handles repeat expressions with inferred counts can be found here. We allow parenthesised inferred const arguments as well as bare underscores. For example: Const Generics was originally RFC'd in RFC #2000 Const Generics. I believe that this feature is covered by this RFC even though the RFC does not explicitly talk about inferred const arguments. It seems natural that in adding a new kind of generic parameter we would also be supporting a way to explicitly infer generic arguments of that kind. Additionally, the only reason this wasnt part of the In summary:
Implementation QualityHigh level implementationThe HIR is now able to represent A naive implementation would cause maintainability issues as inferred arguments could be represented as either To solve this we split HIR's Finally, there are also a fair amount of subtleties around how we could handle repeat expressions with inferred counts. The types team is confident that the current implemention is correct, maintainable and also more flexible enough. More information can be found here. Test coverage/Correctness assuranceTests for this feature can generally be found in tests/ui/const-generics/generic_arg_infer or tests/ui/repeat-expr:
On stable we internally use the new Finally, there was a call for testing for this feature 3 months ago and nobody has reported any bugs following the post: Inferred const generic arguments: Call for Testing! Tooling supportI don't know how r-a handles explicitly inferred const arguments, but at the very least it doesn't seem to give a bunch of errors on passing code. cc @rust-lang/rust-analyzer. Rustfmt doesn't delete explicitly inferred const args so what more can you ask for. Reference PR: rust-lang/reference#1835 Type system interactionsThis feature is almost entirely syntactic- the type system has been (soundly) working with inferred const arguments since the initial stabilization of Const Generics. Apart from array repeat expressions, this feature does not strengthen the type system in any way or expose new parts of it. Array repeat expressions ( test: N/A Headers
Implementation History
@voidc and @camelid have refactored some parts of how we represent const arguments in the HIR (#133589, #125915). This made it possible for me to refactor the HIR to make things less brittle/error prone (#135272), the design for how to accomplish this was a joint effort of @lcnr and myself. In #139635 I updated our handling of repeat expression checks in HIR typechecking to properly handle inferred repeat counts and inference side effects of the Finally thanks to @lcnr @compiler-errors and @oli-obk who have reviewed a lot of the work (be it PRs or otherwise) in this area over the past years. Sorry if I missed anyone's contributions here, 4 years is a long time and we don't seem to have written any of it down along the way ^^' |
(marking as an easy decision because it ought to be an easy decision to start an FCP not necessarily to actually commit to things) |
081d24a
to
f9132af
Compare
@rustbot labels -I-lang-easy-decision +P-lang-drag-1 Thanks for putting up this stabilization and for the obvious amount of work that went in ahead of it. Will have a careful look. (Regarding the label, I like your optimism, but probably this isn't going to be what we mean by an easy decision. Even to propose FCP, one of us has to be ready to commit to it unless we concurrently file a concern.) |
cc @ehuss (Heads-up this one is actually likely to move along quickly.) |
(Just for our notes as I work through this; not a concern...) This stabilization puts weight on the following bit of inference breakage that will ship with Rust 1.89: struct W<T>(Option<T>);
impl Clone for W<u8> {
fn clone(&self) -> Self {
W(None)
}
}
impl Copy for W<u8> {}
fn extract<T: Copy>(x: [W<T>; 2]) -> T {
x[0].0.unwrap()
}
fn main() {
let x = [W(None); 2];
//[1.89]~^ ERROR type annotations needed
//[1.88]~^ OK
_ = extract(x).max(2);
} |
We're also putting some weight on this inference choice: #![feature(generic_arg_infer)]
struct W<T>(Option<T>);
impl Clone for W<u32> {
fn clone(&self) -> Self {
W(None)
}
}
impl Copy for W<u32> {}
trait Trait {}
impl Trait for i32 {}
impl Trait for u32 {}
fn make_goal<T: Trait>(_: &T) {}
fn tie<T>(_: &T, _: &[W<T>; 2]) {}
fn main() {
let a = 1;
make_goal(&a);
let b: [W<_>; 2] = [W(None); _];
// ~
//~^ Do we fall back to `i32` here (and give an error since
// `W<i32>` is not `Copy`), or do we infer `u32` given `W<T>:
// Copy`? We pick `u32`.
tie(&a, &b);
} |
Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns. |
This looks straightforward to me. Thanks @BoxyUwU for the thorough report. The parenthesized consts thing seems like: We can't be fully consistent with the language because it's not consistent with itself, but my understanding from @BoxyUwU is that there's no good reason we can't make it consistent eventually. Specifically, we don't support @rfcbot reviewed |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Fixes #85077
r? lcnr
cc @rust-lang/project-const-generics