1212//! be considered a bug.
1313
1414use crate :: paths:: { PathNS , lookup_path} ;
15+ use rustc_ast:: { LitFloatType , LitIntType , LitKind } ;
1516use rustc_hir:: def:: { DefKind , Res } ;
1617use rustc_hir:: def_id:: DefId ;
1718use rustc_hir:: intravisit:: { InferKind , Visitor , VisitorExt , walk_qpath, walk_ty} ;
18- use rustc_hir:: { self as hir, AmbigArg , Expr , ExprKind , GenericArgs , HirId , Node , PathSegment , QPath , TyKind } ;
19+ use rustc_hir:: { self as hir, AmbigArg , Expr , ExprKind , GenericArgs , HirId , Node , Param , PathSegment , QPath , TyKind } ;
1920use rustc_lint:: LateContext ;
2021use rustc_middle:: ty:: { self , AdtDef , GenericArgKind , Ty } ;
2122use rustc_span:: Span ;
@@ -24,30 +25,32 @@ mod certainty;
2425use certainty:: { Certainty , Meet , join, meet} ;
2526
2627pub 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 ) ,
@@ -188,6 +215,20 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo
188215 certainty
189216}
190217
218+ /// Tries to tell whether `param` resolves to something certain, e.g., a non-wildcard type if
219+ /// present. The certainty `DefId` is cleared before returning.
220+ fn param_certainty ( cx : & LateContext < ' _ > , param : & Param < ' _ > ) -> Certainty {
221+ let owner_did = cx. tcx . hir_enclosing_body_owner ( param. hir_id ) ;
222+ let Some ( fn_decl) = cx. tcx . hir_fn_decl_by_hir_id ( cx. tcx . local_def_id_to_hir_id ( owner_did) ) else {
223+ return Certainty :: Uncertain ;
224+ } ;
225+ let inputs = fn_decl. inputs ;
226+ let body_params = cx. tcx . hir_body_owned_by ( owner_did) . params ;
227+ std:: iter:: zip ( body_params, inputs)
228+ . find ( |( p, _) | p. hir_id == param. hir_id )
229+ . map_or ( Certainty :: Uncertain , |( _, ty) | type_certainty ( cx, ty) . clear_def_id ( ) )
230+ }
231+
191232fn path_segment_certainty (
192233 cx : & LateContext < ' _ > ,
193234 parent_certainty : Certainty ,
@@ -240,15 +281,16 @@ fn path_segment_certainty(
240281
241282 // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
242283 Res :: Local ( hir_id) => match cx. tcx . parent_hir_node ( hir_id) {
243- // An argument's type is always certain.
244- Node :: Param ( ..) => Certainty :: Certain ( None ) ,
284+ // A parameter's type is not always certain, as it may come from an untyped closure definition,
285+ // or from a wildcard in a typed closure definition.
286+ Node :: Param ( param) => param_certainty ( cx, param) ,
245287 // A local's type is certain if its type annotation is certain or it has an initializer whose
246288 // type is certain.
247289 Node :: LetStmt ( local) => {
248290 let lhs = local. ty . map_or ( Certainty :: Uncertain , |ty| type_certainty ( cx, ty) ) ;
249291 let rhs = local
250292 . init
251- . map_or ( Certainty :: Uncertain , |init| expr_type_certainty ( cx, init) ) ;
293+ . map_or ( Certainty :: Uncertain , |init| expr_type_certainty ( cx, init, false ) ) ;
252294 let certainty = lhs. join ( rhs) ;
253295 if resolves_to_type {
254296 certainty
0 commit comments