Skip to content

Commit e77d163

Browse files
authored
Rollup merge of #89251 - estebank:negative-index-literals, r=davidtwco
Detect when negative literal indices are used and suggest appropriate code
2 parents 9593e61 + e19d82f commit e77d163

File tree

5 files changed

+136
-2
lines changed

5 files changed

+136
-2
lines changed

compiler/rustc_typeck/src/check/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2137,7 +2137,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21372137
idx_t
21382138
} else {
21392139
let base_t = self.structurally_resolved_type(base.span, base_t);
2140-
match self.lookup_indexing(expr, base, base_t, idx_t) {
2140+
match self.lookup_indexing(expr, base, base_t, idx, idx_t) {
21412141
Some((index_ty, element_ty)) => {
21422142
// two-phase not needed because index_ty is never mutable
21432143
self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);

compiler/rustc_typeck/src/check/place_op.rs

+56-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::check::method::MethodCallee;
22
use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
3+
use rustc_ast as ast;
4+
use rustc_errors::Applicability;
35
use rustc_hir as hir;
46
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
57
use rustc_infer::infer::InferOk;
@@ -47,6 +49,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
4749
expr: &hir::Expr<'_>,
4850
base_expr: &'tcx hir::Expr<'tcx>,
4951
base_ty: Ty<'tcx>,
52+
index_expr: &'tcx hir::Expr<'tcx>,
5053
idx_ty: Ty<'tcx>,
5154
) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
5255
// FIXME(#18741) -- this is almost but not quite the same as the
@@ -56,12 +59,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5659
let mut autoderef = self.autoderef(base_expr.span, base_ty);
5760
let mut result = None;
5861
while result.is_none() && autoderef.next().is_some() {
59-
result = self.try_index_step(expr, base_expr, &autoderef, idx_ty);
62+
result = self.try_index_step(expr, base_expr, &autoderef, idx_ty, index_expr);
6063
}
6164
self.register_predicates(autoderef.into_obligations());
6265
result
6366
}
6467

68+
fn negative_index(
69+
&self,
70+
ty: Ty<'tcx>,
71+
span: Span,
72+
base_expr: &hir::Expr<'_>,
73+
) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
74+
let ty = self.resolve_vars_if_possible(ty);
75+
let mut err = self.tcx.sess.struct_span_err(
76+
span,
77+
&format!("negative integers cannot be used to index on a `{}`", ty),
78+
);
79+
err.span_label(span, &format!("cannot use a negative integer for indexing on `{}`", ty));
80+
if let (hir::ExprKind::Path(..), Ok(snippet)) =
81+
(&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span))
82+
{
83+
// `foo[-1]` to `foo[foo.len() - 1]`
84+
err.span_suggestion_verbose(
85+
span.shrink_to_lo(),
86+
&format!(
87+
"to access an element starting from the end of the `{}`, compute the index",
88+
ty,
89+
),
90+
format!("{}.len() ", snippet),
91+
Applicability::MachineApplicable,
92+
);
93+
}
94+
err.emit();
95+
Some((self.tcx.ty_error(), self.tcx.ty_error()))
96+
}
97+
6598
/// To type-check `base_expr[index_expr]`, we progressively autoderef
6699
/// (and otherwise adjust) `base_expr`, looking for a type which either
67100
/// supports builtin indexing or overloaded indexing.
@@ -73,6 +106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
73106
base_expr: &hir::Expr<'_>,
74107
autoderef: &Autoderef<'a, 'tcx>,
75108
index_ty: Ty<'tcx>,
109+
index_expr: &hir::Expr<'_>,
76110
) -> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)> {
77111
let adjusted_ty =
78112
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
@@ -82,6 +116,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
82116
expr, base_expr, adjusted_ty, index_ty
83117
);
84118

119+
if let hir::ExprKind::Unary(
120+
hir::UnOp::Neg,
121+
hir::Expr {
122+
kind: hir::ExprKind::Lit(hir::Lit { node: ast::LitKind::Int(..), .. }),
123+
..
124+
},
125+
) = index_expr.kind
126+
{
127+
match adjusted_ty.kind() {
128+
ty::Adt(ty::AdtDef { did, .. }, _)
129+
if self.tcx.is_diagnostic_item(sym::vec_type, *did) =>
130+
{
131+
return self.negative_index(adjusted_ty, index_expr.span, base_expr);
132+
}
133+
ty::Slice(_) | ty::Array(_, _) => {
134+
return self.negative_index(adjusted_ty, index_expr.span, base_expr);
135+
}
136+
_ => {}
137+
}
138+
}
139+
85140
for unsize in [false, true] {
86141
let mut self_ty = adjusted_ty;
87142
if unsize {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run-rustfix
2+
3+
use std::ops::Index;
4+
struct X;
5+
impl Index<i32> for X {
6+
type Output = ();
7+
8+
fn index(&self, _: i32) -> &() {
9+
&()
10+
}
11+
}
12+
13+
fn main() {
14+
let x = vec![1, 2, 3];
15+
x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a
16+
let x = [1, 2, 3];
17+
x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a
18+
let x = &[1, 2, 3];
19+
x[x.len() -1]; //~ ERROR negative integers cannot be used to index on a
20+
let _ = x;
21+
X[-1];
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// run-rustfix
2+
3+
use std::ops::Index;
4+
struct X;
5+
impl Index<i32> for X {
6+
type Output = ();
7+
8+
fn index(&self, _: i32) -> &() {
9+
&()
10+
}
11+
}
12+
13+
fn main() {
14+
let x = vec![1, 2, 3];
15+
x[-1]; //~ ERROR negative integers cannot be used to index on a
16+
let x = [1, 2, 3];
17+
x[-1]; //~ ERROR negative integers cannot be used to index on a
18+
let x = &[1, 2, 3];
19+
x[-1]; //~ ERROR negative integers cannot be used to index on a
20+
let _ = x;
21+
X[-1];
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error: negative integers cannot be used to index on a `Vec<{integer}>`
2+
--> $DIR/negative-literal-index.rs:15:7
3+
|
4+
LL | x[-1];
5+
| ^^ cannot use a negative integer for indexing on `Vec<{integer}>`
6+
|
7+
help: to access an element starting from the end of the `Vec<{integer}>`, compute the index
8+
|
9+
LL | x[x.len() -1];
10+
| +++++++
11+
12+
error: negative integers cannot be used to index on a `[{integer}; 3]`
13+
--> $DIR/negative-literal-index.rs:17:7
14+
|
15+
LL | x[-1];
16+
| ^^ cannot use a negative integer for indexing on `[{integer}; 3]`
17+
|
18+
help: to access an element starting from the end of the `[{integer}; 3]`, compute the index
19+
|
20+
LL | x[x.len() -1];
21+
| +++++++
22+
23+
error: negative integers cannot be used to index on a `[{integer}; 3]`
24+
--> $DIR/negative-literal-index.rs:19:7
25+
|
26+
LL | x[-1];
27+
| ^^ cannot use a negative integer for indexing on `[{integer}; 3]`
28+
|
29+
help: to access an element starting from the end of the `[{integer}; 3]`, compute the index
30+
|
31+
LL | x[x.len() -1];
32+
| +++++++
33+
34+
error: aborting due to 3 previous errors
35+

0 commit comments

Comments
 (0)