1
1
use clippy_utils:: diagnostics:: span_lint_and_then;
2
2
use clippy_utils:: source:: { SpanRangeExt , indent_of, reindent_multiline} ;
3
3
use clippy_utils:: sugg:: Sugg ;
4
+ use clippy_utils:: ty:: expr_type_is_certain;
4
5
use clippy_utils:: { is_expr_default, is_from_proc_macro} ;
5
6
use rustc_errors:: Applicability ;
6
7
use rustc_hir:: { Block , Expr , ExprKind , MatchSource , Node , StmtKind } ;
@@ -111,7 +112,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_
111
112
let arg_snippets_without_redundant_exprs: Vec < _ > = args_to_recover
112
113
. iter ( )
113
114
. filter ( |arg| !is_expr_default_nested ( cx, arg) && ( arg. span . from_expansion ( ) || !is_empty_block ( arg) ) )
114
- . filter_map ( |arg| get_expr_snippet ( cx, arg) )
115
+ . filter_map ( |arg| get_expr_snippet_with_type_certainty ( cx, arg) )
115
116
. collect ( ) ;
116
117
117
118
if let Some ( call_snippet) = expr. span . get_source_text ( cx) {
@@ -160,6 +161,20 @@ fn is_expr_default_nested<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
160
161
if block. expr. is_some( ) && is_expr_default_nested( cx, block. expr. unwrap( ) ) )
161
162
}
162
163
164
+ enum MaybeTypeUncertain < ' tcx > {
165
+ Certain ( Sugg < ' tcx > ) ,
166
+ Uncertain ( Sugg < ' tcx > ) ,
167
+ }
168
+
169
+ impl ToString for MaybeTypeUncertain < ' _ > {
170
+ fn to_string ( & self ) -> String {
171
+ match self {
172
+ MaybeTypeUncertain :: Certain ( sugg) => sugg. to_string ( ) ,
173
+ MaybeTypeUncertain :: Uncertain ( sugg) => format ! ( "let _: () = {}" , sugg) ,
174
+ }
175
+ }
176
+ }
177
+
163
178
fn get_expr_snippet < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) -> Option < Sugg < ' tcx > > {
164
179
let mut app = Applicability :: MachineApplicable ;
165
180
let snip = Sugg :: hir_with_context ( cx, expr, SyntaxContext :: root ( ) , ".." , & mut app) ;
@@ -170,6 +185,25 @@ fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
170
185
Some ( snip)
171
186
}
172
187
188
+ fn get_expr_snippet_with_type_certainty < ' tcx > (
189
+ cx : & LateContext < ' tcx > ,
190
+ expr : & ' tcx Expr < ' tcx > ,
191
+ ) -> Option < MaybeTypeUncertain < ' tcx > > {
192
+ get_expr_snippet ( cx, expr) . map ( |snip| {
193
+ // If the type of the expression is certain, we can use it directly.
194
+ // Otherwise, we wrap it in a `let _: () = ...` to ensure the type is correct.
195
+ if !expr_type_is_certain ( cx, expr) && !is_block_with_no_expr ( expr) {
196
+ MaybeTypeUncertain :: Uncertain ( snip)
197
+ } else {
198
+ MaybeTypeUncertain :: Certain ( snip)
199
+ }
200
+ } )
201
+ }
202
+
203
+ fn is_block_with_no_expr ( expr : & Expr < ' _ > ) -> bool {
204
+ matches ! ( expr. kind, ExprKind :: Block ( Block { expr: None , .. } , _) )
205
+ }
206
+
173
207
fn is_empty_block ( expr : & Expr < ' _ > ) -> bool {
174
208
matches ! (
175
209
expr. kind,
@@ -189,7 +223,7 @@ fn fmt_stmts_and_call(
189
223
call_expr : & Expr < ' _ > ,
190
224
call_snippet : & str ,
191
225
args_snippets : & [ Sugg < ' _ > ] ,
192
- non_empty_block_args_snippets : & [ Sugg < ' _ > ] ,
226
+ non_empty_block_args_snippets : & [ MaybeTypeUncertain < ' _ > ] ,
193
227
) -> String {
194
228
let call_expr_indent = indent_of ( cx, call_expr. span ) . unwrap_or ( 0 ) ;
195
229
let call_snippet_with_replacements = args_snippets. iter ( ) . fold ( call_snippet. to_owned ( ) , |acc, arg| {
0 commit comments