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::{
69 PrintError, PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths,
70};
71use rustc_middle::ty::{
72 self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable,
73 TypeVisitableExt,
74};
75use rustc_span::def_id::LOCAL_CRATE;
76use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym};
77use tracing::{debug, instrument};
78
79use crate::error_reporting::TypeErrCtxt;
80use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags};
81use crate::infer;
82use crate::infer::relate::{self, RelateResult, TypeRelation};
83use crate::infer::{InferCtxt, InferCtxtExt as _, TypeTrace, ValuePairs};
84use crate::solve::deeply_normalize_for_diagnostics;
85use crate::traits::{MatchExpressionArmCause, ObligationCause, ObligationCauseCode};
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, 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 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 { expr_id, .. } => {
615 let hir::Node::Expr(&hir::Expr {
616 kind: hir::ExprKind::If(cond_expr, then_expr, Some(else_expr)),
617 span: expr_span,
618 ..
619 }) = self.tcx.hir_node(expr_id)
620 else {
621 return;
622 };
623 let then_span = self.find_block_span_from_hir_id(then_expr.hir_id);
624 let then_ty = self
625 .typeck_results
626 .as_ref()
627 .expect("if expression only expected inside FnCtxt")
628 .expr_ty(then_expr);
629 let else_span = self.find_block_span_from_hir_id(else_expr.hir_id);
630 let else_ty = self
631 .typeck_results
632 .as_ref()
633 .expect("if expression only expected inside FnCtxt")
634 .expr_ty(else_expr);
635 if let hir::ExprKind::If(_cond, _then, None) = else_expr.kind
636 && else_ty.is_unit()
637 {
638 err.note("`if` expressions without `else` evaluate to `()`");
640 err.note("consider adding an `else` block that evaluates to the expected type");
641 }
642 err.span_label(then_span, "expected because of this");
643
644 let outer_span = if self.tcx.sess.source_map().is_multiline(expr_span) {
645 if then_span.hi() == expr_span.hi() || else_span.hi() == expr_span.hi() {
646 Some(expr_span.shrink_to_lo().to(cond_expr.peel_drop_temps().span))
649 } else {
650 Some(expr_span)
651 }
652 } else {
653 None
654 };
655 if let Some(sp) = outer_span {
656 err.span_label(sp, "`if` and `else` have incompatible types");
657 }
658
659 let then_id = if let hir::ExprKind::Block(then_blk, _) = then_expr.kind {
660 then_blk.hir_id
661 } else {
662 then_expr.hir_id
663 };
664 let else_id = if let hir::ExprKind::Block(else_blk, _) = else_expr.kind {
665 else_blk.hir_id
666 } else {
667 else_expr.hir_id
668 };
669 if let Some(subdiag) = self.suggest_remove_semi_or_return_binding(
670 Some(then_id),
671 then_ty,
672 then_span,
673 Some(else_id),
674 else_ty,
675 else_span,
676 ) {
677 err.subdiagnostic(subdiag);
678 }
679 }
680 ObligationCauseCode::LetElse => {
681 err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
682 err.help("...or use `match` instead of `let...else`");
683 }
684 _ => {
685 if let ObligationCauseCode::WhereClause(_, span)
686 | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
687 cause.code().peel_derives()
688 && !span.is_dummy()
689 && let TypeError::RegionsPlaceholderMismatch = terr
690 {
691 err.span_note(*span, "the lifetime requirement is introduced here");
692 }
693 }
694 }
695 }
696
697 fn should_deref_suggestion_on_mismatch(
700 &self,
701 param_env: ParamEnv<'tcx>,
702 deref_to: Ty<'tcx>,
703 deref_from: Ty<'tcx>,
704 origin_expr: PatternOriginExpr,
705 ) -> Option<String> {
706 let Some((num_derefs, (after_deref_ty, _))) = (self.autoderef_steps)(deref_from)
714 .into_iter()
715 .enumerate()
716 .find(|(_, (ty, _))| self.infcx.can_eq(param_env, *ty, deref_to))
717 else {
718 return None;
719 };
720
721 if num_derefs <= origin_expr.peeled_count {
722 return None;
723 }
724
725 let deref_part = "*".repeat(num_derefs - origin_expr.peeled_count);
726
727 if deref_from.is_ref() && !after_deref_ty.is_ref() {
730 Some(format!("&{deref_part}"))
731 } else {
732 Some(deref_part)
733 }
734 }
735
736 fn highlight_outer(
750 &self,
751 value: &mut DiagStyledString,
752 other_value: &mut DiagStyledString,
753 name: String,
754 args: &[ty::GenericArg<'tcx>],
755 pos: usize,
756 other_ty: Ty<'tcx>,
757 ) {
758 value.push_highlighted(name);
761
762 if args.is_empty() {
763 return;
764 }
765 value.push_highlighted("<");
766
767 for (i, arg) in args.iter().enumerate() {
768 if i > 0 {
769 value.push_normal(", ");
770 }
771
772 match arg.kind() {
773 ty::GenericArgKind::Lifetime(lt) => {
774 let s = lt.to_string();
775 value.push_normal(if s.is_empty() { "'_" } else { &s });
776 }
777 ty::GenericArgKind::Const(ct) => {
778 value.push_normal(ct.to_string());
779 }
780 ty::GenericArgKind::Type(type_arg) => {
783 if i == pos {
784 let values = self.cmp(type_arg, other_ty);
785 value.0.extend((values.0).0);
786 other_value.0.extend((values.1).0);
787 } else {
788 value.push_highlighted(type_arg.to_string());
789 }
790 }
791 }
792 }
793
794 value.push_highlighted(">");
795 }
796
797 fn cmp_type_arg(
818 &self,
819 t1_out: &mut DiagStyledString,
820 t2_out: &mut DiagStyledString,
821 path: String,
822 args: &'tcx [ty::GenericArg<'tcx>],
823 other_path: String,
824 other_ty: Ty<'tcx>,
825 ) -> bool {
826 for (i, arg) in args.iter().enumerate() {
827 if let Some(ta) = arg.as_type() {
828 if ta == other_ty {
829 self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
830 return true;
831 }
832 if let ty::Adt(def, _) = ta.kind() {
833 let path_ = self.tcx.def_path_str(def.did());
834 if path_ == other_path {
835 self.highlight_outer(t1_out, t2_out, path, args, i, other_ty);
836 return true;
837 }
838 }
839 }
840 }
841 false
842 }
843
844 fn push_comma(
846 &self,
847 value: &mut DiagStyledString,
848 other_value: &mut DiagStyledString,
849 pos: usize,
850 ) {
851 if pos > 0 {
852 value.push_normal(", ");
853 other_value.push_normal(", ");
854 }
855 }
856
857 fn cmp_fn_sig(
859 &self,
860 sig1: &ty::PolyFnSig<'tcx>,
861 fn_def1: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
862 sig2: &ty::PolyFnSig<'tcx>,
863 fn_def2: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
864 ) -> (DiagStyledString, DiagStyledString) {
865 let sig1 = &(self.normalize_fn_sig)(*sig1);
866 let sig2 = &(self.normalize_fn_sig)(*sig2);
867
868 let get_lifetimes = |sig| {
869 use rustc_hir::def::Namespace;
870 let (sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS)
871 .name_all_regions(sig, WrapBinderMode::ForAll)
872 .unwrap();
873 let lts: Vec<String> =
874 reg.into_items().map(|(_, kind)| kind.to_string()).into_sorted_stable_ord();
875 (if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig)
876 };
877
878 let (lt1, sig1) = get_lifetimes(sig1);
879 let (lt2, sig2) = get_lifetimes(sig2);
880
881 let mut values =
883 (DiagStyledString::normal("".to_string()), DiagStyledString::normal("".to_string()));
884
885 let safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
888 None => sig.safety.prefix_str(),
889 Some((did, _)) => {
890 if self.tcx.codegen_fn_attrs(did).safe_target_features {
891 "#[target_features] "
892 } else {
893 sig.safety.prefix_str()
894 }
895 }
896 };
897 let safety1 = safety(fn_def1, sig1);
898 let safety2 = safety(fn_def2, sig2);
899 values.0.push(safety1, safety1 != safety2);
900 values.1.push(safety2, safety1 != safety2);
901
902 if sig1.abi != ExternAbi::Rust {
905 values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi);
906 }
907 if sig2.abi != ExternAbi::Rust {
908 values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi);
909 }
910
911 let lifetime_diff = lt1 != lt2;
914 values.0.push(lt1, lifetime_diff);
915 values.1.push(lt2, lifetime_diff);
916
917 values.0.push_normal("fn(");
920 values.1.push_normal("fn(");
921
922 let len1 = sig1.inputs().len();
925 let len2 = sig2.inputs().len();
926 if len1 == len2 {
927 for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
928 self.push_comma(&mut values.0, &mut values.1, i);
929 let (x1, x2) = self.cmp(*l, *r);
930 (values.0).0.extend(x1.0);
931 (values.1).0.extend(x2.0);
932 }
933 } else {
934 for (i, l) in sig1.inputs().iter().enumerate() {
935 values.0.push_highlighted(l.to_string());
936 if i != len1 - 1 {
937 values.0.push_highlighted(", ");
938 }
939 }
940 for (i, r) in sig2.inputs().iter().enumerate() {
941 values.1.push_highlighted(r.to_string());
942 if i != len2 - 1 {
943 values.1.push_highlighted(", ");
944 }
945 }
946 }
947
948 if sig1.c_variadic {
949 if len1 > 0 {
950 values.0.push_normal(", ");
951 }
952 values.0.push("...", !sig2.c_variadic);
953 }
954 if sig2.c_variadic {
955 if len2 > 0 {
956 values.1.push_normal(", ");
957 }
958 values.1.push("...", !sig1.c_variadic);
959 }
960
961 values.0.push_normal(")");
964 values.1.push_normal(")");
965
966 let output1 = sig1.output();
969 let output2 = sig2.output();
970 let (x1, x2) = self.cmp(output1, output2);
971 let output_diff = x1 != x2;
972 if !output1.is_unit() || output_diff {
973 values.0.push_normal(" -> ");
974 (values.0).0.extend(x1.0);
975 }
976 if !output2.is_unit() || output_diff {
977 values.1.push_normal(" -> ");
978 (values.1).0.extend(x2.0);
979 }
980
981 let fmt = |did, args| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
982
983 match (fn_def1, fn_def2) {
984 (Some((fn_def1, Some(fn_args1))), Some((fn_def2, Some(fn_args2)))) => {
985 let path1 = fmt(fn_def1, fn_args1);
986 let path2 = fmt(fn_def2, fn_args2);
987 let same_path = path1 == path2;
988 values.0.push(path1, !same_path);
989 values.1.push(path2, !same_path);
990 }
991 (Some((fn_def1, Some(fn_args1))), None) => {
992 values.0.push_highlighted(fmt(fn_def1, fn_args1));
993 }
994 (None, Some((fn_def2, Some(fn_args2)))) => {
995 values.1.push_highlighted(fmt(fn_def2, fn_args2));
996 }
997 _ => {}
998 }
999
1000 values
1001 }
1002
1003 pub fn cmp_traits(
1004 &self,
1005 def_id1: DefId,
1006 args1: &[ty::GenericArg<'tcx>],
1007 def_id2: DefId,
1008 args2: &[ty::GenericArg<'tcx>],
1009 ) -> (DiagStyledString, DiagStyledString) {
1010 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1011
1012 if def_id1 != def_id2 {
1013 values.0.push_highlighted(self.tcx.def_path_str(def_id1).as_str());
1014 values.1.push_highlighted(self.tcx.def_path_str(def_id2).as_str());
1015 } else {
1016 values.0.push_normal(self.tcx.item_name(def_id1).as_str());
1017 values.1.push_normal(self.tcx.item_name(def_id2).as_str());
1018 }
1019
1020 if args1.len() != args2.len() {
1021 let (pre, post) = if args1.len() > 0 { ("<", ">") } else { ("", "") };
1022 values.0.push_normal(format!(
1023 "{pre}{}{post}",
1024 args1.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ")
1025 ));
1026 let (pre, post) = if args2.len() > 0 { ("<", ">") } else { ("", "") };
1027 values.1.push_normal(format!(
1028 "{pre}{}{post}",
1029 args2.iter().map(|a| a.to_string()).collect::<Vec<_>>().join(", ")
1030 ));
1031 return values;
1032 }
1033
1034 if args1.len() > 0 {
1035 values.0.push_normal("<");
1036 values.1.push_normal("<");
1037 }
1038 for (i, (a, b)) in std::iter::zip(args1, args2).enumerate() {
1039 let a_str = a.to_string();
1040 let b_str = b.to_string();
1041 if let (Some(a), Some(b)) = (a.as_type(), b.as_type()) {
1042 let (a, b) = self.cmp(a, b);
1043 values.0.0.extend(a.0);
1044 values.1.0.extend(b.0);
1045 } else if a_str != b_str {
1046 values.0.push_highlighted(a_str);
1047 values.1.push_highlighted(b_str);
1048 } else {
1049 values.0.push_normal(a_str);
1050 values.1.push_normal(b_str);
1051 }
1052 if i + 1 < args1.len() {
1053 values.0.push_normal(", ");
1054 values.1.push_normal(", ");
1055 }
1056 }
1057 if args1.len() > 0 {
1058 values.0.push_normal(">");
1059 values.1.push_normal(">");
1060 }
1061 values
1062 }
1063
1064 pub fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagStyledString, DiagStyledString) {
1067 debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind());
1068
1069 let recurse = |t1, t2, values: &mut (DiagStyledString, DiagStyledString)| {
1071 let (x1, x2) = self.cmp(t1, t2);
1072 (values.0).0.extend(x1.0);
1073 (values.1).0.extend(x2.0);
1074 };
1075
1076 fn fmt_region<'tcx>(region: ty::Region<'tcx>) -> String {
1077 let mut r = region.to_string();
1078 if r == "'_" {
1079 r.clear();
1080 } else {
1081 r.push(' ');
1082 }
1083 format!("&{r}")
1084 }
1085
1086 fn push_ref<'tcx>(
1087 region: ty::Region<'tcx>,
1088 mutbl: hir::Mutability,
1089 s: &mut DiagStyledString,
1090 ) {
1091 s.push_highlighted(fmt_region(region));
1092 s.push_highlighted(mutbl.prefix_str());
1093 }
1094
1095 fn maybe_highlight<T: Eq + ToString>(
1096 t1: T,
1097 t2: T,
1098 (buf1, buf2): &mut (DiagStyledString, DiagStyledString),
1099 tcx: TyCtxt<'_>,
1100 ) {
1101 let highlight = t1 != t2;
1102 let (t1, t2) = if highlight || tcx.sess.opts.verbose {
1103 (t1.to_string(), t2.to_string())
1104 } else {
1105 ("_".into(), "_".into())
1107 };
1108 buf1.push(t1, highlight);
1109 buf2.push(t2, highlight);
1110 }
1111
1112 fn cmp_ty_refs<'tcx>(
1113 r1: ty::Region<'tcx>,
1114 mut1: hir::Mutability,
1115 r2: ty::Region<'tcx>,
1116 mut2: hir::Mutability,
1117 ss: &mut (DiagStyledString, DiagStyledString),
1118 ) {
1119 let (r1, r2) = (fmt_region(r1), fmt_region(r2));
1120 if r1 != r2 {
1121 ss.0.push_highlighted(r1);
1122 ss.1.push_highlighted(r2);
1123 } else {
1124 ss.0.push_normal(r1);
1125 ss.1.push_normal(r2);
1126 }
1127
1128 if mut1 != mut2 {
1129 ss.0.push_highlighted(mut1.prefix_str());
1130 ss.1.push_highlighted(mut2.prefix_str());
1131 } else {
1132 ss.0.push_normal(mut1.prefix_str());
1133 ss.1.push_normal(mut2.prefix_str());
1134 }
1135 }
1136
1137 match (t1.kind(), t2.kind()) {
1139 (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => {
1140 let did1 = def1.did();
1141 let did2 = def2.did();
1142
1143 let generics1 = self.tcx.generics_of(did1);
1144 let generics2 = self.tcx.generics_of(did2);
1145
1146 let non_default_after_default = generics1
1147 .check_concrete_type_after_default(self.tcx, sub1)
1148 || generics2.check_concrete_type_after_default(self.tcx, sub2);
1149 let sub_no_defaults_1 = if non_default_after_default {
1150 generics1.own_args(sub1)
1151 } else {
1152 generics1.own_args_no_defaults(self.tcx, sub1)
1153 };
1154 let sub_no_defaults_2 = if non_default_after_default {
1155 generics2.own_args(sub2)
1156 } else {
1157 generics2.own_args_no_defaults(self.tcx, sub2)
1158 };
1159 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1160 let path1 = self.tcx.def_path_str(did1);
1161 let path2 = self.tcx.def_path_str(did2);
1162 if did1 == did2 {
1163 values.0.push_normal(path1);
1172 values.1.push_normal(path2);
1173
1174 let len1 = sub_no_defaults_1.len();
1177 let len2 = sub_no_defaults_2.len();
1178 let common_len = cmp::min(len1, len2);
1179 let remainder1 = &sub1[common_len..];
1180 let remainder2 = &sub2[common_len..];
1181 let common_default_params =
1182 iter::zip(remainder1.iter().rev(), remainder2.iter().rev())
1183 .filter(|(a, b)| a == b)
1184 .count();
1185 let len = sub1.len() - common_default_params;
1186
1187 if len > 0 {
1189 values.0.push_normal("<");
1190 values.1.push_normal("<");
1191 }
1192
1193 fn lifetime_display(lifetime: Region<'_>) -> String {
1194 let s = lifetime.to_string();
1195 if s.is_empty() { "'_".to_string() } else { s }
1196 }
1197
1198 for (i, (arg1, arg2)) in sub1.iter().zip(sub2).enumerate().take(len) {
1199 self.push_comma(&mut values.0, &mut values.1, i);
1200 match arg1.kind() {
1201 ty::GenericArgKind::Lifetime(l1) => {
1218 let l1_str = lifetime_display(l1);
1219 let l2 = arg2.expect_region();
1220 let l2_str = lifetime_display(l2);
1221 if l1 != l2 {
1222 values.0.push_highlighted(l1_str);
1223 values.1.push_highlighted(l2_str);
1224 } else if l1.is_bound() || self.tcx.sess.opts.verbose {
1225 values.0.push_normal(l1_str);
1226 values.1.push_normal(l2_str);
1227 } else {
1228 values.0.push_normal("'_");
1229 values.1.push_normal("'_");
1230 }
1231 }
1232 ty::GenericArgKind::Type(ta1) => {
1233 let ta2 = arg2.expect_ty();
1234 if ta1 == ta2 && !self.tcx.sess.opts.verbose {
1235 values.0.push_normal("_");
1236 values.1.push_normal("_");
1237 } else {
1238 recurse(ta1, ta2, &mut values);
1239 }
1240 }
1241 ty::GenericArgKind::Const(ca1) => {
1251 let ca2 = arg2.expect_const();
1252 maybe_highlight(ca1, ca2, &mut values, self.tcx);
1253 }
1254 }
1255 }
1256
1257 if len > 0 {
1260 values.0.push_normal(">");
1261 values.1.push_normal(">");
1262 }
1263 values
1264 } else {
1265 if self.cmp_type_arg(
1271 &mut values.0,
1272 &mut values.1,
1273 path1.clone(),
1274 sub_no_defaults_1,
1275 path2.clone(),
1276 t2,
1277 ) {
1278 return values;
1279 }
1280 if self.cmp_type_arg(
1286 &mut values.1,
1287 &mut values.0,
1288 path2,
1289 sub_no_defaults_2,
1290 path1,
1291 t1,
1292 ) {
1293 return values;
1294 }
1295
1296 let t1_str = t1.to_string();
1303 let t2_str = t2.to_string();
1304 let min_len = t1_str.len().min(t2_str.len());
1305
1306 const SEPARATOR: &str = "::";
1307 let separator_len = SEPARATOR.len();
1308 let split_idx: usize =
1309 iter::zip(t1_str.split(SEPARATOR), t2_str.split(SEPARATOR))
1310 .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str)
1311 .map(|(mod_str, _)| mod_str.len() + separator_len)
1312 .sum();
1313
1314 debug!(?separator_len, ?split_idx, ?min_len, "cmp");
1315
1316 if split_idx >= min_len {
1317 (
1319 DiagStyledString::highlighted(t1_str),
1320 DiagStyledString::highlighted(t2_str),
1321 )
1322 } else {
1323 let (common, uniq1) = t1_str.split_at(split_idx);
1324 let (_, uniq2) = t2_str.split_at(split_idx);
1325 debug!(?common, ?uniq1, ?uniq2, "cmp");
1326
1327 values.0.push_normal(common);
1328 values.0.push_highlighted(uniq1);
1329 values.1.push_normal(common);
1330 values.1.push_highlighted(uniq2);
1331
1332 values
1333 }
1334 }
1335 }
1336
1337 (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) => {
1339 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1340 cmp_ty_refs(r1, mutbl1, r2, mutbl2, &mut values);
1341 recurse(ref_ty1, ref_ty2, &mut values);
1342 values
1343 }
1344 (&ty::Ref(r1, ref_ty1, mutbl1), _) => {
1346 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1347 push_ref(r1, mutbl1, &mut values.0);
1348 recurse(ref_ty1, t2, &mut values);
1349 values
1350 }
1351 (_, &ty::Ref(r2, ref_ty2, mutbl2)) => {
1352 let mut values = (DiagStyledString::new(), DiagStyledString::new());
1353 push_ref(r2, mutbl2, &mut values.1);
1354 recurse(t1, ref_ty2, &mut values);
1355 values
1356 }
1357
1358 (&ty::Tuple(args1), &ty::Tuple(args2)) if args1.len() == args2.len() => {
1360 let mut values = (DiagStyledString::normal("("), DiagStyledString::normal("("));
1361 let len = args1.len();
1362 for (i, (left, right)) in args1.iter().zip(args2).enumerate() {
1363 self.push_comma(&mut values.0, &mut values.1, i);
1364 recurse(left, right, &mut values);
1365 }
1366 if len == 1 {
1367 values.0.push_normal(",");
1369 values.1.push_normal(",");
1370 }
1371 values.0.push_normal(")");
1372 values.1.push_normal(")");
1373 values
1374 }
1375
1376 (ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
1377 let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
1378 let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
1379 self.cmp_fn_sig(
1380 &sig1,
1381 Some((*did1, Some(args1))),
1382 &sig2,
1383 Some((*did2, Some(args2))),
1384 )
1385 }
1386
1387 (ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
1388 let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
1389 self.cmp_fn_sig(&sig1, Some((*did1, Some(args1))), &sig_tys2.with(*hdr2), None)
1390 }
1391
1392 (ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
1393 let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
1394 self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, Some(args2))))
1395 }
1396
1397 (ty::FnPtr(sig_tys1, hdr1), ty::FnPtr(sig_tys2, hdr2)) => {
1398 self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig_tys2.with(*hdr2), None)
1399 }
1400
1401 _ => {
1402 let mut strs = (DiagStyledString::new(), DiagStyledString::new());
1403 maybe_highlight(t1, t2, &mut strs, self.tcx);
1404 strs
1405 }
1406 }
1407 }
1408
1409 #[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))]
1419 pub fn note_type_err(
1420 &self,
1421 diag: &mut Diag<'_>,
1422 cause: &ObligationCause<'tcx>,
1423 secondary_span: Option<(Span, Cow<'static, str>, bool)>,
1424 mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
1425 terr: TypeError<'tcx>,
1426 prefer_label: bool,
1427 override_span: Option<Span>,
1428 ) {
1429 let span = override_span.unwrap_or(cause.span);
1434 if let TypeError::CyclicTy(_) = terr {
1437 values = None;
1438 }
1439 struct OpaqueTypesVisitor<'tcx> {
1440 types: FxIndexMap<TyCategory, FxIndexSet<Span>>,
1441 expected: FxIndexMap<TyCategory, FxIndexSet<Span>>,
1442 found: FxIndexMap<TyCategory, FxIndexSet<Span>>,
1443 ignore_span: Span,
1444 tcx: TyCtxt<'tcx>,
1445 }
1446
1447 impl<'tcx> OpaqueTypesVisitor<'tcx> {
1448 fn visit_expected_found(
1449 tcx: TyCtxt<'tcx>,
1450 expected: impl TypeVisitable<TyCtxt<'tcx>>,
1451 found: impl TypeVisitable<TyCtxt<'tcx>>,
1452 ignore_span: Span,
1453 ) -> Self {
1454 let mut types_visitor = OpaqueTypesVisitor {
1455 types: Default::default(),
1456 expected: Default::default(),
1457 found: Default::default(),
1458 ignore_span,
1459 tcx,
1460 };
1461 expected.visit_with(&mut types_visitor);
1465 std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types);
1466 found.visit_with(&mut types_visitor);
1467 std::mem::swap(&mut types_visitor.found, &mut types_visitor.types);
1468 types_visitor
1469 }
1470
1471 fn report(&self, err: &mut Diag<'_>) {
1472 self.add_labels_for_types(err, "expected", &self.expected);
1473 self.add_labels_for_types(err, "found", &self.found);
1474 }
1475
1476 fn add_labels_for_types(
1477 &self,
1478 err: &mut Diag<'_>,
1479 target: &str,
1480 types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
1481 ) {
1482 for (kind, values) in types.iter() {
1483 let count = values.len();
1484 for &sp in values {
1485 err.span_label(
1486 sp,
1487 format!(
1488 "{}{} {:#}{}",
1489 if count == 1 { "the " } else { "one of the " },
1490 target,
1491 kind,
1492 pluralize!(count),
1493 ),
1494 );
1495 }
1496 }
1497 }
1498 }
1499
1500 impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for OpaqueTypesVisitor<'tcx> {
1501 fn visit_ty(&mut self, t: Ty<'tcx>) {
1502 if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
1503 let span = self.tcx.def_span(def_id);
1504 if !self.ignore_span.overlaps(span)
1520 && !span.is_desugaring(DesugaringKind::Async)
1521 {
1522 self.types.entry(kind).or_default().insert(span);
1523 }
1524 }
1525 t.super_visit_with(self)
1526 }
1527 }
1528
1529 debug!("note_type_err(diag={:?})", diag);
1530 enum Mismatch<'a> {
1531 Variable(ty::error::ExpectedFound<Ty<'a>>),
1532 Fixed(&'static str),
1533 }
1534 let (expected_found, exp_found, is_simple_error, values, param_env) = match values {
1535 None => (None, Mismatch::Fixed("type"), false, None, None),
1536 Some(ty::ParamEnvAnd { param_env, value: values }) => {
1537 let mut values = self.resolve_vars_if_possible(values);
1538 if self.next_trait_solver() {
1539 values = deeply_normalize_for_diagnostics(self, param_env, values);
1540 }
1541 let (is_simple_error, exp_found) = match values {
1542 ValuePairs::Terms(ExpectedFound { expected, found }) => {
1543 match (expected.kind(), found.kind()) {
1544 (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
1545 let is_simple_err =
1546 expected.is_simple_text() && found.is_simple_text();
1547 OpaqueTypesVisitor::visit_expected_found(
1548 self.tcx, expected, found, span,
1549 )
1550 .report(diag);
1551
1552 (
1553 is_simple_err,
1554 Mismatch::Variable(ExpectedFound { expected, found }),
1555 )
1556 }
1557 (ty::TermKind::Const(_), ty::TermKind::Const(_)) => {
1558 (false, Mismatch::Fixed("constant"))
1559 }
1560 _ => (false, Mismatch::Fixed("type")),
1561 }
1562 }
1563 ValuePairs::PolySigs(ExpectedFound { expected, found }) => {
1564 OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
1565 .report(diag);
1566 (false, Mismatch::Fixed("signature"))
1567 }
1568 ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
1569 ValuePairs::Aliases(ExpectedFound { expected, .. }) => {
1570 (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id)))
1571 }
1572 ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")),
1573 ValuePairs::ExistentialTraitRef(_) => {
1574 (false, Mismatch::Fixed("existential trait ref"))
1575 }
1576 ValuePairs::ExistentialProjection(_) => {
1577 (false, Mismatch::Fixed("existential projection"))
1578 }
1579 };
1580 let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else {
1581 diag.downgrade_to_delayed_bug();
1585 return;
1586 };
1587 (Some(vals), exp_found, is_simple_error, Some(values), Some(param_env))
1588 }
1589 };
1590
1591 let mut label_or_note = |span: Span, msg: Cow<'static, str>| {
1592 if (prefer_label && is_simple_error) || &[span] == diag.span.primary_spans() {
1593 diag.span_label(span, msg);
1594 } else {
1595 diag.span_note(span, msg);
1596 }
1597 };
1598 if let Some((secondary_span, secondary_msg, swap_secondary_and_primary)) = secondary_span {
1599 if swap_secondary_and_primary {
1600 let terr = if let Some(infer::ValuePairs::Terms(ExpectedFound {
1601 expected, ..
1602 })) = values
1603 {
1604 Cow::from(format!("expected this to be `{expected}`"))
1605 } else {
1606 terr.to_string(self.tcx)
1607 };
1608 label_or_note(secondary_span, terr);
1609 label_or_note(span, secondary_msg);
1610 } else {
1611 label_or_note(span, terr.to_string(self.tcx));
1612 label_or_note(secondary_span, secondary_msg);
1613 }
1614 } else if let Some(values) = values
1615 && let Some((e, f)) = values.ty()
1616 && let TypeError::ArgumentSorts(..) | TypeError::Sorts(_) = terr
1617 {
1618 let e = self.tcx.erase_regions(e);
1619 let f = self.tcx.erase_regions(f);
1620 let expected = with_forced_trimmed_paths!(e.sort_string(self.tcx));
1621 let found = with_forced_trimmed_paths!(f.sort_string(self.tcx));
1622 if expected == found {
1623 label_or_note(span, terr.to_string(self.tcx));
1624 } else {
1625 label_or_note(span, Cow::from(format!("expected {expected}, found {found}")));
1626 }
1627 } else {
1628 label_or_note(span, terr.to_string(self.tcx));
1629 }
1630
1631 if self.check_and_note_conflicting_crates(diag, terr) {
1632 return;
1633 }
1634
1635 if let Some((expected, found)) = expected_found {
1636 let (expected_label, found_label, exp_found) = match exp_found {
1637 Mismatch::Variable(ef) => (
1638 ef.expected.prefix_string(self.tcx),
1639 ef.found.prefix_string(self.tcx),
1640 Some(ef),
1641 ),
1642 Mismatch::Fixed(s) => (s.into(), s.into(), None),
1643 };
1644
1645 enum Similar<'tcx> {
1646 Adts { expected: ty::AdtDef<'tcx>, found: ty::AdtDef<'tcx> },
1647 PrimitiveFound { expected: ty::AdtDef<'tcx>, found: Ty<'tcx> },
1648 PrimitiveExpected { expected: Ty<'tcx>, found: ty::AdtDef<'tcx> },
1649 }
1650
1651 let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| {
1652 if let ty::Adt(expected, _) = expected.kind()
1653 && let Some(primitive) = found.primitive_symbol()
1654 {
1655 let path = self.tcx.def_path(expected.did()).data;
1656 let name = path.last().unwrap().data.get_opt_name();
1657 if name == Some(primitive) {
1658 return Some(Similar::PrimitiveFound { expected: *expected, found });
1659 }
1660 } else if let Some(primitive) = expected.primitive_symbol()
1661 && let ty::Adt(found, _) = found.kind()
1662 {
1663 let path = self.tcx.def_path(found.did()).data;
1664 let name = path.last().unwrap().data.get_opt_name();
1665 if name == Some(primitive) {
1666 return Some(Similar::PrimitiveExpected { expected, found: *found });
1667 }
1668 } else if let ty::Adt(expected, _) = expected.kind()
1669 && let ty::Adt(found, _) = found.kind()
1670 {
1671 if !expected.did().is_local() && expected.did().krate == found.did().krate {
1672 return None;
1676 }
1677 let f_path = self.tcx.def_path(found.did()).data;
1678 let e_path = self.tcx.def_path(expected.did()).data;
1679
1680 if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last())
1681 && e_last == f_last
1682 {
1683 return Some(Similar::Adts { expected: *expected, found: *found });
1684 }
1685 }
1686 None
1687 };
1688
1689 match terr {
1690 TypeError::Sorts(values) if let Some(s) = similarity(values) => {
1692 let diagnose_primitive =
1693 |prim: Ty<'tcx>, shadow: Ty<'tcx>, defid: DefId, diag: &mut Diag<'_>| {
1694 let name = shadow.sort_string(self.tcx);
1695 diag.note(format!(
1696 "`{prim}` and {name} have similar names, but are actually distinct types"
1697 ));
1698 diag.note(format!(
1699 "one `{prim}` is a primitive defined by the language",
1700 ));
1701 let def_span = self.tcx.def_span(defid);
1702 let msg = if defid.is_local() {
1703 format!("the other {name} is defined in the current crate")
1704 } else {
1705 let crate_name = self.tcx.crate_name(defid.krate);
1706 format!("the other {name} is defined in crate `{crate_name}`")
1707 };
1708 diag.span_note(def_span, msg);
1709 };
1710
1711 let diagnose_adts =
1712 |expected_adt: ty::AdtDef<'tcx>,
1713 found_adt: ty::AdtDef<'tcx>,
1714 diag: &mut Diag<'_>| {
1715 let found_name = values.found.sort_string(self.tcx);
1716 let expected_name = values.expected.sort_string(self.tcx);
1717
1718 let found_defid = found_adt.did();
1719 let expected_defid = expected_adt.did();
1720
1721 diag.note(format!("{found_name} and {expected_name} have similar names, but are actually distinct types"));
1722 for (defid, name) in
1723 [(found_defid, found_name), (expected_defid, expected_name)]
1724 {
1725 let def_span = self.tcx.def_span(defid);
1726
1727 let msg = if found_defid.is_local() && expected_defid.is_local() {
1728 let module = self
1729 .tcx
1730 .parent_module_from_def_id(defid.expect_local())
1731 .to_def_id();
1732 let module_name =
1733 self.tcx.def_path(module).to_string_no_crate_verbose();
1734 format!(
1735 "{name} is defined in module `crate{module_name}` of the current crate"
1736 )
1737 } else if defid.is_local() {
1738 format!("{name} is defined in the current crate")
1739 } else {
1740 let crate_name = self.tcx.crate_name(defid.krate);
1741 format!("{name} is defined in crate `{crate_name}`")
1742 };
1743 diag.span_note(def_span, msg);
1744 }
1745 };
1746
1747 match s {
1748 Similar::Adts { expected, found } => diagnose_adts(expected, found, diag),
1749 Similar::PrimitiveFound { expected, found: prim } => {
1750 diagnose_primitive(prim, values.expected, expected.did(), diag)
1751 }
1752 Similar::PrimitiveExpected { expected: prim, found } => {
1753 diagnose_primitive(prim, values.found, found.did(), diag)
1754 }
1755 }
1756 }
1757 TypeError::Sorts(values) => {
1758 let extra = expected == found
1759 && values.expected.sort_string(self.tcx)
1763 != values.found.sort_string(self.tcx);
1764 let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
1765 (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => {
1766 let sm = self.tcx.sess.source_map();
1767 let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
1768 DiagStyledString::normal(format!(
1769 " (opaque type at <{}:{}:{}>)",
1770 sm.filename_for_diagnostics(&pos.file.name),
1771 pos.line,
1772 pos.col.to_usize() + 1,
1773 ))
1774 }
1775 (true, ty::Alias(ty::Projection, proj))
1776 if self.tcx.is_impl_trait_in_trait(proj.def_id) =>
1777 {
1778 let sm = self.tcx.sess.source_map();
1779 let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo());
1780 DiagStyledString::normal(format!(
1781 " (trait associated opaque type at <{}:{}:{}>)",
1782 sm.filename_for_diagnostics(&pos.file.name),
1783 pos.line,
1784 pos.col.to_usize() + 1,
1785 ))
1786 }
1787 (true, _) => {
1788 let mut s = DiagStyledString::normal(" (");
1789 s.push_highlighted(ty.sort_string(self.tcx));
1790 s.push_normal(")");
1791 s
1792 }
1793 (false, _) => DiagStyledString::normal(""),
1794 };
1795 if !(values.expected.is_simple_text() && values.found.is_simple_text())
1796 || (exp_found.is_some_and(|ef| {
1797 if !ef.expected.is_ty_or_numeric_infer() {
1802 ef.expected != values.expected
1803 } else if !ef.found.is_ty_or_numeric_infer() {
1804 ef.found != values.found
1805 } else {
1806 false
1807 }
1808 }))
1809 {
1810 if let Some(ExpectedFound { found: found_ty, .. }) = exp_found
1811 && !self.tcx.ty_is_opaque_future(found_ty)
1812 {
1813 diag.note_expected_found_extra(
1820 &expected_label,
1821 expected,
1822 &found_label,
1823 found,
1824 sort_string(values.expected),
1825 sort_string(values.found),
1826 );
1827 }
1828 }
1829 }
1830 _ => {
1831 debug!(
1832 "note_type_err: exp_found={:?}, expected={:?} found={:?}",
1833 exp_found, expected, found
1834 );
1835 if !is_simple_error || terr.must_include_note() {
1836 diag.note_expected_found(&expected_label, expected, &found_label, found);
1837
1838 if let Some(ty::Closure(_, args)) =
1839 exp_found.map(|expected_type_found| expected_type_found.found.kind())
1840 {
1841 diag.highlighted_note(vec![
1842 StringPart::normal("closure has signature: `"),
1843 StringPart::highlighted(
1844 self.tcx
1845 .signature_unclosure(
1846 args.as_closure().sig(),
1847 rustc_hir::Safety::Safe,
1848 )
1849 .to_string(),
1850 ),
1851 StringPart::normal("`"),
1852 ]);
1853 }
1854 }
1855 }
1856 }
1857 }
1858 let exp_found = match exp_found {
1859 Mismatch::Variable(exp_found) => Some(exp_found),
1860 Mismatch::Fixed(_) => None,
1861 };
1862 let exp_found = match terr {
1863 ty::error::TypeError::Sorts(terr)
1865 if exp_found.is_some_and(|ef| terr.found == ef.found) =>
1866 {
1867 Some(terr)
1868 }
1869 _ => exp_found,
1870 };
1871 debug!("exp_found {:?} terr {:?} cause.code {:?}", exp_found, terr, cause.code());
1872 if let Some(exp_found) = exp_found {
1873 let should_suggest_fixes =
1874 if let ObligationCauseCode::Pattern { root_ty, .. } = cause.code() {
1875 self.same_type_modulo_infer(*root_ty, exp_found.expected)
1878 } else {
1879 true
1880 };
1881
1882 if should_suggest_fixes
1886 && !matches!(terr, TypeError::RegionsInsufficientlyPolymorphic(..))
1887 {
1888 self.suggest_tuple_pattern(cause, &exp_found, diag);
1889 self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
1890 self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
1891 self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
1892 self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
1893 }
1894 }
1895
1896 self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
1897 if let Some(exp_found) = exp_found
1898 && let exp_found = TypeError::Sorts(exp_found)
1899 && exp_found != terr
1900 {
1901 self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id());
1902 }
1903
1904 if let Some(ValuePairs::TraitRefs(exp_found)) = values
1905 && let ty::Closure(def_id, _) = exp_found.expected.self_ty().kind()
1906 && let Some(def_id) = def_id.as_local()
1907 && terr.involves_regions()
1908 {
1909 let span = self.tcx.def_span(def_id);
1910 diag.span_note(span, "this closure does not fulfill the lifetime requirements");
1911 self.suggest_for_all_lifetime_closure(
1912 span,
1913 self.tcx.hir_node_by_def_id(def_id),
1914 &exp_found,
1915 diag,
1916 );
1917 }
1918
1919 self.note_error_origin(diag, cause, exp_found, terr, param_env);
1922
1923 debug!(?diag);
1924 }
1925
1926 pub fn type_error_additional_suggestions(
1927 &self,
1928 trace: &TypeTrace<'tcx>,
1929 terr: TypeError<'tcx>,
1930 path: &mut Option<PathBuf>,
1931 ) -> Vec<TypeErrorAdditionalDiags> {
1932 let mut suggestions = Vec::new();
1933 let span = trace.cause.span;
1934 let values = self.resolve_vars_if_possible(trace.values);
1935 if let Some((expected, found)) = values.ty() {
1936 match (expected.kind(), found.kind()) {
1937 (ty::Tuple(_), ty::Tuple(_)) => {}
1938 (ty::Tuple(fields), _) => {
1942 suggestions.extend(self.suggest_wrap_to_build_a_tuple(span, found, fields))
1943 }
1944 (ty::Uint(ty::UintTy::U8), ty::Char) => {
1948 if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
1949 && let Some(code) =
1950 code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
1951 && !code.starts_with("\\u")
1953 && code.chars().next().is_some_and(|c| c.is_ascii())
1955 {
1956 suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral {
1957 span,
1958 code: escape_literal(code),
1959 })
1960 }
1961 }
1962 (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
1966 if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
1967 && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
1968 && code.chars().count() == 1
1969 {
1970 suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral {
1971 span,
1972 code: escape_literal(code),
1973 })
1974 }
1975 }
1976 (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
1979 if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
1980 && code.starts_with("'")
1981 && code.ends_with("'")
1982 {
1983 suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral {
1984 start: span.with_hi(span.lo() + BytePos(1)),
1985 end: span.with_lo(span.hi() - BytePos(1)),
1986 });
1987 }
1988 }
1989 (ty::Bool, ty::Tuple(list)) => {
1992 if list.len() == 0 {
1993 suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span));
1994 }
1995 }
1996 (ty::Array(_, _), ty::Array(_, _)) => {
1997 suggestions.extend(self.suggest_specify_actual_length(terr, trace, span))
1998 }
1999 _ => {}
2000 }
2001 }
2002 let code = trace.cause.code();
2003 if let &(ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
2004 source,
2005 ..
2006 })
2007 | ObligationCauseCode::BlockTailExpression(.., source)) = code
2008 && let hir::MatchSource::TryDesugar(_) = source
2009 && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path)
2010 {
2011 suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
2012 found: found_ty.content(),
2013 expected: expected_ty.content(),
2014 });
2015 }
2016 suggestions
2017 }
2018
2019 fn suggest_specify_actual_length(
2020 &self,
2021 terr: TypeError<'tcx>,
2022 trace: &TypeTrace<'tcx>,
2023 span: Span,
2024 ) -> Option<TypeErrorAdditionalDiags> {
2025 let TypeError::ArraySize(sz) = terr else {
2026 return None;
2027 };
2028 let tykind = match self.tcx.hir_node_by_def_id(trace.cause.body_id) {
2029 hir::Node::Item(hir::Item {
2030 kind: hir::ItemKind::Fn { body: body_id, .. }, ..
2031 }) => {
2032 let body = self.tcx.hir_body(*body_id);
2033 struct LetVisitor {
2034 span: Span,
2035 }
2036 impl<'v> Visitor<'v> for LetVisitor {
2037 type Result = ControlFlow<&'v hir::TyKind<'v>>;
2038 fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
2039 if let hir::Stmt {
2042 kind:
2043 hir::StmtKind::Let(hir::LetStmt {
2044 init: Some(hir::Expr { span: init_span, .. }),
2045 ty: Some(array_ty),
2046 ..
2047 }),
2048 ..
2049 } = s
2050 && init_span == &self.span
2051 {
2052 ControlFlow::Break(&array_ty.peel_refs().kind)
2053 } else {
2054 ControlFlow::Continue(())
2055 }
2056 }
2057 }
2058 LetVisitor { span }.visit_body(body).break_value()
2059 }
2060 hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(_, _, ty, _), .. }) => {
2061 Some(&ty.peel_refs().kind)
2062 }
2063 _ => None,
2064 };
2065 if let Some(tykind) = tykind
2066 && let hir::TyKind::Array(_, length_arg) = tykind
2067 && let Some(length_val) = sz.found.try_to_target_usize(self.tcx)
2068 {
2069 Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength {
2070 span: length_arg.span(),
2071 length: length_val,
2072 })
2073 } else {
2074 None
2075 }
2076 }
2077
2078 pub fn report_and_explain_type_error(
2079 &self,
2080 trace: TypeTrace<'tcx>,
2081 param_env: ty::ParamEnv<'tcx>,
2082 terr: TypeError<'tcx>,
2083 ) -> Diag<'a> {
2084 debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
2085
2086 let span = trace.cause.span;
2087 let mut path = None;
2088 let failure_code = trace.cause.as_failure_code_diag(
2089 terr,
2090 span,
2091 self.type_error_additional_suggestions(&trace, terr, &mut path),
2092 );
2093 let mut diag = self.dcx().create_err(failure_code);
2094 *diag.long_ty_path() = path;
2095 self.note_type_err(
2096 &mut diag,
2097 &trace.cause,
2098 None,
2099 Some(param_env.and(trace.values)),
2100 terr,
2101 false,
2102 None,
2103 );
2104 diag
2105 }
2106
2107 fn suggest_wrap_to_build_a_tuple(
2108 &self,
2109 span: Span,
2110 found: Ty<'tcx>,
2111 expected_fields: &List<Ty<'tcx>>,
2112 ) -> Option<TypeErrorAdditionalDiags> {
2113 let [expected_tup_elem] = expected_fields[..] else { return None };
2114
2115 if !self.same_type_modulo_infer(expected_tup_elem, found) {
2116 return None;
2117 }
2118
2119 let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) else { return None };
2120
2121 let sugg = if code.starts_with('(') && code.ends_with(')') {
2122 let before_close = span.hi() - BytePos::from_u32(1);
2123 TypeErrorAdditionalDiags::TupleOnlyComma {
2124 span: span.with_hi(before_close).shrink_to_hi(),
2125 }
2126 } else {
2127 TypeErrorAdditionalDiags::TupleAlsoParentheses {
2128 span_low: span.shrink_to_lo(),
2129 span_high: span.shrink_to_hi(),
2130 }
2131 };
2132 Some(sugg)
2133 }
2134
2135 fn values_str(
2136 &self,
2137 values: ValuePairs<'tcx>,
2138 cause: &ObligationCause<'tcx>,
2139 file: &mut Option<PathBuf>,
2140 ) -> Option<(DiagStyledString, DiagStyledString)> {
2141 match values {
2142 ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
2143 ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file),
2144 ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found),
2145 ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found),
2146 ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found),
2147 ValuePairs::TraitRefs(exp_found) => {
2148 let pretty_exp_found = ty::error::ExpectedFound {
2149 expected: exp_found.expected.print_trait_sugared(),
2150 found: exp_found.found.print_trait_sugared(),
2151 };
2152 match self.expected_found_str(pretty_exp_found) {
2153 Some((expected, found)) if expected == found => {
2154 self.expected_found_str(exp_found)
2155 }
2156 ret => ret,
2157 }
2158 }
2159 ValuePairs::PolySigs(exp_found) => {
2160 let exp_found = self.resolve_vars_if_possible(exp_found);
2161 if exp_found.references_error() {
2162 return None;
2163 }
2164 let (fn_def1, fn_def2) = if let ObligationCauseCode::CompareImplItem {
2165 impl_item_def_id,
2166 trait_item_def_id,
2167 ..
2168 } = *cause.code()
2169 {
2170 (Some((trait_item_def_id, None)), Some((impl_item_def_id.to_def_id(), None)))
2171 } else {
2172 (None, None)
2173 };
2174
2175 Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2))
2176 }
2177 }
2178 }
2179
2180 fn expected_found_str_term(
2181 &self,
2182 exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
2183 path: &mut Option<PathBuf>,
2184 ) -> Option<(DiagStyledString, DiagStyledString)> {
2185 let exp_found = self.resolve_vars_if_possible(exp_found);
2186 if exp_found.references_error() {
2187 return None;
2188 }
2189
2190 Some(match (exp_found.expected.kind(), exp_found.found.kind()) {
2191 (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => {
2192 let (mut exp, mut fnd) = self.cmp(expected, found);
2193 let len = self.tcx.sess().diagnostic_width() + 40;
2197 let exp_s = exp.content();
2198 let fnd_s = fnd.content();
2199 if exp_s.len() > len {
2200 let exp_s = self.tcx.short_string(expected, path);
2201 exp = DiagStyledString::highlighted(exp_s);
2202 }
2203 if fnd_s.len() > len {
2204 let fnd_s = self.tcx.short_string(found, path);
2205 fnd = DiagStyledString::highlighted(fnd_s);
2206 }
2207 (exp, fnd)
2208 }
2209 _ => (
2210 DiagStyledString::highlighted(exp_found.expected.to_string()),
2211 DiagStyledString::highlighted(exp_found.found.to_string()),
2212 ),
2213 })
2214 }
2215
2216 fn expected_found_str<T: fmt::Display + TypeFoldable<TyCtxt<'tcx>>>(
2218 &self,
2219 exp_found: ty::error::ExpectedFound<T>,
2220 ) -> Option<(DiagStyledString, DiagStyledString)> {
2221 let exp_found = self.resolve_vars_if_possible(exp_found);
2222 if exp_found.references_error() {
2223 return None;
2224 }
2225
2226 Some((
2227 DiagStyledString::highlighted(exp_found.expected.to_string()),
2228 DiagStyledString::highlighted(exp_found.found.to_string()),
2229 ))
2230 }
2231
2232 pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool {
2236 span.is_desugaring(DesugaringKind::QuestionMark)
2237 && self.tcx.is_diagnostic_item(sym::From, trait_def_id)
2238 }
2239
2240 pub fn same_type_modulo_infer<T: relate::Relate<TyCtxt<'tcx>>>(&self, a: T, b: T) -> bool {
2247 let (a, b) = self.resolve_vars_if_possible((a, b));
2248 SameTypeModuloInfer(self).relate(a, b).is_ok()
2249 }
2250}
2251
2252struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>);
2253
2254impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> {
2255 fn cx(&self) -> TyCtxt<'tcx> {
2256 self.0.tcx
2257 }
2258
2259 fn relate_with_variance<T: relate::Relate<TyCtxt<'tcx>>>(
2260 &mut self,
2261 _variance: ty::Variance,
2262 _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
2263 a: T,
2264 b: T,
2265 ) -> relate::RelateResult<'tcx, T> {
2266 self.relate(a, b)
2267 }
2268
2269 fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
2270 match (a.kind(), b.kind()) {
2271 (ty::Int(_) | ty::Uint(_), ty::Infer(ty::InferTy::IntVar(_)))
2272 | (
2273 ty::Infer(ty::InferTy::IntVar(_)),
2274 ty::Int(_) | ty::Uint(_) | ty::Infer(ty::InferTy::IntVar(_)),
2275 )
2276 | (ty::Float(_), ty::Infer(ty::InferTy::FloatVar(_)))
2277 | (
2278 ty::Infer(ty::InferTy::FloatVar(_)),
2279 ty::Float(_) | ty::Infer(ty::InferTy::FloatVar(_)),
2280 )
2281 | (ty::Infer(ty::InferTy::TyVar(_)), _)
2282 | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
2283 (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
2284 _ => relate::structurally_relate_tys(self, a, b),
2285 }
2286 }
2287
2288 fn regions(
2289 &mut self,
2290 a: ty::Region<'tcx>,
2291 b: ty::Region<'tcx>,
2292 ) -> RelateResult<'tcx, ty::Region<'tcx>> {
2293 if (a.is_var() && b.is_free())
2294 || (b.is_var() && a.is_free())
2295 || (a.is_var() && b.is_var())
2296 || a == b
2297 {
2298 Ok(a)
2299 } else {
2300 Err(TypeError::Mismatch)
2301 }
2302 }
2303
2304 fn binders<T>(
2305 &mut self,
2306 a: ty::Binder<'tcx, T>,
2307 b: ty::Binder<'tcx, T>,
2308 ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>>
2309 where
2310 T: relate::Relate<TyCtxt<'tcx>>,
2311 {
2312 Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
2313 }
2314
2315 fn consts(
2316 &mut self,
2317 a: ty::Const<'tcx>,
2318 _b: ty::Const<'tcx>,
2319 ) -> relate::RelateResult<'tcx, ty::Const<'tcx>> {
2320 Ok(a)
2323 }
2324}
2325
2326pub enum FailureCode {
2327 Error0317,
2328 Error0580,
2329 Error0308,
2330 Error0644,
2331}
2332
2333#[extension(pub trait ObligationCauseExt<'tcx>)]
2334impl<'tcx> ObligationCause<'tcx> {
2335 fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
2336 match self.code() {
2337 ObligationCauseCode::IfExpressionWithNoElse => FailureCode::Error0317,
2338 ObligationCauseCode::MainFunctionType => FailureCode::Error0580,
2339 ObligationCauseCode::CompareImplItem { .. }
2340 | ObligationCauseCode::MatchExpressionArm(_)
2341 | ObligationCauseCode::IfExpression { .. }
2342 | ObligationCauseCode::LetElse
2343 | ObligationCauseCode::LangFunctionType(_)
2344 | ObligationCauseCode::IntrinsicType
2345 | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
2346
2347 _ => match terr {
2351 TypeError::CyclicTy(ty)
2352 if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
2353 {
2354 FailureCode::Error0644
2355 }
2356 TypeError::IntrinsicCast | TypeError::ForceInlineCast => FailureCode::Error0308,
2357 _ => FailureCode::Error0308,
2358 },
2359 }
2360 }
2361 fn as_failure_code_diag(
2362 &self,
2363 terr: TypeError<'tcx>,
2364 span: Span,
2365 subdiags: Vec<TypeErrorAdditionalDiags>,
2366 ) -> ObligationCauseFailureCode {
2367 match self.code() {
2368 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
2369 ObligationCauseFailureCode::MethodCompat { span, subdiags }
2370 }
2371 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
2372 ObligationCauseFailureCode::TypeCompat { span, subdiags }
2373 }
2374 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
2375 ObligationCauseFailureCode::ConstCompat { span, subdiags }
2376 }
2377 ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
2378 ObligationCauseFailureCode::TryCompat { span, subdiags }
2379 }
2380 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
2381 source, ..
2382 }) => match source {
2383 hir::MatchSource::TryDesugar(_) => {
2384 ObligationCauseFailureCode::TryCompat { span, subdiags }
2385 }
2386 _ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
2387 },
2388 ObligationCauseCode::IfExpression { .. } => {
2389 ObligationCauseFailureCode::IfElseDifferent { span, subdiags }
2390 }
2391 ObligationCauseCode::IfExpressionWithNoElse => {
2392 ObligationCauseFailureCode::NoElse { span }
2393 }
2394 ObligationCauseCode::LetElse => {
2395 ObligationCauseFailureCode::NoDiverge { span, subdiags }
2396 }
2397 ObligationCauseCode::MainFunctionType => {
2398 ObligationCauseFailureCode::FnMainCorrectType { span }
2399 }
2400 &ObligationCauseCode::LangFunctionType(lang_item_name) => {
2401 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
2402 }
2403 ObligationCauseCode::IntrinsicType => {
2404 ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }
2405 }
2406 ObligationCauseCode::MethodReceiver => {
2407 ObligationCauseFailureCode::MethodCorrectType { span, subdiags }
2408 }
2409
2410 _ => match terr {
2414 TypeError::CyclicTy(ty)
2415 if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
2416 {
2417 ObligationCauseFailureCode::ClosureSelfref { span }
2418 }
2419 TypeError::ForceInlineCast => {
2420 ObligationCauseFailureCode::CantCoerceForceInline { span, subdiags }
2421 }
2422 TypeError::IntrinsicCast => {
2423 ObligationCauseFailureCode::CantCoerceIntrinsic { span, subdiags }
2424 }
2425 _ => ObligationCauseFailureCode::Generic { span, subdiags },
2426 },
2427 }
2428 }
2429
2430 fn as_requirement_str(&self) -> &'static str {
2431 match self.code() {
2432 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
2433 "method type is compatible with trait"
2434 }
2435 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
2436 "associated type is compatible with trait"
2437 }
2438 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
2439 "const is compatible with trait"
2440 }
2441 ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
2442 ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
2443 ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
2444 ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
2445 _ => "types are compatible",
2446 }
2447 }
2448}
2449
2450pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
2452
2453impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
2454 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
2455 let kind = match self.0.code() {
2456 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
2457 "method_compat"
2458 }
2459 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
2460 "type_compat"
2461 }
2462 ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
2463 "const_compat"
2464 }
2465 ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
2466 ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
2467 ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
2468 ObligationCauseCode::MethodReceiver => "method_correct_type",
2469 _ => "other",
2470 }
2471 .into();
2472 rustc_errors::DiagArgValue::Str(kind)
2473 }
2474}
2475
2476#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2479pub enum TyCategory {
2480 Closure,
2481 Opaque,
2482 OpaqueFuture,
2483 Coroutine(hir::CoroutineKind),
2484 Foreign,
2485}
2486
2487impl fmt::Display for TyCategory {
2488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2489 match self {
2490 Self::Closure => "closure".fmt(f),
2491 Self::Opaque => "opaque type".fmt(f),
2492 Self::OpaqueFuture => "future".fmt(f),
2493 Self::Coroutine(gk) => gk.fmt(f),
2494 Self::Foreign => "foreign type".fmt(f),
2495 }
2496 }
2497}
2498
2499impl TyCategory {
2500 pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
2501 match *ty.kind() {
2502 ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
2503 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
2504 let kind =
2505 if tcx.ty_is_opaque_future(ty) { Self::OpaqueFuture } else { Self::Opaque };
2506 Some((kind, def_id))
2507 }
2508 ty::Coroutine(def_id, ..) => {
2509 Some((Self::Coroutine(tcx.coroutine_kind(def_id).unwrap()), def_id))
2510 }
2511 ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
2512 _ => None,
2513 }
2514 }
2515}