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