From 4d1b5f0d997b567b558a3fb88bd4724ba6e32f32 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Tue, 16 Aug 2022 00:16:14 +0900 Subject: [PATCH] suggest adding an array length if possible --- compiler/rustc_ast_lowering/src/lib.rs | 4 +- compiler/rustc_errors/src/lib.rs | 1 + compiler/rustc_typeck/src/check/expr.rs | 41 ++++++++++++- .../suggest-array-length.fixed | 14 +++++ .../array-slice-vec/suggest-array-length.rs | 14 +++++ .../suggest-array-length.stderr | 60 +++++++++++++++++++ .../ui/async-await/issues/issue-95307.stderr | 12 ++-- ...ature-gate-generic_arg_infer.normal.stderr | 32 +++++----- 8 files changed, 153 insertions(+), 25 deletions(-) create mode 100644 src/test/ui/array-slice-vec/suggest-array-length.fixed create mode 100644 src/test/ui/array-slice-vec/suggest-array-length.rs create mode 100644 src/test/ui/array-slice-vec/suggest-array-length.stderr diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 38d30d0ffde..bf9034850c9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -49,7 +49,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, Applicability, Handler}; +use rustc_errors::{struct_span_err, Applicability, Handler, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; @@ -2236,7 +2236,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { c.value.span, "using `_` for array lengths is unstable", ) - .emit(); + .stash(c.value.span, StashKey::UnderscoreForArrayLengths); hir::ArrayLen::Body(self.lower_anon_const(c)) } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 15c1858023d..4d4d44580b7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -457,6 +457,7 @@ struct HandlerInner { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum StashKey { ItemNoType, + UnderscoreForArrayLengths, } fn default_track_diagnostic(_: &Diagnostic) {} diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 6a6c03a8cba..34cc5be8ad5 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -28,7 +28,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - ErrorGuaranteed, + ErrorGuaranteed, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -1307,7 +1307,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: expr.span, }) }; - self.tcx.mk_array(element_ty, args.len() as u64) + let array_len = args.len() as u64; + self.suggest_array_len(expr, array_len); + self.tcx.mk_array(element_ty, array_len) + } + + fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) { + if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(expr.hir_id) { + let ty = match self.tcx.hir().find(parent_hir_id) { + Some( + hir::Node::Local(hir::Local { ty: Some(ty), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }), + ) => Some(ty), + _ => None, + }; + if let Some(ty) = ty + && let hir::TyKind::Array(_, length) = ty.kind + && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length + && let Some(span) = self.tcx.hir().opt_span(hir_id) + { + match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { + Some(mut err) => { + err.span_suggestion_verbose( + span, + "consider adding an array length", + array_len, + Applicability::MaybeIncorrect, + ); + err.emit(); + } + None => () + } + } + } } fn check_expr_const_block( @@ -1333,10 +1365,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { element: &'tcx hir::Expr<'tcx>, count: &'tcx hir::ArrayLen, expected: Expectation<'tcx>, - _expr: &'tcx hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let count = self.array_length_to_const(count); + if let Some(count) = count.try_eval_usize(tcx, self.param_env) { + self.suggest_array_len(expr, count); + } let uty = match expected { ExpectHasType(uty) => match *uty.kind() { diff --git a/src/test/ui/array-slice-vec/suggest-array-length.fixed b/src/test/ui/array-slice-vec/suggest-array-length.fixed new file mode 100644 index 00000000000..bae3ab74af6 --- /dev/null +++ b/src/test/ui/array-slice-vec/suggest-array-length.fixed @@ -0,0 +1,14 @@ +// run-rustfix +#![allow(unused_variables, dead_code, non_upper_case_globals)] + +fn main() { + const Foo: [i32; 3] = [1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let foo: [i32; 3] = [1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let bar: [i32; 3] = [0; 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable +} diff --git a/src/test/ui/array-slice-vec/suggest-array-length.rs b/src/test/ui/array-slice-vec/suggest-array-length.rs new file mode 100644 index 00000000000..b0867f4e396 --- /dev/null +++ b/src/test/ui/array-slice-vec/suggest-array-length.rs @@ -0,0 +1,14 @@ +// run-rustfix +#![allow(unused_variables, dead_code, non_upper_case_globals)] + +fn main() { + const Foo: [i32; _] = [1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let foo: [i32; _] = [1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let bar: [i32; _] = [0; 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable +} diff --git a/src/test/ui/array-slice-vec/suggest-array-length.stderr b/src/test/ui/array-slice-vec/suggest-array-length.stderr new file mode 100644 index 00000000000..fdf6f82649a --- /dev/null +++ b/src/test/ui/array-slice-vec/suggest-array-length.stderr @@ -0,0 +1,60 @@ +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:8:20 + | +LL | let foo: [i32; _] = [1, 2, 3]; + | ^ `_` not allowed here + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:11:20 + | +LL | let bar: [i32; _] = [0; 3]; + | ^ `_` not allowed here + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:5:22 + | +LL | const Foo: [i32; _] = [1, 2, 3]; + | ^ `_` not allowed here + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:5:22 + | +LL | const Foo: [i32; _] = [1, 2, 3]; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable +help: consider adding an array length + | +LL | const Foo: [i32; 3] = [1, 2, 3]; + | ~ + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:8:20 + | +LL | let foo: [i32; _] = [1, 2, 3]; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable +help: consider adding an array length + | +LL | let foo: [i32; 3] = [1, 2, 3]; + | ~ + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:11:20 + | +LL | let bar: [i32; _] = [0; 3]; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable +help: consider adding an array length + | +LL | let bar: [i32; 3] = [0; 3]; + | ~ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/async-await/issues/issue-95307.stderr b/src/test/ui/async-await/issues/issue-95307.stderr index 60fca71eb4b..29aebb719d6 100644 --- a/src/test/ui/async-await/issues/issue-95307.stderr +++ b/src/test/ui/async-await/issues/issue-95307.stderr @@ -9,6 +9,12 @@ LL | async fn new() -> [u8; _]; = note: `async` trait functions are not currently supported = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/issue-95307.rs:7:28 + | +LL | async fn new() -> [u8; _]; + | ^ `_` not allowed here + error[E0658]: using `_` for array lengths is unstable --> $DIR/issue-95307.rs:7:28 | @@ -18,12 +24,6 @@ LL | async fn new() -> [u8; _]; = note: see issue #85077 for more information = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable -error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/issue-95307.rs:7:28 - | -LL | async fn new() -> [u8; _]; - | ^ `_` not allowed here - error: aborting due to 3 previous errors Some errors have detailed explanations: E0658, E0706. diff --git a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr index 49eede4794b..4fca436827e 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr @@ -1,18 +1,15 @@ -error[E0658]: using `_` for array lengths is unstable - --> $DIR/feature-gate-generic_arg_infer.rs:11:27 - | -LL | let _x: [u8; 3] = [0; _]; - | ^ - | - = note: see issue #85077 for more information - = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable - error: in expressions, `_` can only be used on the left-hand side of an assignment --> $DIR/feature-gate-generic_arg_infer.rs:11:27 | LL | let _x: [u8; 3] = [0; _]; | ^ `_` not allowed here +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/feature-gate-generic_arg_infer.rs:14:18 + | +LL | let _y: [u8; _] = [0; 3]; + | ^ `_` not allowed here + error[E0658]: using `_` for array lengths is unstable --> $DIR/feature-gate-generic_arg_infer.rs:14:18 | @@ -21,12 +18,10 @@ LL | let _y: [u8; _] = [0; 3]; | = note: see issue #85077 for more information = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable - -error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/feature-gate-generic_arg_infer.rs:14:18 +help: consider adding an array length | -LL | let _y: [u8; _] = [0; 3]; - | ^ `_` not allowed here +LL | let _y: [u8; 3] = [0; 3]; + | ~ error[E0747]: type provided when a constant was expected --> $DIR/feature-gate-generic_arg_infer.rs:20:20 @@ -37,6 +32,15 @@ LL | let _x = foo::<_>([1,2]); = help: const arguments cannot yet be inferred with `_` = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable +error[E0658]: using `_` for array lengths is unstable + --> $DIR/feature-gate-generic_arg_infer.rs:11:27 + | +LL | let _x: [u8; 3] = [0; _]; + | ^ + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + error: aborting due to 5 previous errors Some errors have detailed explanations: E0658, E0747.