Skip to content

Commit

Permalink
Suggest the correct array length on mismatch
Browse files Browse the repository at this point in the history
  • Loading branch information
clubby789 committed Feb 12, 2023
1 parent 71f6675 commit 903ca87
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 2 deletions.
65 changes: 65 additions & 0 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::Node;
use rustc_middle::dep_graph::DepContext;
Expand Down Expand Up @@ -1975,6 +1976,70 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(ty::Bool, ty::Tuple(list)) => if list.len() == 0 {
self.suggest_let_for_letchains(&mut err, &trace.cause, span);
}
(ty::Array(_, _), ty::Array(_, _)) => 'block: {
let hir = self.tcx.hir();
let TypeError::FixedArraySize(sz) = terr else {
break 'block;
};
let tykind = match hir.find_by_def_id(trace.cause.body_id) {
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, body_id),
..
})) => {
let body = hir.body(*body_id);
struct LetVisitor<'v> {
span: Span,
result: Option<&'v hir::Ty<'v>>,
}
impl<'v> Visitor<'v> for LetVisitor<'v> {
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
if self.result.is_some() {
return;
}
// Find a local statement where the initializer has
// the same span as the error and the type is specified.
if let hir::Stmt {
kind: hir::StmtKind::Local(hir::Local {
init: Some(hir::Expr {
span: init_span,
..
}),
ty: Some(array_ty),
..
}),
..
} = s
&& init_span == &self.span {
self.result = Some(*array_ty);
}
}
}
let mut visitor = LetVisitor {span, result: None};
visitor.visit_body(body);
visitor.result.map(|r| &r.peel_refs().kind)
}
Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Const(ty, _),
..
})) => {
Some(&ty.peel_refs().kind)
}
_ => None
};

if let Some(tykind) = tykind
&& let hir::TyKind::Array(_, length) = tykind
&& let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
&& let Some(span) = self.tcx.hir().opt_span(*hir_id)
{
err.span_suggestion(
span,
"consider specifying the actual array length",
sz.found,
Applicability::MaybeIncorrect,
);
}
}
_ => {}
}
}
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/consts/array-literal-len-mismatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const NUMBERS: [u8; 3] = [10, 20];
//~^ ERROR mismatched types
//~^^ HELP consider specifying the actual array length
fn main() {}
11 changes: 11 additions & 0 deletions tests/ui/consts/array-literal-len-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/array-literal-len-mismatch.rs:1:26
|
LL | const NUMBERS: [u8; 3] = [10, 20];
| - ^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| |
| help: consider specifying the actual array length: `2`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
8 changes: 6 additions & 2 deletions tests/ui/consts/const-array-oob-arith.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ error[E0308]: mismatched types
--> $DIR/const-array-oob-arith.rs:5:45
|
LL | const BLUB: [i32; (ARR[0] - 40) as usize] = [5];
| ^^^ expected an array with a fixed size of 2 elements, found one with 1 element
| ---------------------- ^^^ expected an array with a fixed size of 2 elements, found one with 1 element
| |
| help: consider specifying the actual array length: `1`

error[E0308]: mismatched types
--> $DIR/const-array-oob-arith.rs:8:44
|
LL | const BOO: [i32; (ARR[0] - 41) as usize] = [5, 99];
| ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements
| ---------------------- ^^^^^^^ expected an array with a fixed size of 1 element, found one with 2 elements
| |
| help: consider specifying the actual array length: `2`

error: aborting due to 2 previous errors

Expand Down
12 changes: 12 additions & 0 deletions tests/ui/inference/array-len-mismatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn returns_arr() -> [u8; 2] {
[1, 2]
}

fn main() {
let wrong: [u8; 3] = [10, 20];
//~^ ERROR mismatched types
//~^^ HELP consider specifying the actual array length
let wrong: [u8; 3] = returns_arr();
//~^ ERROR mismatched types
//~^^ HELP consider specifying the actual array length
}
21 changes: 21 additions & 0 deletions tests/ui/inference/array-len-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
error[E0308]: mismatched types
--> $DIR/array-len-mismatch.rs:6:26
|
LL | let wrong: [u8; 3] = [10, 20];
| ------- ^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| | |
| | help: consider specifying the actual array length: `2`
| expected due to this

error[E0308]: mismatched types
--> $DIR/array-len-mismatch.rs:9:26
|
LL | let wrong: [u8; 3] = returns_arr();
| ------- ^^^^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements
| | |
| | help: consider specifying the actual array length: `2`
| expected due to this

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 903ca87

Please sign in to comment.