From 7f3fd64ea7f4c416937ba5a6fc3e10afdc387d00 Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Tue, 18 Sep 2018 00:55:26 +0200
Subject: [PATCH 1/5] RFC: Elide array size

---
 text/0000-elide-array-size.md | 100 ++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 text/0000-elide-array-size.md

diff --git a/text/0000-elide-array-size.md b/text/0000-elide-array-size.md
new file mode 100644
index 00000000000..c76db97995a
--- /dev/null
+++ b/text/0000-elide-array-size.md
@@ -0,0 +1,100 @@
+- Feature Name: elide_array_size
+- Start Date: 2018-09-18
+- RFC PR: (leave this empty)
+- Rust Issue: (leave this empty)
+
+# Summary
+[summary]: #summary
+
+In arrays, allow to elide the size in the type and put an underscore there
+instead if it can be deduced from the initializer. For example: `static
+BLORP_NUMBERS: [u32; _] = [0, 8, 15];`.
+
+# Motivation
+[motivation]: #motivation
+
+This will make it easier to set up static data. With the current syntax, one
+needs to count the elements of an array manually to determine its size. Letting
+the compiler find the size reduces the potential for error. It also allows us
+to ascribe the array component type without requiring the size (which is
+perhaps surprisingly not currently allowed).
+
+# Guide-level explanation
+[guide-level-explanation]: #guide-level-explanation
+
+Requiring to write `[MyType; 42]` for a 42-element array gets tedious,
+especially since the compiler already knows the size from the initializer. To
+reduce the strain, Rust allows you to omit the `42` in those type ascriptions.
+
+For example, you might write:
+
+```rust
+const CONST_CHARS: [u8; _] = b"This is really a byte array";
+static STATIC_MASKS: [u8; _] = [0, 1, 3, 7, 15, 31, 63, 127, 255];
+
+fn main() {
+    let local_strs: [&'static str] = ["Hello", "Rust"];
+    ..
+}
+```
+
+# Reference-level explanation
+[reference-level-explanation]: #reference-level-explanation
+
+This feature is a simple extension of the parser plus AST transformation. In
+its proposed form, there are no corner cases, because the only thing it enables
+that is currently disallowed is to put a `_` wildcard in place of the number of
+elements in array types in `let`s, `const`s and `static`s.
+
+In the parser, at the array length position, we must allow underscores. The AST
+may need to be extended to allow underscore; In principle `AnonConst` can
+contain any expression, so `_` could be represented by a `Path`, or the whole
+`AnonConst` could be made `Option`al.
+
+At this point we should disallow a `None` value for `let` bindings without
+initializers or with initializers that are not `ExprKind::Repeat` or
+`ExprKind::Array`.
+
+At the lowering stage, the initializer is checked for the actual array length,
+and the `Ty` is constructed as if the size was given verbatim.
+
+# Drawbacks
+[drawbacks]: #drawbacks
+
+There is a modicum of complexity to extend the parser and AST which needs to be
+done for every Rust parser in existenct. However, the feature is minor, so the
+cost should be acceptable.
+
+Also for longer array declarations the actual size may no longer be obvious
+from the code. However, putting any probable or improbable length in and
+observing the compiler error (if any) is enough to find out; also the author
+hopes that the programmers will put in the lengths if they are essential.
+
+# Rationale and alternatives
+[rationale-and-alternatives]: #rationale-and-alternatives
+
+We could extend this to full inference, which would require us to set the size
+*after* lowering. This would make the feature more powerful, but reduce
+locality. For example if the array isn't initialized in the next 100 lines or
+is initialized from a `static`, or a `fn` that is far away in another module,
+changes to said item would lead to errors down the line that are needlessly
+hard to track down.
+
+We could leave out the wildcard entirely, but `[u32; ]` looks strange and could
+possibly indicate an error, so it's better to use the more balanced `[u32; _]`.
+
+We could do nothing, and waste Rustacean's time by counting or parsing compiler
+errors (unless their accuracy of estimating array length is 100%. I'm sure mine
+isnt).
+
+# Prior art
+[prior-art]: #prior-art
+
+We already allow wildcard lifetimes, which have been beneficial. I'll defer to
+[RFC 2115](https://rust-lang.github.io/rfcs/2115-argument-lifetimes.html) for
+more information.
+
+# Unresolved questions
+[unresolved-questions]: #unresolved-questions
+
+None

From 36365c00af81ce05d0b60225651e3a5b0fe9d726 Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Tue, 18 Sep 2018 08:11:23 +0200
Subject: [PATCH 2/5] fix typos

---
 text/0000-elide-array-size.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/text/0000-elide-array-size.md b/text/0000-elide-array-size.md
index c76db97995a..a8e03c80359 100644
--- a/text/0000-elide-array-size.md
+++ b/text/0000-elide-array-size.md
@@ -33,7 +33,7 @@ const CONST_CHARS: [u8; _] = b"This is really a byte array";
 static STATIC_MASKS: [u8; _] = [0, 1, 3, 7, 15, 31, 63, 127, 255];
 
 fn main() {
-    let local_strs: [&'static str] = ["Hello", "Rust"];
+    let local_strs: [&'static str; _] = ["Hello", "Rust"];
     ..
 }
 ```
@@ -85,7 +85,7 @@ possibly indicate an error, so it's better to use the more balanced `[u32; _]`.
 
 We could do nothing, and waste Rustacean's time by counting or parsing compiler
 errors (unless their accuracy of estimating array length is 100%. I'm sure mine
-isnt).
+isn't).
 
 # Prior art
 [prior-art]: #prior-art

From c9a6b81b9a60945bb613591df32a1fa0fe178ccc Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Tue, 18 Sep 2018 08:24:43 +0200
Subject: [PATCH 3/5] new section: error handling

---
 text/0000-elide-array-size.md | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/text/0000-elide-array-size.md b/text/0000-elide-array-size.md
index a8e03c80359..7859a5178ba 100644
--- a/text/0000-elide-array-size.md
+++ b/text/0000-elide-array-size.md
@@ -58,6 +58,24 @@ initializers or with initializers that are not `ExprKind::Repeat` or
 At the lowering stage, the initializer is checked for the actual array length,
 and the `Ty` is constructed as if the size was given verbatim.
 
+## Error handling
+
+This change would introduce a new type of error, for statements that have no
+initializer or statics that introduce const functions (once they are stable).
+As outlined above, the latter would still need the correct type, though this is
+a small cost, as the type can likely be copied verbatim from the function.
+
+This RFC proposes showing an error message that restates the locality rule and
+suggests writing out the size (which can be inferred in the suggestion if
+possible). This might look like the following (mocked up here):
+
+```
+78: let x: [u32; _];
+                 ^ No initializer to take size from. Please write out the size.
+Suggestion: let x: [u32; 3];
+                         ~
+```
+
 # Drawbacks
 [drawbacks]: #drawbacks
 

From 70ad55db407cff7068b964b39e4bccd7e70f7897 Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Wed, 19 Sep 2018 08:48:34 +0200
Subject: [PATCH 4/5] fix missing deref in code example

---
 text/0000-elide-array-size.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/text/0000-elide-array-size.md b/text/0000-elide-array-size.md
index 7859a5178ba..b0473511c7a 100644
--- a/text/0000-elide-array-size.md
+++ b/text/0000-elide-array-size.md
@@ -29,7 +29,7 @@ reduce the strain, Rust allows you to omit the `42` in those type ascriptions.
 For example, you might write:
 
 ```rust
-const CONST_CHARS: [u8; _] = b"This is really a byte array";
+const CONST_CHARS: [u8; _] = *b"This is really a byte array";
 static STATIC_MASKS: [u8; _] = [0, 1, 3, 7, 15, 31, 63, 127, 255];
 
 fn main() {

From 5babce5cd81d51bcb846655ce7b0c876fc27b17b Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Wed, 26 Sep 2018 21:24:27 +0200
Subject: [PATCH 5/5] apply suggestion by @Centril, @eddyb and others

---
 text/0000-elide-array-size.md | 73 +++++++++++++++--------------------
 1 file changed, 32 insertions(+), 41 deletions(-)

diff --git a/text/0000-elide-array-size.md b/text/0000-elide-array-size.md
index b0473511c7a..047f5c52acc 100644
--- a/text/0000-elide-array-size.md
+++ b/text/0000-elide-array-size.md
@@ -6,18 +6,18 @@
 # Summary
 [summary]: #summary
 
-In arrays, allow to elide the size in the type and put an underscore there
-instead if it can be deduced from the initializer. For example: `static
-BLORP_NUMBERS: [u32; _] = [0, 8, 15];`.
+In arrays declared in `static`s, `const`s and `let` bindings with initializer, 
+allow to elide the size in the type and put an underscore there instead if it 
+can be inferred. For example: `static BLORP_NUMBERS: [u32; _] = [0, 8, 15];`.
 
 # Motivation
 [motivation]: #motivation
 
-This will make it easier to set up static data. With the current syntax, one
-needs to count the elements of an array manually to determine its size. Letting
-the compiler find the size reduces the potential for error. It also allows us
-to ascribe the array component type without requiring the size (which is
-perhaps surprisingly not currently allowed).
+This will make it easier to set up static data. With the current syntax, one 
+needs to count the elements of an array manually to determine its size. Letting 
+the compiler find the size reduces the potential for error. In `let` bindings 
+it also allows us to ascribe the array component type without requiring the 
+size (which is – perhaps surprisingly – not currently allowed).
 
 # Guide-level explanation
 [guide-level-explanation]: #guide-level-explanation
@@ -26,7 +26,7 @@ Requiring to write `[MyType; 42]` for a 42-element array gets tedious,
 especially since the compiler already knows the size from the initializer. To
 reduce the strain, Rust allows you to omit the `42` in those type ascriptions.
 
-For example, you might write:
+For example, you can write:
 
 ```rust
 const CONST_CHARS: [u8; _] = *b"This is really a byte array";
@@ -38,6 +38,9 @@ fn main() {
 }
 ```
 
+In all other positions and on `let` bindings without initializer, the exact
+number keeps being required.
+
 # Reference-level explanation
 [reference-level-explanation]: #reference-level-explanation
 
@@ -46,41 +49,23 @@ its proposed form, there are no corner cases, because the only thing it enables
 that is currently disallowed is to put a `_` wildcard in place of the number of
 elements in array types in `let`s, `const`s and `static`s.
 
-In the parser, at the array length position, we must allow underscores. The AST
+In the parser, at the array length position, we allow underscores. The AST
 may need to be extended to allow underscore; In principle `AnonConst` can
 contain any expression, so `_` could be represented by a `Path`, or the whole
 `AnonConst` could be made `Option`al.
 
-At this point we should disallow a `None` value for `let` bindings without
-initializers or with initializers that are not `ExprKind::Repeat` or
+To ensure locality of reasoning, this RFC proposes a lint for `const` or
+`static` items with initializers other than `ExprKind::Repeat` or
 `ExprKind::Array`.
 
-At the lowering stage, the initializer is checked for the actual array length,
-and the `Ty` is constructed as if the size was given verbatim.
-
-## Error handling
-
-This change would introduce a new type of error, for statements that have no
-initializer or statics that introduce const functions (once they are stable).
-As outlined above, the latter would still need the correct type, though this is
-a small cost, as the type can likely be copied verbatim from the function.
-
-This RFC proposes showing an error message that restates the locality rule and
-suggests writing out the size (which can be inferred in the suggestion if
-possible). This might look like the following (mocked up here):
-
-```
-78: let x: [u32; _];
-                 ^ No initializer to take size from. Please write out the size.
-Suggestion: let x: [u32; 3];
-                         ~
-```
+The length can simply be inferred from the initializer. Care should be taken to 
+keep the error messages useful.
 
 # Drawbacks
 [drawbacks]: #drawbacks
 
 There is a modicum of complexity to extend the parser and AST which needs to be
-done for every Rust parser in existenct. However, the feature is minor, so the
+done for every Rust parser in existence. However, the feature is minor, so the
 cost should be acceptable.
 
 Also for longer array declarations the actual size may no longer be obvious
@@ -88,22 +73,24 @@ from the code. However, putting any probable or improbable length in and
 observing the compiler error (if any) is enough to find out; also the author
 hopes that the programmers will put in the lengths if they are essential.
 
+Finally, it's possible to add a clippy lint that suggests replacing the 
+underscore with the actual length.
+
 # Rationale and alternatives
 [rationale-and-alternatives]: #rationale-and-alternatives
 
-We could extend this to full inference, which would require us to set the size
-*after* lowering. This would make the feature more powerful, but reduce
-locality. For example if the array isn't initialized in the next 100 lines or
-is initialized from a `static`, or a `fn` that is far away in another module,
-changes to said item would lead to errors down the line that are needlessly
-hard to track down.
+This feature is very useful and has been requested numerous times. A draft of
+this RFC actually proposed a very resticted type of inference, which would
+however clash with RFC [#2000](https://github.com/rust-lang/rfcs/pull/2000).
+So the solution is to add the restriction as a lint (either in rustc or
+clippy).
 
 We could leave out the wildcard entirely, but `[u32; ]` looks strange and could
 possibly indicate an error, so it's better to use the more balanced `[u32; _]`.
 
 We could do nothing, and waste Rustacean's time by counting or parsing compiler
 errors (unless their accuracy of estimating array length is 100%. I'm sure mine
-isn't).
+isn't) or use a macro (see below).
 
 # Prior art
 [prior-art]: #prior-art
@@ -112,7 +99,11 @@ We already allow wildcard lifetimes, which have been beneficial. I'll defer to
 [RFC 2115](https://rust-lang.github.io/rfcs/2115-argument-lifetimes.html) for
 more information.
 
+Following the tradition of using macros to prototype language features, Alex
+Durka has built the [counted-array](https://crates.io/crates/counted-array)
+crate which contains a macro to enable the proposed syntax.
+
 # Unresolved questions
 [unresolved-questions]: #unresolved-questions
 
-None
+Bikeshedding the lint name