Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 142ad69

Browse files
Rollup merge of #146042 - estebank:issue-83413, r=lcnr
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 { | +++++ ``` Applying this suggestion will always end up in another E0308 error at the point where the unsigned inference comes from, which should help with understanding what the actual problem is. Fix #83413.
2 parents 5adc0fe + ea2daa3 commit 142ad69

File tree

6 files changed

+103
-27
lines changed

6 files changed

+103
-27
lines changed

‎compiler/rustc_hir_typeck/src/op.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -962,13 +962,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
962962
let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip();
963963
let cause = self.cause(
964964
span,
965-
ObligationCauseCode::BinOp {
966-
lhs_hir_id: lhs_expr.hir_id,
967-
rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id),
968-
rhs_span: opt_rhs_expr.map(|expr| expr.span),
969-
rhs_is_lit: opt_rhs_expr
970-
.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
971-
output_ty: expected.only_has_type(self),
965+
match opt_rhs_expr {
966+
Some(rhs) => ObligationCauseCode::BinOp {
967+
lhs_hir_id: lhs_expr.hir_id,
968+
rhs_hir_id: rhs.hir_id,
969+
rhs_span: rhs.span,
970+
rhs_is_lit: matches!(rhs.kind, hir::ExprKind::Lit(_)),
971+
output_ty: expected.only_has_type(self),
972+
},
973+
None => ObligationCauseCode::UnOp { hir_id: lhs_expr.hir_id },
972974
},
973975
);
974976

‎compiler/rustc_middle/src/traits/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,14 @@ pub enum ObligationCauseCode<'tcx> {
389389
/// against.
390390
MatchImpl(ObligationCause<'tcx>, DefId),
391391

392+
UnOp {
393+
hir_id: HirId,
394+
},
395+
392396
BinOp {
393397
lhs_hir_id: HirId,
394-
rhs_hir_id: Option<HirId>,
395-
rhs_span: Option<Span>,
398+
rhs_hir_id: HirId,
399+
rhs_span: Span,
396400
rhs_is_lit: bool,
397401
output_ty: Option<Ty<'tcx>>,
398402
},

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

Lines changed: 41 additions & 4 deletions
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::UnOp { hir_id, .. } = obligation.cause.code()
967+
&& let hir::Node::Expr(expr) = self.tcx.hir_node(*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 `?`.
@@ -2730,9 +2769,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
27302769
suggested: bool,
27312770
) {
27322771
let body_def_id = obligation.cause.body_id;
2733-
let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } =
2734-
obligation.cause.code()
2735-
{
2772+
let span = if let ObligationCauseCode::BinOp { rhs_span, .. } = obligation.cause.code() {
27362773
*rhs_span
27372774
} else {
27382775
span

‎compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
554554
return true;
555555
}
556556
} else if let (
557-
ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id:Some(rhs_hir_id), .. },
557+
ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. },
558558
predicate,
559559
) = code.peel_derives_with_predicate()
560560
&& let Some(typeck_results) = &self.typeck_results
@@ -2801,6 +2801,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
28012801
| ObligationCauseCode::QuestionMark
28022802
| ObligationCauseCode::CheckAssociatedTypeBounds { .. }
28032803
| ObligationCauseCode::LetElse
2804+
| ObligationCauseCode::UnOp { .. }
28042805
| ObligationCauseCode::BinOp { .. }
28052806
| ObligationCauseCode::AscribeUserTypeProvePredicate(..)
28062807
| ObligationCauseCode::AlwaysApplicableImpl
@@ -3839,9 +3840,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
38393840
trait_pred: ty::PolyTraitPredicate<'tcx>,
38403841
) {
38413842
let rhs_span = match obligation.cause.code() {
3842-
ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => {
3843-
span
3844-
}
3843+
ObligationCauseCode::BinOp { rhs_span, rhs_is_lit, .. } if *rhs_is_lit => rhs_span,
38453844
_ => return,
38463845
};
38473846
if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind()
@@ -5108,16 +5107,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
51085107
let tcx = self.tcx;
51095108
let predicate = predicate.upcast(tcx);
51105109
match *cause_code {
5111-
ObligationCauseCode::BinOp {
5112-
lhs_hir_id,
5113-
rhs_hir_id: Some(rhs_hir_id),
5114-
rhs_span: Some(rhs_span),
5115-
..
5116-
} if let Some(typeck_results) = &self.typeck_results
5117-
&& let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id)
5118-
&& let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id)
5119-
&& let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs)
5120-
&& let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) =>
5110+
ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, rhs_span, .. }
5111+
if let Some(typeck_results) = &self.typeck_results
5112+
&& let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id)
5113+
&& let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id)
5114+
&& let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs)
5115+
&& let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) =>
51215116
{
51225117
if let Some(pred) = predicate.as_trait_clause()
51235118
&& tcx.is_lang_item(pred.def_id(), LangItem::PartialEq)
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)

AltStyle によって変換されたページ (->オリジナル) /