Skip to content

Commit b285d68

Browse files
authoredJun 19, 2020
Rollup merge of #73334 - ayazhafiz:err/num-type-cannot-fit, r=estebank
Note numeric literals that can never fit in an expected type re #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

Lines changed: 13 additions & 1 deletion
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;
Lines changed: 87 additions & 0 deletions
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+
}
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/numeric-cast-no-fix.rs:10:15
3+
|
4+
LL | x_usize > -1_isize;
5+
| ^^^^^^^^ expected `usize`, found `isize`
6+
|
7+
= note: `-1_isize` cannot fit into type `usize`
8+
9+
error[E0308]: mismatched types
10+
--> $DIR/numeric-cast-no-fix.rs:12:14
11+
|
12+
LL | x_u128 > -1_isize;
13+
| ^^^^^^^^ expected `u128`, found `isize`
14+
|
15+
= note: `-1_isize` cannot fit into type `u128`
16+
17+
error[E0308]: mismatched types
18+
--> $DIR/numeric-cast-no-fix.rs:14:13
19+
|
20+
LL | x_u64 > -1_isize;
21+
| ^^^^^^^^ expected `u64`, found `isize`
22+
|
23+
= note: `-1_isize` cannot fit into type `u64`
24+
25+
error[E0308]: mismatched types
26+
--> $DIR/numeric-cast-no-fix.rs:16:13
27+
|
28+
LL | x_u32 > -1_isize;
29+
| ^^^^^^^^ expected `u32`, found `isize`
30+
|
31+
= note: `-1_isize` cannot fit into type `u32`
32+
33+
error[E0308]: mismatched types
34+
--> $DIR/numeric-cast-no-fix.rs:18:13
35+
|
36+
LL | x_u16 > -1_isize;
37+
| ^^^^^^^^ expected `u16`, found `isize`
38+
|
39+
= note: `-1_isize` cannot fit into type `u16`
40+
41+
error[E0308]: mismatched types
42+
--> $DIR/numeric-cast-no-fix.rs:20:12
43+
|
44+
LL | x_u8 > -1_isize;
45+
| ^^^^^^^^ expected `u8`, found `isize`
46+
|
47+
help: you can convert `x_u8` from `u8` to `isize`, matching the type of `-1_isize`
48+
|
49+
LL | isize::from(x_u8) > -1_isize;
50+
| ^^^^^^^^^^^^^^^^^
51+
52+
error[E0308]: mismatched types
53+
--> $DIR/numeric-cast-no-fix.rs:23:15
54+
|
55+
LL | x_usize > -1_i128;
56+
| ^^^^^^^ expected `usize`, found `i128`
57+
|
58+
= note: `-1_i128` cannot fit into type `usize`
59+
60+
error[E0308]: mismatched types
61+
--> $DIR/numeric-cast-no-fix.rs:25:14
62+
|
63+
LL | x_u128 > -1_i128;
64+
| ^^^^^^^ expected `u128`, found `i128`
65+
|
66+
= note: `-1_i128` cannot fit into type `u128`
67+
68+
error[E0308]: mismatched types
69+
--> $DIR/numeric-cast-no-fix.rs:27:13
70+
|
71+
LL | x_u64 > -1_i128;
72+
| ^^^^^^^ expected `u64`, found `i128`
73+
|
74+
help: you can convert `x_u64` from `u64` to `i128`, matching the type of `-1_i128`
75+
|
76+
LL | i128::from(x_u64) > -1_i128;
77+
| ^^^^^^^^^^^^^^^^^
78+
79+
error[E0308]: mismatched types
80+
--> $DIR/numeric-cast-no-fix.rs:29:13
81+
|
82+
LL | x_u32 > -1_i128;
83+
| ^^^^^^^ expected `u32`, found `i128`
84+
|
85+
help: you can convert `x_u32` from `u32` to `i128`, matching the type of `-1_i128`
86+
|
87+
LL | i128::from(x_u32) > -1_i128;
88+
| ^^^^^^^^^^^^^^^^^
89+
90+
error[E0308]: mismatched types
91+
--> $DIR/numeric-cast-no-fix.rs:31:13
92+
|
93+
LL | x_u16 > -1_i128;
94+
| ^^^^^^^ expected `u16`, found `i128`
95+
|
96+
help: you can convert `x_u16` from `u16` to `i128`, matching the type of `-1_i128`
97+
|
98+
LL | i128::from(x_u16) > -1_i128;
99+
| ^^^^^^^^^^^^^^^^^
100+
101+
error[E0308]: mismatched types
102+
--> $DIR/numeric-cast-no-fix.rs:33:12
103+
|
104+
LL | x_u8 > -1_i128;
105+
| ^^^^^^^ expected `u8`, found `i128`
106+
|
107+
help: you can convert `x_u8` from `u8` to `i128`, matching the type of `-1_i128`
108+
|
109+
LL | i128::from(x_u8) > -1_i128;
110+
| ^^^^^^^^^^^^^^^^
111+
112+
error[E0308]: mismatched types
113+
--> $DIR/numeric-cast-no-fix.rs:36:15
114+
|
115+
LL | x_usize > -1_i64;
116+
| ^^^^^^ expected `usize`, found `i64`
117+
|
118+
= note: `-1_i64` cannot fit into type `usize`
119+
120+
error[E0308]: mismatched types
121+
--> $DIR/numeric-cast-no-fix.rs:38:14
122+
|
123+
LL | x_u128 > -1_i64;
124+
| ^^^^^^ expected `u128`, found `i64`
125+
|
126+
= note: `-1_i64` cannot fit into type `u128`
127+
128+
error[E0308]: mismatched types
129+
--> $DIR/numeric-cast-no-fix.rs:40:13
130+
|
131+
LL | x_u64 > -1_i64;
132+
| ^^^^^^ expected `u64`, found `i64`
133+
|
134+
= note: `-1_i64` cannot fit into type `u64`
135+
136+
error[E0308]: mismatched types
137+
--> $DIR/numeric-cast-no-fix.rs:42:13
138+
|
139+
LL | x_u32 > -1_i64;
140+
| ^^^^^^ expected `u32`, found `i64`
141+
|
142+
help: you can convert `x_u32` from `u32` to `i64`, matching the type of `-1_i64`
143+
|
144+
LL | i64::from(x_u32) > -1_i64;
145+
| ^^^^^^^^^^^^^^^^
146+
147+
error[E0308]: mismatched types
148+
--> $DIR/numeric-cast-no-fix.rs:44:13
149+
|
150+
LL | x_u16 > -1_i64;
151+
| ^^^^^^ expected `u16`, found `i64`
152+
|
153+
help: you can convert `x_u16` from `u16` to `i64`, matching the type of `-1_i64`
154+
|
155+
LL | i64::from(x_u16) > -1_i64;
156+
| ^^^^^^^^^^^^^^^^
157+
158+
error[E0308]: mismatched types
159+
--> $DIR/numeric-cast-no-fix.rs:46:12
160+
|
161+
LL | x_u8 > -1_i64;
162+
| ^^^^^^ expected `u8`, found `i64`
163+
|
164+
help: you can convert `x_u8` from `u8` to `i64`, matching the type of `-1_i64`
165+
|
166+
LL | i64::from(x_u8) > -1_i64;
167+
| ^^^^^^^^^^^^^^^
168+
169+
error[E0308]: mismatched types
170+
--> $DIR/numeric-cast-no-fix.rs:49:15
171+
|
172+
LL | x_usize > -1_i32;
173+
| ^^^^^^ expected `usize`, found `i32`
174+
|
175+
= note: `-1_i32` cannot fit into type `usize`
176+
177+
error[E0308]: mismatched types
178+
--> $DIR/numeric-cast-no-fix.rs:51:14
179+
|
180+
LL | x_u128 > -1_i32;
181+
| ^^^^^^ expected `u128`, found `i32`
182+
|
183+
= note: `-1_i32` cannot fit into type `u128`
184+
185+
error[E0308]: mismatched types
186+
--> $DIR/numeric-cast-no-fix.rs:53:13
187+
|
188+
LL | x_u64 > -1_i32;
189+
| ^^^^^^ expected `u64`, found `i32`
190+
|
191+
= note: `-1_i32` cannot fit into type `u64`
192+
193+
error[E0308]: mismatched types
194+
--> $DIR/numeric-cast-no-fix.rs:55:13
195+
|
196+
LL | x_u32 > -1_i32;
197+
| ^^^^^^ expected `u32`, found `i32`
198+
|
199+
= note: `-1_i32` cannot fit into type `u32`
200+
201+
error[E0308]: mismatched types
202+
--> $DIR/numeric-cast-no-fix.rs:57:13
203+
|
204+
LL | x_u16 > -1_i32;
205+
| ^^^^^^ expected `u16`, found `i32`
206+
|
207+
help: you can convert `x_u16` from `u16` to `i32`, matching the type of `-1_i32`
208+
|
209+
LL | i32::from(x_u16) > -1_i32;
210+
| ^^^^^^^^^^^^^^^^
211+
212+
error[E0308]: mismatched types
213+
--> $DIR/numeric-cast-no-fix.rs:59:12
214+
|
215+
LL | x_u8 > -1_i32;
216+
| ^^^^^^ expected `u8`, found `i32`
217+
|
218+
help: you can convert `x_u8` from `u8` to `i32`, matching the type of `-1_i32`
219+
|
220+
LL | i32::from(x_u8) > -1_i32;
221+
| ^^^^^^^^^^^^^^^
222+
223+
error[E0308]: mismatched types
224+
--> $DIR/numeric-cast-no-fix.rs:62:15
225+
|
226+
LL | x_usize > -1_i16;
227+
| ^^^^^^ expected `usize`, found `i16`
228+
|
229+
= note: `-1_i16` cannot fit into type `usize`
230+
231+
error[E0308]: mismatched types
232+
--> $DIR/numeric-cast-no-fix.rs:64:14
233+
|
234+
LL | x_u128 > -1_i16;
235+
| ^^^^^^ expected `u128`, found `i16`
236+
|
237+
= note: `-1_i16` cannot fit into type `u128`
238+
239+
error[E0308]: mismatched types
240+
--> $DIR/numeric-cast-no-fix.rs:66:13
241+
|
242+
LL | x_u64 > -1_i16;
243+
| ^^^^^^ expected `u64`, found `i16`
244+
|
245+
= note: `-1_i16` cannot fit into type `u64`
246+
247+
error[E0308]: mismatched types
248+
--> $DIR/numeric-cast-no-fix.rs:68:13
249+
|
250+
LL | x_u32 > -1_i16;
251+
| ^^^^^^ expected `u32`, found `i16`
252+
|
253+
= note: `-1_i16` cannot fit into type `u32`
254+
255+
error[E0308]: mismatched types
256+
--> $DIR/numeric-cast-no-fix.rs:70:13
257+
|
258+
LL | x_u16 > -1_i16;
259+
| ^^^^^^ expected `u16`, found `i16`
260+
|
261+
= note: `-1_i16` cannot fit into type `u16`
262+
263+
error[E0308]: mismatched types
264+
--> $DIR/numeric-cast-no-fix.rs:72:12
265+
|
266+
LL | x_u8 > -1_i16;
267+
| ^^^^^^ expected `u8`, found `i16`
268+
|
269+
help: you can convert `x_u8` from `u8` to `i16`, matching the type of `-1_i16`
270+
|
271+
LL | i16::from(x_u8) > -1_i16;
272+
| ^^^^^^^^^^^^^^^
273+
274+
error[E0308]: mismatched types
275+
--> $DIR/numeric-cast-no-fix.rs:75:15
276+
|
277+
LL | x_usize > -1_i8;
278+
| ^^^^^ expected `usize`, found `i8`
279+
|
280+
= note: `-1_i8` cannot fit into type `usize`
281+
282+
error[E0308]: mismatched types
283+
--> $DIR/numeric-cast-no-fix.rs:77:14
284+
|
285+
LL | x_u128 > -1_i8;
286+
| ^^^^^ expected `u128`, found `i8`
287+
|
288+
= note: `-1_i8` cannot fit into type `u128`
289+
290+
error[E0308]: mismatched types
291+
--> $DIR/numeric-cast-no-fix.rs:79:13
292+
|
293+
LL | x_u64 > -1_i8;
294+
| ^^^^^ expected `u64`, found `i8`
295+
|
296+
= note: `-1_i8` cannot fit into type `u64`
297+
298+
error[E0308]: mismatched types
299+
--> $DIR/numeric-cast-no-fix.rs:81:13
300+
|
301+
LL | x_u32 > -1_i8;
302+
| ^^^^^ expected `u32`, found `i8`
303+
|
304+
= note: `-1_i8` cannot fit into type `u32`
305+
306+
error[E0308]: mismatched types
307+
--> $DIR/numeric-cast-no-fix.rs:83:13
308+
|
309+
LL | x_u16 > -1_i8;
310+
| ^^^^^ expected `u16`, found `i8`
311+
|
312+
= note: `-1_i8` cannot fit into type `u16`
313+
314+
error[E0308]: mismatched types
315+
--> $DIR/numeric-cast-no-fix.rs:85:12
316+
|
317+
LL | x_u8 > -1_i8;
318+
| ^^^^^ expected `u8`, found `i8`
319+
|
320+
= note: `-1_i8` cannot fit into type `u8`
321+
322+
error: aborting due to 36 previous errors
323+
324+
For more information about this error, try `rustc --explain E0308`.

‎src/test/ui/repeat_count.stderr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,16 @@ error[E0308]: mismatched types
3939
|
4040
LL | let f = [0; -4_isize];
4141
| ^^^^^^^^ expected `usize`, found `isize`
42+
|
43+
= note: `-4_isize` cannot fit into type `usize`
4244

4345
error[E0308]: mismatched types
4446
--> $DIR/repeat_count.rs:22:23
4547
|
4648
LL | let f = [0_usize; -1_isize];
4749
| ^^^^^^^^ expected `usize`, found `isize`
50+
|
51+
= note: `-1_isize` cannot fit into type `usize`
4852

4953
error[E0308]: mismatched types
5054
--> $DIR/repeat_count.rs:25:17

0 commit comments

Comments
 (0)
Please sign in to comment.