Skip to content

Commit b285d68

Browse files
authored
Rollup merge of rust-lang#73334 - ayazhafiz:err/num-type-cannot-fit, r=estebank
Note numeric literals that can never fit in an expected type re rust-lang#72380 (comment) Given the toy code ```rust fn is_positive(n: usize) { n > -1_isize; } ``` We currently get a type mismatch error like the following: ``` error[E0308]: mismatched types --> src/main.rs:2:9 | 2 | n > -1_isize; | ^^^^^^^^ expected `usize`, found `isize` | help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit | 2 | n > (-1_isize).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` But clearly, `-1` can never fit into a `usize`, so the suggestion will always panic. A more useful message would tell the user that the value can never fit in the expected type: ``` error[E0308]: mismatched types --> test.rs:2:9 | 2 | n > -1_isize; | ^^^^^^^^ expected `usize`, found `isize` | note: `-1_isize` can never fit into `usize` --> test.rs:2:9 | 2 | n > -1_isize; | ^^^^^^^^ ``` Which is what this commit implements. I only added this check for negative literals because - Currently we can only perform such a check for literals (constant value propagation is outside the scope of the typechecker at this point) - A lint error for out-of-range numeric literals is already emitted IMO it makes more sense to put this check in librustc_lint, but as far as I can tell the typecheck pass happens before the lint pass, so I've added it here. r? @estebank
2 parents 058971c + 7a89a33 commit b285d68

File tree

4 files changed

+428
-1
lines changed

4 files changed

+428
-1
lines changed

src/librustc_typeck/check/demand.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
783783
let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
784784
if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
785785
};
786+
let is_negative_int =
787+
|expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..));
788+
let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..));
786789

787790
let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
788791

@@ -807,7 +810,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
807810
"you can convert `{}` from `{}` to `{}`, matching the type of `{}`",
808811
lhs_src, expected_ty, checked_ty, src
809812
);
810-
let suggestion = format!("{}::from({})", checked_ty, lhs_src,);
813+
let suggestion = format!("{}::from({})", checked_ty, lhs_src);
811814
(lhs_expr.span, msg, suggestion)
812815
} else {
813816
let msg = format!("{} and panic if the converted value wouldn't fit", msg);
@@ -822,8 +825,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
822825
|err: &mut DiagnosticBuilder<'_>,
823826
found_to_exp_is_fallible: bool,
824827
exp_to_found_is_fallible: bool| {
828+
let always_fallible = found_to_exp_is_fallible
829+
&& (exp_to_found_is_fallible || expected_ty_expr.is_none());
825830
let msg = if literal_is_ty_suffixed(expr) {
826831
&lit_msg
832+
} else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
833+
// We now know that converting either the lhs or rhs is fallible. Before we
834+
// suggest a fallible conversion, check if the value can never fit in the
835+
// expected type.
836+
let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty);
837+
err.note(&msg);
838+
return;
827839
} else if in_const_context {
828840
// Do not recommend `into` or `try_into` in const contexts.
829841
return;
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#[allow(unused_must_use)]
2+
fn main() {
3+
let x_usize: usize = 1;
4+
let x_u128: u128 = 2;
5+
let x_u64: u64 = 3;
6+
let x_u32: u32 = 4;
7+
let x_u16: u16 = 5;
8+
let x_u8: u8 = 6;
9+
10+
x_usize > -1_isize;
11+
//~^ ERROR mismatched types
12+
x_u128 > -1_isize;
13+
//~^ ERROR mismatched types
14+
x_u64 > -1_isize;
15+
//~^ ERROR mismatched types
16+
x_u32 > -1_isize;
17+
//~^ ERROR mismatched types
18+
x_u16 > -1_isize;
19+
//~^ ERROR mismatched types
20+
x_u8 > -1_isize;
21+
//~^ ERROR mismatched types
22+
23+
x_usize > -1_i128;
24+
//~^ ERROR mismatched types
25+
x_u128 > -1_i128;
26+
//~^ ERROR mismatched types
27+
x_u64 > -1_i128;
28+
//~^ ERROR mismatched types
29+
x_u32 > -1_i128;
30+
//~^ ERROR mismatched types
31+
x_u16 > -1_i128;
32+
//~^ ERROR mismatched types
33+
x_u8 > -1_i128;
34+
//~^ ERROR mismatched types
35+
36+
x_usize > -1_i64;
37+
//~^ ERROR mismatched types
38+
x_u128 > -1_i64;
39+
//~^ ERROR mismatched types
40+
x_u64 > -1_i64;
41+
//~^ ERROR mismatched types
42+
x_u32 > -1_i64;
43+
//~^ ERROR mismatched types
44+
x_u16 > -1_i64;
45+
//~^ ERROR mismatched types
46+
x_u8 > -1_i64;
47+
//~^ ERROR mismatched types
48+
49+
x_usize > -1_i32;
50+
//~^ ERROR mismatched types
51+
x_u128 > -1_i32;
52+
//~^ ERROR mismatched types
53+
x_u64 > -1_i32;
54+
//~^ ERROR mismatched types
55+
x_u32 > -1_i32;
56+
//~^ ERROR mismatched types
57+
x_u16 > -1_i32;
58+
//~^ ERROR mismatched types
59+
x_u8 > -1_i32;
60+
//~^ ERROR mismatched types
61+
62+
x_usize > -1_i16;
63+
//~^ ERROR mismatched types
64+
x_u128 > -1_i16;
65+
//~^ ERROR mismatched types
66+
x_u64 > -1_i16;
67+
//~^ ERROR mismatched types
68+
x_u32 > -1_i16;
69+
//~^ ERROR mismatched types
70+
x_u16 > -1_i16;
71+
//~^ ERROR mismatched types
72+
x_u8 > -1_i16;
73+
//~^ ERROR mismatched types
74+
75+
x_usize > -1_i8;
76+
//~^ ERROR mismatched types
77+
x_u128 > -1_i8;
78+
//~^ ERROR mismatched types
79+
x_u64 > -1_i8;
80+
//~^ ERROR mismatched types
81+
x_u32 > -1_i8;
82+
//~^ ERROR mismatched types
83+
x_u16 > -1_i8;
84+
//~^ ERROR mismatched types
85+
x_u8 > -1_i8;
86+
//~^ ERROR mismatched types
87+
}

0 commit comments

Comments
 (0)