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