diff options
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/demand.rs | 54 | ||||
| -rw-r--r-- | library/core/src/num/nonzero.rs | 1 | ||||
| -rw-r--r-- | src/test/ui/mismatched_types/non_zero_assigned_something.rs | 9 | ||||
| -rw-r--r-- | src/test/ui/mismatched_types/non_zero_assigned_something.stderr | 31 |
5 files changed, 105 insertions, 0 deletions
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d5e65c0b442..6ddcfbb05dc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -223,6 +223,16 @@ symbols! { LintPass, Mutex, N, + NonZeroI128, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI8, + NonZeroU128, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU8, None, Ok, Option, diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 867570b42da..31da5cfe7fa 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -34,6 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.annotate_expected_due_to_let_ty(err, expr, error); self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr); self.suggest_compatible_variants(err, expr, expected, expr_ty); + self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty); if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { return; } @@ -418,6 +419,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggest_non_zero_new_unwrap( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + expr_ty: Ty<'tcx>, + ) { + let tcx = self.tcx; + let (adt, unwrap) = match expected.kind() { + // In case Option<NonZero*> is wanted, but * is provided, suggest calling new + ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + // Unwrap option + let Some(fst) = substs.first() else { return }; + let ty::Adt(adt, _) = fst.expect_ty().kind() else { return }; + + (adt, "") + } + // In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types + ty::Adt(adt, _) => (adt, ".unwrap()"), + _ => return, + }; + + let map = [ + (sym::NonZeroU8, tcx.types.u8), + (sym::NonZeroU16, tcx.types.u16), + (sym::NonZeroU32, tcx.types.u32), + (sym::NonZeroU64, tcx.types.u64), + (sym::NonZeroU128, tcx.types.u128), + (sym::NonZeroI8, tcx.types.i8), + (sym::NonZeroI16, tcx.types.i16), + (sym::NonZeroI32, tcx.types.i32), + (sym::NonZeroI64, tcx.types.i64), + (sym::NonZeroI128, tcx.types.i128), + ]; + + let Some((s, _)) = map + .iter() + .find(|&&(s, _)| self.tcx.is_diagnostic_item(s, adt.did())) + .filter(|&&(_, t)| { self.can_coerce(expr_ty, t) }) + else { return }; + + let path = self.tcx.def_path_str(adt.non_enum_variant().def_id); + + err.multipart_suggestion( + format!("consider calling `{s}::new`"), + vec![ + (expr.span.shrink_to_lo(), format!("{path}::new(")), + (expr.span.shrink_to_hi(), format!("){unwrap}")), + ], + Applicability::MaybeIncorrect, + ); + } + pub fn get_conversion_methods( &self, span: Span, diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 92d03b724b4..4de0a0cf564 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -39,6 +39,7 @@ macro_rules! nonzero_integers { #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] #[rustc_nonnull_optimization_guaranteed] + #[rustc_diagnostic_item = stringify!($Ty)] pub struct $Ty($Int); impl $Ty { diff --git a/src/test/ui/mismatched_types/non_zero_assigned_something.rs b/src/test/ui/mismatched_types/non_zero_assigned_something.rs new file mode 100644 index 00000000000..d2adbe01c18 --- /dev/null +++ b/src/test/ui/mismatched_types/non_zero_assigned_something.rs @@ -0,0 +1,9 @@ +fn main() { + let _: std::num::NonZeroU64 = 1; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZeroU64::new` + + let _: Option<std::num::NonZeroU64> = 1; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZeroU64::new` +} diff --git a/src/test/ui/mismatched_types/non_zero_assigned_something.stderr b/src/test/ui/mismatched_types/non_zero_assigned_something.stderr new file mode 100644 index 00000000000..d4b2c902f9b --- /dev/null +++ b/src/test/ui/mismatched_types/non_zero_assigned_something.stderr @@ -0,0 +1,31 @@ +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:2:35 + | +LL | let _: std::num::NonZeroU64 = 1; + | -------------------- ^ expected struct `NonZeroU64`, found integer + | | + | expected due to this + | +help: consider calling `NonZeroU64::new` + | +LL | let _: std::num::NonZeroU64 = NonZeroU64::new(1).unwrap(); + | ++++++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:6:43 + | +LL | let _: Option<std::num::NonZeroU64> = 1; + | ---------------------------- ^ expected enum `Option`, found integer + | | + | expected due to this + | + = note: expected enum `Option<NonZeroU64>` + found type `{integer}` +help: consider calling `NonZeroU64::new` + | +LL | let _: Option<std::num::NonZeroU64> = NonZeroU64::new(1); + | ++++++++++++++++ + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. |
