]> git.lizzy.rs Git - rust.git/commitdiff
implement `generic_arg_infer` for array lengths
authorlcnr <rust@lcnr.de>
Thu, 23 Dec 2021 09:01:51 +0000 (10:01 +0100)
committerlcnr <rust@lcnr.de>
Thu, 23 Dec 2021 09:09:35 +0000 (10:09 +0100)
21 files changed:
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr [new file with mode: 0644]
src/test/ui/inference/infer-arg-test.rs [deleted file]
src/test/ui/inference/infer-arg-test.stderr [deleted file]

index 6ee1dbe4ae3eebee5781aedd0d3454379c811d16..75f384405bb2b5c434940ae89f634d5a6aea57d5 100644 (file)
@@ -34,7 +34,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = self.lower_expr(expr);
-                    let count = self.lower_anon_const(count);
+                    let count = self.lower_array_length(count);
                     hir::ExprKind::Repeat(expr, count)
                 }
                 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
index 77738b2c5cc75dce4969cea76fa81cee12ec31e5..35eb716949a13ccf38368ef890119a70e14a3854 100644 (file)
@@ -56,6 +56,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::LintBuffer;
+use rustc_session::parse::feature_err;
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
@@ -1248,7 +1249,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                 ))
             }
             TyKind::Array(ref ty, ref length) => {
-                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
+                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
             }
             TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
             TyKind::TraitObject(ref bounds, kind) => {
@@ -2039,6 +2040,26 @@ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
         self.expr_block(block, AttrVec::new())
     }
 
+    fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+        match c.value.kind {
+            ExprKind::Underscore => {
+                if self.sess.features_untracked().generic_arg_infer {
+                    hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+                } else {
+                    feature_err(
+                        &self.sess.parse_sess,
+                        sym::generic_arg_infer,
+                        c.value.span,
+                        "using `_` for array lengths is unstable",
+                    )
+                    .emit();
+                    hir::ArrayLen::Body(self.lower_anon_const(c))
+                }
+            }
+            _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+        }
+    }
+
     fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
         self.with_new_scopes(|this| hir::AnonConst {
             hir_id: this.lower_node_id(c.id),
index 69572807e7c9d6cf87853dfa842bbe52849dec64..698472565fbfaa76ef4d909839d06657be9fe102 100644 (file)
@@ -1407,6 +1407,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// A literal.
 pub type Lit = Spanned<LitKind>;
 
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+pub enum ArrayLen {
+    Infer(HirId, Span),
+    Body(AnonConst),
+}
+
+impl ArrayLen {
+    pub fn hir_id(&self) -> HirId {
+        match self {
+            &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id,
+        }
+    }
+}
+
 /// A constant (expression) that's not an item or associated item,
 /// but needs its own `DefId` for type-checking, const-eval, etc.
 /// These are usually found nested inside types (e.g., array lengths)
@@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> {
     ///
     /// E.g., `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
-    Repeat(&'hir Expr<'hir>, AnonConst),
+    Repeat(&'hir Expr<'hir>, ArrayLen),
 
     /// A suspension point for generators (i.e., `yield <expr>`).
     Yield(&'hir Expr<'hir>, YieldSource),
@@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> {
     /// A variable length slice (i.e., `[T]`).
     Slice(&'hir Ty<'hir>),
     /// A fixed length array (i.e., `[T; n]`).
-    Array(&'hir Ty<'hir>, AnonConst),
+    Array(&'hir Ty<'hir>, ArrayLen),
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
index 0fab7cbfeea3472a3d2758f987ba4c0e1304d84f..d0eee422202afff8a23a2e114c42c013f0859749 100644 (file)
@@ -383,6 +383,9 @@ fn visit_arm(&mut self, a: &'v Arm<'v>) {
     fn visit_pat(&mut self, p: &'v Pat<'v>) {
         walk_pat(self, p)
     }
+    fn visit_array_length(&mut self, len: &'v ArrayLen) {
+        walk_array_len(self, len)
+    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         }
         TyKind::Array(ref ty, ref length) => {
             visitor.visit_ty(ty);
-            visitor.visit_anon_const(length)
+            visitor.visit_array_length(length)
         }
         TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
             for bound in bounds {
@@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
     }
 }
 
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+    match len {
+        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+        ArrayLen::Body(c) => visitor.visit_anon_const(c),
+    }
+}
+
 pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
     visitor.visit_id(constant.hir_id);
     visitor.visit_nested_body(constant.body);
@@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
         ExprKind::Repeat(ref element, ref count) => {
             visitor.visit_expr(element);
-            visitor.visit_anon_const(count)
+            visitor.visit_array_length(count)
         }
         ExprKind::Struct(ref qpath, fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.hir_id, expression.span);
index 2f5f158856f1e68f4d0270240bee0aaf0d9f5dfc..54ee553a4f66a939e91d8b9e75b3aec2ddf9d15b 100644 (file)
@@ -358,7 +358,7 @@ pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
                 self.word("[");
                 self.print_type(&ty);
                 self.word("; ");
-                self.print_anon_const(length);
+                self.print_array_length(length);
                 self.word("]");
             }
             hir::TyKind::Typeof(ref e) => {
@@ -1065,6 +1065,13 @@ pub fn print_if(
         self.print_else(elseopt)
     }
 
+    pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
+        match len {
+            hir::ArrayLen::Infer(_, _) => self.word("_"),
+            hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
+        }
+    }
+
     pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
         self.ann.nested(self, Nested::Body(constant.body))
     }
@@ -1140,12 +1147,12 @@ fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
         self.end()
     }
 
