Skip to content

Commit

Permalink
Auto merge of #120165 - reitermarkus:nonzero-switch-alias-direction, …
Browse files Browse the repository at this point in the history
…r=dtolnay

Switch `NonZero` alias direction.

Step 4 mentioned in #100428 (review).

Depends on #120160.

r? `@dtolnay`
  • Loading branch information
bors committed Jan 29, 2024
2 parents 0ea334a + 021739c commit fb4bca0
Show file tree
Hide file tree
Showing 22 changed files with 208 additions and 190 deletions.
54 changes: 29 additions & 25 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2140,46 +2140,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_ty: Ty<'tcx>,
) -> bool {
let tcx = self.tcx;
let (adt, unwrap) = match expected.kind() {
let (adt, substs, unwrap) = match expected.kind() {
// In case Option<NonZero*> is wanted, but * is provided, suggest calling new
ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
// Unwrap option
let ty::Adt(adt, _) = args.type_at(0).kind() else {
ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
let nonzero_type = substs.type_at(0); // Unwrap option type.
let ty::Adt(adt, substs) = nonzero_type.kind() else {
return false;
};

(adt, "")
(adt, substs, "")
}
// In case NonZero* is wanted, but * is provided also add `.unwrap()` to satisfy types
ty::Adt(adt, _) => (adt, ".unwrap()"),
// In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types.
ty::Adt(adt, substs) => (adt, substs, ".unwrap()"),
_ => return false,
};

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),
if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
return false;
}

// FIXME: This can be simplified once `NonZero<T>` is stable.
let coercable_types = [
("NonZeroU8", tcx.types.u8),
("NonZeroU16", tcx.types.u16),
("NonZeroU32", tcx.types.u32),
("NonZeroU64", tcx.types.u64),
("NonZeroU128", tcx.types.u128),
("NonZeroI8", tcx.types.i8),
("NonZeroI16", tcx.types.i16),
("NonZeroI32", tcx.types.i32),
("NonZeroI64", tcx.types.i64),
("NonZeroI128", tcx.types.i128),
];

let Some((s, _)) = map.iter().find(|&&(s, t)| {
self.tcx.is_diagnostic_item(s, adt.did()) && self.can_coerce(expr_ty, t)
let int_type = substs.type_at(0);

let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| {
if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None }
}) else {
return false;
};

let path = self.tcx.def_path_str(adt.non_enum_variant().def_id);

err.multipart_suggestion(
format!("consider calling `{s}::new`"),
format!("consider calling `{nonzero_alias}::new`"),
vec![
(expr.span.shrink_to_lo(), format!("{path}::new(")),
(expr.span.shrink_to_lo(), format!("{nonzero_alias}::new(")),
(expr.span.shrink_to_hi(), format!("){unwrap}")),
],
Applicability::MaybeIncorrect,
Expand Down
12 changes: 1 addition & 11 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,17 +246,7 @@ symbols! {
MutexGuard,
N,
NonNull,
NonZeroI128,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI8,
NonZeroU128,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU8,
NonZeroUsize,
NonZero,
None,
Normal,
Ok,
Expand Down
10 changes: 9 additions & 1 deletion library/core/src/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ pub use dec2flt::ParseFloatError;
#[stable(feature = "rust1", since = "1.0.0")]
pub use error::ParseIntError;

pub(crate) use nonzero::NonZero;
#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "none"
)]
pub use nonzero::ZeroablePrimitive;

#[unstable(feature = "generic_nonzero", issue = "120257")]
pub use nonzero::NonZero;

#[stable(feature = "nonzero", since = "1.28.0")]
pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
Expand Down
50 changes: 32 additions & 18 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
use crate::cmp::Ordering;
use crate::fmt;
use crate::hash::{Hash, Hasher};
#[cfg(bootstrap)]
use crate::marker::StructuralEq;
use crate::marker::StructuralPartialEq;
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
use crate::str::FromStr;
Expand Down Expand Up @@ -30,9 +32,7 @@ mod private {
issue = "none"
)]
#[const_trait]
pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {
type NonZero;
}
pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {}

macro_rules! impl_zeroable_primitive {
($NonZero:ident ( $primitive:ty )) => {
Expand All @@ -48,9 +48,7 @@ macro_rules! impl_zeroable_primitive {
reason = "implementation detail which may disappear or be replaced at any time",
issue = "none"
)]
impl const ZeroablePrimitive for $primitive {
type NonZero = $NonZero;
}
impl const ZeroablePrimitive for $primitive {}
};
}

Expand All @@ -67,12 +65,23 @@ impl_zeroable_primitive!(NonZeroI64(i64));
impl_zeroable_primitive!(NonZeroI128(i128));
impl_zeroable_primitive!(NonZeroIsize(isize));

#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "none"
)]
pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero;
/// A value that is known not to equal zero.
///
/// This enables some memory layout optimization.
/// For example, `Option<NonZero<u32>>` is the same size as `u32`:
///
/// ```
/// #![feature(generic_nonzero)]
/// use core::mem::size_of;
///
/// assert_eq!(size_of::<Option<core::num::NonZero<u32>>>(), size_of::<u32>());
/// ```
#[unstable(feature = "generic_nonzero", issue = "120257")]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
#[rustc_diagnostic_item = "NonZero"]
pub struct NonZero<T: ZeroablePrimitive>(T);

