1use std::borrow::Cow;
49use std::ops::ControlFlow;
50use std::path::PathBuf;
51use std::{cmp, fmt, iter};
52
53use rustc_abi::ExternAbi;
54use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
55use rustc_errors::{
56 Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize,
57};
58use rustc_hir::def::DefKind;
59use rustc_hir::def_id::DefId;
60use rustc_hir::intravisit::Visitor;
61use rustc_hir::lang_items::LangItem;
62use rustc_hir::{self as hir};
63use rustc_macros::extension;
64use rustc_middle::bug;
65use rustc_middle::dep_graph::DepContext;
66use rustc_middle::traits::PatternOriginExpr;
67use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt};
68use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, with_forced_trimmed_paths};
69use rustc_middle::ty::{
70 self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
71 TypeVisitableExt,
72};
73use rustc_span::def_id::LOCAL_CRATE;
74use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym};
75use tracing::{debug, instrument};
76
77use crate::error_reporting::TypeErrCtxt;
78use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags};
79use crate::infer;
80use crate::infer::relate::{self, RelateResult, TypeRelation};
81use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs};
82use crate::solve::deeply_normalize_for_diagnostics;
83use crate::traits::{
84 IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
85};
86
87mod note_and_explain;
88mod suggest;
89
90pub mod need_type_info;
91pub mod nice_region_error;
92pub mod region;
93pub mod sub_relations;
94
95fn escape_literal(s: &str) -> String {
98 let mut escaped = String::with_capacity(s.len());
99 let mut chrs = s.chars().peekable();
100 while let Some(first) = chrs.next() {
101 match (first, chrs.peek()) {
102 ('\\', Some(&delim @ '"') | Some(&delim @ '\'')) => {
103 escaped.push('\\');
104 escaped.push(delim);
105 chrs.next();
106 }
107 ('"' | '\'', _) => {
108 escaped.push('\\');
109 escaped.push(first)
110 }
111 (c, _) => escaped.push(c),
112 };
113 }
114 escaped
115}
116
117impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
118 pub fn type_error_struct_with_diag<M>(
129 &self,
130 sp: Span,
131 mk_diag: M,
132 actual_ty: Ty<'tcx>,
133 ) -> Diag<'a>
134 where
135 M: FnOnce(String) -> Diag<'a>,
136 {
137 let actual_ty = self.resolve_vars_if_possible(actual_ty);
138 debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty);
139
140 let mut err = mk_diag(self.ty_to_string(actual_ty));
141
142 if actual_ty.references_error() {
144 err.downgrade_to_delayed_bug();
145 }
146
147 err
148 }
149
150 pub fn report_mismatched_types(
151 &self,
152 cause: &ObligationCause<'tcx>,
153 param_env: ty::ParamEnv<'tcx>,
154 expected: Ty<'tcx>,
155 actual: Ty<'tcx>,
156 err: TypeError<'tcx>,
157 ) -> Diag<'a> {
158 self.report_and_explain_type_error(
159 TypeTrace::types(cause, expected, actual),
160 param_env,
161 err,
162 )
163 }
164
165 pub fn report_mismatched_consts(
166 &self,
167 cause: &ObligationCause<'tcx>,
168 param_env: ty::ParamEnv<'tcx>,
169 expected: ty::Const<'tcx>,
170 actual: ty::Const<'tcx>,
171 err: TypeError<'tcx>,
172 ) -> Diag<'a> {
173 self.report_and_explain_type_error(
174 TypeTrace::consts(cause, expected, actual),
175 param_env,
176 err,
177 )
178 }
179
180 pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
181 let (def_id, args) = match *ty.kind() {
182 ty::Alias(_, ty::AliasTy { def_id, args, .. })
183 if matches!(self.tcx.def_kind(def_id), DefKind::OpaqueTy) =>
184 {
185 (def_id, args)
186 }
187 ty::Alias(_, ty::AliasTy { def_id, args, .. })
188 if self.tcx.is_impl_trait_in_trait(def_id) =>
189 {
190 (def_id, args)
191 }
192 _ => return None,
193 };
194
195 let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
196 let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
197
198 self.tcx
199 .explicit_item_self_bounds(def_id)
200 .iter_instantiated_copied(self.tcx, args)
201 .find_map(|(predicate, _)| {
202 predicate
203 .kind()
204 .map_bound(|kind| match kind {
205 ty::ClauseKind::Projection(projection_predicate)
206 if projection_predicate.projection_term.def_id == item_def_id =>
207 {
208 projection_predicate.term.as_type()
209 }
210 _ => None,
211 })
212 .no_bound_vars()
213 .flatten()
214 })
215 }
216
217 fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) -> bool {
219 use hir::def_id::CrateNum;
222 use rustc_hir::definitions::DisambiguatedDefPathData;
223 use ty::GenericArg;
224 use ty::print::Printer;
225
226 struct AbsolutePathPrinter<'tcx> {
227 tcx: TyCtxt<'tcx>,
228 segments: Vec<String>,
229 }
230
231 impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
232 fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
233 self.tcx
234 }
235
236 fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
237 Err(fmt::Error)
238 }
239
240 fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
241 Err(fmt::Error)
242 }
243
244 fn print_dyn_existential(
245 &mut self,
246 _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
247 ) -> Result<(), PrintError> {
248 Err(fmt::Error)
249 }
250
251 fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
252 Err(fmt::Error)
253 }
254
255 fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
256 self.segments = vec![self.tcx.crate_name(cnum).to_string()];
257 Ok(())
258 }
259 fn path_qualified(
260 &mut self,
261 _self_ty: Ty<'tcx>,
262 _trait_ref: Option<ty::TraitRef<'tcx>>,
263 ) -> Result<(), PrintError> {
264 Err(fmt::Error)
265 }
266
267 fn path_append_impl(
268 &mut self,
269 _print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
270 _disambiguated_data: &DisambiguatedDefPathData,
271 _self_ty: Ty<'tcx>,
272 _trait_ref: Option<ty::TraitRef<'tcx>>,
273 ) -> Result<(), PrintError> {
274 Err(fmt::Error)
275 }
276 fn path_append(
277 &mut self,
278 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
279 disambiguated_data: &DisambiguatedDefPathData,
280 ) -> Result<(), PrintError> {
281 print_prefix(self)?;
282 self.segments.push(disambiguated_data.to_string());
283 Ok(())
284 }
285 fn path_generic_args(
286 &mut self,
287 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
288 _args: &[GenericArg<'tcx>],
289 ) -> Result<(), PrintError> {
290 print_prefix(self)
291 }
292 }
293
294 let report_path_match = |err: &mut Diag<'_>, did1: DefId, did2: DefId, ty: &str| -> bool {
295 if did1.krate != did2.krate {
299 let abs_path = |def_id| {
300 let mut printer = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] };
301 printer.print_def_path(def_id, &[]).map(|_| printer.segments)
302 };
303
304 let expected_str = self.tcx.def_path_str(did1);
307 let found_str = self.tcx.def_path_str(did2);
308 let Ok(expected_abs) = abs_path(did1) else { return false };
309 let Ok(found_abs) = abs_path(did2) else { return false };
310 let same_path = || -> Result<_, PrintError> {
311 Ok(expected_str == found_str || expected_abs == found_abs)
312 };
313 let (expected, found) = if expected_str == found_str {
317 (expected_abs.join("::"), found_abs.join("::"))
318 } else {
319 (expected_str.clone(), found_str.clone())
320 };
321 if same_path().unwrap_or(false) {
322 let expected_crate_name = self.tcx.crate_name(did1.krate);
325 let found_crate_name = self.tcx.crate_name(did2.krate);
326 let same_crate = expected_crate_name == found_crate_name;
327 let expected_sp = self.tcx.def_span(did1);
328 let found_sp = self.tcx.def_span(did2);
329
330 let both_direct_dependencies = if !did1.is_local()
331 && !did2.is_local()
332 && let Some(data1) = self.tcx.extern_crate(did1.krate)
333 && let Some(data2) = self.tcx.extern_crate(did2.krate)
334 && data1.dependency_of == LOCAL_CRATE
335 && data2.dependency_of == LOCAL_CRATE
336 {
337 true
343 } else {
344 false
345 };
346
347 let mut span: MultiSpan = vec![expected_sp, found_sp].into();
348 span.push_span_label(
349 self.tcx.def_span(did1),
350 format!("this is the expected {ty} `{expected}`"),
351 );
352 span.push_span_label(
353 self.tcx.def_span(did2),
354 format!("this is the found {ty} `{found}`"),
355 );
356 for def_id in [did1, did2] {
357 let crate_name = self.tcx.crate_name(def_id.krate);
358 if !def_id.is_local()
359 && let Some(data) = self.tcx.extern_crate(def_id.krate)
360 {
361 let descr = if same_crate {
362 "one version of".to_string()
363 } else {
364 format!("one {ty} comes from")
365 };
366 let dependency = if both_direct_dependencies {
367 if let rustc_session::cstore::ExternCrateSource::Extern(def_id) =
368 data.src
369 && let Some(name) = self.tcx.opt_item_name(def_id)
370 {
371 format!(", which is renamed locally to `{name}`")
372 } else {
373 String::new()
374 }
375 } else if data.dependency_of == LOCAL_CRATE {
376 ", as a direct dependency of the current crate".to_string()
377 } else {
378 let dep = self.tcx.crate_name(data.dependency_of);
379 format!(", as a dependency of crate `{dep}`")
380 };
381 span.push_span_label(
382 data.span,
383 format!("{descr} crate `{crate_name}` used here{dependency}"),
384 );
385 }
386 }
387 let msg = if (did1.is_local() || did2.is_local()) && same_crate {
388 format!(
389 "the crate `{expected_crate_name}` is compiled multiple times, \
390 possibly with different configurations",
391 )
392 } else if same_crate {
393 format!(
394 "two different versions of crate `{expected_crate_name}` are being \
395 used; two types coming from two different versions of the same crate \
396 are different types even if they look the same",
397 )
398 } else {
399 format!(
400 "two types coming from two different crates are different types even \
401 if they look the same",
402 )
403 };
404 err.span_note(span, msg);
405 if same_crate {
406 err.help("you can use `cargo tree` to explore your dependency tree");
407 }
408 return true;
409 }
410 }
411 false
412 };
413 match terr {
414 TypeError::Sorts(ref exp_found) => {
415 if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) =
418 (exp_found.expected.kind(), exp_found.found.kind())
419 {
420 return report_path_match(err, exp_adt.did(), found_adt.did(), "type");
421 }
422 }
423 TypeError::Traits(ref exp_found) => {
424 return report_path_match(err, exp_found.expected, exp_found.found, "trait");
425 }
426 _ => (), }
428 false
429 }
430
431 fn note_error_origin(
432 &self,
433 err: &mut Diag<'_>,
434 cause: &ObligationCause<'tcx>,
435 exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
436 terr: TypeError<'tcx>,
437 param_env: Option<ParamEnv<'tcx>>,
438 ) {
439 match *cause.code() {
440 ObligationCauseCode::Pattern {
441 origin_expr: Some(origin_expr),
442 span: Some(span),
443 root_ty,
444 } => {
445 let expected_ty = self.resolve_vars_if_possible(root_ty);
446 if !matches!(
447 expected_ty.kind(),
448 ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_))
449 ) {
450 if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
452 && let ty::Adt(def, args) = expected_ty.kind()
453 && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
454 {
455 err.span_label(
456 span,
457 format!("this is an iterator with items of type `{}`", args.type_at(0)),
458 );
459 } else {
460 let expected_ty = self.tcx.short_string(expected_ty, err.long_ty_path());
461 err.span_label(span, format!("this expression has type `{expected_ty}`"));
462 }
463 }
464 if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
465 && let Ok(mut peeled_snippet) =
466 self.tcx.sess.source_map().span_to_snippet(origin_expr.peeled_span)
467 {
468 if origin_expr.peeled_prefix_suggestion_parentheses {
473 peeled_snippet = format!("({peeled_snippet})");
474 }
475
476 if expected_ty.boxed_ty() == Some(found) {
479 err.span_suggestion_verbose(
480 span,
481 "consider dereferencing the boxed value",
482 format!("*{peeled_snippet}"),
483 Applicability::MachineApplicable,
484 );
485 } else if let Some(param_env) = param_env
486 && let Some(prefix) = self.should_deref_suggestion_on_mismatch(
487 param_env,
488 found,
489 expected_ty,
490 origin_expr,
491 )
492 {
493 err.span_suggestion_verbose(
494 span,
495 "consider dereferencing to access the inner value using the Deref trait",
496 format!("{prefix}{peeled_snippet}"),
497 Applicability::MaybeIncorrect,
498 );
499 }
500 }
501 }
502 ObligationCauseCode::Pattern { origin_expr: None, span: Some(span), .. } => {
503 err.span_label(span, "expected due to this");
504 }
505 ObligationCauseCode::BlockTailExpression(
506 _,
507 hir::MatchSource::TryDesugar(scrut_hir_id),
508 ) => {
509 if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
510 let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
511 let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
512 let arg_expr = args.first().expect("try desugaring call w/out arg");
513 self.typeck_results
514 .as_ref()
515 .and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
516 } else {
517 bug!("try desugaring w/out call expr as scrutinee");
518 };
519
520 match scrut_ty {
521 Some(ty) if expected == ty => {
522 let source_map = self.tcx.sess.source_map();
523 err.span_suggestion(
524 source_map.end_point(cause.span),
525 "try removing this `?`",
526 "",
527 Applicability::MachineApplicable,
528 );
529 }
530 _ => {}
531 }
532 }
533 }
534 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
535 arm_block_id,
536 arm_span,
537 arm_ty,
538 prior_arm_block_id,
539 prior_arm_span,
540 prior_arm_ty,
541 source,
542 ref prior_non_diverging_arms,
543 scrut_span,
544 expr_span,
545 ..
546 }) => match source {
547 hir::MatchSource::TryDesugar(scrut_hir_id) => {
548 if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
549 let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
550 let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
551 let arg_expr = args.first().expect("try desugaring call w/out arg");
552 self.typeck_results
553 .as_ref()
554 .and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr))
555 } else {
556 bug!("try desugaring w/out call expr as scrutinee");
557 };
558
559 match scrut_ty {
560 Some(ty) if expected == ty => {
561 let source_map = self.tcx.sess.source_map();
562 err.span_suggestion(
563 source_map.end_point(cause.span),
564 "try removing this `?`",
565 "",
566 Applicability::MachineApplicable,
567 );
568 }
569 _ => {}
570 }
571 }
572 }
573 _ => {
574 let t = self.resolve_vars_if_possible(match exp_found {
576 Some(ty::error::ExpectedFound { expected, .. }) => expected,
577 _ => prior_arm_ty,
578 });
579 let source_map = self.tcx.sess.source_map();
580 let mut any_multiline_arm = source_map.is_multiline(arm_span);
581 if prior_non_diverging_arms.len() <= 4 {
582 for sp in prior_non_diverging_arms {
583 any_multiline_arm |= source_map.is_multiline(*sp);
584 err.span_label(*sp, format!("this is found to be of type `{t}`"));
585 }
586 } else if let Some(sp) = prior_non_diverging_arms.last() {
587 any_multiline_arm |= source_map.is_multiline(*sp);
588 err.span_label(
589 *sp,
590 format!("this and all prior arms are found to be of type `{t}`"),
591 );
592 }
593 let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) {
594 expr_span.shrink_to_lo().to(scrut_span)
597 } else {
598 expr_span
599 };
600 let msg = "`match` arms have incompatible types";
601 err.span_label(outer, msg);
602 if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
603 prior_arm_block_id,
604 prior_arm_ty,
605 prior_arm_span,
606 arm_block_id,
607 arm_ty,
608 arm_span,
609 ) {
610 err.subdiagnostic(subdiag);
611 }
612 }
613 },
614 ObligationCauseCode::IfExpression(box IfExpressionCause {
615 then_id,
616 else_id,
617 then_ty,
618 else_ty,
619 outer_span,
620 ..
621 }) => {
622 let then_span = self.find_block_span_from_hir_id(then_id);
623 let else_span = self.find_block_span_from_hir_id(else_id);
624 if let hir::Node::Expr(e) = self.tcx.hir_node(else_id)
625 && let hir::ExprKind::If(_cond, _then, None) = e.kind
626 && else_ty.is_unit()
627 {
628 err.note("`if` expressions without `else` evaluate to `()`");
630 err.note("consider adding an `else` block that evaluates to the expected type");
631 }
632 err.span_label(then_span, "expected because of this");
633 if let Some(sp) = outer_span {
634 err.span_label(sp, "`if` and `else` have incompatible types");
635 }
636 if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
637 Some(then_id),
638 then_ty,
639 then_span,
640 Some(else_id),
641 else_ty,
642 else_span,
643 ) {
644 err.subdiagnostic(subdiag);
645 }
646 }
647 ObligationCauseCode::LetElse => {
648 err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
649 err.help("...or use `match` instead of `let...else`");
650 }
651 _ => {
652 if let ObligationCauseCode::WhereClause(_, span)
653 | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
654 cause.code().peel_derives()
655 && !span.is_dummy()
656 && let TypeError::RegionsPlaceholderMismatch = terr
657 {
658 err.span_note(*span, "the lifetime requirement is introduced here");
659 }
660 }
661 }
662 }
663
664 fn should_deref_suggestion_on_mismatch(
667 &self,
668 param_env: ParamEnv<'tcx>,
669 deref_to: Ty<'tcx>,
670 deref_from: Ty<'tcx>,
671 origin_expr: PatternOriginExpr,
672 ) -> Option<String> {
673 let Some((num_derefs, (after_deref_ty, _))) = (self.autoderef_steps)(deref_from)
681 .into_iter()
682 .enumerate()
683 .find(|(_, (ty, _))| self.infcx.can_eq(param_env, *ty, deref_to))
684 else {
685 return None;
686 };
687
688 if num_derefs <= origin_expr.peeled_count {
689 return None;
690 }
691
692 let deref_part = "*".repeat(num_derefs - origin_expr.peeled_count);
693
694 if deref_from.is_ref() && !after_deref_ty.is_ref() {
697 Some(format!("&{deref_part}"))
698 } else {
699 Some(deref_part)
700 }
701 }
702
703 fn highlight_outer(
717 &self,
718 value: &mut DiagStyledString,
719 other_value: &mut DiagStyledString,
720 name: String,
721 args: &[ty::GenericArg<'tcx>],
722 pos: usize,
723 other_ty: Ty<'tcx>,
724 ) {
725 value.push_highlighted(name);
728
729 if args.is_empty() {
730 return;
731 }
732 value.push_highlighted("<");
733
734 for (i, arg) in args.iter().enumerate() {
735 if i > 0 {
736 value.push_normal(", ");
737 }
738
739 match arg.unpack() {
740 ty::GenericArgKind::Lifetime(lt) => {
741 let s = lt.to_string();
742 value.push_normal(if s.is_empty() { "'_" } else { &s });
743 }
744 ty::GenericArgKind::Const(ct) => {
745 value.push_normal(ct.to_string());
746 }
747 ty::GenericArgKind::Type(type_arg) => {
750 if i == pos {
751 let values = self.cmp(type_arg, other_ty);
752 value.0.extend((values.0).0);
753 other_value.0.extend((values.1).0);
754 } else {
755 value.push_highlighted(type_arg.to_string());
756 }
757 }
758 }
759 }
760
761 value.push_highlighted(">");
762 }
763
764 fn cmp_type_arg(
785 &self,
786 t1_out: &mut DiagStyledString,
787 t2_out: &mut DiagStyledString,
788 path: String,
789 args: &'tcx [ty::GenericArg<'tcx>],
790 other_path: String,
791 other_ty: Ty<'tcx>,
792 ) -> bool {
793 for (i, arg) in args.iter().enumerate() {
794 if let Some(ta) = arg.as_type() {
795 if ta == other_ty {
796 self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
797 return true;
798 }
799 if let ty::Adt(def, _) = ta.kind() {
800 let path_ = self.tcx.def_path_str(def.did());
801 if path_ == other_path {
802 self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
803 return true;
804 }
805 }
806 }
807 }
808 false
809 }
810
811 fn push_comma(
813 &self,
814 value: &mut DiagStyledString,
815 other_value: &mut DiagStyledString,
816 pos: usize,
817 ) {
818 if pos > 0 {
819 value.push_normal(", ");
820 other_value.push_normal(", ");
821 }
822 }
823
824 fn cmp_fn_sig(
826 &self,
827 sig1: &ty::PolyFnSig<'tcx>,
828 fn_def1: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
829 sig2: &ty::PolyFnSig<'tcx>,
830 fn_def2: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
831 ) -> (DiagStyledString, DiagStyledString) {
832 let sig1 = &(self.normalize_fn_sig)(*sig1);
833 let sig2 = &(self.normalize_fn_sig)(*sig2);
834
835 let get_lifetimes = |sig| {
836 use rustc_hir::def::Namespace;
837 let (sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
838 .name_all_regions(sig)
839 .unwrap();
840 let lts: Vec<String> =
841 reg.into_items().map(|(_, kind)| kind.to_string()).into_sorted_stable_ord();
842 (if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig)
843 };
844
845 let (lt1, sig1) = get_lifetimes(sig1);
846 let (lt2, sig2) = get_lifetimes(sig2);
847
848 let mut values =
850 (DiagStyledString::normal("".to_string()), DiagStyledString::normal("".to_string()));
851
852 let safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
855 None => sig.safety.prefix_str(),
856 Some((did, _)) => {
857 if self.tcx.codegen_fn_attrs(did).safe_target_features {
858 "#[target_features] "
859 } else {
860 sig.safety.prefix_str()
861 }
862 }
863 };
864 let safety1 = safety(fn_def1, sig1);
865 let safety2 = safety(fn_def2, sig2);
866 values.0.push(safety1, safety1 != safety2);
867 values.1.push(safety2, safety1 != safety2);
868
869 if sig1.abi != ExternAbi::Rust {
872 values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi);
873 }
874 if sig2.abi != ExternAbi::Rust {
875 values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi);
876 }
877
878 let lifetime_diff = lt1 != lt2;
881 values.0.push(lt1, lifetime_diff);
882 values.1.push(lt2, lifetime_diff);
883
884 values.0.push_normal("fn(");
887 values.1.push_normal("fn(");
888
889 let len1 = sig1.inputs().len();
892 let len2 = sig2.inputs().len();
893 if len1 == len2 {
894 for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
895 self.push_comma(&mut values.0, &mut values.1, i);
896 let (x1, x2) = self.cmp(*l, *r);
897 (values.0).0.extend(x1.0);
898 (values.1).0.extend(x2.0);
899 }
900 } else {
901 for (i, l) in sig1.inputs().iter().enumerate() {
902 values.0.push_highlighted(l.to_string());
903 if i != len1 - 1 {
904 values.0.push_highlighted(", ");
905 }
906 }
907 for (i, r) in sig2.inputs().iter().enumerate() {
908 values.1.push_highlighted(r.to_string());
909 if i != len2 - 1 {
910 values.1.push_highlighted(", ");
911 }
912 }
913 }
914
915 if sig1.c_variadic {
916 if len1 > 0 {
917 values.0.push_normal(", ");
918 }
919 values.0.push("...", !sig2.c_variadic);
920 }
921 if sig2.c_variadic {
922 if len2 > 0 {
923 values.1.push_normal(", ");
924 }
925 values.1.push("...", !sig1.c_variadic);
926 }
927
928 values.0.push_normal(")");
931 values.1.push_normal(")");
932
933 let output1 = sig1.output();
936 let output2 = sig2.output();
937 let (x1, x2) = self.cmp(output1, output2);
938 let output_diff = x1 != x2;
939 if !output1.is_unit() || output_diff {
940 values.0.push_normal(" -> ");
941 (values.0).0.extend(x1.0);
942 }
943 if !output2.is_unit() || output_diff {
944 values.1.push_normal(" -> ");
945 (values.1).0.extend(x2.0);
946 }
947
948 let fmt = |did, args| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
949
950 match (fn_def1, fn_def2) {
951 (Some((fn_def1, Some(fn_args1))), Some((fn_def2, Some(fn_args2)))) => {
952 let path1 = fmt(fn_def1, fn_args1);
953 let path2 = fmt(fn_def2, fn_args2);
954 let same_path = path1 == path2;
955 values.0.push(path1, !same_path);
956 values.1.push(path2, !same_path);
957 }
958 (Some((fn_def1, Some(fn_args1))), None) => {
959 values.0.push_highlighted(fmt(fn_def1, fn_args1));
960 }
961 (None, Some((fn_def2, Some(fn_args2)))) => {
962 values.1.push_highlighted(fmt(fn_def2, fn_args2));
963 }
964 _ => {}
965 }
966
967 values
968 }
969
970 pub fn cmp_traits(
971 &self,
972 def_id1: DefId,
973 args1: &[ty::GenericArg<'tcx>],
974 def_id2: DefId,
975 args2: &[ty::GenericArg<'tcx>],
976 ) -> (DiagStyledString, DiagStyledString) {
977 let mut values = (DiagStyledString::new(), DiagStyledString::new());
978
979 if def_id1 != def_id2 {
980 values.0.push_highlighted(self.tcx.def_path_str(def_id1).as_str());
981 values.1.push_highlighted(self.tcx.def_path_str(def_id2).as_str());
982 } else {
983 values.0.push_normal(self.tcx.item_name(def_id1).as_str());
984 values.1.push_normal(self.tcx.item_name(def_id2).as_str());
985 }
986
987 if args1.len() != args2.len() {
988 let (pre, post) = if args1.len() > 0 { ("<", ">") } else { ("", "") };
989 values.0.push_normal(format!(
990 "{pre}{}{post}",
991 args1.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ")
992 ));
993 let (pre, post) = if args2.len() > 0 { ("<", ">") } else { ("", "") };
994 values.1.push_normal(format!(
995 "{pre}{}{post}",
996 args2.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ")
997 ));
998 return values;
999 }
1000
1001 if args1.len() > 0 {
1002 values.0.push_normal("<");
1003 values.1.push_normal("<");
1004 }
1005 for (i, (a, b)) in std::iter::zip(args1, args2).enumerate() {
1006 let a_str = a.to_string();
1007 let b_str = b.to_string();
1008 if let (Some(a), Some(b)) = (a.as_type(), b.as_type()) {
1009 let (a, b) = self.cmp(a, b);
1010 values.0.0.extend(a.0);
1011 values.1.0.extend(b.0);
1012 } else if a_str != b_str {
1013 values.0.push_highlighted(a_str);
1014 values.1.push_highlighted(b_str);
1015 } else {
1016 values.0.push_normal(a_str);
1017 values.1.push_normal(b_str);
1018 }
1019 if i + 1 < args1.len() {
1020 values.0.push_normal(", ");
1021 values.1.push_normal(", ");
1022 }
1023 }
1024 if args1.len() > 0 {
1025 values.0.push_normal(">");
1026 values.1.push_normal(">");
1027 }
1028 values
1029 }
1030
1031 pub fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagStyledString, DiagStyledString) {
1034 debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind());
1035
1036 let recurse = |t1, t2, values: &mut (DiagStyledString, DiagStyledString)| {
1038 let (x1, x2) = self.cmp(t1, t2);
1039 (values.0).0.extend(x1.0);
1040 (values.1).0.extend(x2.0);
1041 };
1042
1043 fn fmt_region<'tcx>(region: ty::Region<'tcx>) -> String {
1044 let mut r = region.to_string();
1045 if r == "'_" {
1046 r.clear();
1047 } else {
1048 r.push(' ');
1049 }
1050 format!("&{r}")
1051 }
1052
1053 fn push_ref<'tcx>(
1054 region: ty::Region<'tcx>,
1055 mutbl: hir::Mutability,
1056 s: &mut DiagStyledString,
1057 ) {
1058 s.push_highlighted(fmt_region(region));
1059 s.push_highlighted(mutbl.prefix_str());
1060 }
1061
1062 fn maybe_highlight<T: Eq + ToString>(
1063 t1: T,
1064 t2: T,
1065 (buf1, buf2): &mut (DiagStyledString, DiagStyledString),
1066 tcx: TyCtxt<'_>,
1067 ) {
1068 let highlight = t1 != t2;
1069 let (t1, t2) = if highlight || tcx.sess.opts.verbose {
1070 (t1.to_string(), t2.to_string())
1071 } else {
1072 ("_".into(), "_".into())
1074 };
1075 buf1.push(t1, highlight);
1076 buf2.push(t2, highlight);
1077 }
1078
1079 fn cmp_ty_refs<'tcx>(
1080 r1: ty::Region<'tcx>,
1081 mut1: hir::Mutability,
1082 r2: ty::Region<'tcx>,
1083 mut2: hir::Mutability,
1084 ss: &mut (DiagStyledString, DiagStyledString),
1085 ) {
1086 let (r1, r2) = (fmt_region(r1), fmt_region(r2));
1087 if r1 != r2 {
1088 ss.0.push_highlighted(r1);
1089 ss.1.push_highlighted(r2);
1090 } else {
1091 ss.0.push_normal(r1);
1092 ss.1.push_normal(r2);
1093 }
1094
1095 if mut1 != mut2 {
1096 ss.0.push_highlighted(mut1.prefix_str());
1097 ss.1.push_highlighted(mut2.prefix_str());
1098 } else {
1099 ss.0.push_normal(mut1.prefix_str());
1100 ss.1.push_normal(mut2.prefix_str());
1101 }
1102 }
1103
1104 match (t1.kind(), t2.kind()) {
1106 (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => {
1107 let did1 = def1.did();
1108 let did2 = def2.did();
1109
1110 let generics1 = self.tcx.generics_of(did1);
1111 let generics2 = self.tcx.generics_of(did2);
1112
1113 let non_default_after_default = generics1
1114 .check_concrete_type_after_default(self.tcx, sub1)
1115 || generics2.check_concrete_type_after_default(self.tcx, sub2);
1116 let sub_no_defaults_1 = if non_default_after_default {
1117 generics1.own_args(sub1)
1118 } else {
1119 generics1.own_args_no_defaults(self.tcx, sub1)
1120 };
1121 let sub_no_defaults_2 = if non_default_after_default {
1122 generics2.own_args(sub2)
1123 } else {
1124 generics2.own_args_no_defaults(self.tcx, sub2)
1125 };
1126 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1127 let path1 = self.tcx.def_path_str(did1);
1128 let path2 = self.tcx.def_path_str(did2);
1129 if did1 == did2 {
1130 values.0.push_normal(path1);
1139 values.1.push_normal(path2);
1140
1141 let len1 = sub_no_defaults_1.len();
1144 let len2 = sub_no_defaults_2.len();
1145 let common_len = cmp::min(len1, len2);
1146 let remainder1 = &sub1[common_len..];
1147 let remainder2 = &sub2[common_len..];
1148 let common_default_params =
1149 iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
1150 .filter(|(a, b)| a == b)
1151 .count();
1152 let len = sub1.len() - common_default_params;
1153
1154 if len > 0 {
1156 values.0.push_normal("<");
1157 values.1.push_normal("<");
1158 }
1159
1160 fn lifetime_display(lifetime: Region<'_>) -> String {
1161 let s = lifetime.to_string();
1162 if s.is_empty() { "'_".to_string() } else { s }
1163 }
1164
1165 for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
1166 self.push_comma(&mut values.0, &mut values.1, i);
1167 match arg1.unpack() {
1168 ty::GenericArgKind::Lifetime(l1) => {
1185 let l1_str = lifetime_display(l1);
1186 let l2 = arg2.expect_region();
1187 let l2_str = lifetime_display(l2);
1188 if l1 != l2 {
1189 values.0.push_highlighted(l1_str);
1190 values.1.push_highlighted(l2_str);
1191 } else if l1.is_bound() || self.tcx.sess.opts.verbose {
1192 values.0.push_normal(l1_str);
1193 values.1.push_normal(l2_str);
1194 } else {
1195 values.0.push_normal("'_");
1196 values.1.push_normal("'_");
1197 }
1198 }
1199 ty::GenericArgKind::Type(ta1) => {
1200 let ta2 = arg2.expect_ty();
1201 if ta1 == ta2 && !self.tcx.sess.opts.verbose {
1202 values.0.push_normal("_");
1203 values.1.push_normal("_");
1204 } else {
1205 recurse(ta1, ta2, &mut values);
1206 }
1207 }
1208 ty::GenericArgKind::Const(ca1) => {
1218 let ca2 = arg2.expect_const();
1219 maybe_highlight(ca1, ca2, &mut values, self.tcx);
1220 }
1221 }
1222 }
1223
1224 if len > 0 {
1227 values.0.push_normal(">");
1228 values.1.push_normal(">");
1229 }
1230 values
1231 } else {
1232 if self.cmp_type_arg(
1238 &mut values.0,
1239 &mut values.1,
1240 path1.clone(),
1241 sub_no_defaults_1,
1242 path2.clone(),
1243 t2,
1244 ) {
1245 return values;
1246 }
1247 if self.cmp_type_arg(
1253 &mut values.1,
1254 &mut values.0,
1255 path2,
1256 sub_no_defaults_2,
1257 path1,
1258 t1,
1259 ) {
1260 return values;
1261 }
1262
1263 let t1_str = t1.to_string();
1270 let t2_str = t2.to_string();
1271 let min_len = t1_str.len().min(t2_str.len());
1272
1273 const SEPARATOR: &str = "::";
1274 let separator_len = SEPARATOR.len();
1275 let split_idx: usize =
1276 iter::zip(t1_str.split(SEPARATOR), t2_str.split(SEPARATOR))
1277 .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str)
1278 .map(|(mod_str, _)| mod_str.len() + separator_len)
1279 .sum();
1280
1281 debug!(?separator_len, ?split_idx, ?min_len, "cmp");
1282
1283 if split_idx >= min_len {
1284 (
1286 DiagStyledString::highlighted(t1_str),
1287 DiagStyledString::highlighted(t2_str),
1288 )
1289 } else {
1290 let (common, uniq1) = t1_str.split_at(split_idx);
1291 let (_, uniq2) = t2_str.split_at(split_idx);
1292 debug!(?common, ?uniq1, ?uniq2, "cmp");
1293
1294 values.0.push_normal(common);
1295 values.0.push_highlighted(uniq1);
1296 values.1.push_normal(common);
1297 values.1.push_highlighted(uniq2);
1298
1299 values
1300 }
1301 }
1302 }
1303
1304 (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) => {
1306 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1307 cmp_ty_refs(r1, mutbl1, r2, mutbl2, &mut values);
1308 recurse(ref_ty1, ref_ty2, &mut values);
1309 values
1310 }
1311 (&ty::Ref(r1, ref_ty1, mutbl1), _) => {
1313 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1314 push_ref(r1, mutbl1, &mut values.0);
1315 recurse(ref_ty1, t2, &mut values);
1316 values
1317 }
1318 (_, &ty::Ref(r2, ref_ty2, mutbl2)) => {
1319 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1320 push_ref(r2, mutbl2, &mut values.1);
1321 recurse(t1, ref_ty2, &mut values);
1322 values
1323 }
1324
1325 (&ty::Tuple(args1), &ty::Tuple(args2)) if args1.len() == args2.len() => {
1327 let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
1328 let len = args1.len();
1329 for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
1330 self.push_comma(&mut values.0, &mut values.1, i);
1331 recurse(left, right, &mut values);
1332 }
1333 if len == 1 {
1334 values.0.push_normal(",");
1336 values.1.push_normal(",");
1337 }
1338 values.0.push_normal(")");
1339 values.1.push_normal(")");
1340 values
1341 }
1342
1343 (ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
1344 let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
1345 let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
1346 self.cmp_fn_sig(
1347 &sig1,
1348 Some((*did1, Some(args1))),
1349 &sig2,
1350 Some((*did2, Some(args2))),
1351 )
1352 }
1353
1354 (ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
1355 let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
1356 self.cmp_fn_sig(&sig1, Some((*did1, Some(args1))), &sig_tys2.with(*hdr2), None)
1357 }
1358
1359 (ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
1360 let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
1361 self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, Some(args2))))
1362 }
1363
1364 (ty::FnPtr(sig_tys1, hdr1), ty::FnPtr(sig_tys2, hdr2)) => {
1365 self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig_tys2.with(*hdr2), None)
1366 }
1367
1368 _ => {
1369 let mut strs = (DiagStyledString::new(), DiagStyledString::new());
1370 maybe_highlight(t1, t2, &mut strs, self.tcx);
1371 strs
1372 }
1373 }
1374 }
1375
1376 #[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))]
1386 pub fn note_type_err(
1387 &self,
1388 diag: &mut Diag<'_>,
1389 cause: &ObligationCause<'tcx>,
1390 secondary_span: Option<(Span, Cow<'static, str>, bool)>,
1391 mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
1392 terr: TypeError<'tcx>,
1393 prefer_label: bool,
1394 override_span: Option<Span>,
1395 ) {
1396 let span = override_span.unwrap_or(cause.span);
1401 if let TypeError::CyclicTy(_) = terr {
1404 values = None;
1405 }
1406 struct OpaqueTypesVisitor<'tcx> {
1407 types: FxIndexMap<TyCategory, FxIndexSet<Span>>,
1408 expected: FxIndexMap<TyCategory, FxIndexSet<Span>>,
1409 found: FxIndexMap<TyCategory, FxIndexSet<Span>>,
1410 ignore_span: Span,
1411 tcx: TyCtxt<'tcx>,
1412 }
1413
1414 impl<'tcx> OpaqueTypesVisitor<'tcx> {
1415 fn visit_expected_found(
1416 tcx: TyCtxt<'tcx>,
1417 expected: impl TypeVisitable<TyCtxt<'tcx>>,
1418 found: impl TypeVisitable<TyCtxt<'tcx>>,
1419 ignore_span: Span,
1420 ) -> Self {
1421 let mut types_visitor = OpaqueTypesVisitor {
1422 types: Default::default(),
1423 expected: Default::default(),
1424 found: Default::default(),
1425 ignore_span,
1426 tcx,
1427 };
1428 expected.visit_with(&mut types_visitor);
1432 std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types);
1433 found.visit_with(&mut types_visitor);
1434 std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
1435 types_visitor
1436 }
1437
1438 fn report(&self, err: &mut Diag<'_>) {
1439 self.add_labels_for_types(err, "expected", &self.expected);
1440 self.add_labels_for_types(err, "found", &self.found);
1441 }
1442
1443 fn add_labels_for_types(
1444 &self,
1445 err: &mut Diag<'_>,
1446 target: &str,
1447 types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
1448 ) {
1449 for (kind, values) in types.iter() {
1450 let count = values.len();
1451 for &sp in values {
1452 err.span_label(
1453 sp,
1454 format!(
1455 "{}{} {:#}{}",
1456 if count == 1 { "the " } else { "one of the " },
1457 target,
1458 kind,
1459 pluralize!(count),
1460 ),
1461 );
1462 }
1463 }
1464 }
1465 }
1466
1467 impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypesVisitor<'tcx> {
1468 fn visit_ty(&mut self, t: Ty<'tcx>) {
1469 if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
1470 let span = self.tcx.def_span(def_id);
1471 if !self.ignore_span.overlaps(span)
1487 && !span.is_desugaring(DesugaringKind::Async)
1488 {
1489 self.types.entry(kind).or_default().insert(span);
1490 }
1491 }
1492 t.super_visit_with(self)
1493 }
1494 }
1495
1496 debug!("note_type_err(diag={:?})", diag);
1497 enum Mismatch<'a> {
1498 Variable(ty::error::ExpectedFound<Ty<'a>>),
1499 Fixed(&'static str),
1500 }
1501 let (expected_found, exp_found, is_simple_error, values, param_env) = match values {
1502 None => (None, Mismatch::Fixed("type"), false, None, None),
1503 Some(ty::ParamEnvAnd { param_env, value: values }) => {
1504 let mut values = self.resolve_vars_if_possible(values);
1505 if self.next_trait_solver() {
1506 values = deeply_normalize_for_diagnostics(self, param_env, values);
1507 }
1508 let (is_simple_error, exp_found) = match values {
1509 ValuePairs::Terms(ExpectedFound { expected, found }) => {
1510 match (expected.unpack(), found.unpack()) {
1511 (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
1512 let is_simple_err =
1513 expected.is_simple_text() && found.is_simple_text();
1514 OpaqueTypesVisitor::visit_expected_found(
1515 self.tcx, expected, found, span,
1516 )
1517 .report(diag);
1518
1519 (
1520 is_simple_err,
1521 Mismatch::Variable(ExpectedFound { expected, found }),
1522 )
1523 }
1524 (ty::TermKind::Const(_), ty::TermKind::Const(_)) => {
1525 (false, Mismatch::Fixed("constant"))
1526 }
1527 _ => (false, Mismatch::Fixed("type")),
1528 }
1529 }
1530 ValuePairs::PolySigs(ExpectedFound { expected, found }) => {
1531 OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
1532 .report(diag);
1533 (false, Mismatch::Fixed("signature"))
1534 }
1535 ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
1536 ValuePairs::Aliases(ExpectedFound { expected, .. }) => {
1537 (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
1538 }
1539 ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
1540 ValuePairs::ExistentialTraitRef(_) => {
1541 (false, Mismatch::Fixed("existential trait ref"))
1542 }
1543 ValuePairs::ExistentialProjection(_) => {
1544 (false, Mismatch::Fixed("existential projection"))
1545 }
1546 };
1547 let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else {
1548 diag.downgrade_to_delayed_bug();
1552 return;
1553 };
1554 (Some(vals), exp_found, is_simple_error, Some(values), Some(param_env))
1555 }
1556 };
1557
1558 let mut label_or_note = |span: Span, msg: Cow<'static, str>| {
1559 if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
1560 diag.span_label(span, msg);
1561 } else {
1562 diag.span_note(span, msg);
1563 }
1564 };
1565 if let Some((secondary_span, secondary_msg, swap_secondary_and_primary)) = secondary_span {
1566 if swap_secondary_and_primary {
1567 let terr = if let Some(infer::ValuePairs::Terms(ExpectedFound {
1568 expected, ..
1569 })) = values
1570 {
1571 Cow::from(format!("expected this to be `{expected}`"))
1572 } else {
1573 terr.to_string(self.tcx)
1574 };
1575 label_or_note(secondary_span, terr);
1576 label_or_note(span, secondary_msg);
1577 } else {
1578 label_or_note(span, terr.to_string(self.tcx));
1579 label_or_note(secondary_span, secondary_msg);
1580 }
1581 } else if let Some(values) = values
1582 && let Some((e, f)) = values.ty()
1583 && let TypeError::ArgumentSorts(..) | TypeError::Sorts(_) = terr
1584 {
1585 let e = self.tcx.erase_regions(e);
1586 let f = self.tcx.erase_regions(f);
1587 let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
1588 let found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
1589 if expected == found {
1590 label_or_note(span, terr.to_string(self.tcx));
1591 } else {
1592 label_or_note(span, Cow::from(format!("expected {expected}, found {found}")));
1593 }
1594 } else {
1595 label_or_note(span, terr.to_string(self.tcx));
1596 }
1597
1598 if self.check_and_note_conflicting_crates(diag, terr) {
1599 return;
1600 }
1601
1602 if let Some((expected, found)) = expected_found {
1603 let (expected_label, found_label, exp_found) = match exp_found {
1604 Mismatch::Variable(ef) => (
1605 ef.expected.prefix_string(self.tcx),
1606 ef.found.prefix_string(self.tcx),
1607 Some(ef),
1608 ),
1609 Mismatch::Fixed(s) => (s.into(), s.into(), None),
1610 };
1611
1612 enum Similar<'tcx> {
1613 Adts { expected: ty::AdtDef<'tcx>, found: ty::AdtDef<'tcx> },
1614 PrimitiveFound { expected: ty::AdtDef<'tcx>, found: Ty<'tcx> },
1615 PrimitiveExpected { expected: Ty<'tcx>, found: ty::AdtDef<'tcx> },
1616 }
1617
1618 let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
1619 if let ty::Adt(expected, _) = expected.kind()
1620 && let Some(primitive) = found.primitive_symbol()
1621 {
1622 let path = self.tcx.def_path(expected.did()).data;
1623 let name = path.last().unwrap().data.get_opt_name();
1624 if name == Some(primitive) {
1625 return Some(Similar::PrimitiveFound { expected: *expected, found });
1626 }
1627 } else if let Some(primitive) = expected.primitive_symbol()
1628 && let ty::Adt(found, _) = found.kind()
1629 {
1630 let path = self.tcx.def_path(found.did()).data;
1631 let name = path.last().unwrap().data.get_opt_name();
1632 if name == Some(primitive) {
1633 return Some(Similar::PrimitiveExpected { expected, found: *found });
1634 }
1635 } else if let ty::Adt(expected, _) = expected.kind()
1636 && let ty::Adt(found, _) = found.kind()
1637 {
1638 if !expected.did().is_local() && expected.did().krate == found.did().krate {
1639 return None;
1643 }
1644 let f_path = self.tcx.def_path(found.did()).data;
1645 let e_path = self.tcx.def_path(expected.did()).data;
1646
1647 if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last())
1648 && e_last == f_last
1649 {
1650 return Some(Similar::Adts { expected: *expected, found: *found });
1651 }
1652 }
1653 None
1654 };
1655
1656 match terr {
1657 TypeError::Sorts(values) if let Some(s) = similarity(values) => {
1659 let diagnose_primitive =
1660 |prim: Ty<'tcx>, shadow: Ty<'tcx>, defid: DefId, diag: &mut Diag<'_>| {
1661 let name = shadow.sort_string(self.tcx);
1662 diag.note(format!(
1663 "`{prim}` and {name} have similar names, but are actually distinct types"
1664 ));
1665 diag.note(format!(
1666 "one `{prim}` is a primitive defined by the language",
1667 ));
1668 let def_span = self.tcx.def_span(defid);
1669 let msg = if defid.is_local() {
1670 format!("the other {name} is defined in the current crate")
1671 } else {
1672 let crate_name = self.tcx.crate_name(defid.krate);
1673 format!("the other {name} is defined in crate `{crate_name}`")
1674 };
1675 diag.span_note(def_span, msg);
1676 };
1677
1678 let diagnose_adts =
1679 |expected_adt: ty::AdtDef<'tcx>,
1680 found_adt: ty::AdtDef<'tcx>,
1681 diag: &mut Diag<'_>| {
1682 let found_name = values.found.sort_string(self.tcx);
1683 let expected_name = values.expected.sort_string(self.tcx);
1684
1685 let found_defid = found_adt.did();
1686 let expected_defid = expected_adt.did();
1687
1688 diag.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
1689 for (defid, name) in
1690 [(found_defid, found_name), (expected_defid, expected_name)]
1691 {
1692 let def_span = self.tcx.def_span(defid);
1693
1694 let msg = if found_defid.is_local() && expected_defid.is_local() {
1695 let module = self
1696 .tcx
1697 .parent_module_from_def_id(defid.expect_local())
1698 .to_def_id();
1699 let module_name =
1700 self.tcx.def_path(module).to_string_no_crate_verbose();
1701 format!(
1702 "{name} is defined in module `crate{module_name}` of the current crate"
1703 )
1704 } else if defid.is_local() {
1705 format!("{name} is defined in the current crate")
1706 } else {
1707 let crate_name = self.tcx.crate_name(defid.krate);
1708 format!("{name} is defined in crate `{crate_name}`")
1709 };
1710 diag.span_note(def_span, msg);
1711 }
1712 };
1713
1714 match s {
1715 Similar::Adts { expected, found } => diagnose_adts(expected, found, diag),
1716 Similar::PrimitiveFound { expected, found: prim } => {
1717 diagnose_primitive(prim, values.expected, expected.did(), diag)
1718 }
1719 Similar::PrimitiveExpected { expected: prim, found } => {
1720 diagnose_primitive(prim, values.found, found.did(), diag)
1721 }
1722 }
1723 }
1724 TypeError::Sorts(values) => {
1725 let extra = expected == found
1726 && values.expected.sort_string(self.tcx)
1730 != values.found.sort_string(self.tcx);
1731 let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
1732 (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
1733 let sm = self.tcx.sess.source_map();
1734 let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1735 DiagStyledString::normal(format!(
1736 " (opaque type at <{}:{}:{}>)",
1737 sm.filename_for_diagnostics(&pos.file.name),
1738 pos.line,
1739 pos.col.to_usize() + 1,
1740 ))
1741 }
1742 (true, ty::Alias(ty::Projection, proj))
1743 if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
1744 {
1745 let sm = self.tcx.sess.source_map();
1746 let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
1747 DiagStyledString::normal(format!(
1748 " (trait associated opaque type at <{}:{}:{}>)",
1749 sm.filename_for_diagnostics(&pos.file.name),
1750 pos.line,
1751 pos.col.to_usize() + 1,
1752 ))
1753 }
1754 (true, _) => {
1755 let mut s = DiagStyledString::normal(" (");
1756 s.push_highlighted(ty.sort_string(self.tcx));
1757 s.push_normal(")");
1758 s
1759 }
1760 (false, _) => DiagStyledString::normal(""),
1761 };
1762 if !(values.expected.is_simple_text() && values.found.is_simple_text())
1763 || (exp_found.is_some_and(|ef| {
1764 if !ef.expected.is_ty_or_numeric_infer() {
1769 ef.expected != values.expected
1770 } else if !ef.found.is_ty_or_numeric_infer() {
1771 ef.found != values.found
1772 } else {
1773 false
1774 }
1775 }))
1776 {
1777 if let Some(ExpectedFound { found: found_ty, .. }) = exp_found
1778 && !self.tcx.ty_is_opaque_future(found_ty)
1779 {
1780 diag.note_expected_found_extra(
1787 &expected_label,
1788 expected,
1789 &found_label,
1790 found,
1791 sort_string(values.expected),
1792 sort_string(values.found),
1793 );
1794 }
1795 }
1796 }
1797 _ => {
1798 debug!(
1799 "note_type_err: exp_found={:?}, expected={:?} found={:?}",
1800 exp_found, expected, found
1801 );
1802 if !is_simple_error || terr.must_include_note() {
1803 diag.note_expected_found(&expected_label, expected, &found_label, found);
1804
1805 if let Some(ty::Closure(_, args)) =
1806 exp_found.map(|expected_type_found| expected_type_found.found.kind())
1807 {
1808 diag.highlighted_note(vec![
1809 StringPart::normal("closure has signature: `"),
1810 StringPart::highlighted(
1811 self.tcx
1812 .signature_unclosure(
1813 args.as_closure().sig(),
1814 rustc_hir::Safety::Safe,
1815 )
1816 .to_string(),
1817 ),
1818 StringPart::normal("`"),
1819 ]);
1820 }
1821 }
1822 }
1823 }
1824 }
1825 let exp_found = match exp_found {
1826 Mismatch::Variable(exp_found) => Some(exp_found),
1827 Mismatch::Fixed(_) => None,
1828 };
1829 let exp_found = match terr {
1830 ty::error::TypeError::Sorts(terr)
1832 if exp_found.is_some_and(|ef| terr.found == ef.found) =>
1833 {
1834 Some(terr)
1835 }
1836 _ => exp_found,
1837 };
1838 debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code());
1839 if let Some(exp_found) = exp_found {
1840 let should_suggest_fixes =
1841 if let ObligationCauseCode::Pattern { root_ty, .. } = cause.code() {
1842 self.same_type_modulo_infer(*root_ty, exp_found.expected)
1845 } else {
1846 true
1847 };
1848
1849 if should_suggest_fixes
1853 && !matches!(terr, TypeError::RegionsInsufficientlyPolymorphic(..))
1854 {
1855 self.suggest_tuple_pattern(cause, &exp_found, diag);
1856 self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
1857 self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
1858 self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
1859 self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
1860 }
1861 }
1862
1863 self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
1864 if let Some(exp_found) = exp_found
1865 && let exp_found = TypeError::Sorts(exp_found)
1866 && exp_found != terr
1867 {
1868 self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id());
1869 }
1870
1871 if let Some(ValuePairs::TraitRefs(exp_found)) = values
1872 && let ty::Closure(def_id, _) = exp_found.expected.self_ty().kind()
1873 && let Some(def_id) = def_id.as_local()
1874 && terr.involves_regions()
1875 {
1876 let span = self.tcx.def_span(def_id);
1877 diag.span_note(span, "this closure does not fulfill the lifetime requirements");
1878 self.suggest_for_all_lifetime_closure(
1879 span,
1880 self.tcx.hir_node_by_def_id(def_id),
1881 &exp_found,
1882 diag,
1883 );
1884 }
1885
1886 self.note_error_origin(diag, cause, exp_found, terr, param_env);
1889
1890 debug!(?diag);
1891 }
1892
1893 pub fn type_error_additional_suggestions(
1894 &self,
1895 trace: &TypeTrace<'tcx>,
1896 terr: TypeError<'tcx>,
1897 path: &mut Option<PathBuf>,
1898 ) -> Vec<TypeErrorAdditionalDiags> {
1899 let mut suggestions = Vec::new();
1900 let span = trace.cause.span;
1901 let values = self.resolve_vars_if_possible(trace.values);
1902 if let Some((expected, found)) = values.ty() {
1903 match (expected.kind(), found.kind()) {
1904 (ty::Tuple(_), ty::Tuple(_)) => {}
1905 (ty::Tuple(fields), _) => {
1909 suggestions.extend(self.suggest_wrap_to_build_a_tuple(span, found, fields))
1910 }
1911 (ty::Uint(ty::UintTy::U8), ty::Char) => {
1915 if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
1916 && let Some(code) =
1917 code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
1918 && !code.starts_with("\\u")
1920 && code.chars().next().is_some_and(|c| c.is_ascii())
1922 {
1923 suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral {
1924 span,
1925 code: escape_literal(code),
1926 })
1927 }
1928 }
1929 (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
1933 if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
1934 && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
1935 && code.chars().count() == 1
1936 {
1937 suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral {
1938 span,
1939 code: escape_literal(code),
1940 })
1941 }
1942 }
1943 (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
1946 if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
1947 && code.starts_with("'")
1948 && code.ends_with("'")
1949 {
1950 suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
1951 start: span.with_hi(span.lo() + BytePos(1)),
1952 end: span.with_lo(span.hi() - BytePos(1)),
1953 });
1954 }
1955 }
1956 (ty::Bool, ty::Tuple(list)) => {
1959 if list.len() == 0 {
1960 suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
1961 }
1962 }
1963 (ty::Array(_, _), ty::Array(_, _)) => {
1964 suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
1965 }
1966 _ => {}
1967 }
1968 }
1969 let code = trace.cause.code();
1970 if let &(ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
1971 source,
1972 ..
1973 })
1974 | ObligationCauseCode::BlockTailExpression(.., source)) = code
1975 && let hir::MatchSource::TryDesugar(_) = source
1976 && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path)
1977 {
1978 suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
1979 found: found_ty.content(),
1980 expected: expected_ty.content(),
1981 });
1982 }
1983 suggestions
1984 }
1985
1986 fn suggest_specify_actual_length(
1987 &self,
1988 terr: TypeError<'tcx>,
1989 trace: &TypeTrace<'tcx>,
1990 span: Span,
1991 ) -> Option<TypeErrorAdditionalDiags> {
1992 let hir = self.tcx.hir();
1993 let TypeError::ArraySize(sz) = terr else {
1994 return None;
1995 };
1996 let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
1997 hir::Node::Item(hir::Item {
1998 kind: hir::ItemKind::Fn { body: body_id, .. }, ..
1999 }) => {
2000 let body = hir.body(*body_id);
2001 struct LetVisitor {
2002 span: Span,
2003 }
2004 impl<'v> Visitor<'v> for LetVisitor {
2005 type Result = ControlFlow<&'v hir::TyKind<'v>>;
2006 fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
2007 if let hir::Stmt {
2010 kind:
2011 hir::StmtKind::Let(hir::LetStmt {
2012 init: Some(hir::Expr { span: init_span, .. }),
2013 ty: Some(array_ty),
2014 ..
2015 }),
2016 ..
2017 } = s
2018 && init_span == &self.span
2019 {
2020 ControlFlow::Break(&array_ty.peel_refs().kind)
2021 } else {
2022 ControlFlow::Continue(())
2023 }
2024 }
2025 }
2026 LetVisitor { span }.visit_body(body).break_value()
2027 }
2028 hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }) => {
2029 Some(&ty.peel_refs().kind)
2030 }
2031 _ => None,
2032 };
2033 if let Some(tykind) = tykind
2034 && let hir::TyKind::Array(_, length_arg) = tykind
2035 && let Some(length_val) = sz.found.try_to_target_usize(self.tcx)
2036 {
2037 Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
2038 span: length_arg.span(),
2039 length: length_val,
2040 })
2041 } else {
2042 None
2043 }
2044 }
2045
2046 pub fn report_and_explain_type_error(
2047 &self,
2048 trace: TypeTrace<'tcx>,
2049 param_env: ty::ParamEnv<'tcx>,
2050 terr: TypeError<'tcx>,
2051 ) -> Diag<'a> {
2052 debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
2053
2054 let span = trace.cause.span;
2055 let mut path = None;
2056 let failure_code = trace.cause.as_failure_code_diag(
2057 terr,
2058 span,
2059 self.type_error_additional_suggestions(&trace, terr, &mut path),
2060 );
2061 let mut diag = self.dcx().create_err(failure_code);
2062 *diag.long_ty_path() = path;
2063 self.note_type_err(
2064 &mut diag,
2065 &trace.cause,
2066 None,
2067 Some(param_env.and(trace.values)),
2068 terr,
2069 false,
2070 None,
2071 );
2072 diag
2073 }
2074
2075 fn suggest_wrap_to_build_a_tuple(
2076 &self,
2077 span: Span,
2078 found: Ty<'tcx>,
2079 expected_fields: &List<Ty<'tcx>>,
2080 ) -> Option<TypeErrorAdditionalDiags> {
2081 let [expected_tup_elem] = expected_fields[..] else { return None };
2082
2083 if !self.same_type_modulo_infer(expected_tup_elem, found) {
2084 return None;
2085 }
2086
2087 let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) else { return None };
2088
2089 let sugg = if code.starts_with('(') && code.ends_with(')') {
2090 let before_close = span.hi() - BytePos::from_u32(1);
2091 TypeErrorAdditionalDiags::TupleOnlyComma {
2092 span: span.with_hi(before_close).shrink_to_hi(),
2093 }
2094 } else {
2095 TypeErrorAdditionalDiags::TupleAlsoParentheses {
2096 span_low: span.shrink_to_lo(),
2097 span_high: span.shrink_to_hi(),
2098 }
2099 };
2100 Some(sugg)
2101 }
2102
2103 fn values_str(
2104 &self,
2105 values: ValuePairs<'tcx>,
2106 cause: &ObligationCause<'tcx>,
2107 file: &mut Option<PathBuf>,
2108 ) -> Option<(DiagStyledString, DiagStyledString)> {
2109 match values {
2110 ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
2111 ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file),
2112 ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
2113 ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
2114 ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
2115 ValuePairs::TraitRefs(exp_found) => {
2116 let pretty_exp_found = ty::error::ExpectedFound {
2117 expected: exp_found.expected.print_trait_sugared(),
2118 found: exp_found.found.print_trait_sugared(),
2119 };
2120 match self.expected_found_str(pretty_exp_found) {
2121 Some((expected, found)) if expected == found => {
2122 self.expected_found_str(exp_found)
2123 }
2124 ret => ret,
2125 }
2126 }
2127 ValuePairs::PolySigs(exp_found) => {
2128 let exp_found = self.resolve_vars_if_possible(exp_found);
2129 if exp_found.references_error() {
2130 return None;
2131 }
2132 let (fn_def1, fn_def2) = if let ObligationCauseCode::CompareImplItem {
2133 impl_item_def_id,
2134 trait_item_def_id,
2135 ..
2136 } = *cause.code()
2137 {
2138 (Some((trait_item_def_id, None)), Some((impl_item_def_id.to_def_id(), None)))
2139 } else {
2140 (None, None)
2141 };
2142
2143 Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2))
2144 }
2145 }
2146 }
2147
2148 fn expected_found_str_term(
2149 &self,
2150 exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
2151 path: &mut Option<PathBuf>,
2152 ) -> Option<(DiagStyledString, DiagStyledString)> {
2153 let exp_found = self.resolve_vars_if_possible(exp_found);
2154 if exp_found.references_error() {
2155 return None;
2156 }
2157
2158 Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) {
2159 (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
2160 let (mut exp, mut fnd) = self.cmp(expected, found);
2161 let len = self.tcx.sess().diagnostic_width() + 40;
2165 let exp_s = exp.content();
2166 let fnd_s = fnd.content();
2167 if exp_s.len() > len {
2168 let exp_s = self.tcx.short_string(expected, path);
2169 exp = DiagStyledString::highlighted(exp_s);
2170 }
2171 if fnd_s.len() > len {
2172 let fnd_s = self.tcx.short_string(found, path);
2173 fnd = DiagStyledString::highlighted(fnd_s);
2174 }
2175 (exp, fnd)
2176 }
2177 _ => (
2178 DiagStyledString::highlighted(exp_found.expected.to_string()),
2179 DiagStyledString::highlighted(exp_found.found.to_string()),
2180 ),
2181 })
2182 }
2183
2184 fn expected_found_str<T: fmt::Display + TypeFoldable<TyCtxt<'tcx>>>(
2186 &self,
2187 exp_found: ty::error::ExpectedFound<T>,
2188 ) -> Option<(DiagStyledString, DiagStyledString)> {
2189 let exp_found = self.resolve_vars_if_possible(exp_found);
2190 if exp_found.references_error() {
2191 return None;
2192 }
2193
2194 Some((
2195 DiagStyledString::highlighted(exp_found.expected.to_string()),
2196 DiagStyledString::highlighted(exp_found.found.to_string()),
2197 ))
2198 }
2199
2200 pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool {
2204 span.is_desugaring(DesugaringKind::QuestionMark)
2205 && self.tcx.is_diagnostic_item(sym::From, trait_def_id)
2206 }
2207
2208 pub fn same_type_modulo_infer<T: relate::Relate<TyCtxt<'tcx>>>(&self, a: T, b: T) -> bool {
2215 let (a, b) = self.resolve_vars_if_possible((a, b));
2216 SameTypeModuloInfer(self).relate(a, b).is_ok()
2217 }
2218}
2219
2220struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>);
2221
2222impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> {
2223 fn cx(&self) -> TyCtxt<'tcx> {
2224 self.0.tcx
2225 }
2226
2227 fn relate_with_variance<T: relate::Relate<TyCtxt<'tcx>>>(
2228 &mut self,
2229 _variance: ty::Variance,
2230 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
2231 a: T,
2232 b: T,
2233 ) -> relate::RelateResult<'tcx, T> {
2234 self.relate(a, b)
2235 }
2236
2237 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
2238 match (a.kind(), b.kind()) {
2239 (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_)))
2240 | (
2241 ty::Infer(ty::InferTy::IntVar(_)),
2242 ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)),
2243 )
2244 | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_)))
2245 | (
2246 ty::Infer(ty::InferTy::FloatVar(_)),
2247 ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)),
2248 )
2249 | (ty::Infer(ty::InferTy::TyVar(_)), _)
2250 | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
2251 (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
2252 _ => relate::structurally_relate_tys(self, a, b),
2253 }
2254 }
2255
2256 fn regions(
2257 &mut self,
2258 a: ty::Region<'tcx>,
2259 b: ty::Region<'tcx>,
2260 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
2261 if (a.is_var() && b.is_free())
2262 || (b.is_var() && a.is_free())
2263 || (a.is_var() && b.is_var())
2264 || a == b
2265 {
2266 Ok(a)
2267 } else {
2268 Err(TypeError::Mismatch)
2269 }
2270 }
2271
2272 fn binders<T>(
2273 &mut self,
2274 a: ty::Binder<'tcx, T>,
2275 b: ty::Binder<'tcx, T>,
2276 ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>>
2277 where
2278 T: relate::Relate<TyCtxt<'tcx>>,
2279 {
2280 Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
2281 }
2282
2283 fn consts(
2284 &mut self,
2285 a: ty::Const<'tcx>,
2286 _b: ty::Const<'tcx>,
2287 ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> {
2288 Ok(a)
2291 }
2292}
2293
2294pub enum FailureCode {
2295 Error0317,
2296 Error0580,
2297 Error0308,
2298 Error0644,
2299}
2300
2301#[extension(pub trait ObligationCauseExt<'tcx>)]
2302impl<'tcx> ObligationCause<'tcx> {
2303 fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
2304 match self.code() {
2305 ObligationCauseCode::IfExpressionWithNoElse => FailureCode::Error0317,
2306 ObligationCauseCode::MainFunctionType => FailureCode::Error0580,
2307 ObligationCauseCode::CompareImplItem { .. }
2308 | ObligationCauseCode::MatchExpressionArm(_)
2309 | ObligationCauseCode::IfExpression { .. }
2310 | ObligationCauseCode::LetElse
2311 | ObligationCauseCode::LangFunctionType(_)
2312 | ObligationCauseCode::IntrinsicType
2313 | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
2314
2315 _ => match terr {
2319 TypeError::CyclicTy(ty)
2320 if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
2321 {
2322 FailureCode::Error0644
2323 }
2324 TypeError::IntrinsicCast | TypeError::ForceInlineCast => FailureCode::Error0308,
2325 _ => FailureCode::Error0308,
2326 },
2327 }
2328 }
2329 fn as_failure_code_diag(
2330 &self,
2331 terr: TypeError<'tcx>,
2332 span: Span,
2333 subdiags: Vec<TypeErrorAdditionalDiags>,
2334 ) -> ObligationCauseFailureCode {
2335 match self.code() {
2336 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
2337 ObligationCauseFailureCode::MethodCompat { span, subdiags }
2338 }
2339 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
2340 ObligationCauseFailureCode::TypeCompat { span, subdiags }
2341 }
2342 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
2343 ObligationCauseFailureCode::ConstCompat { span, subdiags }
2344 }
2345 ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
2346 ObligationCauseFailureCode::TryCompat { span, subdiags }
2347 }
2348 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
2349 source, ..
2350 }) => match source {
2351 hir::MatchSource::TryDesugar(_) => {
2352 ObligationCauseFailureCode::TryCompat { span, subdiags }
2353 }
2354 _ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
2355 },
2356 ObligationCauseCode::IfExpression { .. } => {
2357 ObligationCauseFailureCode::IfElseDifferent { span, subdiags }
2358 }
2359 ObligationCauseCode::IfExpressionWithNoElse => {
2360 ObligationCauseFailureCode::NoElse { span }
2361 }
2362 ObligationCauseCode::LetElse => {
2363 ObligationCauseFailureCode::NoDiverge { span, subdiags }
2364 }
2365 ObligationCauseCode::MainFunctionType => {
2366 ObligationCauseFailureCode::FnMainCorrectType { span }
2367 }
2368 &ObligationCauseCode::LangFunctionType(lang_item_name) => {
2369 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
2370 }
2371 ObligationCauseCode::IntrinsicType => {
2372 ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }
2373 }
2374 ObligationCauseCode::MethodReceiver => {
2375 ObligationCauseFailureCode::MethodCorrectType { span, subdiags }
2376 }
2377
2378 _ => match terr {
2382 TypeError::CyclicTy(ty)
2383 if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
2384 {
2385 ObligationCauseFailureCode::ClosureSelfref { span }
2386 }
2387 TypeError::ForceInlineCast => {
2388 ObligationCauseFailureCode::CantCoerceForceInline { span, subdiags }
2389 }
2390 TypeError::IntrinsicCast => {
2391 ObligationCauseFailureCode::CantCoerceIntrinsic { span, subdiags }
2392 }
2393 _ => ObligationCauseFailureCode::Generic { span, subdiags },
2394 },
2395 }
2396 }
2397
2398 fn as_requirement_str(&self) -> &'static str {
2399 match self.code() {
2400 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
2401 "method type is compatible with trait"
2402 }
2403 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
2404 "associated type is compatible with trait"
2405 }
2406 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
2407 "const is compatible with trait"
2408 }
2409 ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
2410 ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
2411 ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
2412 ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
2413 _ => "types are compatible",
2414 }
2415 }
2416}
2417
2418pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
2420
2421impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
2422 fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
2423 let kind = match self.0.code() {
2424 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
2425 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
2426 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
2427 "const_compat"
2428 }
2429 ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
2430 ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
2431 ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
2432 ObligationCauseCode::MethodReceiver => "method_correct_type",
2433 _ => "other",
2434 }
2435 .into();
2436 rustc_errors::DiagArgValue::Str(kind)
2437 }
2438}
2439
2440#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2443pub enum TyCategory {
2444 Closure,
2445 Opaque,
2446 OpaqueFuture,
2447 Coroutine(hir::CoroutineKind),
2448 Foreign,
2449}
2450
2451impl fmt::Display for TyCategory {
2452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2453 match self {
2454 Self::Closure => "closure".fmt(f),
2455 Self::Opaque => "opaque type".fmt(f),
2456 Self::OpaqueFuture => "future".fmt(f),
2457 Self::Coroutine(gk) => gk.fmt(f),
2458 Self::Foreign => "foreign type".fmt(f),
2459 }
2460 }
2461}
2462
2463impl TyCategory {
2464 pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
2465 match *ty.kind() {
2466 ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
2467 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
2468 let kind =
2469 if tcx.ty_is_opaque_future(ty) { Self::OpaqueFuture } else { Self::Opaque };
2470 Some((kind, def_id))
2471 }
2472 ty::Coroutine(def_id, ..) => {
2473 Some((Self::Coroutine(tcx.coroutine_kind(def_id).unwrap()), def_id))
2474 }
2475 ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
2476 _ => None,
2477 }
2478 }
2479}