-    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
+    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
         self.ibox(INDENT_UNIT);
         self.word("[");
         self.print_expr(element);
         self.word_space(";");
-        self.print_anon_const(count);
+        self.print_array_length(count);
         self.word("]");
         self.end()
     }
index 092fe131174703b32343eb75f608ed07900fd302..bdde6b4a356c195206cb146b006d1df6946aa919 100644 (file)
@@ -583,9 +583,12 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                 ExprKind::ConstBlock { value }
             }
             // Now comes the rote stuff:
-            hir::ExprKind::Repeat(ref v, ref count) => {
-                let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
-                let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+            hir::ExprKind::Repeat(ref v, _) => {
+                let ty = self.typeck_results().expr_ty(expr);
+                let count = match ty.kind() {
+                    ty::Array(_, ct) => ct,
+                    _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
+                };
 
                 ExprKind::Repeat { value: self.mirror_expr(v), count }
             }
index f1a5282b08871323aa2b0a18be0103481ae1fffd..23f5b17fa78893187e796d3fe5c5fa452041cb27 100644 (file)
@@ -1326,12 +1326,18 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
                 }
                 intravisit::walk_qpath(self, path, t.hir_id, t.span);
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 self.visit_ty(ty);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
                 let item = self.tcx.hir().item(item_id);
@@ -1390,12 +1396,18 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     v.visit_expr(&body.value)
                 });
             }
