Skip to content

Commit 7d2abed

Browse files
committed
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.
1 parent d78622e commit 7d2abed

File tree

1 file changed

+40
-13
lines changed
  • clippy_utils/src/ty/type_certainty

1 file changed

+40
-13
lines changed

clippy_utils/src/ty/type_certainty/mod.rs

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! be considered a bug.
1313
1414
use crate::def_path_res;
15+
use rustc_ast::{LitFloatType, LitIntType, LitKind};
1516
use rustc_hir::def::{DefKind, Res};
1617
use rustc_hir::def_id::DefId;
1718
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};
@@ -24,30 +25,32 @@ mod certainty;
2425
use certainty::{Certainty, Meet, join, meet};
2526

2627
pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
27-
expr_type_certainty(cx, expr).is_certain()
28+
expr_type_certainty(cx, expr, false).is_certain()
2829
}
2930

30-
fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
31+
/// Determine the type certainty of `expr`. `in_arg` indicates that the expression happens within
32+
/// the evaluation of a function or method call argument.
33+
fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>, in_arg: bool) -> Certainty {
3134
let certainty = match &expr.kind {
3235
ExprKind::Unary(_, expr)
3336
| ExprKind::Field(expr, _)
3437
| ExprKind::Index(expr, _, _)
35-
| ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
38+
| ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr, in_arg),
3639

37-
ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
40+
ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))),
3841

3942
ExprKind::Call(callee, args) => {
40-
let lhs = expr_type_certainty(cx, callee);
43+
let lhs = expr_type_certainty(cx, callee, false);
4144
let rhs = if type_is_inferable_from_arguments(cx, expr) {
42-
meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
45+
meet(args.iter().map(|arg| expr_type_certainty(cx, arg, true)))
4346
} else {
4447
Certainty::Uncertain
4548
};
4649
lhs.join_clearing_def_ids(rhs)
4750
},
4851

4952
ExprKind::MethodCall(method, receiver, args, _) => {
50-
let mut receiver_type_certainty = expr_type_certainty(cx, receiver);
53+
let mut receiver_type_certainty = expr_type_certainty(cx, receiver, false);
5154
// Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method
5255
// identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`,
5356
// for example. So update the `DefId` in `receiver_type_certainty` (if any).
@@ -59,24 +62,48 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
5962
let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
6063
let rhs = if type_is_inferable_from_arguments(cx, expr) {
6164
meet(
62-
std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
65+
std::iter::once(receiver_type_certainty)
66+
.chain(args.iter().map(|arg| expr_type_certainty(cx, arg, true))),
6367
)
6468
} else {
6569
Certainty::Uncertain
6670
};
6771
lhs.join(rhs)
6872
},
6973

70-
ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
74+
ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr, in_arg))),
7175

72-
ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)),
76+
ExprKind::Binary(_, lhs, rhs) => {
77+
// If one of the side of the expression is uncertain, the certainty will come from the other side,
78+
// with no information on the type.
79+
match (
80+
expr_type_certainty(cx, lhs, in_arg),
81+
expr_type_certainty(cx, rhs, in_arg),
82+
) {
83+
(Certainty::Uncertain, Certainty::Certain(_)) | (Certainty::Certain(_), Certainty::Uncertain) => {
84+
Certainty::Certain(None)
85+
},
86+
(l, r) => l.meet(r),
87+
}
88+
},
7389

74-
ExprKind::Lit(_) => Certainty::Certain(None),
90+
ExprKind::Lit(lit) => {
91+
if !in_arg
92+
&& matches!(
93+
lit.node,
94+
LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed)
95+
)
96+
{
97+
Certainty::Uncertain
98+
} else {
99+
Certainty::Certain(None)
100+
}
101+
},
75102

76103
ExprKind::Cast(_, ty) => type_certainty(cx, ty),
77104

78105
ExprKind::If(_, if_expr, Some(else_expr)) => {
79-
expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr))
106+
expr_type_certainty(cx, if_expr, in_arg).join(expr_type_certainty(cx, else_expr, in_arg))
80107
},
81108

82109
ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false),
@@ -248,7 +275,7 @@ fn path_segment_certainty(
248275
let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
249276
let rhs = local
250277
.init
251-
.map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init));
278+
.map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init, false));
252279
let certainty = lhs.join(rhs);
253280
if resolves_to_type {
254281
certainty

0 commit comments

Comments
 (0)