From 1d4ddab1bf5c523bdf6e3b7e9cff3c3224c6ed04 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 24 Jul 2022 22:26:44 +0900 Subject: [PATCH 1/3] suggest dereferencing index when trying to use a reference of usize as index --- .../src/traits/error_reporting/mod.rs | 1 + .../src/traits/error_reporting/suggestions.rs | 27 ++++++++++++++++ compiler/rustc_typeck/src/check/expr.rs | 13 ++++++++ src/test/ui/index-help.stderr | 4 +-- src/test/ui/indexing-requires-a-uint.stderr | 4 +-- src/test/ui/integral-indexing.stderr | 32 +++++++++---------- .../ui/on-unimplemented/slice-index.stderr | 8 ++--- src/test/ui/str/str-idx.stderr | 8 ++--- src/test/ui/str/str-mut-idx.stderr | 8 ++--- .../suggest-dereferencing-index.fixed | 7 ++++ .../suggest-dereferencing-index.rs | 7 ++++ .../suggest-dereferencing-index.stderr | 17 ++++++++++ 12 files changed, 104 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/suggestions/suggest-dereferencing-index.fixed create mode 100644 src/test/ui/suggestions/suggest-dereferencing-index.rs create mode 100644 src/test/ui/suggestions/suggest-dereferencing-index.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 2f92a77a795..1b7928a10bd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -534,6 +534,7 @@ fn report_selection_error( } self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); + self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); let mut suggested = self.suggest_dereferences(&obligation, &mut err, trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 7ab85e7fa66..c51f3dacd54 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -320,6 +320,13 @@ fn suggest_derive( err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ); + + fn suggest_dereferencing_index( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ); } fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { @@ -2927,6 +2934,26 @@ fn suggest_derive( ); } } + + fn suggest_dereferencing_index( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diagnostic, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) { + if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() + && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) + && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind() + && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind() + { + err.span_suggestion_verbose( + obligation.cause.span.shrink_to_lo(), + "consider dereferencing here", + '*', + Applicability::MaybeIncorrect, + ); + } + } } /// Collect all the returned expressions within the input expression. diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8e4cd2392e0..4c0a2bd9199 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2648,6 +2648,19 @@ fn check_expr_index( Some((index_ty, element_ty)) => { // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); + self.select_obligations_where_possible(false, |errors| { + for error in errors { + match error.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(predicate) + if self.tcx.is_diagnostic_item( + sym::SliceIndex, + predicate.trait_ref.def_id, + ) => {} + _ => continue, + } + error.obligation.cause.span = idx.span; + } + }); element_ty } None => { diff --git a/src/test/ui/index-help.stderr b/src/test/ui/index-help.stderr index 7f51a48111b..b36f4dab829 100644 --- a/src/test/ui/index-help.stderr +++ b/src/test/ui/index-help.stderr @@ -1,8 +1,8 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32` - --> $DIR/index-help.rs:3:5 + --> $DIR/index-help.rs:3:7 | LL | x[0i32]; - | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32` = help: the trait `SliceIndex<[T]>` is implemented for `usize` diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index 0a24855a6a7..fbff20f8dee 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -1,8 +1,8 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8` - --> $DIR/indexing-requires-a-uint.rs:6:5 + --> $DIR/indexing-requires-a-uint.rs:6:9 | LL | [0][0u8]; - | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8` = help: the trait `SliceIndex<[T]>` is implemented for `usize` diff --git a/src/test/ui/integral-indexing.stderr b/src/test/ui/integral-indexing.stderr index be3398552dc..3f9094d124e 100644 --- a/src/test/ui/integral-indexing.stderr +++ b/src/test/ui/integral-indexing.stderr @@ -1,78 +1,78 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` - --> $DIR/integral-indexing.rs:6:5 + --> $DIR/integral-indexing.rs:6:7 | LL | v[3u8]; - | ^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `u8` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `i8` - --> $DIR/integral-indexing.rs:7:5 + --> $DIR/integral-indexing.rs:7:7 | LL | v[3i8]; - | ^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `i8` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `u32` - --> $DIR/integral-indexing.rs:8:5 + --> $DIR/integral-indexing.rs:8:7 | LL | v[3u32]; - | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `u32` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `i32` - --> $DIR/integral-indexing.rs:9:5 + --> $DIR/integral-indexing.rs:9:7 | LL | v[3i32]; - | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[isize]>` is not implemented for `i32` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[u8]` cannot be indexed by `u8` - --> $DIR/integral-indexing.rs:12:5 + --> $DIR/integral-indexing.rs:12:18 | LL | s.as_bytes()[3u8]; - | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `u8` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `i8` - --> $DIR/integral-indexing.rs:13:5 + --> $DIR/integral-indexing.rs:13:18 | LL | s.as_bytes()[3i8]; - | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `i8` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `u32` - --> $DIR/integral-indexing.rs:14:5 + --> $DIR/integral-indexing.rs:14:18 | LL | s.as_bytes()[3u32]; - | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `u32` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `i32` - --> $DIR/integral-indexing.rs:15:5 + --> $DIR/integral-indexing.rs:15:18 | LL | s.as_bytes()[3i32]; - | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[u8]>` is not implemented for `i32` = help: the trait `SliceIndex<[T]>` is implemented for `usize` diff --git a/src/test/ui/on-unimplemented/slice-index.stderr b/src/test/ui/on-unimplemented/slice-index.stderr index ae7d2e1d823..72f67a68515 100644 --- a/src/test/ui/on-unimplemented/slice-index.stderr +++ b/src/test/ui/on-unimplemented/slice-index.stderr @@ -1,18 +1,18 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32` - --> $DIR/slice-index.rs:8:5 + --> $DIR/slice-index.rs:8:7 | LL | x[1i32]; - | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[i32]>` is not implemented for `i32` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index` for `[i32]` error[E0277]: the type `[i32]` cannot be indexed by `RangeTo` - --> $DIR/slice-index.rs:9:5 + --> $DIR/slice-index.rs:9:7 | LL | x[..1i32]; - | ^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` + | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo` = help: the following other types implement trait `SliceIndex`: diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr index 45450788b9c..9079a18d6a6 100644 --- a/src/test/ui/str/str-idx.stderr +++ b/src/test/ui/str/str-idx.stderr @@ -1,8 +1,8 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` - --> $DIR/str-idx.rs:3:17 + --> $DIR/str-idx.rs:3:19 | LL | let _: u8 = s[4]; - | ^^^^ string indices are ranges of `usize` + | ^ string indices are ranges of `usize` | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` @@ -47,10 +47,10 @@ LL | pub const unsafe fn get_unchecked>(&self, i: | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::::get_unchecked` error[E0277]: the type `str` cannot be indexed by `char` - --> $DIR/str-idx.rs:6:17 + --> $DIR/str-idx.rs:6:19 | LL | let _: u8 = s['c']; - | ^^^^^^ string indices are ranges of `usize` + | ^^^ string indices are ranges of `usize` | = help: the trait `SliceIndex` is not implemented for `char` = note: required because of the requirements on the impl of `Index` for `str` diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index 9ae08563027..2d062e56a9b 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -25,10 +25,10 @@ LL | s[1..2] = bot(); = note: the left-hand-side of an assignment must have a statically known size error[E0277]: the type `str` cannot be indexed by `usize` - --> $DIR/str-mut-idx.rs:7:5 + --> $DIR/str-mut-idx.rs:7:7 | LL | s[1usize] = bot(); - | ^^^^^^^^^ string indices are ranges of `usize` + | ^^^^^^ string indices are ranges of `usize` | = help: the trait `SliceIndex` is not implemented for `usize` = help: the trait `SliceIndex<[T]>` is implemented for `usize` @@ -71,10 +71,10 @@ LL | pub const unsafe fn get_unchecked_mut>( | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `core::str::::get_unchecked_mut` error[E0277]: the type `str` cannot be indexed by `char` - --> $DIR/str-mut-idx.rs:13:5 + --> $DIR/str-mut-idx.rs:13:7 | LL | s['c']; - | ^^^^^^ string indices are ranges of `usize` + | ^^^ string indices are ranges of `usize` | = help: the trait `SliceIndex` is not implemented for `char` = note: required because of the requirements on the impl of `Index` for `str` diff --git a/src/test/ui/suggestions/suggest-dereferencing-index.fixed b/src/test/ui/suggestions/suggest-dereferencing-index.fixed new file mode 100644 index 00000000000..dd4ae4eb14c --- /dev/null +++ b/src/test/ui/suggestions/suggest-dereferencing-index.fixed @@ -0,0 +1,7 @@ +// run-rustfix +#![allow(unused_variables)] + +fn main() { + let i: &usize = &1; + let one_item_please: i32 = [1, 2, 3][*i]; //~ ERROR the type `[{integer}]` cannot be indexed by `&usize` +} diff --git a/src/test/ui/suggestions/suggest-dereferencing-index.rs b/src/test/ui/suggestions/suggest-dereferencing-index.rs new file mode 100644 index 00000000000..82ebacc49f2 --- /dev/null +++ b/src/test/ui/suggestions/suggest-dereferencing-index.rs @@ -0,0 +1,7 @@ +// run-rustfix +#![allow(unused_variables)] + +fn main() { + let i: &usize = &1; + let one_item_please: i32 = [1, 2, 3][i]; //~ ERROR the type `[{integer}]` cannot be indexed by `&usize` +} diff --git a/src/test/ui/suggestions/suggest-dereferencing-index.stderr b/src/test/ui/suggestions/suggest-dereferencing-index.stderr new file mode 100644 index 00000000000..c0bb5044338 --- /dev/null +++ b/src/test/ui/suggestions/suggest-dereferencing-index.stderr @@ -0,0 +1,17 @@ +error[E0277]: the type `[{integer}]` cannot be indexed by `&usize` + --> $DIR/suggest-dereferencing-index.rs:6:42 + | +LL | let one_item_please: i32 = [1, 2, 3][i]; + | ^ slice indices are of type `usize` or ranges of `usize` + | + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize` + = help: the trait `SliceIndex<[T]>` is implemented for `usize` + = note: required because of the requirements on the impl of `Index<&usize>` for `[{integer}]` +help: consider dereferencing here + | +LL | let one_item_please: i32 = [1, 2, 3][*i]; + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 06f89b7924af4657e847742bf0e40eafaaee52f9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 29 Jul 2022 14:12:17 +0900 Subject: [PATCH 2/3] implement `point_at_index_if_possible` --- compiler/rustc_typeck/src/check/expr.rs | 28 +++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 4c0a2bd9199..b2a5c055e46 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2649,17 +2649,7 @@ fn check_expr_index( // two-phase not needed because index_ty is never mutable self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No); self.select_obligations_where_possible(false, |errors| { - for error in errors { - match error.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Trait(predicate) - if self.tcx.is_diagnostic_item( - sym::SliceIndex, - predicate.trait_ref.def_id, - ) => {} - _ => continue, - } - error.obligation.cause.span = idx.span; - } + self.point_at_index_if_possible(errors, idx.span) }); element_ty } @@ -2704,6 +2694,22 @@ fn check_expr_index( } } + fn point_at_index_if_possible( + &self, + errors: &mut Vec>, + span: Span, + ) { + for error in errors { + match error.obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Trait(predicate) + if self.tcx.is_diagnostic_item(sym::SliceIndex, predicate.trait_ref.def_id) => { + } + _ => continue, + } + error.obligation.cause.span = span; + } + } + fn check_expr_yield( &self, value: &'tcx hir::Expr<'tcx>, From 3ae669d758f7a7c0498d9208ef231718e50fb0ae Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 29 Jul 2022 14:12:37 +0900 Subject: [PATCH 3/3] check if T is slice fix msg --- .../src/traits/error_reporting/suggestions.rs | 5 +++-- src/test/ui/suggestions/suggest-dereferencing-index.stderr | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index c51f3dacd54..6ad7ee32a4f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2943,14 +2943,15 @@ fn suggest_dereferencing_index( ) { if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) + && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.substs.type_at(1).kind() && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind() && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind() { err.span_suggestion_verbose( obligation.cause.span.shrink_to_lo(), - "consider dereferencing here", + "dereference this index", '*', - Applicability::MaybeIncorrect, + Applicability::MachineApplicable, ); } } diff --git a/src/test/ui/suggestions/suggest-dereferencing-index.stderr b/src/test/ui/suggestions/suggest-dereferencing-index.stderr index c0bb5044338..c8b87af7bd8 100644 --- a/src/test/ui/suggestions/suggest-dereferencing-index.stderr +++ b/src/test/ui/suggestions/suggest-dereferencing-index.stderr @@ -7,7 +7,7 @@ LL | let one_item_please: i32 = [1, 2, 3][i]; = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize` = help: the trait `SliceIndex<[T]>` is implemented for `usize` = note: required because of the requirements on the impl of `Index<&usize>` for `[{integer}]` -help: consider dereferencing here +help: dereference this index | LL | let one_item_please: i32 = [1, 2, 3][*i]; | +