-            hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+            hir::ExprKind::Repeat(ref expr, ref length) => {
                 self.visit_expr(expr);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             // In particular, we take this branch for call and path expressions,
             // where we'll index the idents involved just by continuing to walk.
index e43344ad6d9eff888d516d082d52d2cec971fe67..5d0de4441992a03224776e4661e600bae07a8881 100644 (file)
@@ -310,9 +310,13 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 let nested = bounds_to_string(&bounds);
                 Ok(text_sig(nested))
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 let nested_ty = ty.make(offset + 1, id, scx)?;
-                let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
+                let hir_id = match length {
+                    &hir::ArrayLen::Infer(hir_id, _) => hir_id,
+                    hir::ArrayLen::Body(anon_const) => anon_const.hir_id,
+                };
+                let expr = id_to_string(&scx.tcx.hir(), hir_id).replace('\n', " ");
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
index caa5c71e21cd940525ff88bae9411e9a08b724be..956696546da8ef9a9298bab17427d54f17c522ca 100644 (file)
@@ -104,7 +104,7 @@ fn generic_arg_mismatch_err(
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
             ) if tcx.type_of(param.def_id) == tcx.types.usize => {
-                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
                 if let Ok(snippet) = snippet {
                     err.span_suggestion(
                         arg.span(),
index 8db706c3709c1451767dd68a37bc67a53b9318e9..8226ffbccc4316a53244c4facc3f6243cd0915ee 100644 (file)
@@ -2363,8 +2363,14 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                 self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
             }
             hir::TyKind::Array(ref ty, ref length) => {
-                let length_def_id = tcx.hir().local_def_id(length.hir_id);
-                let length = ty::Const::from_anon_const(tcx, length_def_id);
+                let length = match length {
+                    &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+                    hir::ArrayLen::Body(constant) => {
+                        let length_def_id = tcx.hir().local_def_id(constant.hir_id);
+                        ty::Const::from_anon_const(tcx, length_def_id)
+                    }
+                };
+
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
index 096c4fcf472075ed92f463d408cfd651608c2883..ea46478450977598ca7348fdca11f41d862a5268 100644 (file)
@@ -1238,12 +1238,12 @@ fn check_expr_const_block(
     fn check_expr_repeat(
         &self,
         element: &'tcx hir::Expr<'tcx>,
-        count: &'tcx hir::AnonConst,
+        count: &'tcx hir::ArrayLen,
         expected: Expectation<'tcx>,
         _expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count = self.to_const(count);
+        let count = self.array_length_to_const(count);
 
         let uty = match expected {
             ExpectHasType(uty) => match *uty.kind() {
index 67630fd4e582bd24c1084df4ed781f40f082beab..1aca2911533ad0d8af297a55205011aca1bffe71 100644 (file)
@@ -498,6 +498,13 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         ty
     }
 
+    pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+        match length {
+            &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
+            hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
+        }
+    }
+
     pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
index e7b728d491b67d4a0f984522db46c5512f2a0dfd..dc303ad5e04f2c447a4bc38f0f1c6535a1f5ab21 100644 (file)
@@ -182,7 +182,7 @@ struct CollectItemTypesVisitor<'tcx> {
         sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
+    let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -314,8 +314,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-fn bad_placeholder_type<'tcx>(
+fn bad_placeholder<'tcx>(
     tcx: TyCtxt<'tcx>,
+    placeholder_kind: &'static str,
     mut spans: Vec<Span>,
     kind: &'static str,
 ) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -326,7 +327,8 @@ fn bad_placeholder_type<'tcx>(
         tcx.sess,
         spans.clone(),
         E0121,
-        "the type placeholder `_` is not allowed within types on item signatures for {}",
+        "the {} placeholder `_` is not allowed within types on item signatures for {}",
+        placeholder_kind,
         kind
     );
     for span in spans {
@@ -393,7 +395,7 @@ fn ct_infer(
         _: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> &'tcx Const<'tcx> {
-        bad_placeholder_type(self.tcx(), vec![span], "generic").emit();
+        bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
         // Typeck doesn't expect erased regions to be returned from `type_of`.
         let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
             ty::ReErased => self.tcx.lifetimes.re_static,
@@ -1482,7 +1484,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
                     // as they shouldn't be able to cause query cycle errors.
                     Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                        if constant.hir_id() == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
                         if constant.hir_id == hir_id =>
                     {
                         Some(parent_def_id.to_def_id())
@@ -1788,7 +1794,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
 
                     let mut visitor = PlaceholderHirTyCollector::default();
                     visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
+                    let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
                     let ret_ty = fn_sig.skip_binder().output();
                     if !ret_ty.references_error() {
                         if !ret_ty.is_closure() {
index 99fddcb00ceca52b2a2994e8c16a174d4b5d8a62..04e887bf7420f80a893c6856af57b133a8e9e653 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_span::{Span, DUMMY_SP};
 
 use super::ItemCtxt;
-use super::{bad_placeholder_type, is_suggestable_infer_ty};
+use super::{bad_placeholder, is_suggestable_infer_ty};
 
 /// Computes the relevant generic parameter for a potential generic const argument.
 ///
@@ -490,7 +490,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
                 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    if constant.hir_id == hir_id =>
+                    if constant.hir_id() == hir_id =>
                 {
                     tcx.types.usize
                 }
@@ -788,7 +788,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             err.emit();
         }
         None => {
-            let mut diag = bad_placeholder_type(tcx, vec![span], kind);
+            let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs
new file mode 100644 (file)
index 0000000..56b88a4
--- /dev/null
@@ -0,0 +1,12 @@
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; _] {
+    //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics
+    // FIXME(generic_arg_infer): this error message should say in the return type or sth like that.
+    [0; 3]
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr
new file mode 100644 (file)
index 0000000..eaa12b4
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics
+  --> $DIR/array-in-sig.rs:4:18
+   |
+LL | fn foo() -> [u8; _] {
+   |                  ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs
new file mode 100644 (file)
index 0000000..d3e53d7
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; 3] {
+    let x: [u8; _] = [0; _];
+    x
+}
+
+fn main() {
+    assert_eq!([0; _], foo());
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs
new file mode 100644 (file)
index 0000000..29aa0f5
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(generic_arg_infer)]
+
+struct All<'a, T, const N: usize> {
+  v: &'a T,
+}
+
+struct BadInfer<_>;
+//~^ ERROR expected identifier
+//~| ERROR parameter `_` is never used
+
+fn all_fn<'a, T, const N: usize>() {}
+
+fn bad_infer_fn<_>() {}
+//~^ ERROR expected identifier
+
+
+fn main() {
+  let a: All<_, _, _>;
+  all_fn();
+  let v: [u8; _];
+  let v: [u8; 10] = [0; _];
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
new file mode 100644 (file)
index 0000000..e6d0c74
--- /dev/null
@@ -0,0 +1,24 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/infer-arg-test.rs:7:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/infer-arg-test.rs:13:17
+   |
+LL | fn bad_infer_fn<_>() {}
+   |                 ^ expected identifier, found reserved identifier
+
+error[E0392]: parameter `_` is never used
+  --> $DIR/infer-arg-test.rs:7:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ unused parameter
+   |
+   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/inference/infer-arg-test.rs b/src/test/ui/inference/infer-arg-test.rs
deleted file mode 100644 (file)
index 1b67ccd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(generic_arg_infer)]
-
-struct All<'a, T, const N: usize> {
-  v: &'a T,
-}
-
-struct BadInfer<_>;
-//~^ ERROR expected identifier
-//~| ERROR parameter `_` is never used
-
-fn all_fn<'a, T, const N: usize>() {}
-
-fn bad_infer_fn<_>() {}
-//~^ ERROR expected identifier
-
-
-fn main() {
-  let a: All<_, _, _>;
-  all_fn();
-  let v: [u8; _];
-  //~^ ERROR in expressions
-  let v: [u8; 10] = [0; _];
-  //~^ ERROR in expressions
-}
diff --git a/src/test/ui/inference/infer-arg-test.stderr b/src/test/ui/inference/infer-arg-test.stderr
deleted file mode 100644 (file)
index 30e171e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/infer-arg-test.rs:7:17
-   |
-LL | struct BadInfer<_>;
-   |                 ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/infer-arg-test.rs:13:17
-   |
-LL | fn bad_infer_fn<_>() {}
-   |                 ^ expected identifier, found reserved identifier
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/infer-arg-test.rs:20:15
-   |
-LL |   let v: [u8; _];
-   |               ^ `_` not allowed here
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/infer-arg-test.rs:22:25
-   |
-LL |   let v: [u8; 10] = [0; _];
-   |                         ^ `_` not allowed here
-
-error[E0392]: parameter `_` is never used
-  --> $DIR/infer-arg-test.rs:7:17
-   |
-LL | struct BadInfer<_>;
-   |                 ^ unused parameter
-   |
-   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0392`.