]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/check/demand.rs
Auto merge of #88865 - guswynn:must_not_suspend, r=oli-obk
[rust.git] / compiler / rustc_typeck / src / check / demand.rs
1 use crate::check::FnCtxt;
2 use rustc_infer::infer::InferOk;
3 use rustc_trait_selection::infer::InferCtxtExt as _;
4 use rustc_trait_selection::traits::ObligationCause;
5
6 use rustc_ast::util::parser::PREC_POSTFIX;
7 use rustc_errors::{Applicability, DiagnosticBuilder};
8 use rustc_hir as hir;
9 use rustc_hir::lang_items::LangItem;
10 use rustc_hir::{is_range_literal, Node};
11 use rustc_middle::lint::in_external_macro;
12 use rustc_middle::ty::adjustment::AllowTwoPhase;
13 use rustc_middle::ty::print::with_no_trimmed_paths;
14 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
15 use rustc_span::symbol::sym;
16 use rustc_span::{BytePos, Span};
17
18 use super::method::probe;
19
20 use std::iter;
21
22 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23     pub fn emit_coerce_suggestions(
24         &self,
25         err: &mut DiagnosticBuilder<'_>,
26         expr: &hir::Expr<'_>,
27         expr_ty: Ty<'tcx>,
28         expected: Ty<'tcx>,
29         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
30     ) {
31         self.annotate_expected_due_to_let_ty(err, expr);
32         self.suggest_compatible_variants(err, expr, expected, expr_ty);
33         self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
34         if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
35             return;
36         }
37         self.suggest_no_capture_closure(err, expected, expr_ty);
38         self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
39         self.suggest_missing_parentheses(err, expr);
40         self.note_need_for_fn_pointer(err, expected, expr_ty);
41         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
42         self.report_closure_inferred_return_type(err, expected);
43     }
44
45     // Requires that the two types unify, and prints an error message if
46     // they don't.
47     pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
48         if let Some(mut e) = self.demand_suptype_diag(sp, expected, actual) {
49             e.emit();
50         }
51     }
52
53     pub fn demand_suptype_diag(
54         &self,
55         sp: Span,
56         expected: Ty<'tcx>,
57         actual: Ty<'tcx>,
58     ) -> Option<DiagnosticBuilder<'tcx>> {
59         self.demand_suptype_with_origin(&self.misc(sp), expected, actual)
60     }
61
62     pub fn demand_suptype_with_origin(
63         &self,
64         cause: &ObligationCause<'tcx>,
65         expected: Ty<'tcx>,
66         actual: Ty<'tcx>,
67     ) -> Option<DiagnosticBuilder<'tcx>> {
68         match self.at(cause, self.param_env).sup(expected, actual) {
69             Ok(InferOk { obligations, value: () }) => {
70                 self.register_predicates(obligations);
71                 None
72             }
73             Err(e) => Some(self.report_mismatched_types(&cause, expected, actual, e)),
74         }
75     }
76
77     pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
78         if let Some(mut err) = self.demand_eqtype_diag(sp, expected, actual) {
79             err.emit();
80         }
81     }
82
83     pub fn demand_eqtype_diag(
84         &self,
85         sp: Span,
86         expected: Ty<'tcx>,
87         actual: Ty<'tcx>,
88     ) -> Option<DiagnosticBuilder<'tcx>> {
89         self.demand_eqtype_with_origin(&self.misc(sp), expected, actual)
90     }
91
92     pub fn demand_eqtype_with_origin(
93         &self,
94         cause: &ObligationCause<'tcx>,
95         expected: Ty<'tcx>,
96         actual: Ty<'tcx>,
97     ) -> Option<DiagnosticBuilder<'tcx>> {
98         match self.at(cause, self.param_env).eq(expected, actual) {
99             Ok(InferOk { obligations, value: () }) => {
100                 self.register_predicates(obligations);
101                 None
102             }
103             Err(e) => Some(self.report_mismatched_types(cause, expected, actual, e)),
104         }
105     }
106
107     pub fn demand_coerce(
108         &self,
109         expr: &hir::Expr<'_>,
110         checked_ty: Ty<'tcx>,
111         expected: Ty<'tcx>,
112         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
113         allow_two_phase: AllowTwoPhase,
114     ) -> Ty<'tcx> {
115         let (ty, err) =
116             self.demand_coerce_diag(expr, checked_ty, expected, expected_ty_expr, allow_two_phase);
117         if let Some(mut err) = err {
118             err.emit();
119         }
120         ty
121     }
122
123     /// Checks that the type of `expr` can be coerced to `expected`.
124     ///
125     /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!`
126     /// will be permitted if the diverges flag is currently "always".
127     pub fn demand_coerce_diag(
128         &self,
129         expr: &hir::Expr<'_>,
130         checked_ty: Ty<'tcx>,
131         expected: Ty<'tcx>,
132         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
133         allow_two_phase: AllowTwoPhase,
134     ) -> (Ty<'tcx>, Option<DiagnosticBuilder<'tcx>>) {
135         let expected = self.resolve_vars_with_obligations(expected);
136
137         let e = match self.try_coerce(expr, checked_ty, expected, allow_two_phase, None) {
138             Ok(ty) => return (ty, None),
139             Err(e) => e,
140         };
141
142         let expr = expr.peel_drop_temps();
143         let cause = self.misc(expr.span);
144         let expr_ty = self.resolve_vars_with_obligations(checked_ty);
145         let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e);
146
147         if self.is_assign_to_bool(expr, expected) {
148             // Error reported in `check_assign` so avoid emitting error again.
149             err.delay_as_bug();
150             return (expected, None);
151         }
152
153         self.emit_coerce_suggestions(&mut err, expr, expr_ty, expected, expected_ty_expr);
154
155         (expected, Some(err))
156     }
157
158     fn annotate_expected_due_to_let_ty(
159         &self,
160         err: &mut DiagnosticBuilder<'_>,
161         expr: &hir::Expr<'_>,
162     ) {
163         let parent = self.tcx.hir().get_parent_node(expr.hir_id);
164         if let Some(hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. })) =
165             self.tcx.hir().find(parent)
166         {
167             if init.hir_id == expr.hir_id {
168                 // Point at `let` assignment type.
169                 err.span_label(ty.span, "expected due to this");
170             }
171         }
172     }
173
174     /// Returns whether the expected type is `bool` and the expression is `x = y`.
175     pub fn is_assign_to_bool(&self, expr: &hir::Expr<'_>, expected: Ty<'tcx>) -> bool {
176         if let hir::ExprKind::Assign(..) = expr.kind {
177             return expected == self.tcx.types.bool;
178         }
179         false
180     }
181
182     /// If the expected type is an enum (Issue #55250) with any variants whose
183     /// sole field is of the found type, suggest such variants. (Issue #42764)
184     fn suggest_compatible_variants(
185         &self,
186         err: &mut DiagnosticBuilder<'_>,
187         expr: &hir::Expr<'_>,
188         expected: Ty<'tcx>,
189         expr_ty: Ty<'tcx>,
190     ) {
191         if let ty::Adt(expected_adt, substs) = expected.kind() {
192             if !expected_adt.is_enum() {
193                 return;
194             }
195
196             let mut compatible_variants = expected_adt
197                 .variants
198                 .iter()
199                 .filter(|variant| variant.fields.len() == 1)
200                 .filter_map(|variant| {
201                     let sole_field = &variant.fields[0];
202                     let sole_field_ty = sole_field.ty(self.tcx, substs);
203                     if self.can_coerce(expr_ty, sole_field_ty) {
204                         let variant_path =
205                             with_no_trimmed_paths(|| self.tcx.def_path_str(variant.def_id));
206                         // FIXME #56861: DRYer prelude filtering
207                         if let Some(path) = variant_path.strip_prefix("std::prelude::") {
208                             if let Some((_, path)) = path.split_once("::") {
209                                 return Some(path.to_string());
210                             }
211                         }
212                         Some(variant_path)
213                     } else {
214                         None
215                     }
216                 })
217                 .peekable();
218
219             if compatible_variants.peek().is_some() {
220                 if let Ok(expr_text) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
221                     let suggestions = compatible_variants.map(|v| format!("{}({})", v, expr_text));
222                     let msg = "try using a variant of the expected enum";
223                     err.span_suggestions(
224                         expr.span,
225                         msg,
226                         suggestions,
227                         Applicability::MaybeIncorrect,
228                     );
229                 }
230             }
231         }
232     }
233
234     pub fn get_conversion_methods(
235         &self,
236         span: Span,
237         expected: Ty<'tcx>,
238         checked_ty: Ty<'tcx>,
239         hir_id: hir::HirId,
240     ) -> Vec<AssocItem> {
241         let mut methods =
242             self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
243         methods.retain(|m| {
244             self.has_only_self_parameter(m)
245                 && self
246                     .tcx
247                     .get_attrs(m.def_id)
248                     .iter()
249                     // This special internal attribute is used to permit
250                     // "identity-like" conversion methods to be suggested here.
251                     //
252                     // FIXME (#46459 and #46460): ideally
253                     // `std::convert::Into::into` and `std::borrow:ToOwned` would
254                     // also be `#[rustc_conversion_suggestion]`, if not for
255                     // method-probing false-positives and -negatives (respectively).
256                     //
257                     // FIXME? Other potential candidate methods: `as_ref` and
258                     // `as_mut`?
259                     .any(|a| a.has_name(sym::rustc_conversion_suggestion))
260         });
261
262         methods
263     }
264
265     /// This function checks whether the method is not static and does not accept other parameters than `self`.
266     fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
267         match method.kind {
268             ty::AssocKind::Fn => {
269                 method.fn_has_self_parameter
270                     && self.tcx.fn_sig(method.def_id).inputs().skip_binder().len() == 1
271             }
272             _ => false,
273         }
274     }
275
276     /// Identify some cases where `as_ref()` would be appropriate and suggest it.
277     ///
278     /// Given the following code:
279     /// ```
280     /// struct Foo;
281     /// fn takes_ref(_: &Foo) {}
282     /// let ref opt = Some(Foo);
283     ///
284     /// opt.map(|param| takes_ref(param));
285     /// ```
286     /// Suggest using `opt.as_ref().map(|param| takes_ref(param));` instead.
287     ///
288     /// It only checks for `Option` and `Result` and won't work with
289     /// ```
290     /// opt.map(|param| { takes_ref(param) });
291     /// ```
292     fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, String)> {
293         let path = match expr.kind {
294             hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => path,
295             _ => return None,
296         };
297
298         let local_id = match path.res {
299             hir::def::Res::Local(id) => id,
300             _ => return None,
301         };
302
303         let local_parent = self.tcx.hir().get_parent_node(local_id);
304         let param_hir_id = match self.tcx.hir().find(local_parent) {
305             Some(Node::Param(hir::Param { hir_id, .. })) => hir_id,
306             _ => return None,
307         };
308
309         let param_parent = self.tcx.hir().get_parent_node(*param_hir_id);
310         let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(param_parent) {
311             Some(Node::Expr(hir::Expr {
312                 hir_id,
313                 kind: hir::ExprKind::Closure(_, decl, ..),
314                 ..
315             })) => (hir_id, decl),
316             _ => return None,
317         };
318
319         let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id);
320         let hir = self.tcx.hir().find(expr_parent);
321         let closure_params_len = closure_fn_decl.inputs.len();
322         let (method_path, method_span, method_expr) = match (hir, closure_params_len) {
323             (
324                 Some(Node::Expr(hir::Expr {
325                     kind: hir::ExprKind::MethodCall(path, span, expr, _),
326                     ..
327                 })),
328                 1,
329             ) => (path, span, expr),
330             _ => return None,
331         };
332
333         let self_ty = self.typeck_results.borrow().node_type(method_expr[0].hir_id);
334         let self_ty = format!("{:?}", self_ty);
335         let name = method_path.ident.name;
336         let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
337             || self_ty.starts_with("&std::result::Result")
338             || self_ty.starts_with("std::option::Option")
339             || self_ty.starts_with("std::result::Result"))
340             && (name == sym::map || name == sym::and_then);
341         match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) {
342             (true, Ok(src)) => {
343                 let suggestion = format!("as_ref().{}", src);
344                 Some((*method_span, "consider using `as_ref` instead", suggestion))
345             }
346             _ => None,
347         }
348     }
349
350     crate fn is_hir_id_from_struct_pattern_shorthand_field(
351         &self,
352         hir_id: hir::HirId,
353         sp: Span,
354     ) -> bool {
355         let sm = self.sess().source_map();
356         let parent_id = self.tcx.hir().get_parent_node(hir_id);
357         if let Some(parent) = self.tcx.hir().find(parent_id) {
358             // Account for fields
359             if let Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) = parent
360             {
361                 if let Ok(src) = sm.span_to_snippet(sp) {
362                     for field in *fields {
363                         if field.ident.as_str() == src && field.is_shorthand {
364                             return true;
365                         }
366                     }
367                 }
368             }
369         }
370         false
371     }
372
373     /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
374     crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
375         match self.tcx.hir().find(hir_id)? {
376             Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
377             _ => None,
378         }
379     }
380
381     /// Returns whether the given expression is an `else if`.
382     crate fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
383         if let hir::ExprKind::If(..) = expr.kind {
384             let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
385             if let Some(Node::Expr(hir::Expr {
386                 kind: hir::ExprKind::If(_, _, Some(else_expr)),
387                 ..
388             })) = self.tcx.hir().find(parent_id)
389             {
390                 return else_expr.hir_id == expr.hir_id;
391             }
392         }
393         false
394     }
395
396     /// This function is used to determine potential "simple" improvements or users' errors and
397     /// provide them useful help. For example:
398     ///
399     /// ```
400     /// fn some_fn(s: &str) {}
401     ///
402     /// let x = "hey!".to_owned();
403     /// some_fn(x); // error
404     /// ```
405     ///
406     /// No need to find every potential function which could make a coercion to transform a
407     /// `String` into a `&str` since a `&` would do the trick!
408     ///
409     /// In addition of this check, it also checks between references mutability state. If the
410     /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
411     /// `&mut`!".
412     pub fn check_ref(
413         &self,
414         expr: &hir::Expr<'_>,
415         checked_ty: Ty<'tcx>,
416         expected: Ty<'tcx>,
417     ) -> Option<(Span, &'static str, String, Applicability, bool /* verbose */)> {
418         let sess = self.sess();
419         let sp = expr.span;
420
421         // If the span is from an external macro, there's no suggestion we can make.
422         if in_external_macro(sess, sp) {
423             return None;
424         }
425
426         let sm = sess.source_map();
427
428         let replace_prefix = |s: &str, old: &str, new: &str| {
429             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
430         };
431
432         let is_struct_pat_shorthand_field =
433             self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
434
435         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
436         let expr = expr.peel_drop_temps();
437
438         match (&expr.kind, expected.kind(), checked_ty.kind()) {
439             (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) {
440                 (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
441                     if let hir::ExprKind::Lit(_) = expr.kind {
442                         if let Ok(src) = sm.span_to_snippet(sp) {
443                             if let Some(_) = replace_prefix(&src, "b\"", "\"") {
444                                 let pos = sp.lo() + BytePos(1);
445                                 return Some((
446                                     sp.with_hi(pos),
447                                     "consider removing the leading `b`",
448                                     String::new(),
449                                     Applicability::MachineApplicable,
450                                     true,
451                                 ));
452                             }
453                         }
454                     }
455                 }
456                 (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
457                     if let hir::ExprKind::Lit(_) = expr.kind {
458                         if let Ok(src) = sm.span_to_snippet(sp) {
459                             if let Some(_) = replace_prefix(&src, "\"", "b\"") {
460                                 return Some((
461                                     sp.shrink_to_lo(),
462                                     "consider adding a leading `b`",
463                                     "b".to_string(),
464                                     Applicability::MachineApplicable,
465                                     true,
466                                 ));
467                             }
468                         }
469                     }
470                 }
471                 _ => {}
472             },
473             (_, &ty::Ref(_, _, mutability), _) => {
474                 // Check if it can work when put into a ref. For example:
475                 //
476                 // ```
477                 // fn bar(x: &mut i32) {}
478                 //
479                 // let x = 0u32;
480                 // bar(&x); // error, expected &mut
481                 // ```
482                 let ref_ty = match mutability {
483                     hir::Mutability::Mut => {
484                         self.tcx.mk_mut_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
485                     }
486                     hir::Mutability::Not => {
487                         self.tcx.mk_imm_ref(self.tcx.mk_region(ty::ReStatic), checked_ty)
488                     }
489                 };
490                 if self.can_coerce(ref_ty, expected) {
491                     let mut sugg_sp = sp;
492                     if let hir::ExprKind::MethodCall(ref segment, sp, ref args, _) = expr.kind {
493                         let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(sp));
494                         if let ([arg], Some(true), sym::clone) = (
495                             &args[..],
496                             self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
497                                 |did| {
498                                     let ai = self.tcx.associated_item(did);
499                                     ai.container == ty::TraitContainer(clone_trait)
500                                 },
501                             ),
502                             segment.ident.name,
503                         ) {
504                             // If this expression had a clone call when suggesting borrowing
505                             // we want to suggest removing it because it'd now be unnecessary.
506                             sugg_sp = arg.span;
507                         }
508                     }
509                     if let Ok(src) = sm.span_to_snippet(sugg_sp) {
510                         let needs_parens = match expr.kind {
511                             // parenthesize if needed (Issue #46756)
512                             hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
513                             // parenthesize borrows of range literals (Issue #54505)
514                             _ if is_range_literal(expr) => true,
515                             _ => false,
516                         };
517                         let sugg_expr = if needs_parens { format!("({})", src) } else { src };
518
519                         if let Some(sugg) = self.can_use_as_ref(expr) {
520                             return Some((
521                                 sugg.0,
522                                 sugg.1,
523                                 sugg.2,
524                                 Applicability::MachineApplicable,
525                                 false,
526                             ));
527                         }
528                         let field_name = if is_struct_pat_shorthand_field {
529                             format!("{}: ", sugg_expr)
530                         } else {
531                             String::new()
532                         };
533                         if let Some(hir::Node::Expr(hir::Expr {
534                             kind: hir::ExprKind::Assign(left_expr, ..),
535                             ..
536                         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
537                         {
538                             if mutability == hir::Mutability::Mut {
539                                 // Found the following case:
540                                 // fn foo(opt: &mut Option<String>){ opt = None }
541                                 //                                   ---   ^^^^
542                                 //                                   |     |
543                                 //    consider dereferencing here: `*opt`  |
544                                 // expected mutable reference, found enum `Option`
545                                 if sm.span_to_snippet(left_expr.span).is_ok() {
546                                     return Some((
547                                         left_expr.span.shrink_to_lo(),
548                                         "consider dereferencing here to assign to the mutable \
549                                          borrowed piece of memory",
550                                         "*".to_string(),
551                                         Applicability::MachineApplicable,
552                                         true,
553                                     ));
554                                 }
555                             }
556                         }
557
558                         return Some(match mutability {
559                             hir::Mutability::Mut => (
560                                 sp,
561                                 "consider mutably borrowing here",
562                                 format!("{}&mut {}", field_name, sugg_expr),
563                                 Applicability::MachineApplicable,
564                                 false,
565                             ),
566                             hir::Mutability::Not => (
567                                 sp,
568                                 "consider borrowing here",
569                                 format!("{}&{}", field_name, sugg_expr),
570                                 Applicability::MachineApplicable,
571                                 false,
572                             ),
573                         });
574                     }
575                 }
576             }
577             (
578                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
579                 _,
580                 &ty::Ref(_, checked, _),
581             ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
582                 // We have `&T`, check if what was expected was `T`. If so,
583                 // we may want to suggest removing a `&`.
584                 if sm.is_imported(expr.span) {
585                     // Go through the spans from which this span was expanded,
586                     // and find the one that's pointing inside `sp`.
587                     //
588                     // E.g. for `&format!("")`, where we want the span to the
589                     // `format!()` invocation instead of its expansion.
590                     if let Some(call_span) =
591                         iter::successors(Some(expr.span), |s| s.parent_callsite())
592                             .find(|&s| sp.contains(s))
593                     {
594                         if sm.span_to_snippet(call_span).is_ok() {
595                             return Some((
596                                 sp.with_hi(call_span.lo()),
597                                 "consider removing the borrow",
598                                 String::new(),
599                                 Applicability::MachineApplicable,
600                                 true,
601                             ));
602                         }
603                     }
604                     return None;
605                 }
606                 if sp.contains(expr.span) {
607                     if sm.span_to_snippet(expr.span).is_ok() {
608                         return Some((
609                             sp.with_hi(expr.span.lo()),
610                             "consider removing the borrow",
611                             String::new(),
612                             Applicability::MachineApplicable,
613                             true,
614                         ));
615                     }
616                 }
617             }
618             (
619                 _,
620                 &ty::RawPtr(TypeAndMut { ty: ty_b, mutbl: mutbl_b }),
621                 &ty::Ref(_, ty_a, mutbl_a),
622             ) => {
623                 if let Some(steps) = self.deref_steps(ty_a, ty_b) {
624                     // Only suggest valid if dereferencing needed.
625                     if steps > 0 {
626                         // The pointer type implements `Copy` trait so the suggestion is always valid.
627                         if let Ok(src) = sm.span_to_snippet(sp) {
628                             let derefs = "*".repeat(steps);
629                             if let Some((span, src, applicability)) = match mutbl_b {
630                                 hir::Mutability::Mut => {
631                                     let new_prefix = "&mut ".to_owned() + &derefs;
632                                     match mutbl_a {
633                                         hir::Mutability::Mut => {
634                                             replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
635                                                 let pos = sp.lo() + BytePos(5);
636                                                 let sp = sp.with_lo(pos).with_hi(pos);
637                                                 (sp, derefs, Applicability::MachineApplicable)
638                                             })
639                                         }
640                                         hir::Mutability::Not => {
641                                             replace_prefix(&src, "&", &new_prefix).map(|_| {
642                                                 let pos = sp.lo() + BytePos(1);
643                                                 let sp = sp.with_lo(pos).with_hi(pos);
644                                                 (
645                                                     sp,
646                                                     format!("mut {}", derefs),
647                                                     Applicability::Unspecified,
648                                                 )
649                                             })
650                                         }
651                                     }
652                                 }
653                                 hir::Mutability::Not => {
654                                     let new_prefix = "&".to_owned() + &derefs;
655                                     match mutbl_a {
656                                         hir::Mutability::Mut => {
657                                             replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
658                                                 let lo = sp.lo() + BytePos(1);
659                                                 let hi = sp.lo() + BytePos(5);
660                                                 let sp = sp.with_lo(lo).with_hi(hi);
661                                                 (sp, derefs, Applicability::MachineApplicable)
662                                             })
663                                         }
664                                         hir::Mutability::Not => {
665                                             replace_prefix(&src, "&", &new_prefix).map(|_| {
666                                                 let pos = sp.lo() + BytePos(1);
667                                                 let sp = sp.with_lo(pos).with_hi(pos);
668                                                 (sp, derefs, Applicability::MachineApplicable)
669                                             })
670                                         }
671                                     }
672                                 }
673                             } {
674                                 return Some((
675                                     span,
676                                     "consider dereferencing",
677                                     src,
678                                     applicability,
679                                     true,
680                                 ));
681                             }
682                         }
683                     }
684                 }
685             }
686             _ if sp == expr.span => {
687                 if let Some(steps) = self.deref_steps(checked_ty, expected) {
688                     let expr = expr.peel_blocks();
689
690                     if steps == 1 {
691                         if let hir::ExprKind::AddrOf(_, mutbl, inner) = expr.kind {
692                             // If the expression has `&`, removing it would fix the error
693                             let prefix_span = expr.span.with_hi(inner.span.lo());
694                             let message = match mutbl {
695                                 hir::Mutability::Not => "consider removing the `&`",
696                                 hir::Mutability::Mut => "consider removing the `&mut`",
697                             };
698                             let suggestion = String::new();
699                             return Some((
700                                 prefix_span,
701                                 message,
702                                 suggestion,
703                                 Applicability::MachineApplicable,
704                                 false,
705                             ));
706                         } else if self.infcx.type_is_copy_modulo_regions(
707                             self.param_env,
708                             expected,
709                             sp,
710                         ) {
711                             // For this suggestion to make sense, the type would need to be `Copy`.
712                             if let Ok(code) = sm.span_to_snippet(expr.span) {
713                                 let message = if checked_ty.is_region_ptr() {
714                                     "consider dereferencing the borrow"
715                                 } else {
716                                     "consider dereferencing the type"
717                                 };
718                                 let (span, suggestion) = if is_struct_pat_shorthand_field {
719                                     (expr.span, format!("{}: *{}", code, code))
720                                 } else if self.is_else_if_block(expr) {
721                                     // Don't suggest nonsense like `else *if`
722                                     return None;
723                                 } else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
724                                     (expr.span.shrink_to_lo(), "*".to_string())
725                                 } else {
726                                     (expr.span.shrink_to_lo(), "*".to_string())
727                                 };
728                                 return Some((
729                                     span,
730                                     message,
731                                     suggestion,
732                                     Applicability::MachineApplicable,
733                                     true,
734                                 ));
735                             }
736                         }
737                     }
738                 }
739             }
740             _ => {}
741         }
742         None
743     }
744
745     pub fn check_for_cast(
746         &self,
747         err: &mut DiagnosticBuilder<'_>,
748         expr: &hir::Expr<'_>,
749         checked_ty: Ty<'tcx>,
750         expected_ty: Ty<'tcx>,
751         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
752     ) -> bool {
753         if self.tcx.sess.source_map().is_imported(expr.span) {
754             // Ignore if span is from within a macro.
755             return false;
756         }
757
758         let src = if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
759             src
760         } else {
761             return false;
762         };
763
764         // If casting this expression to a given numeric type would be appropriate in case of a type
765         // mismatch.
766         //
767         // We want to minimize the amount of casting operations that are suggested, as it can be a
768         // lossy operation with potentially bad side effects, so we only suggest when encountering
769         // an expression that indicates that the original type couldn't be directly changed.
770         //
771         // For now, don't suggest casting with `as`.
772         let can_cast = false;
773
774         let mut sugg = vec![];
775
776         if let Some(hir::Node::Expr(hir::Expr {
777             kind: hir::ExprKind::Struct(_, fields, _), ..
778         })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.hir_id))
779         {
780             // `expr` is a literal field for a struct, only suggest if appropriate
781             match (*fields)
782                 .iter()
783                 .find(|field| field.expr.hir_id == expr.hir_id && field.is_shorthand)
784             {
785                 // This is a field literal
786                 Some(field) => {
787                     sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident)));
788                 }
789                 // Likely a field was meant, but this field wasn't found. Do not suggest anything.
790                 None => return false,
791             }
792         };
793
794         if let hir::ExprKind::Call(path, args) = &expr.kind {
795             if let (hir::ExprKind::Path(hir::QPath::TypeRelative(base_ty, path_segment)), 1) =
796                 (&path.kind, args.len())
797             {
798                 // `expr` is a conversion like `u32::from(val)`, do not suggest anything (#63697).
799                 if let (hir::TyKind::Path(hir::QPath::Resolved(None, base_ty_path)), sym::from) =
800                     (&base_ty.kind, path_segment.ident.name)
801                 {
802                     if let Some(ident) = &base_ty_path.segments.iter().map(|s| s.ident).next() {
803                         match ident.name {
804                             sym::i128
805                             | sym::i64
806                             | sym::i32
807                             | sym::i16
808                             | sym::i8
809                             | sym::u128
810                             | sym::u64
811                             | sym::u32
812                             | sym::u16
813                             | sym::u8
814                             | sym::isize
815                             | sym::usize
816                                 if base_ty_path.segments.len() == 1 =>
817                             {
818                                 return false;
819                             }
820                             _ => {}
821                         }
822                     }
823                 }
824             }
825         }
826
827         let msg = format!(
828             "you can convert {} `{}` to {} `{}`",
829             checked_ty.kind().article(),
830             checked_ty,
831             expected_ty.kind().article(),
832             expected_ty,
833         );
834         let cast_msg = format!(
835             "you can cast {} `{}` to {} `{}`",
836             checked_ty.kind().article(),
837             checked_ty,
838             expected_ty.kind().article(),
839             expected_ty,
840         );
841         let lit_msg = format!(
842             "change the type of the numeric literal from `{}` to `{}`",
843             checked_ty, expected_ty,
844         );
845
846         let close_paren = if expr.precedence().order() < PREC_POSTFIX {
847             sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
848             ")"
849         } else {
850             ""
851         };
852
853         let mut cast_suggestion = sugg.clone();
854         cast_suggestion
855             .push((expr.span.shrink_to_hi(), format!("{} as {}", close_paren, expected_ty)));
856         let mut into_suggestion = sugg.clone();
857         into_suggestion.push((expr.span.shrink_to_hi(), format!("{}.into()", close_paren)));
858         let mut suffix_suggestion = sugg.clone();
859         suffix_suggestion.push((
860             if matches!(
861                 (&expected_ty.kind(), &checked_ty.kind()),
862                 (ty::Int(_) | ty::Uint(_), ty::Float(_))
863             ) {
864                 // Remove fractional part from literal, for example `42.0f32` into `42`
865                 let src = src.trim_end_matches(&checked_ty.to_string());
866                 let len = src.split('.').next().unwrap().len();
867                 expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
868             } else {
869                 let len = src.trim_end_matches(&checked_ty.to_string()).len();
870                 expr.span.with_lo(expr.span.lo() + BytePos(len as u32))
871             },
872             if expr.precedence().order() < PREC_POSTFIX {
873                 // Readd `)`
874                 format!("{})", expected_ty)
875             } else {
876                 expected_ty.to_string()
877             },
878         ));
879         let literal_is_ty_suffixed = |expr: &hir::Expr<'_>| {
880             if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
881         };
882         let is_negative_int =
883             |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..));
884         let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..));
885
886         let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
887
888         let suggest_fallible_into_or_lhs_from =
889             |err: &mut DiagnosticBuilder<'_>, exp_to_found_is_fallible: bool| {
890                 // If we know the expression the expected type is derived from, we might be able
891                 // to suggest a widening conversion rather than a narrowing one (which may
892                 // panic). For example, given x: u8 and y: u32, if we know the span of "x",
893                 //   x > y
894                 // can be given the suggestion "u32::from(x) > y" rather than
895                 // "x > y.try_into().unwrap()".
896                 let lhs_expr_and_src = expected_ty_expr.and_then(|expr| {
897                     self.tcx
898                         .sess
899                         .source_map()
900                         .span_to_snippet(expr.span)
901                         .ok()
902                         .map(|src| (expr, src))
903                 });
904                 let (msg, suggestion) = if let (Some((lhs_expr, lhs_src)), false) =
905                     (lhs_expr_and_src, exp_to_found_is_fallible)
906                 {
907                     let msg = format!(
908                         "you can convert `{}` from `{}` to `{}`, matching the type of `{}`",
909                         lhs_src, expected_ty, checked_ty, src
910                     );
911                     let suggestion = vec![
912                         (lhs_expr.span.shrink_to_lo(), format!("{}::from(", checked_ty)),
913                         (lhs_expr.span.shrink_to_hi(), ")".to_string()),
914                     ];
915                     (msg, suggestion)
916                 } else {
917                     let msg = format!("{} and panic if the converted value doesn't fit", msg);
918                     let mut suggestion = sugg.clone();
919                     suggestion.push((
920                         expr.span.shrink_to_hi(),
921                         format!("{}.try_into().unwrap()", close_paren),
922                     ));
923                     (msg, suggestion)
924                 };
925                 err.multipart_suggestion_verbose(
926                     &msg,
927                     suggestion,
928                     Applicability::MachineApplicable,
929                 );
930             };
931
932         let suggest_to_change_suffix_or_into =
933             |err: &mut DiagnosticBuilder<'_>,
934              found_to_exp_is_fallible: bool,
935              exp_to_found_is_fallible: bool| {
936                 let exp_is_lhs =
937                     expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false);
938
939                 if exp_is_lhs {
940                     return;
941                 }
942
943                 let always_fallible = found_to_exp_is_fallible
944                     && (exp_to_found_is_fallible || expected_ty_expr.is_none());
945                 let msg = if literal_is_ty_suffixed(expr) {
946                     &lit_msg
947                 } else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
948                     // We now know that converting either the lhs or rhs is fallible. Before we
949                     // suggest a fallible conversion, check if the value can never fit in the
950                     // expected type.
951                     let msg = format!("`{}` cannot fit into type `{}`", src, expected_ty);
952                     err.note(&msg);
953                     return;
954                 } else if in_const_context {
955                     // Do not recommend `into` or `try_into` in const contexts.
956                     return;
957                 } else if found_to_exp_is_fallible {
958                     return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
959                 } else {
960                     &msg
961                 };
962                 let suggestion = if literal_is_ty_suffixed(expr) {
963                     suffix_suggestion.clone()
964                 } else {
965                     into_suggestion.clone()
966                 };
967                 err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
968             };
969
970         match (&expected_ty.kind(), &checked_ty.kind()) {
971             (&ty::Int(ref exp), &ty::Int(ref found)) => {
972                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
973                 {
974                     (Some(exp), Some(found)) if exp < found => (true, false),
975                     (Some(exp), Some(found)) if exp > found => (false, true),
976                     (None, Some(8 | 16)) => (false, true),
977                     (Some(8 | 16), None) => (true, false),
978                     (None, _) | (_, None) => (true, true),
979                     _ => (false, false),
980                 };
981                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
982                 true
983             }
984             (&ty::Uint(ref exp), &ty::Uint(ref found)) => {
985                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
986                 {
987                     (Some(exp), Some(found)) if exp < found => (true, false),
988                     (Some(exp), Some(found)) if exp > found => (false, true),
989                     (None, Some(8 | 16)) => (false, true),
990                     (Some(8 | 16), None) => (true, false),
991                     (None, _) | (_, None) => (true, true),
992                     _ => (false, false),
993                 };
994                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
995                 true
996             }
997             (&ty::Int(exp), &ty::Uint(found)) => {
998                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
999                 {
1000                     (Some(exp), Some(found)) if found < exp => (false, true),
1001                     (None, Some(8)) => (false, true),
1002                     _ => (true, true),
1003                 };
1004                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1005                 true
1006             }
1007             (&ty::Uint(exp), &ty::Int(found)) => {
1008                 let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width())
1009                 {
1010                     (Some(exp), Some(found)) if found > exp => (true, false),
1011                     (Some(8), None) => (true, false),
1012                     _ => (true, true),
1013                 };
1014                 suggest_to_change_suffix_or_into(err, f2e_is_fallible, e2f_is_fallible);
1015                 true
1016             }
1017             (&ty::Float(ref exp), &ty::Float(ref found)) => {
1018                 if found.bit_width() < exp.bit_width() {
1019                     suggest_to_change_suffix_or_into(err, false, true);
1020                 } else if literal_is_ty_suffixed(expr) {
1021                     err.multipart_suggestion_verbose(
1022                         &lit_msg,
1023                         suffix_suggestion,
1024                         Applicability::MachineApplicable,
1025                     );
1026                 } else if can_cast {
1027                     // Missing try_into implementation for `f64` to `f32`
1028                     err.multipart_suggestion_verbose(
1029                         &format!("{}, producing the closest possible value", cast_msg),
1030                         cast_suggestion,
1031                         Applicability::MaybeIncorrect, // lossy conversion
1032                     );
1033                 }
1034                 true
1035             }
1036             (&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
1037                 if literal_is_ty_suffixed(expr) {
1038                     err.multipart_suggestion_verbose(
1039                         &lit_msg,
1040                         suffix_suggestion,
1041                         Applicability::MachineApplicable,
1042                     );
1043                 } else if can_cast {
1044                     // Missing try_into implementation for `{float}` to `{integer}`
1045                     err.multipart_suggestion_verbose(
1046                         &format!("{}, rounding the float towards zero", msg),
1047                         cast_suggestion,
1048                         Applicability::MaybeIncorrect, // lossy conversion
1049                     );
1050                 }
1051                 true
1052             }
1053             (&ty::Float(ref exp), &ty::Uint(ref found)) => {
1054                 // if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
1055                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
1056                     err.multipart_suggestion_verbose(
1057                         &format!(
1058                             "{}, producing the floating point representation of the integer",
1059                             msg,
1060                         ),
1061                         into_suggestion,
1062                         Applicability::MachineApplicable,
1063                     );
1064                 } else if literal_is_ty_suffixed(expr) {
1065                     err.multipart_suggestion_verbose(
1066                         &lit_msg,
1067                         suffix_suggestion,
1068                         Applicability::MachineApplicable,
1069                     );
1070                 } else {
1071                     // Missing try_into implementation for `{integer}` to `{float}`
1072                     err.multipart_suggestion_verbose(
1073                         &format!(
1074                             "{}, producing the floating point representation of the integer,
1075                                  rounded if necessary",
1076                             cast_msg,
1077                         ),
1078                         cast_suggestion,
1079                         Applicability::MaybeIncorrect, // lossy conversion
1080                     );
1081                 }
1082                 true
1083             }
1084             (&ty::Float(ref exp), &ty::Int(ref found)) => {
1085                 // if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
1086                 if exp.bit_width() > found.bit_width().unwrap_or(256) {
1087                     err.multipart_suggestion_verbose(
1088                         &format!(
1089                             "{}, producing the floating point representation of the integer",
1090                             &msg,
1091                         ),
1092                         into_suggestion,
1093                         Applicability::MachineApplicable,
1094                     );
1095                 } else if literal_is_ty_suffixed(expr) {
1096                     err.multipart_suggestion_verbose(
1097                         &lit_msg,
1098                         suffix_suggestion,
1099                         Applicability::MachineApplicable,
1100                     );
1101                 } else {
1102                     // Missing try_into implementation for `{integer}` to `{float}`
1103                     err.multipart_suggestion_verbose(
1104                         &format!(
1105                             "{}, producing the floating point representation of the integer, \
1106                                 rounded if necessary",
1107                             &msg,
1108                         ),
1109                         cast_suggestion,
1110                         Applicability::MaybeIncorrect, // lossy conversion
1111                     );
1112                 }
1113                 true
1114             }
1115             _ => false,
1116         }
1117     }
1118
1119     // Report the type inferred by the return statement.
1120     fn report_closure_inferred_return_type(
1121         &self,
1122         err: &mut DiagnosticBuilder<'_>,
1123         expected: Ty<'tcx>,
1124     ) {
1125         if let Some(sp) = self.ret_coercion_span.get() {
1126             // If the closure has an explicit return type annotation, or if
1127             // the closure's return type has been inferred from outside
1128             // requirements (such as an Fn* trait bound), then a type error
1129             // may occur at the first return expression we see in the closure
1130             // (if it conflicts with the declared return type). Skip adding a
1131             // note in this case, since it would be incorrect.
1132             if !self.return_type_pre_known {
1133                 err.span_note(
1134                     sp,
1135                     &format!(
1136                         "return type inferred to be `{}` here",
1137                         self.resolve_vars_if_possible(expected)
1138                     ),
1139                 );
1140             }
1141         }
1142     }
1143 }