Skip to content

Commit 7163e7f

Browse files
committed
Suggest a fix for NonZero* <- * coercion error
1 parent 37c21d6 commit 7163e7f

File tree

5 files changed

+105
-0
lines changed

5 files changed

+105
-0
lines changed

compiler/rustc_span/src/symbol.rs

+10
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,16 @@ symbols! {
223223
LintPass,
224224
Mutex,
225225
N,
226+
NonZeroI128,
227+
NonZeroI16,
228+
NonZeroI32,
229+
NonZeroI64,
230+
NonZeroI8,
231+
NonZeroU128,
232+
NonZeroU16,
233+
NonZeroU32,
234+
NonZeroU64,
235+
NonZeroU8,
226236
None,
227237
Ok,
228238
Option,

compiler/rustc_typeck/src/check/demand.rs

+54
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3434
self.annotate_expected_due_to_let_ty(err, expr, error);
3535
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
3636
self.suggest_compatible_variants(err, expr, expected, expr_ty);
37+
self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty);
3738
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
3839
return;
3940
}
@@ -418,6 +419,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
418419
}
419420
}
420421

422+
fn suggest_non_zero_new_unwrap(
423+
&self,
424+
err: &mut Diagnostic,
425+
expr: &hir::Expr<'_>,
426+
expected: Ty<'tcx>,
427+
expr_ty: Ty<'tcx>,
428+
) {
429+
let tcx = self.tcx;
430+
let (adt, unwrap) = match expected.kind() {
431+
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
432+
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
433+
// Unwrap option
434+
let Some(fst) = substs.first() else { return };
435+
let ty::Adt(adt, _) = fst.expect_ty().kind() else { return };
436+
437+
(adt, "")
438+
}
439+
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
440+
ty::Adt(adt, _) => (adt, ".unwrap()"),
441+
_ => return,
442+
};
443+
444+
let map = [
445+
(sym::NonZeroU8, tcx.types.u8),
446+
(sym::NonZeroU16, tcx.types.u16),
447+
(sym::NonZeroU32, tcx.types.u32),
448+
(sym::NonZeroU64, tcx.types.u64),
449+
(sym::NonZeroU128, tcx.types.u128),
450+
(sym::NonZeroI8, tcx.types.i8),
451+
(sym::NonZeroI16, tcx.types.i16),
452+
(sym::NonZeroI32, tcx.types.i32),
453+
(sym::NonZeroI64, tcx.types.i64),
454+
(sym::NonZeroI128, tcx.types.i128),
455+
];
456+
457+
let Some((s, _)) = map
458+
.iter()
459+
.find(|&&(s, _)| self.tcx.is_diagnostic_item(s, adt.did()))
460+
.filter(|&&(_, t)| { self.can_coerce(expr_ty, t) })
461+
else { return };
462+
463+
let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);
464+
465+
err.multipart_suggestion(
466+
format!("consider calling `{s}::new`"),
467+
vec![
468+
(expr.span.shrink_to_lo(), format!("{path}::new(")),
469+
(expr.span.shrink_to_hi(), format!("){unwrap}")),
470+
],
471+
Applicability::MaybeIncorrect,
472+
);
473+
}
474+
421475
pub fn get_conversion_methods(
422476
&self,
423477
span: Span,

library/core/src/num/nonzero.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ macro_rules! nonzero_integers {
3939
#[repr(transparent)]
4040
#[rustc_layout_scalar_valid_range_start(1)]
4141
#[rustc_nonnull_optimization_guaranteed]
42+
#[rustc_diagnostic_item = stringify!($Ty)]
4243
pub struct $Ty($Int);
4344

4445
impl $Ty {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn main() {
2+
let _: std::num::NonZeroU64 = 1;
3+
//~^ ERROR mismatched types
4+
//~| HELP consider calling `NonZeroU64::new`
5+
6+
let _: Option<std::num::NonZeroU64> = 1;
7+
//~^ ERROR mismatched types
8+
//~| HELP consider calling `NonZeroU64::new`
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/non_zero_assigned_something.rs:2:35
3+
|
4+
LL | let _: std::num::NonZeroU64 = 1;
5+
| -------------------- ^ expected struct `NonZeroU64`, found integer
6+
| |
7+
| expected due to this
8+
|
9+
help: consider calling `NonZeroU64::new`
10+
|
11+
LL | let _: std::num::NonZeroU64 = NonZeroU64::new(1).unwrap();
12+
| ++++++++++++++++ ++++++++++
13+
14+
error[E0308]: mismatched types
15+
--> $DIR/non_zero_assigned_something.rs:6:43
16+
|
17+
LL | let _: Option<std::num::NonZeroU64> = 1;
18+
| ---------------------------- ^ expected enum `Option`, found integer
19+
| |
20+
| expected due to this
21+
|
22+
= note: expected enum `Option<NonZeroU64>`
23+
found type `{integer}`
24+
help: consider calling `NonZeroU64::new`
25+
|
26+
LL | let _: Option<std::num::NonZeroU64> = NonZeroU64::new(1);
27+
| ++++++++++++++++ +
28+
29+
error: aborting due to 2 previous errors
30+
31+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)