diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c11db63ba11ff..f94aee2920997 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -426,6 +426,8 @@ language_item_table! { String, sym::String, string, Target::Struct, GenericRequirement::None; CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None; + NonZero, sym::NonZero, non_zero, Target::Struct, GenericRequirement::Exact(1); + // Experimental lang items for implementing contract pre- and post-condition checking. ContractBuildCheckEnsures, sym::contract_build_check_ensures, contract_build_check_ensures_fn, Target::Fn, GenericRequirement::None; ContractCheckRequires, sym::contract_check_requires, contract_check_requires_fn, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index b2a229ad65183..477daa55c6b32 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -263,6 +263,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // It cannot convert closures that require unsafe. self.coerce_closure_to_fn(a, closure_def_id_a, args_a, b) } + ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), hir::LangItem::NonZero) => { + self.coerce_non_zero(a, args.type_at(0), b) + } _ => { // Otherwise, just use unification rules. self.unify(a, b) @@ -827,6 +830,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b)) } + fn coerce_non_zero( + &self, + non_zero: Ty<'tcx>, + wrapped_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, + ) -> CoerceResult<'tcx> { + if target_ty.is_ty_var() { + return self.unify(non_zero, target_ty); + } + self.commit_if_ok(|_| self.unify_and(wrapped_ty, target_ty, [], Adjust::NonZeroIntoInner)) + .or_else(|_| self.unify(non_zero, target_ty)) + } + fn coerce_from_safe_fn( &self, fn_ty_a: ty::PolyFnSig<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 2034131882820..6cbeaff3ac88c 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -854,6 +854,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx }; self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); } + + adjustment::Adjust::NonZeroIntoInner => {} } place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?; } @@ -1336,6 +1338,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) | adjustment::Adjust::Borrow(_) + | adjustment::Adjust::NonZeroIntoInner | adjustment::Adjust::ReborrowPin(..) => { // Result is an rvalue. Ok(self.cat_rvalue(expr.hir_id, target)) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 58751f232d032..ec6301539f0a9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -290,7 +290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(const_trait_impl): We could enforce these; they correspond to // `&mut T: DerefMut` tho, so it's kinda moot. } - Adjust::Borrow(_) => { + Adjust::NonZeroIntoInner | Adjust::Borrow(_) => { // No effects to enforce here. } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index dd6eb73a3a0aa..9e63234de4f95 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2487,7 +2487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return false, }; - if !self.tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + if !self.tcx.is_lang_item(adt.did(), LangItem::NonZero) { return false; } diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 5490a3aac9b7a..109337d321a4e 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -171,6 +171,7 @@ fn has_implicit_borrow(Adjustment { kind, .. }: &Adjustment<'_>) -> Option<(Muta | Adjust::Pointer(..) | Adjust::ReborrowPin(..) | Adjust::Deref(None) + | Adjust::NonZeroIntoInner | Adjust::Borrow(AutoBorrow::RawPtr(..)) => None, } } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 74573455f531a..8911aae96f0d3 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -105,6 +105,9 @@ pub enum Adjust { /// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`. ReborrowPin(hir::Mutability), + + /// Turn a `NonZero` into `T` + NonZeroIntoInner, } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b694409f327bd..e5b355403be47 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -239,6 +239,34 @@ impl<'tcx> ThirBuildCx<'tcx> { debug!(?kind); kind } + Adjust::NonZeroIntoInner => { + // These only happen on `NonZero` + let ty::Adt(adt, args) = expr.ty.kind() else { + span_bug!(span, "nonzero adjustment not based on adt: {expr:#?}") + }; + // Find the right field type + let ty = self + .tcx + .type_of(adt.variant(FIRST_VARIANT).fields[FieldIdx::ZERO].did) + .instantiate(self.tcx, args); + // Get rid of the `ZeroablePrimitive` projection + let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty); + let lhs = self.thir.exprs.push(expr); + ExprKind::Field { + lhs: self.thir.exprs.push(Expr { + span, + temp_lifetime, + ty, + kind: ExprKind::Field { + lhs, + variant_index: FIRST_VARIANT, + name: FieldIdx::ZERO, + }, + }), + variant_index: FIRST_VARIANT, + name: FieldIdx::ZERO, + } + } }; Expr { temp_lifetime, ty: adjustment.target, span, kind } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 11d50e0f89f30..87701702015d5 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -123,7 +123,7 @@ impl_zeroable_primitive!( #[stable(feature = "generic_nonzero", since = "1.79.0")] #[repr(transparent)] #[rustc_nonnull_optimization_guaranteed] -#[rustc_diagnostic_item = "NonZero"] +#[lang = "NonZero"] pub struct NonZero(T::NonZeroInner); macro_rules! impl_nonzero_fmt { diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs index 22df1f3f485e1..cf266998f0fa6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs @@ -2,9 +2,9 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_inside_always_const_context; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::is_type_lang_item; use rustc_errors::Applicability; -use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, QPath, UnsafeSource}; +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, QPath, UnsafeSource}; use rustc_lint::LateContext; use rustc_span::sym; @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<' && segment.ident.name == sym::new_unchecked && let [init_arg] = args && is_inside_always_const_context(cx.tcx, expr.hir_id) - && is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::NonZero) + && is_type_lang_item(cx, cx.typeck_results().node_type(ty.hir_id), LangItem::NonZero) && msrv.meets(cx, msrvs::CONST_UNWRAP) { let mut app = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs index 1b8ab1bdedf8a..6864d4b880567 100644 --- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs +++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use clippy_utils::sym; use rustc_ast::ast::BinOpKind; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; @@ -81,7 +81,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit // Check if the receiver type is a NonZero type if let ty::Adt(adt_def, _) = receiver_ty.kind() && adt_def.is_struct() - && cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero) + && cx.tcx.is_lang_item(adt_def.did(), LangItem::NonZero) && let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) { let arg_snippet = get_arg_snippet(cx, arg, rcv_path); diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index a78a342d4fe39..8556621978aaa 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -5,6 +5,7 @@ use clippy_utils::diagnostics::span_lint; 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_hir::LangItem; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; @@ -102,7 +103,7 @@ impl ArithmeticSideEffects { let ty::Adt(adt, substs) = ty.kind() else { return false }; - if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + if !tcx.is_lang_item(adt.did(), LangItem::NonZero) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs index 7b98afa9b40bd..850993087f041 100644 --- a/src/tools/clippy/clippy_lints/src/operators/integer_division.rs +++ b/src/tools/clippy/clippy_lints/src/operators/integer_division.rs @@ -1,8 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::ty::is_type_diagnostic_item; -use rustc_hir as hir; +use clippy_utils::ty::is_type_lang_item; +use rustc_hir::{self as hir, LangItem}; use rustc_lint::LateContext; -use rustc_span::symbol::sym; use super::INTEGER_DIVISION; @@ -16,7 +15,7 @@ pub(crate) fn check<'tcx>( if op == hir::BinOpKind::Div && cx.typeck_results().expr_ty(left).is_integral() && let right_ty = cx.typeck_results().expr_ty(right) - && (right_ty.is_integral() || is_type_diagnostic_item(cx, right_ty, sym::NonZero)) + && (right_ty.is_integral() || is_type_lang_item(cx, right_ty, LangItem::NonZero)) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then(cx, INTEGER_DIVISION, expr.span, "integer division", |diag| { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index f27aaa2fa77aa..41b121307c4c6 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -2,7 +2,7 @@ use super::TRANSMUTE_INT_TO_NON_ZERO; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, LangItem}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::sym; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( return false; }; - if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) { + if !tcx.is_lang_item(adt.did(), LangItem::NonZero) { return false; } diff --git a/tests/ui/mismatched_types/non_zero_assigned_lit.rs b/tests/ui/mismatched_types/non_zero_assigned_lit.rs new file mode 100644 index 0000000000000..9c4814b5bfdf6 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_lit.rs @@ -0,0 +1,8 @@ +#![allow(overflowing_literals)] + +fn main() { + let x: std::num::NonZero = -128; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + assert_eq!(x.get(), -128_i8); +} diff --git a/tests/ui/mismatched_types/non_zero_assigned_lit.stderr b/tests/ui/mismatched_types/non_zero_assigned_lit.stderr new file mode 100644 index 0000000000000..2e0f6486810f2 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_lit.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_lit.rs:4:36 + | +LL | let x: std::num::NonZero = -128; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let x: std::num::NonZero = NonZero::new(-128).unwrap(); + | +++++++++++++ ++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs new file mode 100644 index 0000000000000..c66991b512cbc --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.rs @@ -0,0 +1,14 @@ +#![allow(overflowing_literals)] + +fn main() { + let _: std::num::NonZero = 256; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = -128; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -129; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` +} diff --git a/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr new file mode 100644 index 0000000000000..cfcae44db0af0 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_assigned_oflo_lit.stderr @@ -0,0 +1,48 @@ +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_oflo_lit.rs:4:36 + | +LL | let _: std::num::NonZero = 256; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(256).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_oflo_lit.rs:8:36 + | +LL | let _: std::num::NonZero = -128; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-128).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_oflo_lit.rs:11:36 + | +LL | let _: std::num::NonZero = -129; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-129).unwrap(); + | +++++++++++++ ++++++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.rs b/tests/ui/mismatched_types/non_zero_assigned_something.rs index e94d5249d6a84..51322a88a2115 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.rs +++ b/tests/ui/mismatched_types/non_zero_assigned_something.rs @@ -1,7 +1,47 @@ fn main() { + let _: std::num::NonZero = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: Option> = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 1; //~^ ERROR mismatched types //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 1u8; + //~^ ERROR mismatched types + let _: std::num::NonZero = 1u64; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = 255; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 256; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = -10; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + + let _: std::num::NonZero = -128; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -129; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = -1; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 0; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` + let _: std::num::NonZero = 1; + //~^ ERROR mismatched types + //~| HELP consider calling `NonZero::new` let _: Option> = 1; //~^ ERROR mismatched types diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr index aa015bd2efcc9..f50d2960f8686 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr @@ -1,6 +1,36 @@ error[E0308]: mismatched types --> $DIR/non_zero_assigned_something.rs:2:37 | +LL | let _: std::num::NonZero = 0; + | ---------------------- ^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(0).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:6:45 + | +LL | let _: Option> = 0; + | ------------------------------ ^ expected `Option>`, found integer + | | + | expected due to this + | + = note: expected enum `Option>` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: Option> = NonZero::new(0); + | +++++++++++++ + + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:10:37 + | LL | let _: std::num::NonZero = 1; | ---------------------- ^ expected `NonZero`, found integer | | @@ -14,7 +44,153 @@ LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); | +++++++++++++ ++++++++++ error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:6:45 + --> $DIR/non_zero_assigned_something.rs:13:37 + | +LL | let _: std::num::NonZero = 1u8; + | ---------------------- ^^^ expected `NonZero`, found `u8` + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `u8` + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:15:37 + | +LL | let _: std::num::NonZero = 1u64; + | ---------------------- ^^^^ expected `NonZero`, found `u64` + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `u64` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(1u64).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:19:36 + | +LL | let _: std::num::NonZero = 255; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(255).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:22:36 + | +LL | let _: std::num::NonZero = 256; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(256).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:26:36 + | +LL | let _: std::num::NonZero = -10; + | --------------------- ^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-10).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:30:36 + | +LL | let _: std::num::NonZero = -128; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-128).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:33:36 + | +LL | let _: std::num::NonZero = -129; + | --------------------- ^^^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-129).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:36:36 + | +LL | let _: std::num::NonZero = -1; + | --------------------- ^^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(-1).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:39:36 + | +LL | let _: std::num::NonZero = 0; + | --------------------- ^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(0).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:42:36 + | +LL | let _: std::num::NonZero = 1; + | --------------------- ^ expected `NonZero`, found integer + | | + | expected due to this + | + = note: expected struct `NonZero` + found type `{integer}` +help: consider calling `NonZero::new` + | +LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); + | +++++++++++++ ++++++++++ + +error[E0308]: mismatched types + --> $DIR/non_zero_assigned_something.rs:46:45 | LL | let _: Option> = 1; | ------------------------------ ^ expected `Option>`, found integer @@ -28,6 +204,6 @@ help: consider calling `NonZero::new` LL | let _: Option> = NonZero::new(1); | +++++++++++++ + -error: aborting due to 2 previous errors +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/non_zero_coerce.rs b/tests/ui/mismatched_types/non_zero_coerce.rs new file mode 100644 index 0000000000000..b0599506b25dc --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce.rs @@ -0,0 +1,32 @@ +//@ check-pass + +use std::num::NonZero; + +trait Foo: Sized { + fn bar(self, other: T) {} +} + +impl Foo for u8 {} +impl Foo for u16 {} + +trait Bar {} +impl Bar for u8 {} +impl Bar for u16 {} +fn foo(_: impl Bar) {} + +fn main() { + // Check that we can coerce + let x = NonZero::new(5_u8).unwrap(); + let y: u8 = x; + + // Can coerce by looking at the trait + let x = NonZero::new(5_u8).unwrap(); + 5_u8.bar(x); + + // Check that we can infer the nonzero wrapped type through the coercion + let a = NonZero::new(5).unwrap(); + let b: u8 = a; + + let a = NonZero::new(5).unwrap(); + 5_u8.bar(a); +} diff --git a/tests/ui/mismatched_types/non_zero_coerce_fail.rs b/tests/ui/mismatched_types/non_zero_coerce_fail.rs new file mode 100644 index 0000000000000..f5d4cace8e3ed --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce_fail.rs @@ -0,0 +1,31 @@ +use std::num::NonZero; + +trait Foo: Sized { + fn foo(&self) {} + fn bar(self) {} +} + +impl Foo for u8 {} +impl Foo for u16 {} + +fn foo(_: impl Foo) {} + +fn main() { + let x = NonZero::new(5_u8).unwrap(); + x.foo(); + //~^ ERROR: no method named `foo` found for struct `NonZero` in the current scope + x.bar(); + //~^ ERROR: no method named `bar` found for struct `NonZero` in the current scope + foo(x); + //~^ ERROR: the trait bound `NonZero: Foo` is not satisfied + foo(x as _); + + let a = NonZero::new(5).unwrap(); + a.foo(); + //~^ ERROR: no method named `foo` found for struct `NonZero` in the current scope + a.bar(); + //~^ ERROR: no method named `bar` found for struct `NonZero` in the current scope + foo(a); + //~^ ERROR: the trait bound `NonZero<{integer}>: Foo` is not satisfied + foo(a as _); +} diff --git a/tests/ui/mismatched_types/non_zero_coerce_fail.stderr b/tests/ui/mismatched_types/non_zero_coerce_fail.stderr new file mode 100644 index 0000000000000..4c619254e8317 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce_fail.stderr @@ -0,0 +1,90 @@ +error[E0599]: no method named `foo` found for struct `NonZero` in the current scope + --> $DIR/non_zero_coerce_fail.rs:15:7 + | +LL | x.foo(); + | ^^^ method not found in `NonZero` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/non_zero_coerce_fail.rs:3:1 + | +LL | trait Foo: Sized { + | ^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `bar` found for struct `NonZero` in the current scope + --> $DIR/non_zero_coerce_fail.rs:17:7 + | +LL | x.bar(); + | ^^^ method not found in `NonZero` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `bar`, perhaps you need to implement it + --> $DIR/non_zero_coerce_fail.rs:3:1 + | +LL | trait Foo: Sized { + | ^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `NonZero: Foo` is not satisfied + --> $DIR/non_zero_coerce_fail.rs:19:9 + | +LL | foo(x); + | --- ^ the trait `Foo` is not implemented for `NonZero` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Foo`: + u16 + u8 +note: required by a bound in `foo` + --> $DIR/non_zero_coerce_fail.rs:11:16 + | +LL | fn foo(_: impl Foo) {} + | ^^^ required by this bound in `foo` + +error[E0599]: no method named `foo` found for struct `NonZero` in the current scope + --> $DIR/non_zero_coerce_fail.rs:24:7 + | +LL | a.foo(); + | ^^^ method not found in `NonZero<{integer}>` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `foo`, perhaps you need to implement it + --> $DIR/non_zero_coerce_fail.rs:3:1 + | +LL | trait Foo: Sized { + | ^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `bar` found for struct `NonZero` in the current scope + --> $DIR/non_zero_coerce_fail.rs:26:7 + | +LL | a.bar(); + | ^^^ method not found in `NonZero<{integer}>` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Foo` defines an item `bar`, perhaps you need to implement it + --> $DIR/non_zero_coerce_fail.rs:3:1 + | +LL | trait Foo: Sized { + | ^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `NonZero<{integer}>: Foo` is not satisfied + --> $DIR/non_zero_coerce_fail.rs:28:9 + | +LL | foo(a); + | --- ^ the trait `Foo` is not implemented for `NonZero<{integer}>` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Foo`: + u16 + u8 +note: required by a bound in `foo` + --> $DIR/non_zero_coerce_fail.rs:11:16 + | +LL | fn foo(_: impl Foo) {} + | ^^^ required by this bound in `foo` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0599. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/non_zero_coerce_fail2.rs b/tests/ui/mismatched_types/non_zero_coerce_fail2.rs new file mode 100644 index 0000000000000..12c0992162bd5 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce_fail2.rs @@ -0,0 +1,29 @@ +use std::num::NonZero; + +trait Foo: Sized { + fn foo(&self, other: &T) {} + fn bar(self, other: T) {} +} + +impl Foo for u8 {} +impl Foo for u16 {} + +fn main() { + let x = NonZero::new(5_u8).unwrap(); + 5_u8.foo(&x); + //~^ ERROR: mismatched types + 5_u8.bar(x); + 5.foo(&x); + //~^ ERROR: the trait bound `{integer}: Foo>` is not satisfied + 5.bar(x); + //~^ ERROR: the trait bound `{integer}: Foo>` is not satisfied + + let a = NonZero::new(5).unwrap(); + 5_u8.foo(&a); + //~^ ERROR: mismatched types + 5_u8.bar(a); + 5.foo(&a); + //~^ ERROR: the trait bound `{integer}: Foo>` is not satisfied + 5.bar(a); + //~^ ERROR: the trait bound `{integer}: Foo>` is not satisfied +} diff --git a/tests/ui/mismatched_types/non_zero_coerce_fail2.stderr b/tests/ui/mismatched_types/non_zero_coerce_fail2.stderr new file mode 100644 index 0000000000000..e09c7eafff755 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce_fail2.stderr @@ -0,0 +1,84 @@ +error[E0308]: mismatched types + --> $DIR/non_zero_coerce_fail2.rs:13:14 + | +LL | 5_u8.foo(&x); + | --- ^^ expected `&u8`, found `&NonZero` + | | + | arguments to this method are incorrect + | + = note: expected reference `&u8` + found reference `&NonZero` +note: method defined here + --> $DIR/non_zero_coerce_fail2.rs:4:8 + | +LL | fn foo(&self, other: &T) {} + | ^^^ --------- + +error[E0277]: the trait bound `{integer}: Foo>` is not satisfied + --> $DIR/non_zero_coerce_fail2.rs:16:11 + | +LL | 5.foo(&x); + | --- ^^ the trait `Foo>` is not implemented for `{integer}` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Foo`: + `u16` implements `Foo` + `u8` implements `Foo` + +error[E0277]: the trait bound `{integer}: Foo>` is not satisfied + --> $DIR/non_zero_coerce_fail2.rs:18:11 + | +LL | 5.bar(x); + | --- ^ the trait `Foo>` is not implemented for `{integer}` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Foo`: + `u16` implements `Foo` + `u8` implements `Foo` + +error[E0308]: mismatched types + --> $DIR/non_zero_coerce_fail2.rs:22:14 + | +LL | 5_u8.foo(&a); + | --- ^^ expected `&u8`, found `&NonZero<{integer}>` + | | + | arguments to this method are incorrect + | + = note: expected reference `&u8` + found reference `&NonZero<{integer}>` +note: method defined here + --> $DIR/non_zero_coerce_fail2.rs:4:8 + | +LL | fn foo(&self, other: &T) {} + | ^^^ --------- + +error[E0277]: the trait bound `{integer}: Foo>` is not satisfied + --> $DIR/non_zero_coerce_fail2.rs:25:11 + | +LL | 5.foo(&a); + | --- ^^ the trait `Foo>` is not implemented for `{integer}` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Foo`: + `u16` implements `Foo` + `u8` implements `Foo` + +error[E0277]: the trait bound `{integer}: Foo>` is not satisfied + --> $DIR/non_zero_coerce_fail2.rs:27:11 + | +LL | 5.bar(a); + | --- ^ the trait `Foo>` is not implemented for `{integer}` + | | + | required by a bound introduced by this call + | + = help: the following other types implement trait `Foo`: + `u16` implements `Foo` + `u8` implements `Foo` + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/non_zero_coerce_fail_infer.rs b/tests/ui/mismatched_types/non_zero_coerce_fail_infer.rs new file mode 100644 index 0000000000000..a0f98e726474b --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce_fail_infer.rs @@ -0,0 +1,14 @@ +use std::num::NonZero; + +trait Foo {} + +impl Foo for u8 {} +impl Foo for u16 {} + +fn foo(_: impl Foo) {} + +fn main() { + let x = NonZero::new(5_u8).unwrap(); + foo(x as _); + //~^ ERROR: type annotations needed +} diff --git a/tests/ui/mismatched_types/non_zero_coerce_fail_infer.stderr b/tests/ui/mismatched_types/non_zero_coerce_fail_infer.stderr new file mode 100644 index 0000000000000..cd95a18469984 --- /dev/null +++ b/tests/ui/mismatched_types/non_zero_coerce_fail_infer.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/non_zero_coerce_fail_infer.rs:12:14 + | +LL | foo(x as _); + | ^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`.