Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch NonZero alias direction. #120165

Merged
merged 5 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading
Loading