12
12
//! be considered a bug.
13
13
14
14
use crate :: def_path_res;
15
+ use rustc_ast:: { LitFloatType , LitIntType , LitKind } ;
15
16
use rustc_hir:: def:: { DefKind , Res } ;
16
17
use rustc_hir:: def_id:: DefId ;
17
18
use rustc_hir:: intravisit:: { InferKind , Visitor , VisitorExt , walk_qpath, walk_ty} ;
@@ -24,30 +25,32 @@ mod certainty;
24
25
use certainty:: { Certainty , Meet , join, meet} ;
25
26
26
27
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 ( )
28
29
}
29
30
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 {
31
34
let certainty = match & expr. kind {
32
35
ExprKind :: Unary ( _, expr)
33
36
| ExprKind :: Field ( expr, _)
34
37
| ExprKind :: Index ( expr, _, _)
35
- | ExprKind :: AddrOf ( _, _, expr) => expr_type_certainty ( cx, expr) ,
38
+ | ExprKind :: AddrOf ( _, _, expr) => expr_type_certainty ( cx, expr, in_arg ) ,
36
39
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 ) ) ) ,
38
41
39
42
ExprKind :: Call ( callee, args) => {
40
- let lhs = expr_type_certainty ( cx, callee) ;
43
+ let lhs = expr_type_certainty ( cx, callee, false ) ;
41
44
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 ) ) )
43
46
} else {
44
47
Certainty :: Uncertain
45
48
} ;
46
49
lhs. join_clearing_def_ids ( rhs)
47
50
} ,
48
51
49
52
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 ) ;
51
54
// Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method
52
55
// identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`,
53
56
// 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 {
59
62
let lhs = path_segment_certainty ( cx, receiver_type_certainty, method, false ) ;
60
63
let rhs = if type_is_inferable_from_arguments ( cx, expr) {
61
64
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 ) ) ) ,
63
67
)
64
68
} else {
65
69
Certainty :: Uncertain
66
70
} ;
67
71
lhs. join ( rhs)
68
72
} ,
69
73
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 ) ) ) ,
71
75
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
+ } ,
73
89
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
+ } ,
75
102
76
103
ExprKind :: Cast ( _, ty) => type_certainty ( cx, ty) ,
77
104
78
105
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 ) )
80
107
} ,
81
108
82
109
ExprKind :: Path ( qpath) => qpath_certainty ( cx, qpath, false ) ,
@@ -248,7 +275,7 @@ fn path_segment_certainty(
248
275
let lhs = local. ty . map_or ( Certainty :: Uncertain , |ty| type_certainty ( cx, ty) ) ;
249
276
let rhs = local
250
277
. init
251
- . map_or ( Certainty :: Uncertain , |init| expr_type_certainty ( cx, init) ) ;
278
+ . map_or ( Certainty :: Uncertain , |init| expr_type_certainty ( cx, init, false ) ) ;
252
279
let certainty = lhs. join ( rhs) ;
253
280
if resolves_to_type {
254
281
certainty
0 commit comments