Skip to content

Commit 18a36bc

Browse files
committed
Detect negative literal inferred to unsigned integer
``` error[E0277]: the trait bound `usize: Neg` is not satisfied --> $DIR/negative-literal-infered-to-unsigned.rs:2:14 | LL | for x in -5..5 { | ^^ the trait `Neg` is not implemented for `usize` | help: consider specifying an integer type that can be negative | LL | for x in -5isize..5 { | +++++ ```
1 parent fe55364 commit 18a36bc

File tree

3 files changed

+78
-1
lines changed

3 files changed

+78
-1
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use std::borrow::Cow;
33
use std::path::PathBuf;
44

55
use rustc_abi::ExternAbi;
6-
use rustc_ast::TraitObjectSyntax;
6+
use rustc_ast::ast::LitKind;
7+
use rustc_ast::{LitIntType, TraitObjectSyntax};
78
use rustc_data_structures::fx::FxHashMap;
89
use rustc_data_structures::unord::UnordSet;
910
use rustc_errors::codes::*;
@@ -280,6 +281,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
280281
(suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
281282
}
282283

284+
suggested |= self.detect_negative_literal(
285+
&obligation,
286+
main_trait_predicate,
287+
&mut err,
288+
);
289+
283290
if let Some(ret_span) = self.return_type_span(&obligation) {
284291
if is_try_conversion {
285292
let ty = self.tcx.short_string(
@@ -950,6 +957,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
950957
Ok(())
951958
}
952959

960+
fn detect_negative_literal(
961+
&self,
962+
obligation: &PredicateObligation<'tcx>,
963+
trait_pred: ty::PolyTraitPredicate<'tcx>,
964+
err: &mut Diag<'_>,
965+
) -> bool {
966+
if let ObligationCauseCode::BinOp { lhs_hir_id, .. } = obligation.cause.code()
967+
&& let hir::Node::Expr(expr) = self.tcx.hir_node(*lhs_hir_id)
968+
&& let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = expr.kind
969+
&& let hir::ExprKind::Lit(lit) = inner.kind
970+
&& let LitKind::Int(_, LitIntType::Unsuffixed) = lit.node
971+
{
972+
err.span_suggestion_verbose(
973+
lit.span.shrink_to_hi(),
974+
"consider specifying an integer type that can be negative",
975+
match trait_pred.skip_binder().self_ty().kind() {
976+
ty::Uint(ty::UintTy::Usize) => "isize",
977+
ty::Uint(ty::UintTy::U8) => "i8",
978+
ty::Uint(ty::UintTy::U16) => "i16",
979+
ty::Uint(ty::UintTy::U32) => "i32",
980+
ty::Uint(ty::UintTy::U64) => "i64",
981+
ty::Uint(ty::UintTy::U128) => "i128",
982+
_ => "i64",
983+
}
984+
.to_string(),
985+
Applicability::MaybeIncorrect,
986+
);
987+
return true;
988+
}
989+
false
990+
}
991+
953992
/// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
954993
/// identify those method chain sub-expressions that could or could not have been annotated
955994
/// with `?`.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn main() {
2+
for x in -5..5 {
3+
//~^ ERROR: the trait bound `usize: Neg` is not satisfied
4+
//~| HELP: consider specifying an integer type that can be negative
5+
do_something(x);
6+
}
7+
let x = -5;
8+
//~^ ERROR: the trait bound `usize: Neg` is not satisfied
9+
//~| HELP: consider specifying an integer type that can be negative
10+
do_something(x);
11+
}
12+
13+
fn do_something(_val: usize) {}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0277]: the trait bound `usize: Neg` is not satisfied
2+
--> $DIR/negative-literal-infered-to-unsigned.rs:2:14
3+
|
4+
LL | for x in -5..5 {
5+
| ^^ the trait `Neg` is not implemented for `usize`
6+
|
7+
help: consider specifying an integer type that can be negative
8+
|
9+
LL | for x in -5isize..5 {
10+
| +++++
11+
12+
error[E0277]: the trait bound `usize: Neg` is not satisfied
13+
--> $DIR/negative-literal-infered-to-unsigned.rs:7:13
14+
|
15+
LL | let x = -5;
16+
| ^^ the trait `Neg` is not implemented for `usize`
17+
|
18+
help: consider specifying an integer type that can be negative
19+
|
20+
LL | let x = -5isize;
21+
| +++++
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)