1use std::{fmt, iter, mem};
2
3use itertools::Itertools;
4use rustc_data_structures::fx::FxIndexSet;
5use rustc_errors::codes::*;
6use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize};
7use rustc_hir::def::{CtorOf, DefKind, Res};
8use rustc_hir::def_id::DefId;
9use rustc_hir::intravisit::Visitor;
10use rustc_hir::{ExprKind, HirId, Node, QPath};
11use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
12use rustc_hir_analysis::check::potentially_plural_count;
13use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
14use rustc_index::IndexVec;
15use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace};
16use rustc_middle::ty::adjustment::AllowTwoPhase;
17use rustc_middle::ty::error::TypeError;
18use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
19use rustc_middle::{bug, span_bug};
20use rustc_session::Session;
21use rustc_span::{DUMMY_SP, Ident, Span, kw, sym};
22use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt};
23use rustc_trait_selection::infer::InferCtxtExt;
24use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
25use smallvec::SmallVec;
26use tracing::debug;
27use {rustc_ast as ast, rustc_hir as hir};
28
29use crate::Expectation::*;
30use crate::TupleArgumentsFlag::*;
31use crate::coercion::CoerceMany;
32use crate::errors::SuggestPtrNullMut;
33use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
34use crate::fn_ctxt::infer::FnCall;
35use crate::gather_locals::Declaration;
36use crate::method::MethodCallee;
37use crate::method::probe::IsSuggestion;
38use crate::method::probe::Mode::MethodCall;
39use crate::method::probe::ProbeScope::TraitsInScope;
40use crate::{
41 BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors,
42 struct_span_code_err,
43};
44
45rustc_index::newtype_index! {
46 #[orderable]
47 #[debug_format = "GenericIdx({})"]
48 pub(crate) struct GenericIdx {}
49}
50
51#[derive(Clone, Copy, Default)]
52pub(crate) enum DivergingBlockBehavior {
53 #[default]
61 Never,
62
63 Unit,
72}
73
74impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
75 pub(in super::super) fn check_casts(&mut self) {
76 let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut());
79
80 debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
81 for cast in deferred_cast_checks.drain(..) {
82 cast.check(self);
83 }
84
85 *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
86 }
87
88 pub(in super::super) fn check_transmutes(&self) {
89 let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut();
90 debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len());
91 for (from, to, hir_id) in deferred_transmute_checks.drain(..) {
92 self.check_transmute(from, to, hir_id);
93 }
94 }
95
96 pub(in super::super) fn check_asms(&self) {
97 let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut();
98 debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len());
99 for (asm, hir_id) in deferred_asm_checks.drain(..) {
100 let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id);
101 InlineAsmCtxt::new(
102 enclosing_id,
103 &self.infcx,
104 self.typing_env(self.param_env),
105 &*self.typeck_results.borrow(),
106 )
107 .check_asm(asm);
108 }
109 }
110
111 pub(in super::super) fn check_repeat_exprs(&self) {
112 let mut deferred_repeat_expr_checks = self.deferred_repeat_expr_checks.borrow_mut();
113 debug!("FnCtxt::check_repeat_exprs: {} deferred checks", deferred_repeat_expr_checks.len());
114 for (element, element_ty, count) in deferred_repeat_expr_checks.drain(..) {
115 let count =
119 self.structurally_resolve_const(element.span, self.normalize(element.span, count));
120
121 if count.references_error() {
124 continue;
125 }
126
127 if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) {
131 self.enforce_repeat_element_needs_copy_bound(element, element_ty);
132 }
133 }
134 }
135
136 pub(in super::super) fn check_method_argument_types(
137 &self,
138 sp: Span,
139 expr: &'tcx hir::Expr<'tcx>,
140 method: Result<MethodCallee<'tcx>, ErrorGuaranteed>,
141 args_no_rcvr: &'tcx [hir::Expr<'tcx>],
142 tuple_arguments: TupleArgumentsFlag,
143 expected: Expectation<'tcx>,
144 ) -> Ty<'tcx> {
145 let has_error = match method {
146 Ok(method) => method.args.error_reported().and(method.sig.error_reported()),
147 Err(guar) => Err(guar),
148 };
149 if let Err(guar) = has_error {
150 let err_inputs = self.err_args(
151 method.map_or(args_no_rcvr.len(), |method| method.sig.inputs().len() - 1),
152 guar,
153 );
154 let err_output = Ty::new_error(self.tcx, guar);
155
156 let err_inputs = match tuple_arguments {
157 DontTupleArguments => err_inputs,
158 TupleArguments => vec![Ty::new_tup(self.tcx, &err_inputs)],
159 };
160
161 self.check_argument_types(
162 sp,
163 expr,
164 &err_inputs,
165 err_output,
166 NoExpectation,
167 args_no_rcvr,
168 false,
169 tuple_arguments,
170 method.ok().map(|method| method.def_id),
171 );
172 return err_output;
173 }
174
175 let method = method.unwrap();
176 self.check_argument_types(
177 sp,
178 expr,
179 &method.sig.inputs()[1..],
180 method.sig.output(),
181 expected,
182 args_no_rcvr,
183 method.sig.c_variadic,
184 tuple_arguments,
185 Some(method.def_id),
186 );
187
188 method.sig.output()
189 }
190
191 pub(in super::super) fn check_argument_types(
194 &self,
195 call_span: Span,
197 call_expr: &'tcx hir::Expr<'tcx>,
199 formal_input_tys: &[Ty<'tcx>],
201 formal_output: Ty<'tcx>,
202 expectation: Expectation<'tcx>,
204 provided_args: &'tcx [hir::Expr<'tcx>],
206 c_variadic: bool,
208 tuple_arguments: TupleArgumentsFlag,
210 fn_def_id: Option<DefId>,
212 ) {
213 let tcx = self.tcx;
214
215 for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
230 self.register_wf_obligation(
231 fn_input_ty.into(),
232 arg_expr.span,
233 ObligationCauseCode::WellFormed(None),
234 );
235 }
236
237 let formal_output = self.resolve_vars_with_obligations(formal_output);
242 let expected_input_tys: Option<Vec<_>> = expectation
243 .only_has_type(self)
244 .and_then(|expected_output| {
245 self.fudge_inference_if_ok(|| {
246 let ocx = ObligationCtxt::new(self);
247
248 let origin = self.misc(call_span);
253 ocx.sup(&origin, self.param_env, expected_output, formal_output)?;
254 if !ocx.select_where_possible().is_empty() {
255 return Err(TypeError::Mismatch);
256 }
257
258 Ok(Some(
261 formal_input_tys
262 .iter()
263 .map(|&ty| self.resolve_vars_if_possible(ty))
264 .collect(),
265 ))
266 })
267 .ok()
268 })
269 .unwrap_or_default();
270
271 let mut err_code = E0061;
272
273 let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
275 let tuple_type = self.structurally_resolve_type(call_span, formal_input_tys[0]);
276 match tuple_type.kind() {
277 ty::Tuple(arg_types) => {
279 if arg_types.len() != provided_args.len() {
281 err_code = E0057;
282 }
283 let expected_input_tys = match expected_input_tys {
284 Some(expected_input_tys) => match expected_input_tys.get(0) {
285 Some(ty) => match ty.kind() {
286 ty::Tuple(tys) => Some(tys.iter().collect()),
287 _ => None,
288 },
289 None => None,
290 },
291 None => None,
292 };
293 (arg_types.iter().collect(), expected_input_tys)
294 }
295 _ => {
296 let guar = struct_span_code_err!(
299 self.dcx(),
300 call_span,
301 E0059,
302 "cannot use call notation; the first type parameter \
303 for the function trait is neither a tuple nor unit"
304 )
305 .emit();
306 (self.err_args(provided_args.len(), guar), None)
307 }
308 }
309 } else {
310 (formal_input_tys.to_vec(), expected_input_tys)
311 };
312
313 let expected_input_tys = if let Some(expected_input_tys) = expected_input_tys {
315 assert_eq!(expected_input_tys.len(), formal_input_tys.len());
316 expected_input_tys
317 } else {
318 formal_input_tys.clone()
319 };
320
321 let minimum_input_count = expected_input_tys.len();
322 let provided_arg_count = provided_args.len();
323
324 let demand_compatible = |idx| {
328 let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
329 let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
330 let provided_arg = &provided_args[idx];
331
332 debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
333
334 let expectation = Expectation::rvalue_hint(self, expected_input_ty);
338
339 let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
340
341 let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
345
346 let coerced_ty = self.resolve_vars_with_obligations(coerced_ty);
350
351 let coerce_error =
352 self.coerce(provided_arg, checked_ty, coerced_ty, AllowTwoPhase::Yes, None).err();
353 if coerce_error.is_some() {
354 return Compatibility::Incompatible(coerce_error);
355 }
356
357 let formal_ty_error = self.at(&self.misc(provided_arg.span), self.param_env).eq(
360 DefineOpaqueTypes::Yes,
361 formal_input_ty,
362 coerced_ty,
363 );
364
365 match formal_ty_error {
367 Ok(InferOk { obligations, value: () }) => {
368 self.register_predicates(obligations);
369 Compatibility::Compatible
370 }
371 Err(err) => Compatibility::Incompatible(Some(err)),
372 }
373 };
374
375 let mut compatibility_diagonal =
378 vec![Compatibility::Incompatible(None); provided_args.len()];
379
380 let mut call_appears_satisfied = if c_variadic {
385 provided_arg_count >= minimum_input_count
386 } else {
387 provided_arg_count == minimum_input_count
388 };
389
390 for check_closures in [false, true] {
396 if check_closures {
400 self.select_obligations_where_possible(|_| {})
401 }
402
403 for (idx, arg) in provided_args.iter().enumerate() {
406 if !check_closures {
410 self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
411 }
412
413 if idx >= minimum_input_count {
419 continue;
420 }
421
422 let is_closure = if let ExprKind::Closure(closure) = arg.kind {
428 !tcx.coroutine_is_async(closure.def_id.to_def_id())
429 } else {
430 false
431 };
432 if is_closure != check_closures {
433 continue;
434 }
435
436 let compatible = demand_compatible(idx);
437 let is_compatible = matches!(compatible, Compatibility::Compatible);
438 compatibility_diagonal[idx] = compatible;
439
440 if !is_compatible {
441 call_appears_satisfied = false;
442 }
443 }
444 }
445
446 if c_variadic && provided_arg_count < minimum_input_count {
447 err_code = E0060;
448 }
449
450 for arg in provided_args.iter().skip(minimum_input_count) {
451 let arg_ty = self.check_expr(arg);
453
454 if c_variadic {
459 fn variadic_error<'tcx>(
460 sess: &'tcx Session,
461 span: Span,
462 ty: Ty<'tcx>,
463 cast_ty: &str,
464 ) {
465 sess.dcx().emit_err(errors::PassToVariadicFunction {
466 span,
467 ty,
468 cast_ty,
469 sugg_span: span.shrink_to_hi(),
470 teach: sess.teach(E0617),
471 });
472 }
473
474 let arg_ty = self.structurally_resolve_type(arg.span, arg_ty);
477 match arg_ty.kind() {
478 ty::Float(ty::FloatTy::F32) => {
479 variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
480 }
481 ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => {
482 variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
483 }
484 ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => {
485 variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
486 }
487 ty::FnDef(..) => {
488 let fn_ptr = Ty::new_fn_ptr(self.tcx, arg_ty.fn_sig(self.tcx));
489 let fn_ptr = self.resolve_vars_if_possible(fn_ptr).to_string();
490
491 let fn_item_spa = arg.span;
492 tcx.sess.dcx().emit_err(errors::PassFnItemToVariadicFunction {
493 span: fn_item_spa,
494 sugg_span: fn_item_spa.shrink_to_hi(),
495 replace: fn_ptr,
496 });
497 }
498 _ => {}
499 }
500 }
501 }
502
503 if !call_appears_satisfied {
504 let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal);
505 let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic {
506 minimum_input_count
507 } else {
508 provided_arg_count
509 }));
510 debug_assert_eq!(
511 formal_input_tys.len(),
512 expected_input_tys.len(),
513 "expected formal_input_tys to be the same size as expected_input_tys"
514 );
515 let formal_and_expected_inputs = IndexVec::from_iter(
516 formal_input_tys
517 .iter()
518 .copied()
519 .zip_eq(expected_input_tys.iter().copied())
520 .map(|vars| self.resolve_vars_if_possible(vars)),
521 );
522
523 self.report_arg_errors(
524 compatibility_diagonal,
525 formal_and_expected_inputs,
526 provided_args,
527 c_variadic,
528 err_code,
529 fn_def_id,
530 call_span,
531 call_expr,
532 tuple_arguments,
533 );
534 }
535 }
536
537 fn report_arg_errors(
538 &self,
539 compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>,
540 formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
541 provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>,
542 c_variadic: bool,
543 err_code: ErrCode,
544 fn_def_id: Option<DefId>,
545 call_span: Span,
546 call_expr: &'tcx hir::Expr<'tcx>,
547 tuple_arguments: TupleArgumentsFlag,
548 ) -> ErrorGuaranteed {
549 let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind {
551 hir::ExprKind::Call(
552 hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. },
553 _,
554 ) => {
555 if let Res::Def(DefKind::Ctor(of, _), _) =
556 self.typeck_results.borrow().qpath_res(qpath, *hir_id)
557 {
558 let name = match of {
559 CtorOf::Struct => "struct",
560 CtorOf::Variant => "enum variant",
561 };
562 (call_span, None, *span, name, false)
563 } else {
564 (call_span, None, *span, "function", false)
565 }
566 }
567 hir::ExprKind::Call(hir::Expr { span, .. }, _) => {
568 (call_span, None, *span, "function", false)
569 }
570 hir::ExprKind::MethodCall(path_segment, _, _, span) => {
571 let ident_span = path_segment.ident.span;
572 let ident_span = if let Some(args) = path_segment.args {
573 ident_span.with_hi(args.span_ext.hi())
574 } else {
575 ident_span
576 };
577 (*span, Some(path_segment.ident), ident_span, "method", true)
578 }
579 k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
580 };
581 let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span);
582
583 fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
585 tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var())
586 }
587
588 let tcx = self.tcx;
589
590 let normalize_span = |span: Span| -> Span {
594 let normalized_span = span.find_ancestor_inside_same_ctxt(error_span).unwrap_or(span);
595 if normalized_span.source_equal(error_span) { span } else { normalized_span }
599 };
600
601 let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args
603 .iter()
604 .map(|expr| {
605 let ty = self
606 .typeck_results
607 .borrow()
608 .expr_ty_adjusted_opt(*expr)
609 .unwrap_or_else(|| Ty::new_misc_error(tcx));
610 (self.resolve_vars_if_possible(ty), normalize_span(expr.span))
611 })
612 .collect();
613 let callee_expr = match &call_expr.peel_blocks().kind {
614 hir::ExprKind::Call(callee, _) => Some(*callee),
615 hir::ExprKind::MethodCall(_, receiver, ..) => {
616 if let Some((DefKind::AssocFn, def_id)) =
617 self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
618 && let Some(assoc) = tcx.opt_associated_item(def_id)
619 && assoc.is_method()
620 {
621 Some(*receiver)
622 } else {
623 None
624 }
625 }
626 _ => None,
627 };
628 let callee_ty = callee_expr
629 .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr));
630
631 let similar_assoc = |call_name: Ident| -> Option<(ty::AssocItem, ty::FnSig<'_>)> {
633 if let Some(callee_ty) = callee_ty
634 && let Ok(Some(assoc)) = self.probe_op(
635 call_name.span,
636 MethodCall,
637 Some(call_name),
638 None,
639 IsSuggestion(true),
640 callee_ty.peel_refs(),
641 callee_expr.unwrap().hir_id,
642 TraitsInScope,
643 |mut ctxt| ctxt.probe_for_similar_candidate(),
644 )
645 && assoc.is_method()
646 {
647 let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
648 let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
649
650 self.instantiate_binder_with_fresh_vars(call_name.span, FnCall, fn_sig);
651 }
652 None
653 };
654
655 let suggest_confusable = |err: &mut Diag<'_>| {
656 let Some(call_name) = call_ident else {
657 return;
658 };
659 let Some(callee_ty) = callee_ty else {
660 return;
661 };
662 let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect();
663 if let Some(_name) = self.confusable_method_name(
671 err,
672 callee_ty.peel_refs(),
673 call_name,
674 Some(input_types.clone()),
675 ) {
676 return;
677 }
678 if let Some((assoc, fn_sig)) = similar_assoc(call_name)
680 && fn_sig.inputs()[1..]
681 .iter()
682 .zip(input_types.iter())
683 .all(|(expected, found)| self.may_coerce(*expected, *found))
684 && fn_sig.inputs()[1..].len() == input_types.len()
685 {
686 let assoc_name = assoc.name();
687 err.span_suggestion_verbose(
688 call_name.span,
689 format!("you might have meant to use `{}`", assoc_name),
690 assoc_name,
691 Applicability::MaybeIncorrect,
692 );
693 return;
694 }
695 if let Some(_name) =
697 self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None)
698 {
699 return;
700 }
701 if let Some((assoc, fn_sig)) = similar_assoc(call_name)
704 && fn_sig.inputs()[1..].len() == input_types.len()
705 {
706 err.span_note(
707 tcx.def_span(assoc.def_id),
708 format!(
709 "there's is a method with similar name `{}`, but the arguments don't match",
710 assoc.name(),
711 ),
712 );
713 return;
714 }
715 if let Some((assoc, _)) = similar_assoc(call_name) {
717 err.span_note(
718 tcx.def_span(assoc.def_id),
719 format!(
720 "there's is a method with similar name `{}`, but their argument count \
721 doesn't match",
722 assoc.name(),
723 ),
724 );
725 return;
726 }
727 };
728 let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| {
732 if provided_idx.as_usize() == expected_idx.as_usize() {
733 return compatibility_diagonal[provided_idx].clone();
734 }
735
736 let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx];
737 if (formal_input_ty, expected_input_ty).references_error() {
741 return Compatibility::Incompatible(None);
742 }
743
744 let (arg_ty, arg_span) = provided_arg_tys[provided_idx];
745
746 let expectation = Expectation::rvalue_hint(self, expected_input_ty);
747 let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
748 let can_coerce = self.may_coerce(arg_ty, coerced_ty);
749 if !can_coerce {
750 return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts(
751 ty::error::ExpectedFound::new(coerced_ty, arg_ty),
752 )));
753 }
754
755 let subtyping_error = self.probe(|_| {
757 self.at(&self.misc(arg_span), self.param_env)
758 .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty)
759 .err()
760 });
761
762 let references_error = (coerced_ty, arg_ty).references_error();
765 match (references_error, subtyping_error) {
766 (false, None) => Compatibility::Compatible,
767 (_, subtyping_error) => Compatibility::Incompatible(subtyping_error),
768 }
769 };
770
771 let mk_trace = |span, (formal_ty, expected_ty), provided_ty| {
772 let mismatched_ty = if expected_ty == provided_ty {
773 formal_ty
777 } else {
778 expected_ty
779 };
780 TypeTrace::types(&self.misc(span), mismatched_ty, provided_ty)
781 };
782
783 let (mut errors, matched_inputs) =
792 ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible)
793 .find_errors();
794
795 if let Some((mismatch_idx, terr)) =
797 compatibility_diagonal.iter_enumerated().find_map(|(i, c)| {
798 if let Compatibility::Incompatible(Some(terr)) = c {
799 Some((i, *terr))
800 } else {
801 None
802 }
803 })
804 {
805 if let Some(ty::Tuple(tys)) =
809 formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind())
810 && !tys.is_empty()
812 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
813 {
814 let provided_args_to_tuple = &provided_arg_tys[mismatch_idx..];
816 let (provided_args_to_tuple, provided_args_after_tuple) =
817 provided_args_to_tuple.split_at(tys.len());
818 let provided_as_tuple =
819 Ty::new_tup_from_iter(tcx, provided_args_to_tuple.iter().map(|&(ty, _)| ty));
820
821 let mut satisfied = true;
822 for ((_, expected_ty), provided_ty) in std::iter::zip(
824 formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(),
825 [provided_as_tuple]
826 .into_iter()
827 .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)),
828 ) {
829 if !self.may_coerce(provided_ty, *expected_ty) {
830 satisfied = false;
831 break;
832 }
833 }
834
835 if satisfied
839 && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple
840 {
841 let mut err;
842 if tys.len() == 1 {
843 err = self.err_ctxt().report_and_explain_type_error(
846 mk_trace(
847 lo,
848 formal_and_expected_inputs[mismatch_idx.to_expected_idx()],
849 provided_arg_tys[mismatch_idx].0,
850 ),
851 self.param_env,
852 terr,
853 );
854 err.span_label(
855 full_call_span,
856 format!("arguments to this {call_name} are incorrect"),
857 );
858 } else {
859 err = self.dcx().struct_span_err(
860 full_call_span,
861 format!(
862 "{call_name} takes {}{} but {} {} supplied",
863 if c_variadic { "at least " } else { "" },
864 potentially_plural_count(
865 formal_and_expected_inputs.len(),
866 "argument"
867 ),
868 potentially_plural_count(provided_args.len(), "argument"),
869 pluralize!("was", provided_args.len())
870 ),
871 );
872 err.code(err_code.to_owned());
873 err.multipart_suggestion_verbose(
874 "wrap these arguments in parentheses to construct a tuple",
875 vec![
876 (lo.shrink_to_lo(), "(".to_string()),
877 (hi.shrink_to_hi(), ")".to_string()),
878 ],
879 Applicability::MachineApplicable,
880 );
881 };
882 self.label_fn_like(
883 &mut err,
884 fn_def_id,
885 callee_ty,
886 call_expr,
887 None,
888 Some(mismatch_idx.as_usize()),
889 &matched_inputs,
890 &formal_and_expected_inputs,
891 is_method,
892 tuple_arguments,
893 );
894 suggest_confusable(&mut err);
895 return err.emit();
896 }
897 }
898 }
899
900 if errors.is_empty() {
916 if cfg!(debug_assertions) {
917 span_bug!(error_span, "expected errors from argument matrix");
918 } else {
919 let mut err =
920 self.dcx().create_err(errors::ArgMismatchIndeterminate { span: error_span });
921 suggest_confusable(&mut err);
922 return err.emit();
923 }
924 }
925
926 let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| {
927 if let ty::Adt(adt, _) = ty.kind()
928 && self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did())
929 && let hir::ExprKind::Struct(
930 hir::QPath::LangItem(hir::LangItem::RangeFull, _),
931 [],
932 _,
933 ) = expr.kind
934 {
935 let explanation = if self.tcx.features().default_field_values() {
938 "this is only supported on non-tuple struct literals"
939 } else if self.tcx.sess.is_nightly_build() {
940 "this is only supported on non-tuple struct literals when \
941 `#![feature(default_field_values)]` is enabled"
942 } else {
943 "this is not supported"
944 };
945 let msg = format!(
946 "you might have meant to use `..` to skip providing a value for \
947 expected fields, but {explanation}; it is instead interpreted as a \
948 `std::ops::RangeFull` literal",
949 );
950 err.span_help(expr.span, msg);
951 }
952 };
953
954 let mut reported = None;
955 errors.retain(|error| {
956 let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) =
957 error
958 else {
959 return true;
960 };
961 let (provided_ty, provided_span) = provided_arg_tys[*provided_idx];
962 let trace =
963 mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty);
964 if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) {
965 let mut err =
966 self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *e);
967 suggest_confusable(&mut err);
968 reported = Some(err.emit());
969 return false;
970 }
971 true
972 });
973
974 if let Some(reported) = reported
976 && errors.is_empty()
977 {
978 return reported;
979 }
980 assert!(!errors.is_empty());
981
982 if let &[
988 Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))),
989 ] = &errors[..]
990 {
991 let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
992 let (provided_ty, provided_arg_span) = provided_arg_tys[provided_idx];
993 let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty);
994 let mut err = self.err_ctxt().report_and_explain_type_error(trace, self.param_env, err);
995 self.emit_coerce_suggestions(
996 &mut err,
997 provided_args[provided_idx],
998 provided_ty,
999 Expectation::rvalue_hint(self, expected_ty)
1000 .only_has_type(self)
1001 .unwrap_or(formal_ty),
1002 None,
1003 None,
1004 );
1005 err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect"));
1006
1007 self.label_generic_mismatches(
1008 &mut err,
1009 fn_def_id,
1010 &matched_inputs,
1011 &provided_arg_tys,
1012 &formal_and_expected_inputs,
1013 is_method,
1014 );
1015
1016 if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind
1017 && provided_idx.as_usize() == expected_idx.as_usize()
1018 {
1019 self.note_source_of_type_mismatch_constraint(
1020 &mut err,
1021 rcvr,
1022 crate::demand::TypeMismatchSource::Arg {
1023 call_expr,
1024 incompatible_arg: provided_idx.as_usize(),
1025 },
1026 );
1027 }
1028
1029 self.suggest_ptr_null_mut(
1030 expected_ty,
1031 provided_ty,
1032 provided_args[provided_idx],
1033 &mut err,
1034 );
1035
1036 self.suggest_deref_unwrap_or(
1037 &mut err,
1038 callee_ty,
1039 call_ident,
1040 expected_ty,
1041 provided_ty,
1042 provided_args[provided_idx],
1043 is_method,
1044 );
1045
1046 self.label_fn_like(
1048 &mut err,
1049 fn_def_id,
1050 callee_ty,
1051 call_expr,
1052 Some(expected_ty),
1053 Some(expected_idx.as_usize()),
1054 &matched_inputs,
1055 &formal_and_expected_inputs,
1056 is_method,
1057 tuple_arguments,
1058 );
1059 suggest_confusable(&mut err);
1060 detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]);
1061 return err.emit();
1062 }
1063
1064 if let [Error::Extra(provided_idx)] = &errors[..] {
1069 let remove_idx_is_perfect = |idx: usize| -> bool {
1070 let removed_arg_tys = provided_arg_tys
1071 .iter()
1072 .enumerate()
1073 .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) })
1074 .collect::<IndexVec<ProvidedIdx, _>>();
1075 std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all(
1076 |((expected_ty, _), (provided_ty, _))| {
1077 !provided_ty.references_error()
1078 && self.may_coerce(*provided_ty, *expected_ty)
1079 },
1080 )
1081 };
1082
1083 if !remove_idx_is_perfect(provided_idx.as_usize()) {
1084 if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) {
1085 errors = vec![Error::Extra(ProvidedIdx::from_usize(i))];
1086 }
1087 }
1088 }
1089
1090 let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
1091 struct_span_code_err!(
1092 self.dcx(),
1093 full_call_span,
1094 E0308,
1095 "arguments to this {} are incorrect",
1096 call_name,
1097 )
1098 } else {
1099 self.dcx()
1100 .struct_span_err(
1101 full_call_span,
1102 format!(
1103 "this {} takes {}{} but {} {} supplied",
1104 call_name,
1105 if c_variadic { "at least " } else { "" },
1106 potentially_plural_count(formal_and_expected_inputs.len(), "argument"),
1107 potentially_plural_count(provided_args.len(), "argument"),
1108 pluralize!("was", provided_args.len())
1109 ),
1110 )
1111 .with_code(err_code.to_owned())
1112 };
1113
1114 suggest_confusable(&mut err);
1115 let mut labels = vec![];
1117 enum SuggestionText {
1120 None,
1121 Provide(bool),
1122 Remove(bool),
1123 Swap,
1124 Reorder,
1125 DidYouMean,
1126 }
1127 let mut suggestion_text = SuggestionText::None;
1128
1129 let ty_to_snippet = |ty: Ty<'tcx>, expected_idx: ExpectedIdx| {
1130 if ty.is_unit() {
1131 "()".to_string()
1132 } else if ty.is_suggestable(tcx, false) {
1133 format!("/* {ty} */")
1134 } else if let Some(fn_def_id) = fn_def_id
1135 && self.tcx.def_kind(fn_def_id).is_fn_like()
1136 && let self_implicit =
1137 matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize
1138 && let Some(Some(arg)) =
1139 self.tcx.fn_arg_idents(fn_def_id).get(expected_idx.as_usize() + self_implicit)
1140 && arg.name != kw::SelfLower
1141 {
1142 format!("/* {} */", arg.name)
1143 } else {
1144 "/* value */".to_string()
1145 }
1146 };
1147
1148 let mut errors = errors.into_iter().peekable();
1149 let mut only_extras_so_far = errors
1150 .peek()
1151 .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
1152 let mut prev_extra_idx = None;
1153 let mut suggestions = vec![];
1154 while let Some(error) = errors.next() {
1155 only_extras_so_far &= matches!(error, Error::Extra(_));
1156
1157 match error {
1158 Error::Invalid(provided_idx, expected_idx, compatibility) => {
1159 let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx];
1160 let (provided_ty, provided_span) = provided_arg_tys[provided_idx];
1161 if let Compatibility::Incompatible(error) = compatibility {
1162 let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
1163 if let Some(e) = error {
1164 self.err_ctxt().note_type_err(
1165 &mut err,
1166 &trace.cause,
1167 None,
1168 Some(self.param_env.and(trace.values)),
1169 e,
1170 true,
1171 None,
1172 );
1173 }
1174 }
1175
1176 self.emit_coerce_suggestions(
1177 &mut err,
1178 provided_args[provided_idx],
1179 provided_ty,
1180 Expectation::rvalue_hint(self, expected_ty)
1181 .only_has_type(self)
1182 .unwrap_or(formal_ty),
1183 None,
1184 None,
1185 );
1186 detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]);
1187 }
1188 Error::Extra(arg_idx) => {
1189 let (provided_ty, provided_span) = provided_arg_tys[arg_idx];
1190 let provided_ty_name = if !has_error_or_infer([provided_ty]) {
1191 format!(" of type `{provided_ty}`")
1193 } else {
1194 "".to_string()
1195 };
1196 let idx = if provided_arg_tys.len() == 1 {
1197 "".to_string()
1198 } else {
1199 format!(" #{}", arg_idx.as_usize() + 1)
1200 };
1201 labels.push((
1202 provided_span,
1203 format!("unexpected argument{idx}{provided_ty_name}"),
1204 ));
1205 let mut span = provided_span;
1206 if span.can_be_used_for_suggestions()
1207 && error_span.can_be_used_for_suggestions()
1208 {
1209 if arg_idx.index() > 0
1210 && let Some((_, prev)) =
1211 provided_arg_tys.get(ProvidedIdx::from_usize(arg_idx.index() - 1))
1212 {
1213 span = prev.shrink_to_hi().to(span);
1215 }
1216
1217 let trim_next_comma = match errors.peek() {
1224 Some(Error::Extra(provided_idx))
1225 if only_extras_so_far
1226 && provided_idx.index() > arg_idx.index() + 1 =>
1227 {
1235 prev_extra_idx.is_none_or(|prev_extra_idx| {
1236 prev_extra_idx + 1 == arg_idx.index()
1237 })
1238 }
1239 None if only_extras_so_far => true,
1241 _ => false,
1243 };
1244
1245 if trim_next_comma {
1246 let next = provided_arg_tys
1247 .get(arg_idx + 1)
1248 .map(|&(_, sp)| sp)
1249 .unwrap_or_else(|| {
1250 self.tcx().sess.source_map().end_point(call_expr.span)
1255 });
1256
1257 span = span.until(next);
1259 }
1260
1261 suggestions.push((span, String::new()));
1262
1263 suggestion_text = match suggestion_text {
1264 SuggestionText::None => SuggestionText::Remove(false),
1265 SuggestionText::Remove(_) => SuggestionText::Remove(true),
1266 _ => SuggestionText::DidYouMean,
1267 };
1268 prev_extra_idx = Some(arg_idx.index())
1269 }
1270 detect_dotdot(&mut err, provided_ty, provided_args[arg_idx]);
1271 }
1272 Error::Missing(expected_idx) => {
1273 let mut missing_idxs = vec![expected_idx];
1277 while let Some(e) = errors.next_if(|e| {
1278 matches!(e, Error::Missing(next_expected_idx)
1279 if *next_expected_idx == *missing_idxs.last().unwrap() + 1)
1280 }) {
1281 match e {
1282 Error::Missing(expected_idx) => missing_idxs.push(expected_idx),
1283 _ => unreachable!(
1284 "control flow ensures that we should always get an `Error::Missing`"
1285 ),
1286 }
1287 }
1288
1289 match &missing_idxs[..] {
1294 &[expected_idx] => {
1295 let (_, input_ty) = formal_and_expected_inputs[expected_idx];
1296 let span = if let Some((_, arg_span)) =
1297 provided_arg_tys.get(expected_idx.to_provided_idx())
1298 {
1299 *arg_span
1300 } else {
1301 args_span
1302 };
1303 let rendered = if !has_error_or_infer([input_ty]) {
1304 format!(" of type `{input_ty}`")
1305 } else {
1306 "".to_string()
1307 };
1308 labels.push((
1309 span,
1310 format!(
1311 "argument #{}{rendered} is missing",
1312 expected_idx.as_usize() + 1
1313 ),
1314 ));
1315
1316 suggestion_text = match suggestion_text {
1317 SuggestionText::None => SuggestionText::Provide(false),
1318 SuggestionText::Provide(_) => SuggestionText::Provide(true),
1319 _ => SuggestionText::DidYouMean,
1320 };
1321 }
1322 &[first_idx, second_idx] => {
1323 let (_, first_expected_ty) = formal_and_expected_inputs[first_idx];
1324 let (_, second_expected_ty) = formal_and_expected_inputs[second_idx];
1325 let span = if let (Some((_, first_span)), Some((_, second_span))) = (
1326 provided_arg_tys.get(first_idx.to_provided_idx()),
1327 provided_arg_tys.get(second_idx.to_provided_idx()),
1328 ) {
1329 first_span.to(*second_span)
1330 } else {
1331 args_span
1332 };
1333 let rendered =
1334 if !has_error_or_infer([first_expected_ty, second_expected_ty]) {
1335 format!(
1336 " of type `{first_expected_ty}` and `{second_expected_ty}`"
1337 )
1338 } else {
1339 "".to_string()
1340 };
1341 labels.push((span, format!("two arguments{rendered} are missing")));
1342 suggestion_text = match suggestion_text {
1343 SuggestionText::None | SuggestionText::Provide(_) => {
1344 SuggestionText::Provide(true)
1345 }
1346 _ => SuggestionText::DidYouMean,
1347 };
1348 }
1349 &[first_idx, second_idx, third_idx] => {
1350 let (_, first_expected_ty) = formal_and_expected_inputs[first_idx];
1351 let (_, second_expected_ty) = formal_and_expected_inputs[second_idx];
1352 let (_, third_expected_ty) = formal_and_expected_inputs[third_idx];
1353 let span = if let (Some((_, first_span)), Some((_, third_span))) = (
1354 provided_arg_tys.get(first_idx.to_provided_idx()),
1355 provided_arg_tys.get(third_idx.to_provided_idx()),
1356 ) {
1357 first_span.to(*third_span)
1358 } else {
1359 args_span
1360 };
1361 let rendered = if !has_error_or_infer([
1362 first_expected_ty,
1363 second_expected_ty,
1364 third_expected_ty,
1365 ]) {
1366 format!(
1367 " of type `{first_expected_ty}`, `{second_expected_ty}`, and `{third_expected_ty}`"
1368 )
1369 } else {
1370 "".to_string()
1371 };
1372 labels.push((span, format!("three arguments{rendered} are missing")));
1373 suggestion_text = match suggestion_text {
1374 SuggestionText::None | SuggestionText::Provide(_) => {
1375 SuggestionText::Provide(true)
1376 }
1377 _ => SuggestionText::DidYouMean,
1378 };
1379 }
1380 missing_idxs => {
1381 let first_idx = *missing_idxs.first().unwrap();
1382 let last_idx = *missing_idxs.last().unwrap();
1383 let span = if let (Some((_, first_span)), Some((_, last_span))) = (
1387 provided_arg_tys.get(first_idx.to_provided_idx()),
1388 provided_arg_tys.get(last_idx.to_provided_idx()),
1389 ) {
1390 first_span.to(*last_span)
1391 } else {
1392 args_span
1393 };
1394 labels.push((span, "multiple arguments are missing".to_string()));
1395 suggestion_text = match suggestion_text {
1396 SuggestionText::None | SuggestionText::Provide(_) => {
1397 SuggestionText::Provide(true)
1398 }
1399 _ => SuggestionText::DidYouMean,
1400 };
1401 }
1402 }
1403 }
1404 Error::Swap(
1405 first_provided_idx,
1406 second_provided_idx,
1407 first_expected_idx,
1408 second_expected_idx,
1409 ) => {
1410 let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx];
1411 let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx];
1412 let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) {
1413 format!(", found `{first_provided_ty}`")
1414 } else {
1415 String::new()
1416 };
1417 labels.push((
1418 first_span,
1419 format!("expected `{first_expected_ty}`{first_provided_ty_name}"),
1420 ));
1421
1422 let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx];
1423 let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx];
1424 let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) {
1425 format!(", found `{second_provided_ty}`")
1426 } else {
1427 String::new()
1428 };
1429 labels.push((
1430 second_span,
1431 format!("expected `{second_expected_ty}`{second_provided_ty_name}"),
1432 ));
1433
1434 suggestion_text = match suggestion_text {
1435 SuggestionText::None => SuggestionText::Swap,
1436 _ => SuggestionText::DidYouMean,
1437 };
1438 }
1439 Error::Permutation(args) => {
1440 for (dst_arg, dest_input) in args {
1441 let (_, expected_ty) = formal_and_expected_inputs[dst_arg];
1442 let (provided_ty, provided_span) = provided_arg_tys[dest_input];
1443 let provided_ty_name = if !has_error_or_infer([provided_ty]) {
1444 format!(", found `{provided_ty}`")
1445 } else {
1446 String::new()
1447 };
1448 labels.push((
1449 provided_span,
1450 format!("expected `{expected_ty}`{provided_ty_name}"),
1451 ));
1452 }
1453
1454 suggestion_text = match suggestion_text {
1455 SuggestionText::None => SuggestionText::Reorder,
1456 _ => SuggestionText::DidYouMean,
1457 };
1458 }
1459 }
1460 }
1461
1462 self.label_generic_mismatches(
1463 &mut err,
1464 fn_def_id,
1465 &matched_inputs,
1466 &provided_arg_tys,
1467 &formal_and_expected_inputs,
1468 is_method,
1469 );
1470
1471 let mut prev = -1;
1491 for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
1492 if let Some(provided_idx) = provided_idx {
1495 prev = provided_idx.index() as i64;
1496 continue;
1497 }
1498 let idx = ProvidedIdx::from_usize((prev + 1) as usize);
1499 if let Some((_, arg_span)) = provided_arg_tys.get(idx) {
1500 prev += 1;
1501 let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
1506 suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx)));
1507 }
1508 }
1509
1510 if labels.len() <= 5 {
1512 for (span, label) in labels {
1513 err.span_label(span, label);
1514 }
1515 }
1516
1517 self.label_fn_like(
1519 &mut err,
1520 fn_def_id,
1521 callee_ty,
1522 call_expr,
1523 None,
1524 None,
1525 &matched_inputs,
1526 &formal_and_expected_inputs,
1527 is_method,
1528 tuple_arguments,
1529 );
1530
1531 let suggestion_text = match suggestion_text {
1533 SuggestionText::None => None,
1534 SuggestionText::Provide(plural) => {
1535 Some(format!("provide the argument{}", if plural { "s" } else { "" }))
1536 }
1537 SuggestionText::Remove(plural) => {
1538 err.multipart_suggestion_verbose(
1539 format!("remove the extra argument{}", if plural { "s" } else { "" }),
1540 suggestions,
1541 Applicability::HasPlaceholders,
1542 );
1543 None
1544 }
1545 SuggestionText::Swap => Some("swap these arguments".to_string()),
1546 SuggestionText::Reorder => Some("reorder these arguments".to_string()),
1547 SuggestionText::DidYouMean => Some("did you mean".to_string()),
1548 };
1549 if let Some(suggestion_text) = suggestion_text {
1550 let source_map = self.sess().source_map();
1551 let (mut suggestion, suggestion_span) = if let Some(call_span) =
1552 full_call_span.find_ancestor_inside_same_ctxt(error_span)
1553 {
1554 ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi()))
1555 } else {
1556 (
1557 format!(
1558 "{}(",
1559 source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| {
1560 fn_def_id.map_or("".to_string(), |fn_def_id| {
1561 tcx.item_name(fn_def_id).to_string()
1562 })
1563 })
1564 ),
1565 error_span,
1566 )
1567 };
1568 let mut needs_comma = false;
1569 for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
1570 if needs_comma {
1571 suggestion += ", ";
1572 } else {
1573 needs_comma = true;
1574 }
1575 let suggestion_text = if let Some(provided_idx) = provided_idx
1576 && let (_, provided_span) = provided_arg_tys[*provided_idx]
1577 && let Ok(arg_text) = source_map.span_to_snippet(provided_span)
1578 {
1579 arg_text
1580 } else {
1581 let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
1583 ty_to_snippet(expected_ty, expected_idx)
1584 };
1585 suggestion += &suggestion_text;
1586 }
1587 suggestion += ")";
1588 err.span_suggestion_verbose(
1589 suggestion_span,
1590 suggestion_text,
1591 suggestion,
1592 Applicability::HasPlaceholders,
1593 );
1594 }
1595
1596 err.emit()
1597 }
1598
1599 fn suggest_ptr_null_mut(
1600 &self,
1601 expected_ty: Ty<'tcx>,
1602 provided_ty: Ty<'tcx>,
1603 arg: &hir::Expr<'tcx>,
1604 err: &mut Diag<'_>,
1605 ) {
1606 if let ty::RawPtr(_, hir::Mutability::Mut) = expected_ty.kind()
1607 && let ty::RawPtr(_, hir::Mutability::Not) = provided_ty.kind()
1608 && let hir::ExprKind::Call(callee, _) = arg.kind
1609 && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind
1610 && let Res::Def(_, def_id) = path.res
1611 && self.tcx.get_diagnostic_item(sym::ptr_null) == Some(def_id)
1612 {
1613 err.subdiagnostic(SuggestPtrNullMut { span: arg.span });
1616 }
1617 }
1618
1619 pub(in super::super) fn check_expr_lit(
1621 &self,
1622 lit: &hir::Lit,
1623 expected: Expectation<'tcx>,
1624 ) -> Ty<'tcx> {
1625 let tcx = self.tcx;
1626
1627 match lit.node {
1628 ast::LitKind::Str(..) => Ty::new_static_str(tcx),
1629 ast::LitKind::ByteStr(ref v, _) => Ty::new_imm_ref(
1630 tcx,
1631 tcx.lifetimes.re_static,
1632 Ty::new_array(tcx, tcx.types.u8, v.len() as u64),
1633 ),
1634 ast::LitKind::Byte(_) => tcx.types.u8,
1635 ast::LitKind::Char(_) => tcx.types.char,
1636 ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)),
1637 ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)),
1638 ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) => {
1639 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
1640 ty::Int(_) | ty::Uint(_) => Some(ty),
1641 ty::Char => Some(tcx.types.u8),
1645 ty::RawPtr(..) => Some(tcx.types.usize),
1646 ty::FnDef(..) | ty::FnPtr(..) => Some(tcx.types.usize),
1647 &ty::Pat(base, _) if base.is_integral() => {
1648 let layout = tcx
1649 .layout_of(self.typing_env(self.param_env).as_query_input(ty))
1650 .ok()?;
1651 assert!(!layout.uninhabited);
1652
1653 match layout.backend_repr {
1654 rustc_abi::BackendRepr::Scalar(scalar) => {
1655 scalar.valid_range(&tcx).contains(u128::from(i.get())).then_some(ty)
1656 }
1657 _ => unreachable!(),
1658 }
1659 }
1660 _ => None,
1661 });
1662 opt_ty.unwrap_or_else(|| self.next_int_var())
1663 }
1664 ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => {
1665 Ty::new_float(tcx, ty::float_ty(t))
1666 }
1667 ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
1668 let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
1669 ty::Float(_) => Some(ty),
1670 _ => None,
1671 });
1672 opt_ty.unwrap_or_else(|| self.next_float_var())
1673 }
1674 ast::LitKind::Bool(_) => tcx.types.bool,
1675 ast::LitKind::CStr(_, _) => Ty::new_imm_ref(
1676 tcx,
1677 tcx.lifetimes.re_static,
1678 tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
1679 .skip_binder(),
1680 ),
1681 ast::LitKind::Err(guar) => Ty::new_error(tcx, guar),
1682 }
1683 }
1684
1685 pub(crate) fn check_struct_path(
1686 &self,
1687 qpath: &QPath<'tcx>,
1688 hir_id: HirId,
1689 ) -> Result<(&'tcx ty::VariantDef, Ty<'tcx>), ErrorGuaranteed> {
1690 let path_span = qpath.span();
1691 let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
1692 let variant = match def {
1693 Res::Err => {
1694 let guar =
1695 self.dcx().span_delayed_bug(path_span, "`Res::Err` but no error emitted");
1696 self.set_tainted_by_errors(guar);
1697 return Err(guar);
1698 }
1699 Res::Def(DefKind::Variant, _) => match ty.normalized.ty_adt_def() {
1700 Some(adt) => {
1701 Some((adt.variant_of_res(def), adt.did(), Self::user_args_for_adt(ty)))
1702 }
1703 _ => bug!("unexpected type: {:?}", ty.normalized),
1704 },
1705 Res::Def(
1706 DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy,
1707 _,
1708 )
1709 | Res::SelfTyParam { .. }
1710 | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() {
1711 Some(adt) if !adt.is_enum() => {
1712 Some((adt.non_enum_variant(), adt.did(), Self::user_args_for_adt(ty)))
1713 }
1714 _ => None,
1715 },
1716 _ => bug!("unexpected definition: {:?}", def),
1717 };
1718
1719 if let Some((variant, did, ty::UserArgs { args, user_self_ty })) = variant {
1720 debug!("check_struct_path: did={:?} args={:?}", did, args);
1721
1722 self.write_user_type_annotation_from_args(hir_id, did, args, user_self_ty);
1724
1725 self.add_required_obligations_for_hir(path_span, did, args, hir_id);
1727
1728 Ok((variant, ty.normalized))
1729 } else {
1730 Err(match *ty.normalized.kind() {
1731 ty::Error(guar) => {
1732 guar
1737 }
1738 _ => struct_span_code_err!(
1739 self.dcx(),
1740 path_span,
1741 E0071,
1742 "expected struct, variant or union type, found {}",
1743 ty.normalized.sort_string(self.tcx)
1744 )
1745 .with_span_label(path_span, "not a struct")
1746 .emit(),
1747 })
1748 }
1749 }
1750
1751 fn check_decl_initializer(
1752 &self,
1753 hir_id: HirId,
1754 pat: &'tcx hir::Pat<'tcx>,
1755 init: &'tcx hir::Expr<'tcx>,
1756 ) -> Ty<'tcx> {
1757 let ref_bindings = pat.contains_explicit_ref_binding();
1762
1763 let local_ty = self.local_ty(init.span, hir_id);
1764 if let Some(m) = ref_bindings {
1765 let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
1774 if let Err(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) {
1775 self.emit_type_mismatch_suggestions(
1776 &mut diag,
1777 init.peel_drop_temps(),
1778 init_ty,
1779 local_ty,
1780 None,
1781 None,
1782 );
1783 diag.emit();
1784 }
1785 init_ty
1786 } else {
1787 self.check_expr_coercible_to_type(init, local_ty, None)
1788 }
1789 }
1790
1791 pub(in super::super) fn check_decl(&self, decl: Declaration<'tcx>) -> Ty<'tcx> {
1792 let decl_ty = self.local_ty(decl.span, decl.hir_id);
1794
1795 if let Some(ref init) = decl.init {
1797 let init_ty = self.check_decl_initializer(decl.hir_id, decl.pat, init);
1798 self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, init_ty);
1799 }
1800
1801 let (origin_expr, ty_span) = match (decl.ty, decl.init) {
1803 (Some(ty), _) => (None, Some(ty.span)), (_, Some(init)) => {
1805 (Some(init), Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
1806 } _ => (None, None), };
1809
1810 self.check_pat_top(decl.pat, decl_ty, ty_span, origin_expr, Some(decl.origin));
1812 let pat_ty = self.node_ty(decl.pat.hir_id);
1813 self.overwrite_local_ty_if_err(decl.hir_id, decl.pat, pat_ty);
1814
1815 if let Some(blk) = decl.origin.try_get_else() {
1816 let previous_diverges = self.diverges.get();
1817 let else_ty = self.check_expr_block(blk, NoExpectation);
1818 let cause = self.cause(blk.span, ObligationCauseCode::LetElse);
1819 if let Err(err) = self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
1820 {
1821 err.emit();
1822 }
1823 self.diverges.set(previous_diverges);
1824 }
1825 decl_ty
1826 }
1827
1828 fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
1830 let ty = self.check_decl(local.into());
1831 self.write_ty(local.hir_id, ty);
1832 if local.pat.is_never_pattern() {
1833 self.diverges.set(Diverges::Always {
1834 span: local.pat.span,
1835 custom_note: Some("any code following a never pattern is unreachable"),
1836 });
1837 }
1838 }
1839
1840 fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
1841 match stmt.kind {
1843 hir::StmtKind::Item(..) => return,
1844 hir::StmtKind::Let(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
1845 }
1846
1847 self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
1848
1849 let old_diverges = self.diverges.replace(Diverges::Maybe);
1851
1852 match stmt.kind {
1853 hir::StmtKind::Let(l) => {
1854 self.check_decl_local(l);
1855 }
1856 hir::StmtKind::Item(_) => {}
1858 hir::StmtKind::Expr(ref expr) => {
1859 self.check_expr_has_type_or_error(expr, self.tcx.types.unit, |err| {
1861 if expr.can_have_side_effects() {
1862 self.suggest_semicolon_at_end(expr.span, err);
1863 }
1864 });
1865 }
1866 hir::StmtKind::Semi(expr) => {
1867 self.check_expr(expr);
1868 }
1869 }
1870
1871 self.diverges.set(self.diverges.get() | old_diverges);
1873 }
1874
1875 pub(crate) fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
1876 let unit = self.tcx.types.unit;
1877 let ty = self.check_expr_block(blk, ExpectHasType(unit));
1878
1879 if !ty.is_never() {
1882 self.demand_suptype(blk.span, unit, ty);
1883 }
1884 }
1885
1886 pub(in super::super) fn check_expr_block(
1887 &self,
1888 blk: &'tcx hir::Block<'tcx>,
1889 expected: Expectation<'tcx>,
1890 ) -> Ty<'tcx> {
1891 let coerce_to_ty = expected.coercion_target_type(self, blk.span);
1908 let coerce = if blk.targeted_by_break {
1909 CoerceMany::new(coerce_to_ty)
1910 } else {
1911 CoerceMany::with_coercion_sites(coerce_to_ty, blk.expr.as_slice())
1912 };
1913
1914 let prev_diverges = self.diverges.get();
1915 let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
1916
1917 let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
1918 for s in blk.stmts {
1919 self.check_stmt(s);
1920 }
1921
1922 let tail_expr_ty =
1925 blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected)));
1926
1927 let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
1928 let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
1929 let coerce = ctxt.coerce.as_mut().unwrap();
1930 if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty {
1931 let span = self.get_expr_coercion_span(tail_expr);
1932 let cause = self.cause(
1933 span,
1934 ObligationCauseCode::BlockTailExpression(blk.hir_id, hir::MatchSource::Normal),
1935 );
1936 let ty_for_diagnostic = coerce.merged_ty();
1937 coerce.coerce_inner(
1941 self,
1942 &cause,
1943 Some(tail_expr),
1944 tail_expr_ty,
1945 |diag| {
1946 self.suggest_block_to_brackets(diag, blk, tail_expr_ty, ty_for_diagnostic);
1947 },
1948 false,
1949 );
1950 } else {
1951 if !self.diverges.get().is_always()
1962 || matches!(self.diverging_block_behavior, DivergingBlockBehavior::Unit)
1963 {
1964 let mut sp = blk.span;
1970 let mut fn_span = None;
1971 if let Some((fn_def_id, decl)) = self.get_fn_decl(blk.hir_id) {
1972 let ret_sp = decl.output.span();
1973 if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
1974 if block_sp == blk.span {
1978 sp = ret_sp;
1979 fn_span = self.tcx.def_ident_span(fn_def_id);
1980 }
1981 }
1982 }
1983 coerce.coerce_forced_unit(
1984 self,
1985 &self.misc(sp),
1986 |err| {
1987 if let Some(expected_ty) = expected.only_has_type(self) {
1988 if blk.stmts.is_empty() && blk.expr.is_none() {
1989 self.suggest_boxing_when_appropriate(
1990 err,
1991 blk.span,
1992 blk.hir_id,
1993 expected_ty,
1994 self.tcx.types.unit,
1995 );
1996 }
1997 if !self.err_ctxt().consider_removing_semicolon(
1998 blk,
1999 expected_ty,
2000 err,
2001 ) {
2002 self.err_ctxt().consider_returning_binding(
2003 blk,
2004 expected_ty,
2005 err,
2006 );
2007 }
2008 if expected_ty == self.tcx.types.bool {
2009 if let hir::Block {
2014 stmts:
2015 [
2016 hir::Stmt {
2017 kind:
2018 hir::StmtKind::Let(hir::LetStmt {
2019 source:
2020 hir::LocalSource::AssignDesugar(_),
2021 ..
2022 }),
2023 ..
2024 },
2025 hir::Stmt {
2026 kind:
2027 hir::StmtKind::Expr(hir::Expr {
2028 kind: hir::ExprKind::Assign(lhs, ..),
2029 ..
2030 }),
2031 ..
2032 },
2033 ],
2034 ..
2035 } = blk
2036 {
2037 self.comes_from_while_condition(blk.hir_id, |_| {
2038 let res = self.typeck_results.borrow().expr_ty_opt(lhs);
2042
2043 if !lhs.is_syntactic_place_expr()
2044 || res.references_error()
2045 {
2046 err.downgrade_to_delayed_bug();
2047 }
2048 })
2049 }
2050 }
2051 }
2052 if let Some(fn_span) = fn_span {
2053 err.span_label(
2054 fn_span,
2055 "implicitly returns `()` as its body has no tail or `return` \
2056 expression",
2057 );
2058 }
2059 },
2060 false,
2061 );
2062 }
2063 }
2064 });
2065
2066 if ctxt.may_break {
2067 self.diverges.set(prev_diverges);
2070 }
2071
2072 let ty = ctxt.coerce.unwrap().complete(self);
2073
2074 self.write_ty(blk.hir_id, ty);
2075
2076 ty
2077 }
2078
2079 fn parent_item_span(&self, id: HirId) -> Option<Span> {
2080 let node = self.tcx.hir_node_by_def_id(self.tcx.hir_get_parent_item(id).def_id);
2081 match node {
2082 Node::Item(&hir::Item { kind: hir::ItemKind::Fn { body: body_id, .. }, .. })
2083 | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
2084 let body = self.tcx.hir_body(body_id);
2085 if let ExprKind::Block(block, _) = &body.value.kind {
2086 return Some(block.span);
2087 }
2088 }
2089 _ => {}
2090 }
2091 None
2092 }
2093
2094 fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
2102 let check_in_progress = |elem: &hir::Expr<'_>| {
2103 self.typeck_results.borrow().node_type_opt(elem.hir_id).filter(|ty| !ty.is_never()).map(
2104 |_| match elem.kind {
2105 hir::ExprKind::Block(block, _) => block.expr.map_or(block.span, |e| e.span),
2107 _ => elem.span,
2108 },
2109 )
2110 };
2111
2112 if let hir::ExprKind::If(_, _, Some(el)) = expr.kind {
2113 if let Some(rslt) = check_in_progress(el) {
2114 return rslt;
2115 }
2116 }
2117
2118 if let hir::ExprKind::Match(_, arms, _) = expr.kind {
2119 let mut iter = arms.iter().filter_map(|arm| check_in_progress(arm.body));
2120 if let Some(span) = iter.next() {
2121 if iter.next().is_none() {
2122 return span;
2123 }
2124 }
2125 }
2126
2127 expr.span
2128 }
2129
2130 fn overwrite_local_ty_if_err(&self, hir_id: HirId, pat: &'tcx hir::Pat<'tcx>, ty: Ty<'tcx>) {
2131 if let Err(guar) = ty.error_reported() {
2132 struct OverwritePatternsWithError {
2133 pat_hir_ids: Vec<hir::HirId>,
2134 }
2135 impl<'tcx> Visitor<'tcx> for OverwritePatternsWithError {
2136 fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
2137 self.pat_hir_ids.push(p.hir_id);
2138 hir::intravisit::walk_pat(self, p);
2139 }
2140 }
2141 let err = Ty::new_error(self.tcx, guar);
2143 self.write_ty(hir_id, err);
2144 self.write_ty(pat.hir_id, err);
2145 let mut visitor = OverwritePatternsWithError { pat_hir_ids: vec![] };
2146 hir::intravisit::walk_pat(&mut visitor, pat);
2147 for hir_id in visitor.pat_hir_ids {
2150 self.write_ty(hir_id, err);
2151 }
2152 self.locals.borrow_mut().insert(hir_id, err);
2153 self.locals.borrow_mut().insert(pat.hir_id, err);
2154 }
2155 }
2156
2157 fn finish_resolving_struct_path(
2160 &self,
2161 qpath: &QPath<'tcx>,
2162 path_span: Span,
2163 hir_id: HirId,
2164 ) -> (Res, LoweredTy<'tcx>) {
2165 match *qpath {
2166 QPath::Resolved(ref maybe_qself, path) => {
2167 let self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself).raw);
2168 let ty = self.lowerer().lower_path(self_ty, path, hir_id, true);
2169 (path.res, LoweredTy::from_raw(self, path_span, ty))
2170 }
2171 QPath::TypeRelative(qself, segment) => {
2172 let ty = self.lower_ty(qself);
2173
2174 let result = self
2175 .lowerer()
2176 .lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true);
2177 let ty = result
2178 .map(|(ty, _, _)| ty)
2179 .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
2180 let ty = LoweredTy::from_raw(self, path_span, ty);
2181 let result = result.map(|(_, kind, def_id)| (kind, def_id));
2182
2183 self.write_resolution(hir_id, result);
2185
2186 (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
2187 }
2188 QPath::LangItem(lang_item, span) => {
2189 let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id);
2190 (res, LoweredTy::from_raw(self, path_span, ty))
2191 }
2192 }
2193 }
2194
2195 pub(super) fn adjust_fulfillment_errors_for_expr_obligation(
2202 &self,
2203 errors: &mut Vec<traits::FulfillmentError<'tcx>>,
2204 ) {
2205 let mut remap_cause = FxIndexSet::default();
2211 let mut not_adjusted = vec![];
2212
2213 for error in errors {
2214 let before_span = error.obligation.cause.span;
2215 if self.adjust_fulfillment_error_for_expr_obligation(error)
2216 || before_span != error.obligation.cause.span
2217 {
2218 remap_cause.insert((
2219 before_span,
2220 error.obligation.predicate,
2221 error.obligation.cause.clone(),
2222 ));
2223 } else {
2224 not_adjusted.push(error);
2227 }
2228 }
2229
2230 for error in not_adjusted {
2238 for (span, predicate, cause) in &remap_cause {
2239 if *predicate == error.obligation.predicate
2240 && span.contains(error.obligation.cause.span)
2241 {
2242 error.obligation.cause = cause.clone();
2243 continue;
2244 }
2245 }
2246 }
2247 }
2248
2249 fn label_fn_like(
2250 &self,
2251 err: &mut Diag<'_>,
2252 callable_def_id: Option<DefId>,
2253 callee_ty: Option<Ty<'tcx>>,
2254 call_expr: &'tcx hir::Expr<'tcx>,
2255 expected_ty: Option<Ty<'tcx>>,
2256 expected_idx: Option<usize>,
2258 matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
2259 formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
2260 is_method: bool,
2261 tuple_arguments: TupleArgumentsFlag,
2262 ) {
2263 let Some(mut def_id) = callable_def_id else {
2264 return;
2265 };
2266
2267 if tuple_arguments == TupleArguments
2272 && let Some(assoc_item) = self.tcx.opt_associated_item(def_id)
2273 && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id)
2278 && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id)
2279 && let Some(call_kind) = self.tcx.fn_trait_kind_from_def_id(maybe_trait_def_id)
2281 && let Some(callee_ty) = callee_ty
2282 {
2283 let callee_ty = callee_ty.peel_refs();
2284 match *callee_ty.kind() {
2285 ty::Param(param) => {
2286 let param = self.tcx.generics_of(self.body_id).type_param(param, self.tcx);
2287 if param.kind.is_synthetic() {
2288 def_id = param.def_id;
2290 } else {
2291 let instantiated = self
2294 .tcx
2295 .explicit_predicates_of(self.body_id)
2296 .instantiate_identity(self.tcx);
2297 for (predicate, span) in instantiated {
2301 if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
2302 && pred.self_ty().peel_refs() == callee_ty
2303 && self.tcx.is_fn_trait(pred.def_id())
2304 {
2305 err.span_note(span, "callable defined here");
2306 return;
2307 }
2308 }
2309 }
2310 }
2311 ty::Alias(ty::Opaque, ty::AliasTy { def_id: new_def_id, .. })
2312 | ty::Closure(new_def_id, _)
2313 | ty::FnDef(new_def_id, _) => {
2314 def_id = new_def_id;
2315 }
2316 _ => {
2317 let new_def_id = self.probe(|_| {
2319 let trait_ref = ty::TraitRef::new(
2320 self.tcx,
2321 self.tcx.fn_trait_kind_to_def_id(call_kind)?,
2322 [callee_ty, self.next_ty_var(DUMMY_SP)],
2323 );
2324 let obligation = traits::Obligation::new(
2325 self.tcx,
2326 traits::ObligationCause::dummy(),
2327 self.param_env,
2328 trait_ref,
2329 );
2330 match SelectionContext::new(self).select(&obligation) {
2331 Ok(Some(traits::ImplSource::UserDefined(impl_source))) => {
2332 Some(impl_source.impl_def_id)
2333 }
2334 _ => None,
2335 }
2336 });
2337 if let Some(new_def_id) = new_def_id {
2338 def_id = new_def_id;
2339 } else {
2340 return;
2341 }
2342 }
2343 }
2344 }
2345
2346 if let Some(def_span) = self.tcx.def_ident_span(def_id)
2347 && !def_span.is_dummy()
2348 {
2349 let mut spans: MultiSpan = def_span.into();
2350 if let Some((params_with_generics, hir_generics)) =
2351 self.get_hir_param_info(def_id, is_method)
2352 {
2353 struct MismatchedParam<'a> {
2354 idx: ExpectedIdx,
2355 generic: GenericIdx,
2356 param: &'a FnParam<'a>,
2357 deps: SmallVec<[ExpectedIdx; 4]>,
2358 }
2359
2360 debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
2361 let mut mismatched_params = Vec::<MismatchedParam<'_>>::new();
2363 if let Some(expected_idx) = expected_idx {
2364 let expected_idx = ExpectedIdx::from_usize(expected_idx);
2365 let &(expected_generic, ref expected_param) =
2366 ¶ms_with_generics[expected_idx];
2367 if let Some(expected_generic) = expected_generic {
2368 mismatched_params.push(MismatchedParam {
2369 idx: expected_idx,
2370 generic: expected_generic,
2371 param: expected_param,
2372 deps: SmallVec::new(),
2373 });
2374 } else {
2375 spans.push_span_label(expected_param.span(), "");
2377 }
2378 } else {
2379 mismatched_params.extend(
2380 params_with_generics.iter_enumerated().zip(matched_inputs).filter_map(
2381 |((idx, &(generic, ref param)), matched_idx)| {
2382 if matched_idx.is_some() {
2383 None
2384 } else if let Some(generic) = generic {
2385 Some(MismatchedParam {
2386 idx,
2387 generic,
2388 param,
2389 deps: SmallVec::new(),
2390 })
2391 } else {
2392 spans.push_span_label(param.span(), "");
2394 None
2395 }
2396 },
2397 ),
2398 );
2399 }
2400
2401 if !mismatched_params.is_empty() {
2402 let mut dependants = IndexVec::<ExpectedIdx, _>::from_fn_n(
2405 |_| SmallVec::<[u32; 4]>::new(),
2406 params_with_generics.len(),
2407 );
2408 let mut generic_uses = IndexVec::<GenericIdx, _>::from_fn_n(
2409 |_| SmallVec::<[ExpectedIdx; 4]>::new(),
2410 hir_generics.params.len(),
2411 );
2412 for (idx, param) in mismatched_params.iter_mut().enumerate() {
2413 for ((other_idx, &(other_generic, _)), &other_matched_idx) in
2414 params_with_generics.iter_enumerated().zip(matched_inputs)
2415 {
2416 if other_generic == Some(param.generic) && other_matched_idx.is_some() {
2417 generic_uses[param.generic].extend([param.idx, other_idx]);
2418 dependants[other_idx].push(idx as u32);
2419 param.deps.push(other_idx);
2420 }
2421 }
2422 }
2423
2424 for param in &mismatched_params {
2427 if let Some(deps_list) = listify(¶m.deps, |&dep| {
2428 params_with_generics[dep].1.display(dep.as_usize()).to_string()
2429 }) {
2430 spans.push_span_label(
2431 param.param.span(),
2432 format!(
2433 "this parameter needs to match the {} type of {deps_list}",
2434 self.resolve_vars_if_possible(
2435 formal_and_expected_inputs[param.deps[0]].1
2436 )
2437 .sort_string(self.tcx),
2438 ),
2439 );
2440 } else {
2441 spans.push_span_label(param.param.span(), "");
2443 }
2444 }
2445 for ((&(_, param), deps), &(_, expected_ty)) in
2447 params_with_generics.iter().zip(&dependants).zip(formal_and_expected_inputs)
2448 {
2449 if let Some(deps_list) = listify(deps, |&dep| {
2450 let param = &mismatched_params[dep as usize];
2451 param.param.display(param.idx.as_usize()).to_string()
2452 }) {
2453 spans.push_span_label(
2454 param.span(),
2455 format!(
2456 "{deps_list} need{} to match the {} type of this parameter",
2457 pluralize!((deps.len() != 1) as u32),
2458 self.resolve_vars_if_possible(expected_ty)
2459 .sort_string(self.tcx),
2460 ),
2461 );
2462 }
2463 }
2464 for (param, uses) in hir_generics.params.iter().zip(&mut generic_uses) {
2466 uses.sort();
2467 uses.dedup();
2468 if let Some(param_list) = listify(uses, |&idx| {
2469 params_with_generics[idx].1.display(idx.as_usize()).to_string()
2470 }) {
2471 spans.push_span_label(
2472 param.span,
2473 format!(
2474 "{param_list} {} reference this parameter `{}`",
2475 if uses.len() == 2 { "both" } else { "all" },
2476 param.name.ident().name,
2477 ),
2478 );
2479 }
2480 }
2481 }
2482 }
2483 err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
2484 } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id)
2485 && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
2486 {
2487 let param = expected_idx
2488 .and_then(|expected_idx| self.tcx.hir_body(*body).params.get(expected_idx));
2489 let (kind, span) = if let Some(param) = param {
2490 let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] };
2493 let parent_def_id = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id;
2494 match self.tcx.hir_node_by_def_id(parent_def_id) {
2495 hir::Node::Item(item) => call_finder.visit_item(item),
2496 hir::Node::TraitItem(item) => call_finder.visit_trait_item(item),
2497 hir::Node::ImplItem(item) => call_finder.visit_impl_item(item),
2498 _ => {}
2499 }
2500 let typeck = self.typeck_results.borrow();
2501 for (rcvr, args) in call_finder.calls {
2502 if rcvr.hir_id.owner == typeck.hir_owner
2503 && let Some(rcvr_ty) = typeck.node_type_opt(rcvr.hir_id)
2504 && let ty::Closure(call_def_id, _) = rcvr_ty.kind()
2505 && def_id == *call_def_id
2506 && let Some(idx) = expected_idx
2507 && let Some(arg) = args.get(idx)
2508 && let Some(arg_ty) = typeck.node_type_opt(arg.hir_id)
2509 && let Some(expected_ty) = expected_ty
2510 && self.can_eq(self.param_env, arg_ty, expected_ty)
2511 {
2512 let mut sp: MultiSpan = vec![arg.span].into();
2513 sp.push_span_label(
2514 arg.span,
2515 format!("expected because this argument is of type `{arg_ty}`"),
2516 );
2517 sp.push_span_label(rcvr.span, "in this closure call");
2518 err.span_note(
2519 sp,
2520 format!(
2521 "expected because the closure was earlier called with an \
2522 argument of type `{arg_ty}`",
2523 ),
2524 );
2525 break;
2526 }
2527 }
2528
2529 ("closure parameter", param.span)
2530 } else {
2531 ("closure", self.tcx.def_span(def_id))
2532 };
2533 err.span_note(span, format!("{kind} defined here"));
2534 } else {
2535 err.span_note(
2536 self.tcx.def_span(def_id),
2537 format!("{} defined here", self.tcx.def_descr(def_id)),
2538 );
2539 }
2540 }
2541
2542 fn label_generic_mismatches(
2543 &self,
2544 err: &mut Diag<'_>,
2545 callable_def_id: Option<DefId>,
2546 matched_inputs: &IndexVec<ExpectedIdx, Option<ProvidedIdx>>,
2547 provided_arg_tys: &IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>,
2548 formal_and_expected_inputs: &IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>,
2549 is_method: bool,
2550 ) {
2551 let Some(def_id) = callable_def_id else {
2552 return;
2553 };
2554
2555 if let Some((params_with_generics, _)) = self.get_hir_param_info(def_id, is_method) {
2556 debug_assert_eq!(params_with_generics.len(), matched_inputs.len());
2557 for (idx, (generic_param, _)) in params_with_generics.iter_enumerated() {
2558 if matched_inputs[idx].is_none() {
2559 continue;
2560 }
2561
2562 let Some((_, matched_arg_span)) = provided_arg_tys.get(idx.to_provided_idx())
2563 else {
2564 continue;
2565 };
2566
2567 let Some(generic_param) = generic_param else {
2568 continue;
2569 };
2570
2571 let idxs_matched = params_with_generics
2572 .iter_enumerated()
2573 .filter(|&(other_idx, (other_generic_param, _))| {
2574 if other_idx == idx {
2575 return false;
2576 }
2577 let Some(other_generic_param) = other_generic_param else {
2578 return false;
2579 };
2580 if matched_inputs[other_idx].is_some() {
2581 return false;
2582 }
2583 other_generic_param == generic_param
2584 })
2585 .count();
2586
2587 if idxs_matched == 0 {
2588 continue;
2589 }
2590
2591 let expected_display_type = self
2592 .resolve_vars_if_possible(formal_and_expected_inputs[idx].1)
2593 .sort_string(self.tcx);
2594 let label = if idxs_matched == params_with_generics.len() - 1 {
2595 format!(
2596 "expected all arguments to be this {} type because they need to match the type of this parameter",
2597 expected_display_type
2598 )
2599 } else {
2600 format!(
2601 "expected some other arguments to be {} {} type to match the type of this parameter",
2602 a_or_an(&expected_display_type),
2603 expected_display_type,
2604 )
2605 };
2606
2607 err.span_label(*matched_arg_span, label);
2608 }
2609 }
2610 }
2611
2612 fn get_hir_param_info(
2617 &self,
2618 def_id: DefId,
2619 is_method: bool,
2620 ) -> Option<(IndexVec<ExpectedIdx, (Option<GenericIdx>, FnParam<'_>)>, &hir::Generics<'_>)>
2621 {
2622 let (sig, generics, body_id, params) = match self.tcx.hir_get_if_local(def_id)? {
2623 hir::Node::TraitItem(&hir::TraitItem {
2624 generics,
2625 kind: hir::TraitItemKind::Fn(sig, trait_fn),
2626 ..
2627 }) => match trait_fn {
2628 hir::TraitFn::Required(params) => (sig, generics, None, Some(params)),
2629 hir::TraitFn::Provided(body) => (sig, generics, Some(body), None),
2630 },
2631 hir::Node::ImplItem(&hir::ImplItem {
2632 generics,
2633 kind: hir::ImplItemKind::Fn(sig, body),
2634 ..
2635 })
2636 | hir::Node::Item(&hir::Item {
2637 kind: hir::ItemKind::Fn { sig, generics, body, .. },
2638 ..
2639 }) => (sig, generics, Some(body), None),
2640 hir::Node::ForeignItem(&hir::ForeignItem {
2641 kind: hir::ForeignItemKind::Fn(sig, params, generics),
2642 ..
2643 }) => (sig, generics, None, Some(params)),
2644 _ => return None,
2645 };
2646
2647 let fn_inputs = sig.decl.inputs.get(is_method as usize..)?.iter().map(|param| {
2650 if let hir::TyKind::Path(QPath::Resolved(
2651 _,
2652 &hir::Path { res: Res::Def(_, res_def_id), .. },
2653 )) = param.kind
2654 {
2655 generics
2656 .params
2657 .iter()
2658 .position(|param| param.def_id.to_def_id() == res_def_id)
2659 .map(GenericIdx::from_usize)
2660 } else {
2661 None
2662 }
2663 });
2664 match (body_id, params) {
2665 (Some(_), Some(_)) | (None, None) => unreachable!(),
2666 (Some(body), None) => {
2667 let params = self.tcx.hir_body(body).params;
2668 let params =
2669 params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
2670 debug_assert_eq!(params.len(), fn_inputs.len());
2671 Some((
2672 fn_inputs.zip(params.iter().map(|param| FnParam::Param(param))).collect(),
2673 generics,
2674 ))
2675 }
2676 (None, Some(params)) => {
2677 let params =
2678 params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?;
2679 debug_assert_eq!(params.len(), fn_inputs.len());
2680 Some((
2681 fn_inputs.zip(params.iter().map(|&ident| FnParam::Ident(ident))).collect(),
2682 generics,
2683 ))
2684 }
2685 }
2686 }
2687}
2688
2689struct FindClosureArg<'tcx> {
2690 tcx: TyCtxt<'tcx>,
2691 calls: Vec<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
2692}
2693
2694impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
2695 type NestedFilter = rustc_middle::hir::nested_filter::All;
2696
2697 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
2698 self.tcx
2699 }
2700
2701 fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
2702 if let hir::ExprKind::Call(rcvr, args) = ex.kind {
2703 self.calls.push((rcvr, args));
2704 }
2705 hir::intravisit::walk_expr(self, ex);
2706 }
2707}
2708
2709#[derive(Clone, Copy)]
2710enum FnParam<'hir> {
2711 Param(&'hir hir::Param<'hir>),
2712 Ident(Option<Ident>),
2713}
2714
2715impl FnParam<'_> {
2716 fn span(&self) -> Span {
2717 match self {
2718 Self::Param(param) => param.span,
2719 Self::Ident(ident) => {
2720 if let Some(ident) = ident {
2721 ident.span
2722 } else {
2723 DUMMY_SP
2724 }
2725 }
2726 }
2727 }
2728
2729 fn display(&self, idx: usize) -> impl '_ + fmt::Display {
2730 struct D<'a>(FnParam<'a>, usize);
2731 impl fmt::Display for D<'_> {
2732 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2733 let unique_name = match self.0 {
2736 FnParam::Param(param)
2737 if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind =>
2738 {
2739 Some(ident.name)
2740 }
2741 FnParam::Ident(ident)
2742 if let Some(ident) = ident
2743 && ident.name != kw::Underscore =>
2744 {
2745 Some(ident.name)
2746 }
2747 _ => None,
2748 };
2749 if let Some(unique_name) = unique_name {
2750 write!(f, "`{unique_name}`")
2751 } else {
2752 write!(f, "parameter #{}", self.1 + 1)
2753 }
2754 }
2755 }
2756 D(*self, idx)
2757 }
2758}