diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index c88a0539d70e..964a0e194e6d 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::ty::expr_type_is_certain; use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; @@ -143,7 +144,10 @@ pub(super) fn check<'tcx>( } } - if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) { + if cast_from.kind() == cast_to.kind() + && !expr.span.in_external_macro(cx.sess().source_map()) + && expr_type_is_certain(cx, cast_expr) + { enum MaybeParenOrBlock { Paren, Block, @@ -167,7 +171,7 @@ pub(super) fn check<'tcx>( sym::assert_ne_macro, sym::debug_assert_ne_macro, ]; - matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if + matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym))) } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 24864e8ef96d..d3a584c60780 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -6,6 +6,7 @@ #![feature(assert_matches)] #![feature(unwrap_infallible)] #![feature(array_windows)] +#![feature(try_trait_v2)] #![recursion_limit = "512"] #![allow( clippy::missing_errors_doc, diff --git a/clippy_utils/src/ty/type_certainty/certainty.rs b/clippy_utils/src/ty/type_certainty/certainty.rs index 0e69ffa2212d..b2f5d857b8f4 100644 --- a/clippy_utils/src/ty/type_certainty/certainty.rs +++ b/clippy_utils/src/ty/type_certainty/certainty.rs @@ -1,5 +1,12 @@ use rustc_hir::def_id::DefId; use std::fmt::Debug; +use std::ops::{ControlFlow, FromResidual, Try}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum TypeKind { + PrimTy, + AdtDef(DefId), +} #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Certainty { @@ -7,9 +14,9 @@ pub enum Certainty { Uncertain, /// The type can be determined purely from subexpressions. If the argument is `Some(..)`, the - /// specific `DefId` is known. Such arguments are needed to handle path segments whose `res` is - /// `Res::Err`. - Certain(Option), + /// specific primitive type or `DefId` is known. Such arguments are needed to handle path + /// segments whose `res` is `Res::Err`. + Certain(Option), /// The heuristic believes that more than one `DefId` applies to a type---this is a bug. Contradiction, @@ -23,7 +30,7 @@ pub trait TryJoin: Sized { fn try_join(self, other: Self) -> Option; } -impl Meet for Option { +impl Meet for Option { fn meet(self, other: Self) -> Self { match (self, other) { (None, _) | (_, None) => None, @@ -32,11 +39,11 @@ impl Meet for Option { } } -impl TryJoin for Option { +impl TryJoin for Option { fn try_join(self, other: Self) -> Option { match (self, other) { (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(Some(lhs)), - (Some(def_id), _) | (_, Some(def_id)) => Some(Some(def_id)), + (Some(ty_kind), _) | (_, Some(ty_kind)) => Some(Some(ty_kind)), (None, None) => Some(None), } } @@ -79,11 +86,11 @@ impl Certainty { /// Join two `Certainty`s after clearing their `DefId`s. This method should be used when `self` /// or `other` do not necessarily refer to types, e.g., when they are aggregations of other /// `Certainty`s. - pub fn join_clearing_def_ids(self, other: Self) -> Self { - self.clear_def_id().join(other.clear_def_id()) + pub fn join_clearing_types(self, other: Self) -> Self { + self.clear_type().join(other.clear_type()) } - pub fn clear_def_id(self) -> Certainty { + pub fn clear_type(self) -> Certainty { if matches!(self, Certainty::Certain(_)) { Certainty::Certain(None) } else { @@ -91,9 +98,17 @@ impl Certainty { } } + pub fn with_prim_ty(self) -> Certainty { + if matches!(self, Certainty::Certain(_)) { + Certainty::Certain(Some(TypeKind::PrimTy)) + } else { + self + } + } + pub fn with_def_id(self, def_id: DefId) -> Certainty { if matches!(self, Certainty::Certain(_)) { - Certainty::Certain(Some(def_id)) + Certainty::Certain(Some(TypeKind::AdtDef(def_id))) } else { self } @@ -101,7 +116,7 @@ impl Certainty { pub fn to_def_id(self) -> Option { match self { - Certainty::Certain(inner) => inner, + Certainty::Certain(Some(TypeKind::AdtDef(def_id))) => Some(def_id), _ => None, } } @@ -120,3 +135,28 @@ pub fn meet(iter: impl Iterator) -> Certainty { pub fn join(iter: impl Iterator) -> Certainty { iter.fold(Certainty::Uncertain, Certainty::join) } + +pub struct NoCertainty(Certainty); + +impl FromResidual for Certainty { + fn from_residual(residual: NoCertainty) -> Self { + residual.0 + } +} + +impl Try for Certainty { + type Output = Certainty; + + type Residual = NoCertainty; + + fn from_output(output: Self::Output) -> Self { + output + } + + fn branch(self) -> ControlFlow { + match self { + Certainty::Certain(_) => ControlFlow::Continue(self), + _ => ControlFlow::Break(NoCertainty(self)), + } + } +} diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs index d9c7e6eac9f6..0b2a796d0dbe 100644 --- a/clippy_utils/src/ty/type_certainty/mod.rs +++ b/clippy_utils/src/ty/type_certainty/mod.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty}; use rustc_span::Span; mod certainty; -use certainty::{Certainty, Meet, join, meet}; +use certainty::{Certainty, Meet, TypeKind, join, meet}; pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { expr_type_certainty(cx, expr, false).is_certain() @@ -46,11 +46,12 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> C } else { Certainty::Uncertain }; - lhs.join_clearing_def_ids(rhs) + lhs.join_clearing_types(rhs) }, ExprKind::MethodCall(method, receiver, args, _) => { - let mut receiver_type_certainty = expr_type_certainty(cx, receiver, false); + let mut receiver_type_certainty = expr_type_certainty(cx, receiver, false)?; + // Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method // identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`, // for example. So update the `DefId` in `receiver_type_certainty` (if any). @@ -66,7 +67,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> C .chain(args.iter().map(|arg| expr_type_certainty(cx, arg, true))), ) } else { - Certainty::Uncertain + return Certainty::Uncertain; }; lhs.join(rhs) }, @@ -110,15 +111,20 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> C ExprKind::Struct(qpath, _, _) => qpath_certainty(cx, qpath, true), + ExprKind::Block(block, _) => block + .expr + .map_or(Certainty::Certain(None), |expr| expr_type_certainty(cx, expr, false)), + _ => Certainty::Uncertain, }; - let expr_ty = cx.typeck_results().expr_ty(expr); - if let Some(def_id) = adt_def_id(expr_ty) { - certainty.with_def_id(def_id) - } else { - certainty.clear_def_id() - } + let result = match cx.typeck_results().expr_ty(expr).kind() { + ty::Adt(adt_def, _) => certainty.with_def_id(adt_def.did()), + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => certainty.with_prim_ty(), + _ => certainty.clear_type(), + }; + + result } struct CertaintyVisitor<'cx, 'tcx> { @@ -205,7 +211,11 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo .map_or(Certainty::Uncertain, |def_id| { let generics = cx.tcx.generics_of(def_id); if generics.is_empty() { - Certainty::Certain(if resolves_to_type { Some(def_id) } else { None }) + Certainty::Certain(if resolves_to_type { + Some(TypeKind::AdtDef(def_id)) + } else { + None + }) } else { Certainty::Uncertain } @@ -226,7 +236,7 @@ fn param_certainty(cx: &LateContext<'_>, param: &Param<'_>) -> Certainty { let body_params = cx.tcx.hir_body_owned_by(owner_did).params; std::iter::zip(body_params, inputs) .find(|(p, _)| p.hir_id == param.hir_id) - .map_or(Certainty::Uncertain, |(_, ty)| type_certainty(cx, ty).clear_def_id()) + .map_or(Certainty::Uncertain, |(_, ty)| type_certainty(cx, ty).clear_type()) } fn path_segment_certainty( @@ -259,7 +269,7 @@ fn path_segment_certainty( .args .map_or(Certainty::Uncertain, |args| generic_args_certainty(cx, args)); // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value. - let certainty = lhs.join_clearing_def_ids(rhs); + let certainty = lhs.join_clearing_types(rhs); if resolves_to_type { if let DefKind::TyAlias = cx.tcx.def_kind(def_id) { adt_def_id(cx.tcx.type_of(def_id).instantiate_identity()) @@ -275,9 +285,7 @@ fn path_segment_certainty( } }, - Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(_) => { - Certainty::Certain(None) - }, + Res::PrimTy(_) => Certainty::Certain(Some(TypeKind::PrimTy)), // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`. Res::Local(hir_id) => match cx.tcx.parent_hir_node(hir_id) { @@ -295,13 +303,13 @@ fn path_segment_certainty( if resolves_to_type { certainty } else { - certainty.clear_def_id() + certainty.clear_type() } }, _ => Certainty::Uncertain, }, - _ => Certainty::Uncertain, + _ => Certainty::Certain(None), }; debug_assert!(resolves_to_type || certainty.to_def_id().is_none()); certainty diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index 91ff4b9ee771..54e8fb400b75 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -6,6 +6,7 @@ clippy::no_effect, clippy::nonstandard_macro_braces, clippy::unnecessary_operation, + clippy::double_parens, nonstandard_style, unused )] @@ -283,4 +284,43 @@ mod fixable { let _ = 5i32 as i64; //~^ unnecessary_cast } + + fn issue_14366(i: u32) { + // Do not remove the cast if it helps determining the type + let _ = ((1.0 / 8.0) as f64).powf(i as f64); + + // But remove useless casts anyway + let _ = (((1.0 / 8.0) as f64)).powf(i as f64); + //~^ unnecessary_cast + } + + fn ambiguity() { + pub trait T {} + impl T for u32 {} + impl T for String {} + fn f(_: impl T) {} + + f((1 + 2) as u32); + f(((1 + 2u32))); + //~^ unnecessary_cast + } + + fn with_blocks(a: i64, b: i64, c: u64) { + let threshold = if c < 10 { a } else { b }; + let _ = threshold; + //~^ unnecessary_cast + } + + fn with_prim_ty() { + let threshold = 20; + let threshold = if threshold == 0 { + i64::MAX + } else if threshold <= 60 { + 10 + } else { + 0 + }; + let _ = threshold; + //~^ unnecessary_cast + } } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 5444a914db16..f3f9c3cd76fa 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -6,6 +6,7 @@ clippy::no_effect, clippy::nonstandard_macro_braces, clippy::unnecessary_operation, + clippy::double_parens, nonstandard_style, unused )] @@ -283,4 +284,43 @@ mod fixable { let _ = 5i32 as i64 as i64; //~^ unnecessary_cast } + + fn issue_14366(i: u32) { + // Do not remove the cast if it helps determining the type + let _ = ((1.0 / 8.0) as f64).powf(i as f64); + + // But remove useless casts anyway + let _ = (((1.0 / 8.0) as f64) as f64).powf(i as f64); + //~^ unnecessary_cast + } + + fn ambiguity() { + pub trait T {} + impl T for u32 {} + impl T for String {} + fn f(_: impl T) {} + + f((1 + 2) as u32); + f((1 + 2u32) as u32); + //~^ unnecessary_cast + } + + fn with_blocks(a: i64, b: i64, c: u64) { + let threshold = if c < 10 { a } else { b }; + let _ = threshold as i64; + //~^ unnecessary_cast + } + + fn with_prim_ty() { + let threshold = 20; + let threshold = if threshold == 0 { + i64::MAX + } else if threshold <= 60 { + 10 + } else { + 0 + }; + let _ = threshold as i64; + //~^ unnecessary_cast + } } diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index 3e3c5eb81c10..06f690cef3e4 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -1,5 +1,5 @@ error: casting raw pointers to the same type and constness is unnecessary (`*const T` -> `*const T`) - --> tests/ui/unnecessary_cast.rs:19:5 + --> tests/ui/unnecessary_cast.rs:20:5 | LL | ptr as *const T | ^^^^^^^^^^^^^^^ help: try: `ptr` @@ -8,262 +8,286 @@ LL | ptr as *const T = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:55:5 + --> tests/ui/unnecessary_cast.rs:56:5 | LL | 1i32 as i32; | ^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:57:5 + --> tests/ui/unnecessary_cast.rs:58:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) - --> tests/ui/unnecessary_cast.rs:59:5 + --> tests/ui/unnecessary_cast.rs:60:5 | LL | false as bool; | ^^^^^^^^^^^^^ help: try: `false` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:63:5 + --> tests/ui/unnecessary_cast.rs:64:5 | LL | -1_i32 as i32; | ^^^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:65:5 + --> tests/ui/unnecessary_cast.rs:66:5 | LL | - 1_i32 as i32; | ^^^^^^^^^^^^^^ help: try: `- 1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:67:5 + --> tests/ui/unnecessary_cast.rs:68:5 | LL | -1f32 as f32; | ^^^^^^^^^^^^ help: try: `-1_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:69:5 + --> tests/ui/unnecessary_cast.rs:70:5 | LL | 1_i32 as i32; | ^^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:71:5 + --> tests/ui/unnecessary_cast.rs:72:5 | LL | 1_f32 as f32; | ^^^^^^^^^^^^ help: try: `1_f32` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:74:22 + --> tests/ui/unnecessary_cast.rs:75:22 | LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:77:5 + --> tests/ui/unnecessary_cast.rs:78:5 | LL | [1u8, 2].as_ptr() as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`) - --> tests/ui/unnecessary_cast.rs:80:5 + --> tests/ui/unnecessary_cast.rs:81:5 | LL | [1u8, 2].as_mut_ptr() as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) - --> tests/ui/unnecessary_cast.rs:92:5 + --> tests/ui/unnecessary_cast.rs:93:5 | LL | owo::([1u32].as_ptr()) as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::([1u32].as_ptr())` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:94:5 + --> tests/ui/unnecessary_cast.rs:95:5 | LL | uwu::([1u32].as_ptr()) as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) - --> tests/ui/unnecessary_cast.rs:97:5 + --> tests/ui/unnecessary_cast.rs:98:5 | LL | uwu::([1u32].as_ptr()) as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:133:5 + --> tests/ui/unnecessary_cast.rs:134:5 | LL | aaa() as u32; | ^^^^^^^^^^^^ help: try: `aaa()` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:136:5 + --> tests/ui/unnecessary_cast.rs:137:5 | LL | aaa() as u32; | ^^^^^^^^^^^^ help: try: `aaa()` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:173:9 + --> tests/ui/unnecessary_cast.rs:174:9 | LL | 100 as f32; | ^^^^^^^^^^ help: try: `100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:175:9 + --> tests/ui/unnecessary_cast.rs:176:9 | LL | 100 as f64; | ^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:177:9 + --> tests/ui/unnecessary_cast.rs:178:9 | LL | 100_i32 as f64; | ^^^^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:179:17 + --> tests/ui/unnecessary_cast.rs:180:17 | LL | let _ = -100 as f32; | ^^^^^^^^^^^ help: try: `-100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:181:17 + --> tests/ui/unnecessary_cast.rs:182:17 | LL | let _ = -100 as f64; | ^^^^^^^^^^^ help: try: `-100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:183:17 + --> tests/ui/unnecessary_cast.rs:184:17 | LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:185:9 + --> tests/ui/unnecessary_cast.rs:186:9 | LL | 100. as f32; | ^^^^^^^^^^^ help: try: `100_f32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:187:9 + --> tests/ui/unnecessary_cast.rs:188:9 | LL | 100. as f64; | ^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:200:9 + --> tests/ui/unnecessary_cast.rs:201:9 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:202:9 + --> tests/ui/unnecessary_cast.rs:203:9 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> tests/ui/unnecessary_cast.rs:204:9 + --> tests/ui/unnecessary_cast.rs:205:9 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> tests/ui/unnecessary_cast.rs:206:9 + --> tests/ui/unnecessary_cast.rs:207:9 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:208:9 + --> tests/ui/unnecessary_cast.rs:209:9 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:211:9 + --> tests/ui/unnecessary_cast.rs:212:9 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:213:9 + --> tests/ui/unnecessary_cast.rs:214:9 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:218:17 + --> tests/ui/unnecessary_cast.rs:219:17 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:220:17 + --> tests/ui/unnecessary_cast.rs:221:17 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` error: casting to the same type is unnecessary (`i32` -> `i32`) - --> tests/ui/unnecessary_cast.rs:227:18 + --> tests/ui/unnecessary_cast.rs:228:18 | LL | let _ = &(x as i32); | ^^^^^^^^^^ help: try: `{ x }` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:234:22 + --> tests/ui/unnecessary_cast.rs:235:22 | LL | let _: i32 = -(1) as i32; | ^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i64` is unnecessary - --> tests/ui/unnecessary_cast.rs:237:22 + --> tests/ui/unnecessary_cast.rs:238:22 | LL | let _: i64 = -(1) as i64; | ^^^^^^^^^^^ help: try: `-1_i64` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:245:22 + --> tests/ui/unnecessary_cast.rs:246:22 | LL | let _: f64 = (-8.0 as f64).exp(); | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:248:23 + --> tests/ui/unnecessary_cast.rs:249:23 | LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior | ^^^^^^^^^^^^ help: try: `8.0_f64` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> tests/ui/unnecessary_cast.rs:258:20 + --> tests/ui/unnecessary_cast.rs:259:20 | LL | let _num = foo() as f32; | ^^^^^^^^^^^^ help: try: `foo()` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:269:9 + --> tests/ui/unnecessary_cast.rs:270:9 | LL | (*x as usize).pow(2) | ^^^^^^^^^^^^^ help: try: `(*x)` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:277:31 + --> tests/ui/unnecessary_cast.rs:278:31 | LL | assert_eq!(vec.len(), x as usize); | ^^^^^^^^^^ help: try: `x` error: casting to the same type is unnecessary (`i64` -> `i64`) - --> tests/ui/unnecessary_cast.rs:280:17 + --> tests/ui/unnecessary_cast.rs:281:17 | LL | let _ = (5i32 as i64 as i64).abs(); | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` error: casting to the same type is unnecessary (`i64` -> `i64`) - --> tests/ui/unnecessary_cast.rs:283:17 + --> tests/ui/unnecessary_cast.rs:284:17 | LL | let _ = 5i32 as i64 as i64; | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` -error: aborting due to 44 previous errors +error: casting to the same type is unnecessary (`f64` -> `f64`) + --> tests/ui/unnecessary_cast.rs:293:17 + | +LL | let _ = (((1.0 / 8.0) as f64) as f64).powf(i as f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(((1.0 / 8.0) as f64))` + +error: casting to the same type is unnecessary (`u32` -> `u32`) + --> tests/ui/unnecessary_cast.rs:304:11 + | +LL | f((1 + 2u32) as u32); + | ^^^^^^^^^^^^^^^^^ help: try: `((1 + 2u32))` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:310:17 + | +LL | let _ = threshold as i64; + | ^^^^^^^^^^^^^^^^ help: try: `threshold` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:323:17 + | +LL | let _ = threshold as i64; + | ^^^^^^^^^^^^^^^^ help: try: `threshold` + +error: aborting due to 48 previous errors