macro_rules! impl_nonzero_fmt {
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
Expand Down Expand Up @@ -131,12 +140,7 @@ macro_rules! nonzero_integer {
///
/// [null pointer optimization]: crate::option#representation
#[$stability]
#[derive(Copy, Eq)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
#[rustc_diagnostic_item = stringify!($Ty)]
pub struct $Ty($Int);
pub type $Ty = NonZero<$Int>;

impl $Ty {
/// Creates a non-zero without checking whether the value is non-zero.
Expand Down Expand Up @@ -543,6 +547,9 @@ macro_rules! nonzero_integer {
}
}

#[$stability]
impl Copy for $Ty {}

#[$stability]
impl PartialEq for $Ty {
#[inline]
Expand All @@ -559,6 +566,13 @@ macro_rules! nonzero_integer {
#[unstable(feature = "structural_match", issue = "31434")]
impl StructuralPartialEq for $Ty {}

#[$stability]
impl Eq for $Ty {}

#[unstable(feature = "structural_match", issue = "31434")]
#[cfg(bootstrap)]
impl StructuralEq for $Ty {}

#[$stability]
impl PartialOrd for $Ty {
#[inline]
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@
#![feature(float_gamma)]
#![feature(float_minimum_maximum)]
#![feature(float_next_up_down)]
#![feature(generic_nonzero)]
#![feature(hasher_prefixfree_extras)]
#![feature(hashmap_internals)]
#![feature(hint_assert_unchecked)]
Expand Down
10 changes: 10 additions & 0 deletions library/std/src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ pub use core::num::Wrapping;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::{FpCategory, ParseFloatError, ParseIntError, TryFromIntError};

#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
issue = "none"
)]
pub use core::num::ZeroablePrimitive;

#[unstable(feature = "generic_nonzero", issue = "120257")]
pub use core::num::NonZero;

#[stable(feature = "signed_nonzero", since = "1.34.0")]
pub use core::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
#[stable(feature = "nonzero", since = "1.28.0")]
Expand Down
35 changes: 1 addition & 34 deletions src/etc/natvis/libcore.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -41,40 +41,7 @@
</Expand>
</Type>

<Type Name="core::num::nonzero::NonZeroI8">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroI16">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroI32">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroI64">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroI128">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroIsize">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroU8">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroU16">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroU32">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroU64">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroU128">
<DisplayString>{__0}</DisplayString>
</Type>
<Type Name="core::num::nonzero::NonZeroUsize">
<Type Name="core::num::nonzero::NonZero&lt;*&gt;">
<DisplayString>{__0}</DisplayString>
</Type>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use super::ARITHMETIC_SIDE_EFFECTS;
use clippy_utils::consts::{constant, constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::type_diagnostic_name;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
Expand Down Expand Up @@ -88,37 +88,44 @@ impl ArithmeticSideEffects {
}

/// Verifies built-in types that have specific allowed operations
fn has_specific_allowed_type_and_operation(
cx: &LateContext<'_>,
lhs_ty: Ty<'_>,
fn has_specific_allowed_type_and_operation<'tcx>(
cx: &LateContext<'tcx>,
lhs_ty: Ty<'tcx>,
op: &Spanned<hir::BinOpKind>,
rhs_ty: Ty<'_>,
rhs_ty: Ty<'tcx>,
) -> bool {
let is_div_or_rem = matches!(op.node, hir::BinOpKind::Div | hir::BinOpKind::Rem);
let is_non_zero_u = |symbol: Option<Symbol>| {
matches!(
symbol,
Some(
sym::NonZeroU128
| sym::NonZeroU16
| sym::NonZeroU32
| sym::NonZeroU64
| sym::NonZeroU8
| sym::NonZeroUsize
)
)
let is_non_zero_u = |cx: &LateContext<'tcx>, ty: Ty<'tcx>| {
let tcx = cx.tcx;

let ty::Adt(adt, substs) = ty.kind() else { return false };

if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
return false;
};

let int_type = substs.type_at(0);
let unsigned_int_types = [
tcx.types.u8,
tcx.types.u16,
tcx.types.u32,
tcx.types.u64,
tcx.types.u128,
tcx.types.usize,
];

unsigned_int_types.contains(&int_type)
};
let is_sat_or_wrap = |ty: Ty<'_>| {
let is_sat = type_diagnostic_name(cx, ty) == Some(sym::Saturating);
let is_wrap = type_diagnostic_name(cx, ty) == Some(sym::Wrapping);
is_sat || is_wrap
is_type_diagnostic_item(cx, ty, sym::Saturating) || is_type_diagnostic_item(cx, ty, sym::Wrapping)
};

// If the RHS is NonZeroU*, then division or module by zero will never occur
if is_non_zero_u(type_diagnostic_name(cx, rhs_ty)) && is_div_or_rem {
// If the RHS is `NonZero<u*>`, then division or module by zero will never occur.
if is_non_zero_u(cx, rhs_ty) && is_div_or_rem {
return true;
}
// `Saturation` and `Wrapping` can overflow if the RHS is zero in a division or module

// `Saturation` and `Wrapping` can overflow if the RHS is zero in a division or module.
if is_sat_or_wrap(lhs_ty) {
return !is_div_or_rem;
}
Expand Down

0 comments on commit fb4bca0

Please sign in to comment.