about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-03-28 16:07:41 +0100
committerSamuel Tardieu <sam@rfc1149.net>2025-07-03 22:14:00 +0200
commit08f5ebafa62a5fd3a30bc3f8e4f2c50ae2a2ecbf (patch)
treeb92554d034c18611cc53a2fe11cf48ecbb6608ba
parent321542e6117c6e3a5ac2bf50310e87afdde50668 (diff)
downloadrust-08f5ebafa62a5fd3a30bc3f8e4f2c50ae2a2ecbf.tar.gz
rust-08f5ebafa62a5fd3a30bc3f8e4f2c50ae2a2ecbf.zip
Mark unsuffixed type literals are type uncertain by default
However, if they appear within the context of a function argument, they
will be marked as certain, as they might eventually be considered `i32`
by default if the context is not more specific.

Also, in the case of binary expressions, if one of the side is
uncertain, then the certainty will come from the other side.
-rw-r--r--clippy_utils/src/ty/type_certainty/mod.rs53
1 files changed, 40 insertions, 13 deletions
diff --git a/clippy_utils/src/ty/type_certainty/mod.rs b/clippy_utils/src/ty/type_certainty/mod.rs
index 84df36c75bf..20bb0d44c59 100644
--- a/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/clippy_utils/src/ty/type_certainty/mod.rs
@@ -12,6 +12,7 @@
 //! be considered a bug.
 
 use crate::paths::{PathNS, lookup_path};
+use rustc_ast::{LitFloatType, LitIntType, LitKind};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
@@ -24,22 +25,24 @@ mod certainty;
 use certainty::{Certainty, Meet, join, meet};
 
 pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    expr_type_certainty(cx, expr).is_certain()
+    expr_type_certainty(cx, expr, false).is_certain()
 }
 
-fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
+/// Determine the type certainty of `expr`. `in_arg` indicates that the expression happens within
+/// the evaluation of a function or method call argument.
+fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> Certainty {
     let certainty = match &expr.kind {
         ExprKind::Unary(_, expr)
         | ExprKind::Field(expr, _)
         | ExprKind::Index(expr, _, _)
-        | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
+        | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr, in_arg),
 
-        ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+        ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))),
 
         ExprKind::Call(callee, args) => {
-            let lhs = expr_type_certainty(cx, callee);
+            let lhs = expr_type_certainty(cx, callee, false);
             let rhs = if type_is_inferable_from_arguments(cx, expr) {
-                meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
+                meet(args.iter().map(|arg| expr_type_certainty(cx, arg, true)))
             } else {
                 Certainty::Uncertain
             };
@@ -47,7 +50,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
         },
 
         ExprKind::MethodCall(method, receiver, args, _) => {
-            let mut receiver_type_certainty = expr_type_certainty(cx, receiver);
+            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).
@@ -59,7 +62,8 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
             let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
             let rhs = if type_is_inferable_from_arguments(cx, expr) {
                 meet(
-                    std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
+                    std::iter::once(receiver_type_certainty)
+                        .chain(args.iter().map(|arg| expr_type_certainty(cx, arg, true))),
                 )
             } else {
                 Certainty::Uncertain
@@ -67,16 +71,39 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
             lhs.join(rhs)
         },
 
-        ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+        ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))),
 
-        ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)),
+        ExprKind::Binary(_, lhs, rhs) => {
+            // If one of the side of the expression is uncertain, the certainty will come from the other side,
+            // with no information on the type.
+            match (
+                expr_type_certainty(cx, lhs, in_arg),
+                expr_type_certainty(cx, rhs, in_arg),
+            ) {
+                (Certainty::Uncertain, Certainty::Certain(_)) | (Certainty::Certain(_), Certainty::Uncertain) => {
+                    Certainty::Certain(None)
+                },
+                (l, r) => l.meet(r),
+            }
+        },
 
-        ExprKind::Lit(_) => Certainty::Certain(None),
+        ExprKind::Lit(lit) => {
+            if !in_arg
+                && matches!(
+                    lit.node,
+                    LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)
+                )
+            {
+                Certainty::Uncertain
+            } else {
+                Certainty::Certain(None)
+            }
+        },
 
         ExprKind::Cast(_, ty) => type_certainty(cx, ty),
 
         ExprKind::If(_, if_expr, Some(else_expr)) => {
-            expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr))
+            expr_type_certainty(cx, if_expr, in_arg).join(expr_type_certainty(cx, else_expr, in_arg))
         },
 
         ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false),
@@ -248,7 +275,7 @@ fn path_segment_certainty(
                 let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
                 let rhs = local
                     .init
-                    .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init));
+                    .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init, false));
                 let certainty = lhs.join(rhs);
                 if resolves_to_type {
                     certainty