1// ignore-tidy-filelength2use core::ops::ControlFlow;3use std::borrow::Cow;4use std::collections::hash_set;5use std::path::PathBuf;67use rustc_ast::ast::LitKind;8use rustc_ast::{LitIntType, TraitObjectSyntax};9use rustc_data_structures::fx::{FxHashMap, FxHashSet};10use rustc_data_structures::unord::UnordSet;11use rustc_errors::codes::*;12use rustc_errors::{13 Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions, msg,14 pluralize, struct_span_code_err,15};16use rustc_hir::attrs::diagnostic::CustomDiagnostic;17use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};18use rustc_hir::intravisit::Visitor;19use rustc_hir::{self as hir, LangItem, Node, find_attr};20use rustc_infer::infer::{InferOk, TypeTrace};21use rustc_infer::traits::ImplSource;22use rustc_infer::traits::solve::Goal;23use rustc_middle::traits::SignatureMismatchData;24use rustc_middle::traits::select::OverflowError;25use rustc_middle::ty::abstract_const::NotConstEvaluatable;26use rustc_middle::ty::error::{ExpectedFound, TypeError};27use rustc_middle::ty::print::{28 PrintPolyTraitPredicateExt, PrintPolyTraitRefExt as _, PrintTraitPredicateExt as _,29 PrintTraitRefExt as _, with_forced_trimmed_paths,30};31use rustc_middle::ty::{32 self, GenericArgKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,33 TypeVisitableExt, Unnormalized, Upcast,34};35use rustc_middle::{bug, span_bug};36use rustc_span::def_id::CrateNum;37use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym};38use tracing::{debug, instrument};3940use super::suggestions::get_explanation_based_on_obligation;41use super::{ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate};42use crate::error_reporting::TypeErrCtxt;43use crate::error_reporting::infer::TyCategory;44use crate::error_reporting::traits::report_dyn_incompatibility;45use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn};46use crate::infer::{self, InferCtxt, InferCtxtExt as _};47use crate::traits::query::evaluate_obligation::InferCtxtExt as _;48use crate::traits::{49 MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode,50 ObligationCtxt, PredicateObligation, SelectionContext, SelectionError, elaborate,51 specialization_graph,52};5354impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {55 /// The `root_obligation` parameter should be the `root_obligation` field56 /// from a `FulfillmentError`. If no `FulfillmentError` is available,57 /// then it should be the same as `obligation`.58 pub fn report_selection_error(59 &self,60 mut obligation: PredicateObligation<'tcx>,61 root_obligation: &PredicateObligation<'tcx>,62 error: &SelectionError<'tcx>,63 ) -> ErrorGuaranteed {64 let tcx = self.tcx;65 let mut span = obligation.cause.span;66 let mut long_ty_file = None;6768 let mut err = match *error {69 SelectionError::Unimplemented => {70 // If this obligation was generated as a result of well-formedness checking, see if we71 // can get a better error message by performing HIR-based well-formedness checking.72 if let ObligationCauseCode::WellFormed(Some(wf_loc)) =73 root_obligation.cause.code().peel_derives()74 && !obligation.predicate.has_non_region_infer()75 {76 if let Some(cause) = self77 .tcx78 .diagnostic_hir_wf_check((tcx.erase_and_anonymize_regions(obligation.predicate), *wf_loc))79 {80 obligation.cause = cause.clone();81 span = obligation.cause.span;82 }83 }8485 if let ObligationCauseCode::CompareImplItem {86 impl_item_def_id,87 trait_item_def_id,88 kind: _,89 } = *obligation.cause.code()90 {91 debug!("ObligationCauseCode::CompareImplItemObligation");92 return self.report_extra_impl_obligation(93 span,94 impl_item_def_id,95 trait_item_def_id,96 &format!("`{}`", obligation.predicate),97 )98 .emit()99 }100101 // Report a const-param specific error102 if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()103 {104 return self.report_const_param_not_wf(ty, &obligation).emit();105 }106107 let bound_predicate = obligation.predicate.kind();108 match bound_predicate.skip_binder() {109 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {110 let leaf_trait_predicate =111 self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate));112113 // Let's use the root obligation as the main message, when we care about the114 // most general case ("X doesn't implement Pattern<'_>") over the case that115 // happened to fail ("char doesn't implement Fn(&mut char)").116 //117 // We rely on a few heuristics to identify cases where this root118 // obligation is more important than the leaf obligation:119 let (main_trait_predicate, main_obligation) = if let ty::PredicateKind::Clause(120 ty::ClauseKind::Trait(root_pred)121 ) = root_obligation.predicate.kind().skip_binder()122 && !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()123 && !root_pred.self_ty().has_escaping_bound_vars()124 // The type of the leaf predicate is (roughly) the same as the type125 // from the root predicate, as a proxy for "we care about the root"126 // FIXME: this doesn't account for trivial derefs, but works as a first127 // approximation.128 && (129 // `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait`130 self.can_eq(131 obligation.param_env,132 leaf_trait_predicate.self_ty().skip_binder(),133 root_pred.self_ty().peel_refs(),134 )135 // `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator`136 || self.can_eq(137 obligation.param_env,138 leaf_trait_predicate.self_ty().skip_binder(),139 root_pred.self_ty(),140 )141 )142 // The leaf trait and the root trait are different, so as to avoid143 // talking about `&mut T: Trait` and instead remain talking about144 // `T: Trait` instead145 && leaf_trait_predicate.def_id() != root_pred.def_id()146 // The root trait is not `Unsize`, as to avoid talking about it in147 // `tests/ui/coercion/coerce-issue-49593-box-never.rs`.148 && !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize)149 {150 (151 self.resolve_vars_if_possible(152 root_obligation.predicate.kind().rebind(root_pred),153 ),154 root_obligation,155 )156 } else {157 (leaf_trait_predicate, &obligation)158 };159160 if let Some(guar) = self.emit_specialized_closure_kind_error(161 &obligation,162 leaf_trait_predicate,163 ) {164 return guar;165 }166167 if let Err(guar) = leaf_trait_predicate.error_reported()168 {169 return guar;170 }171 // Silence redundant errors on binding access that are already172 // reported on the binding definition (#56607).173 if let Err(guar) = self.fn_arg_obligation(&obligation) {174 return guar;175 }176 let (post_message, pre_message, type_def) = self177 .get_parent_trait_ref(obligation.cause.code())178 .map(|(t, s)| {179 let t = self.tcx.short_string(t, &mut long_ty_file);180 (181 format!(" in `{t}`"),182 format!("within `{t}`, "),183 s.map(|s| (format!("within this `{t}`"), s)),184 )185 })186 .unwrap_or_default();187188 let CustomDiagnostic {189 message,190 label,191 notes,192 parent_label,193 } = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file);194195 let have_alt_message = message.is_some() || label.is_some();196197 let message = message.unwrap_or_else(|| self.get_standard_error_message(198 main_trait_predicate,199 None,200 post_message,201 &mut long_ty_file,202 ));203 let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());204 let is_question_mark = matches!(205 root_obligation.cause.code().peel_derives(),206 ObligationCauseCode::QuestionMark,207 ) && !(208 self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id())209 || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try)210 );211 let is_unsize =212 self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);213 let question_mark_message = "the question mark operation (`?`) implicitly \214 performs a conversion on the error value \215 using the `From` trait";216 let (message, notes) = if is_try_conversion {217 let ty = self.tcx.short_string(218 main_trait_predicate.skip_binder().self_ty(),219 &mut long_ty_file,220 );221 // We have a `-> Result<_, E1>` and `gives_E2()?`.222 (223 format!("`?` couldn't convert the error to `{ty}`"),224 vec![question_mark_message.to_owned()],225 )226 } else if is_question_mark {227 let main_trait_predicate =228 self.tcx.short_string(main_trait_predicate, &mut long_ty_file);229 // Similar to the case above, but in this case the conversion is for a230 // trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when231 // `E: Error` isn't met.232 (233 format!(234 "`?` couldn't convert the error: `{main_trait_predicate}` is \235 not satisfied",236 ),237 vec![question_mark_message.to_owned()],238 )239 } else {240 (message, notes)241 };242243 let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(244 main_trait_predicate.def_id(),245 LangItem::TransmuteTrait,246 ) {247 // Recompute the safe transmute reason and use that for the error reporting248 let (report_obligation, report_pred) =249 self.select_transmute_obligation_for_reporting(250 &obligation,251 main_trait_predicate,252 root_obligation,253 );254255 match self.get_safe_transmute_error_and_reason(256 report_obligation,257 report_pred,258 span,259 ) {260 GetSafeTransmuteErrorAndReason::Silent => {261 return self.dcx().span_delayed_bug(262 span, "silent safe transmute error"263 );264 }265 GetSafeTransmuteErrorAndReason::Default => {266 (message, None)267 }268 GetSafeTransmuteErrorAndReason::Error {269 err_msg,270 safe_transmute_explanation,271 } => (err_msg, safe_transmute_explanation),272 }273 } else {274 (message, None)275 };276277 let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);278279 let trait_def_id = main_trait_predicate.def_id();280 let leaf_trait_def_id = leaf_trait_predicate.def_id();281 if (self.tcx.is_diagnostic_item(sym::From, trait_def_id)282 || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id))283 && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id)284 || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id))285 {286 let trait_ref = leaf_trait_predicate.skip_binder().trait_ref;287288 if let Some(found_ty) = trait_ref.args.get(1).and_then(|arg| arg.as_type())289 {290 let ty = main_trait_predicate.skip_binder().self_ty();291292 if let Some(cast_ty) = self.find_explicit_cast_type(293 obligation.param_env,294 found_ty,295 ty,296 ) {297 let found_ty_str =298 self.tcx.short_string(found_ty, &mut long_ty_file);299 let cast_ty_str =300 self.tcx.short_string(cast_ty, &mut long_ty_file);301302 err.help(format!(303 "consider casting the `{found_ty_str}` value to `{cast_ty_str}`",304 ));305 }306 }307 }308309310 *err.long_ty_path() = long_ty_file;311312 let mut suggested = false;313 let mut noted_missing_impl = false;314 if is_try_conversion || is_question_mark {315 (suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);316 }317318 suggested |= self.detect_negative_literal(319 &obligation,320 main_trait_predicate,321 &mut err,322 );323324 if let Some(ret_span) = self.return_type_span(&obligation) {325 if is_try_conversion {326 let ty = self.tcx.short_string(327 main_trait_predicate.skip_binder().self_ty(),328 err.long_ty_path(),329 );330 err.span_label(331 ret_span,332 format!("expected `{ty}` because of this"),333 );334 } else if is_question_mark {335 let main_trait_predicate =336 self.tcx.short_string(main_trait_predicate, err.long_ty_path());337 err.span_label(338 ret_span,339 format!("required `{main_trait_predicate}` because of this"),340 );341 }342 }343344 if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {345 self.add_tuple_trait_message(346 obligation.cause.code().peel_derives(),347 &mut err,348 );349 }350351 let explanation = get_explanation_based_on_obligation(352 self.tcx,353 &obligation,354 leaf_trait_predicate,355 pre_message,356 err.long_ty_path(),357 );358359 self.check_for_binding_assigned_block_without_tail_expression(360 &obligation,361 &mut err,362 leaf_trait_predicate,363 );364 self.suggest_add_result_as_return_type(365 &obligation,366 &mut err,367 leaf_trait_predicate,368 );369370 if self.suggest_add_reference_to_arg(371 &obligation,372 &mut err,373 leaf_trait_predicate,374 have_alt_message,375 ) {376 self.note_obligation_cause(&mut err, &obligation);377 return err.emit();378 }379380 let ty_span = match leaf_trait_predicate.self_ty().skip_binder().kind() {381 ty::Adt(def, _) if def.did().is_local()382 && !self.can_suggest_derive(&obligation, leaf_trait_predicate) => self.tcx.def_span(def.did()),383 _ => DUMMY_SP,384 };385 if let Some(s) = label {386 // If it has a custom `#[rustc_on_unimplemented]`387 // error message, let's display it as the label!388 err.span_label(span, s);389 if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_))390 // When the self type is a type param We don't need to "the trait391 // `std::marker::Sized` is not implemented for `T`" as we will point392 // at the type param with a label to suggest constraining it.393 && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id())394 // Don't say "the trait `FromResidual<Option<Infallible>>` is395 // not implemented for `Result<T, E>`".396 {397 // We do this just so that the JSON output's `help` position is the398 // right one and not `file.rs:1:1`. The render is the same.399 if ty_span == DUMMY_SP {400 err.help(explanation);401 } else {402 err.span_help(ty_span, explanation);403 }404 }405 } else if let Some(custom_explanation) = safe_transmute_explanation {406 err.span_label(span, custom_explanation);407 } else if (explanation.len() > self.tcx.sess.diagnostic_width() || ty_span != DUMMY_SP) && !noted_missing_impl {408 // Really long types don't look good as span labels, instead move it409 // to a `help`.410 err.span_label(span, "unsatisfied trait bound");411412 // We do this just so that the JSON output's `help` position is the413 // right one and not `file.rs:1:1`. The render is the same.414 if ty_span == DUMMY_SP {415 err.help(explanation);416 } else {417 err.span_help(ty_span, explanation);418 }419 } else {420 err.span_label(span, explanation);421 }422423 if let ObligationCauseCode::Coercion { source, target } =424 *obligation.cause.code().peel_derives()425 {426 if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) {427 self.suggest_borrowing_for_object_cast(428 &mut err,429 root_obligation,430 source,431 target,432 );433 }434 }435436 if let Some((msg, span)) = type_def {437 err.span_label(span, msg);438 }439 for note in notes {440 // If it has a custom `#[rustc_on_unimplemented]` note, let's display it441 err.note(note);442 }443 if let Some(s) = parent_label {444 let body = obligation.cause.body_id;445 err.span_label(tcx.def_span(body), s);446 }447448 self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_predicate);449 self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate);450 suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);451 suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);452 suggested |= self.suggest_cast_to_fn_pointer(453 &obligation,454 &mut err,455 leaf_trait_predicate,456 main_trait_predicate,457 span,458 );459 suggested |=460 self.suggest_remove_reference(&obligation, &mut err, leaf_trait_predicate);461 suggested |= self.suggest_semicolon_removal(462 &obligation,463 &mut err,464 span,465 leaf_trait_predicate,466 );467 self.note_different_trait_with_same_name(&mut err, &obligation, leaf_trait_predicate);468 self.note_adt_version_mismatch(&mut err, leaf_trait_predicate);469 self.suggest_remove_await(&obligation, &mut err);470 self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);471472 if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Try) {473 self.suggest_await_before_try(474 &mut err,475 &obligation,476 leaf_trait_predicate,477 span,478 );479 }480481 if self.suggest_add_clone_to_arg(&obligation, &mut err, leaf_trait_predicate) {482 return err.emit();483 }484485 if self.suggest_impl_trait(&mut err, &obligation, leaf_trait_predicate) {486 return err.emit();487 }488489 if is_unsize {490 // If the obligation failed due to a missing implementation of the491 // `Unsize` trait, give a pointer to why that might be the case492 err.note(493 "all implementations of `Unsize` are provided \494 automatically by the compiler, see \495 <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \496 for more information",497 );498 }499500 let is_fn_trait = tcx.is_fn_trait(leaf_trait_predicate.def_id());501 let is_target_feature_fn = if let ty::FnDef(def_id, _) =502 *leaf_trait_predicate.skip_binder().self_ty().kind()503 {504 !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()505 } else {506 false507 };508 if is_fn_trait && is_target_feature_fn {509 err.note(510 "`#[target_feature]` functions do not implement the `Fn` traits",511 );512 err.note(513 "try casting the function to a `fn` pointer or wrapping it in a closure",514 );515 }516517 self.note_field_shadowed_by_private_candidate_in_cause(518 &mut err,519 &obligation.cause,520 obligation.param_env,521 );522 self.try_to_add_help_message(523 &root_obligation,524 &obligation,525 leaf_trait_predicate,526 &mut err,527 span,528 is_fn_trait,529 suggested,530 );531532 // Changing mutability doesn't make a difference to whether we have533 // an `Unsize` impl (Fixes ICE in #71036)534 if !is_unsize {535 self.suggest_change_mut(&obligation, &mut err, leaf_trait_predicate);536 }537538 // If this error is due to `!: Trait` not implemented but `(): Trait` is539 // implemented, and fallback has occurred, then it could be due to a540 // variable that used to fallback to `()` now falling back to `!`. Issue a541 // note informing about the change in behaviour.542 if leaf_trait_predicate.skip_binder().self_ty().is_never()543 && self.diverging_fallback_has_occurred544 {545 let predicate = leaf_trait_predicate.map_bound(|trait_pred| {546 trait_pred.with_replaced_self_ty(self.tcx, tcx.types.unit)547 });548 let unit_obligation = obligation.with(tcx, predicate);549 if self.predicate_may_hold(&unit_obligation) {550 err.note(551 "this error might have been caused by changes to \552 Rust's type-inference algorithm (see issue #148922 \553 <https://github.com/rust-lang/rust/issues/148922> \554 for more information)",555 );556 err.help("you might have intended to use the type `()` here instead");557 }558 }559560 self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause);561 self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate);562563 // Return early if the trait is Debug or Display and the invocation564 // originates within a standard library macro, because the output565 // is otherwise overwhelming and unhelpful (see #85844 for an566 // example).567568 let in_std_macro =569 match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {570 Some(macro_def_id) => {571 let crate_name = tcx.crate_name(macro_def_id.krate);572 STDLIB_STABLE_CRATES.contains(&crate_name)573 }574 None => false,575 };576577 if in_std_macro578 && matches!(579 self.tcx.get_diagnostic_name(leaf_trait_predicate.def_id()),580 Some(sym::Debug | sym::Display)581 )582 {583 return err.emit();584 }585586 err587 }588589 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => {590 self.report_host_effect_error(bound_predicate.rebind(predicate), &obligation, span)591 }592593 ty::PredicateKind::Subtype(predicate) => {594 // Errors for Subtype predicates show up as595 // `FulfillmentErrorCode::SubtypeError`,596 // not selection error.597 span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)598 }599600 ty::PredicateKind::Coerce(predicate) => {601 // Errors for Coerce predicates show up as602 // `FulfillmentErrorCode::SubtypeError`,603 // not selection error.604 span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)605 }606607 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))608 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => {609 span_bug!(610 span,611 "outlives clauses should not error outside borrowck. obligation: `{:?}`",612 obligation613 )614 }615616 ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {617 span_bug!(618 span,619 "projection clauses should be implied from elsewhere. obligation: `{:?}`",620 obligation621 )622 }623624 ty::PredicateKind::DynCompatible(trait_def_id) => {625 let violations = self.tcx.dyn_compatibility_violations(trait_def_id);626 let mut err = report_dyn_incompatibility(627 self.tcx,628 span,629 None,630 trait_def_id,631 violations,632 );633 if let hir::Node::Item(item) =634 self.tcx.hir_node_by_def_id(obligation.cause.body_id)635 && let hir::ItemKind::Impl(impl_) = item.kind636 && let None = impl_.of_trait637 && let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind638 && let TraitObjectSyntax::None = tagged_ptr.tag()639 && impl_.self_ty.span.edition().at_least_rust_2021()640 {641 // Silence the dyn-compatibility error in favor of the missing dyn on642 // self type error. #131051.643 err.downgrade_to_delayed_bug();644 }645 err646 }647648 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {649 let ty = self.resolve_vars_if_possible(ty);650 if self.next_trait_solver() {651 if let Err(guar) = ty.error_reported() {652 return guar;653 }654655 // FIXME: we'll need a better message which takes into account656 // which bounds actually failed to hold.657 self.dcx().struct_span_err(658 span,659 format!("the type `{ty}` is not well-formed"),660 )661 } else {662 // WF predicates cannot themselves make663 // errors. They can only block due to664 // ambiguity; otherwise, they always665 // degenerate into other obligations666 // (which may fail).667 span_bug!(span, "WF predicate not satisfied for {:?}", ty);668 }669 }670671 // Errors for `ConstEvaluatable` predicates show up as672 // `SelectionError::ConstEvalFailure`,673 // not `Unimplemented`.674 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))675 // Errors for `ConstEquate` predicates show up as676 // `SelectionError::ConstEvalFailure`,677 // not `Unimplemented`.678 | ty::PredicateKind::ConstEquate { .. }679 // Ambiguous predicates should never error680 | ty::PredicateKind::Ambiguous681 // We never return Err when proving UnstableFeature goal.682 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature { .. })683 | ty::PredicateKind::NormalizesTo { .. }684 | ty::PredicateKind::AliasRelate { .. }685 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {686 span_bug!(687 span,688 "Unexpected `Predicate` for `SelectionError`: `{:?}`",689 obligation690 )691 }692 }693 }694695 SelectionError::SignatureMismatch(box SignatureMismatchData {696 found_trait_ref,697 expected_trait_ref,698 terr: terr @ TypeError::CyclicTy(_),699 }) => self.report_cyclic_signature_error(700 &obligation,701 found_trait_ref,702 expected_trait_ref,703 terr,704 ),705 SelectionError::SignatureMismatch(box SignatureMismatchData {706 found_trait_ref,707 expected_trait_ref,708 terr: _,709 }) => {710 match self.report_signature_mismatch_error(711 &obligation,712 span,713 found_trait_ref,714 expected_trait_ref,715 ) {716 Ok(err) => err,717 Err(guar) => return guar,718 }719 }720721 SelectionError::TraitDynIncompatible(did) => {722 let violations = self.tcx.dyn_compatibility_violations(did);723 report_dyn_incompatibility(self.tcx, span, None, did, violations)724 }725726 SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {727 bug!(728 "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`"729 )730 }731 SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {732 match self.report_not_const_evaluatable_error(&obligation, span) {733 Ok(err) => err,734 Err(guar) => return guar,735 }736 }737738 // Already reported in the query.739 SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar)) |740 // Already reported.741 SelectionError::Overflow(OverflowError::Error(guar)) => {742 self.set_tainted_by_errors(guar);743 return guar744 },745746 SelectionError::Overflow(_) => {747 bug!("overflow should be handled before the `report_selection_error` path");748 }749750 SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => {751 let expected_ty_str = self.tcx.short_string(expected_ty, &mut long_ty_file);752 let ct_str = self.tcx.short_string(ct, &mut long_ty_file);753 let mut diag = self.dcx().struct_span_err(754 span,755 format!("the constant `{ct_str}` is not of type `{expected_ty_str}`"),756 );757 diag.long_ty_path = long_ty_file;758759 self.note_type_err(760 &mut diag,761 &obligation.cause,762 None,763 None,764 TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)),765 false,766 None,767 );768 diag769 }770 };771772 self.note_obligation_cause(&mut err, &obligation);773 err.emit()774 }775}776777impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {778 pub(super) fn apply_do_not_recommend(779 &self,780 obligation: &mut PredicateObligation<'tcx>,781 ) -> bool {782 let mut base_cause = obligation.cause.code().clone();783 let mut applied_do_not_recommend = false;784 loop {785 if let ObligationCauseCode::ImplDerived(ref c) = base_cause {786 if self.tcx.do_not_recommend_impl(c.impl_or_alias_def_id) {787 let code = (*c.derived.parent_code).clone();788 obligation.cause.map_code(|_| code);789 obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);790 applied_do_not_recommend = true;791 }792 }793 if let Some(parent_cause) = base_cause.parent() {794 base_cause = parent_cause.clone();795 } else {796 break;797 }798 }799800 applied_do_not_recommend801 }802803 fn report_host_effect_error(804 &self,805 predicate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,806 main_obligation: &PredicateObligation<'tcx>,807 span: Span,808 ) -> Diag<'a> {809 // FIXME(const_trait_impl): We should recompute the predicate with `[const]`810 // if it's `const`, and if it holds, explain that this bound only811 // *conditionally* holds.812 let trait_ref = predicate.map_bound(|predicate| ty::TraitPredicate {813 trait_ref: predicate.trait_ref,814 polarity: ty::PredicatePolarity::Positive,815 });816 let mut file = None;817818 let err_msg = self.get_standard_error_message(819 trait_ref,820 Some(predicate.constness()),821 String::new(),822 &mut file,823 );824 let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);825 *diag.long_ty_path() = file;826 let obligation = Obligation::new(827 self.tcx,828 ObligationCause::dummy(),829 main_obligation.param_env,830 trait_ref,831 );832 if !self.predicate_may_hold(&obligation) {833 diag.downgrade_to_delayed_bug();834 }835836 if let Ok(Some(ImplSource::UserDefined(impl_data))) =837 self.enter_forall(trait_ref, |trait_ref_for_select| {838 SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref_for_select))839 })840 {841 let impl_did = impl_data.impl_def_id;842 let trait_did = trait_ref.def_id();843 let impl_span = self.tcx.def_span(impl_did);844 let trait_name = self.tcx.item_name(trait_did);845846 if self.tcx.is_const_trait(trait_did) && !self.tcx.is_const_trait_impl(impl_did) {847 if !impl_did.is_local() {848 diag.span_note(849 impl_span,850 format!("trait `{trait_name}` is implemented but not `const`"),851 );852 }853854 if let Some(command) =855 find_attr!(self.tcx, impl_did, OnConst {directive, ..} => directive.as_deref())856 .flatten()857 {858 let (_, format_args) = self.on_unimplemented_components(859 trait_ref,860 main_obligation,861 diag.long_ty_path(),862 );863 let CustomDiagnostic { message, label, notes, parent_label: _ } =864 command.eval(None, &format_args);865866 if let Some(message) = message {867 diag.primary_message(message);868 }869 if let Some(label) = label {870 diag.span_label(span, label);871 }872 for note in notes {873 diag.note(note);874 }875 } else if let Some(impl_did) = impl_did.as_local()876 && let item = self.tcx.hir_expect_item(impl_did)877 && let hir::ItemKind::Impl(item) = item.kind878 && let Some(of_trait) = item.of_trait879 {880 // trait is const, impl is local and not const881 diag.span_suggestion_verbose(882 of_trait.trait_ref.path.span.shrink_to_lo(),883 format!("make the `impl` of trait `{trait_name}` `const`"),884 "const ".to_string(),885 Applicability::MaybeIncorrect,886 );887 }888 }889 } else if let ty::Param(param) = trait_ref.self_ty().skip_binder().kind()890 && let Some(generics) =891 self.tcx.hir_node_by_def_id(main_obligation.cause.body_id).generics()892 {893 let constraint = ty::print::with_no_trimmed_paths!(format!(894 "[const] {}",895 trait_ref.map_bound(|tr| tr.trait_ref).print_trait_sugared(),896 ));897 ty::suggest_constraining_type_param(898 self.tcx,899 generics,900 &mut diag,901 param.name.as_str(),902 &constraint,903 Some(trait_ref.def_id()),904 None,905 );906 }907 diag908 }909910 fn emit_specialized_closure_kind_error(911 &self,912 obligation: &PredicateObligation<'tcx>,913 mut trait_pred: ty::PolyTraitPredicate<'tcx>,914 ) -> Option<ErrorGuaranteed> {915 // If we end up on an `AsyncFnKindHelper` goal, try to unwrap the parent916 // `AsyncFn*` goal.917 if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) {918 let mut code = obligation.cause.code();919 // Unwrap a `FunctionArg` cause, which has been refined from a derived obligation.920 if let ObligationCauseCode::FunctionArg { parent_code, .. } = code {921 code = &**parent_code;922 }923 // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.924 if let Some((_, Some(parent))) = code.parent_with_predicate() {925 trait_pred = parent;926 }927 }928929 let self_ty = trait_pred.self_ty().skip_binder();930931 let (expected_kind, trait_prefix) =932 if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {933 (expected_kind, "")934 } else if let Some(expected_kind) =935 self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id())936 {937 (expected_kind, "Async")938 } else {939 return None;940 };941942 let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() {943 ty::Closure(def_id, args) => {944 (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), false)945 }946 ty::CoroutineClosure(def_id, args) => (947 def_id,948 args.as_coroutine_closure()949 .coroutine_closure_sig()950 .map_bound(|sig| sig.tupled_inputs_ty),951 !args.as_coroutine_closure().tupled_upvars_ty().is_ty_var()952 && args.as_coroutine_closure().has_self_borrows(),953 ),954 _ => return None,955 };956957 let expected_args = trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));958959 // Verify that the arguments are compatible. If the signature is960 // mismatched, then we have a totally different error to report.961 if self.enter_forall(found_args, |found_args| {962 self.enter_forall(expected_args, |expected_args| {963 !self.can_eq(obligation.param_env, expected_args, found_args)964 })965 }) {966 return None;967 }968969 if let Some(found_kind) = self.closure_kind(self_ty)970 && !found_kind.extends(expected_kind)971 {972 let mut err = self.report_closure_error(973 &obligation,974 closure_def_id,975 found_kind,976 expected_kind,977 trait_prefix,978 );979 self.note_obligation_cause(&mut err, &obligation);980 return Some(err.emit());981 }982983 // If the closure has captures, then perhaps the reason that the trait984 // is unimplemented is because async closures don't implement `Fn`/`FnMut`985 // if they have captures.986 if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce {987 let coro_kind = match self988 .tcx989 .coroutine_kind(self.tcx.coroutine_for_closure(closure_def_id))990 .unwrap()991 {992 rustc_hir::CoroutineKind::Desugared(desugaring, _) => desugaring.to_string(),993 coro => coro.to_string(),994 };995 let mut err = self.dcx().create_err(CoroClosureNotFn {996 span: self.tcx.def_span(closure_def_id),997 kind: expected_kind.as_str(),998 coro_kind,999 });1000 self.note_obligation_cause(&mut err, &obligation);1001 return Some(err.emit());1002 }10031004 None1005 }10061007 fn fn_arg_obligation(1008 &self,1009 obligation: &PredicateObligation<'tcx>,1010 ) -> Result<(), ErrorGuaranteed> {1011 if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1012 && let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id)1013 && let arg = arg.peel_borrows()1014 && let hir::ExprKind::Path(hir::QPath::Resolved(1015 None,1016 hir::Path { res: hir::def::Res::Local(hir_id), .. },1017 )) = arg.kind1018 && let Node::Pat(pat) = self.tcx.hir_node(*hir_id)1019 && let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span)1020 && preds.contains(&obligation.as_goal())1021 {1022 return Err(*guar);1023 }1024 Ok(())1025 }10261027 fn detect_negative_literal(1028 &self,1029 obligation: &PredicateObligation<'tcx>,1030 trait_pred: ty::PolyTraitPredicate<'tcx>,1031 err: &mut Diag<'_>,1032 ) -> bool {1033 if let ObligationCauseCode::UnOp { hir_id, .. } = obligation.cause.code()1034 && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)1035 && let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = expr.kind1036 && let hir::ExprKind::Lit(lit) = inner.kind1037 && let LitKind::Int(_, LitIntType::Unsuffixed) = lit.node1038 {1039 err.span_suggestion_verbose(1040 lit.span.shrink_to_hi(),1041 "consider specifying an integer type that can be negative",1042 match trait_pred.skip_binder().self_ty().kind() {1043 ty::Uint(ty::UintTy::Usize) => "isize",1044 ty::Uint(ty::UintTy::U8) => "i8",1045 ty::Uint(ty::UintTy::U16) => "i16",1046 ty::Uint(ty::UintTy::U32) => "i32",1047 ty::Uint(ty::UintTy::U64) => "i64",1048 ty::Uint(ty::UintTy::U128) => "i128",1049 _ => "i64",1050 }1051 .to_string(),1052 Applicability::MaybeIncorrect,1053 );1054 return true;1055 }1056 false1057 }10581059 /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,1060 /// identify those method chain sub-expressions that could or could not have been annotated1061 /// with `?`.1062 fn try_conversion_context(1063 &self,1064 obligation: &PredicateObligation<'tcx>,1065 trait_pred: ty::PolyTraitPredicate<'tcx>,1066 err: &mut Diag<'_>,1067 ) -> (bool, bool) {1068 let span = obligation.cause.span;1069 /// Look for the (direct) sub-expr of `?`, and return it if it's a `.` method call.1070 struct FindMethodSubexprOfTry {1071 search_span: Span,1072 }1073 impl<'v> Visitor<'v> for FindMethodSubexprOfTry {1074 type Result = ControlFlow<&'v hir::Expr<'v>>;1075 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {1076 if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind1077 && ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span)1078 && let hir::ExprKind::Call(_, [expr, ..]) = expr.kind1079 {1080 ControlFlow::Break(expr)1081 } else {1082 hir::intravisit::walk_expr(self, ex)1083 }1084 }1085 }1086 let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);1087 let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return (false, false) };1088 let ControlFlow::Break(expr) =1089 (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id))1090 else {1091 return (false, false);1092 };1093 let Some(typeck) = &self.typeck_results else {1094 return (false, false);1095 };1096 let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else {1097 return (false, false);1098 };1099 let self_ty = trait_pred.skip_binder().self_ty();1100 let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());1101 let noted_missing_impl =1102 self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);11031104 let mut prev_ty = self.resolve_vars_if_possible(1105 typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),1106 );11071108 // We always look at the `E` type, because that's the only one affected by `?`. If the1109 // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole1110 // expression, after the `?` has "unwrapped" the `T`.1111 let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> {1112 let ty::Adt(def, args) = prev_ty.kind() else {1113 return None;1114 };1115 let Some(arg) = args.get(1) else {1116 return None;1117 };1118 if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {1119 return None;1120 }1121 arg.as_type()1122 };11231124 let mut suggested = false;1125 let mut chain = vec![];11261127 // The following logic is similar to `point_at_chain`, but that's focused on associated types1128 let mut expr = expr;1129 while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {1130 // Point at every method call in the chain with the `Result` type.1131 // let foo = bar.iter().map(mapper)?;1132 // ------ -----------1133 expr = rcvr_expr;1134 chain.push((span, prev_ty));11351136 let next_ty = self.resolve_vars_if_possible(1137 typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),1138 );11391140 let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| {1141 let ty::Adt(def, _) = ty.kind() else {1142 return false;1143 };1144 self.tcx.is_diagnostic_item(symbol, def.did())1145 };1146 // For each method in the chain, see if this is `Result::map_err` or1147 // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect1148 // trailing `;`.1149 if let Some(ty) = get_e_type(prev_ty)1150 && let Some(found_ty) = found_ty1151 // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%1152 // accurate check, but we are in the wrong stage to do that and looking for1153 // `Result::map_err` by checking the Self type and the path segment is enough.1154 // sym::ok_or_else1155 && (1156 ( // Result::map_err1157 path_segment.ident.name == sym::map_err1158 && is_diagnostic_item(sym::Result, next_ty)1159 ) || ( // Option::ok_or_else1160 path_segment.ident.name == sym::ok_or_else1161 && is_diagnostic_item(sym::Option, next_ty)1162 )1163 )1164 // Found `Result<_, ()>?`1165 && let ty::Tuple(tys) = found_ty.kind()1166 && tys.is_empty()1167 // The current method call returns `Result<_, ()>`1168 && self.can_eq(obligation.param_env, ty, found_ty)1169 // There's a single argument in the method call and it is a closure1170 && let [arg] = args1171 && let hir::ExprKind::Closure(closure) = arg.kind1172 // The closure has a block for its body with no tail expression1173 && let body = self.tcx.hir_body(closure.body)1174 && let hir::ExprKind::Block(block, _) = body.value.kind1175 && let None = block.expr1176 // The last statement is of a type that can be converted to the return error type1177 && let [.., stmt] = block.stmts1178 && let hir::StmtKind::Semi(expr) = stmt.kind1179 && let expr_ty = self.resolve_vars_if_possible(1180 typeck.expr_ty_adjusted_opt(expr)1181 .unwrap_or(Ty::new_misc_error(self.tcx)),1182 )1183 && self1184 .infcx1185 .type_implements_trait(1186 self.tcx.get_diagnostic_item(sym::From).unwrap(),1187 [self_ty, expr_ty],1188 obligation.param_env,1189 )1190 .must_apply_modulo_regions()1191 {1192 suggested = true;1193 err.span_suggestion_short(1194 stmt.span.with_lo(expr.span.hi()),1195 "remove this semicolon",1196 String::new(),1197 Applicability::MachineApplicable,1198 );1199 }12001201 prev_ty = next_ty;12021203 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind1204 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path1205 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)1206 {1207 let parent = self.tcx.parent_hir_node(binding.hir_id);1208 // We've reached the root of the method call chain...1209 if let hir::Node::LetStmt(local) = parent1210 && let Some(binding_expr) = local.init1211 {1212 // ...and it is a binding. Get the binding creation and continue the chain.1213 expr = binding_expr;1214 }1215 if let hir::Node::Param(_param) = parent {1216 // ...and it is an fn argument.1217 break;1218 }1219 }1220 }1221 // `expr` is now the "root" expression of the method call chain, which can be any1222 // expression kind, like a method call or a path. If this expression is `Result<T, E>` as1223 // well, then we also point at it.1224 prev_ty = self.resolve_vars_if_possible(1225 typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),1226 );1227 chain.push((expr.span, prev_ty));12281229 let mut prev = None;1230 let mut iter = chain.into_iter().rev().peekable();1231 while let Some((span, err_ty)) = iter.next() {1232 let is_last = iter.peek().is_none();1233 let err_ty = get_e_type(err_ty);1234 let err_ty = match (err_ty, prev) {1235 (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {1236 err_ty1237 }1238 (Some(err_ty), None) => err_ty,1239 _ => {1240 prev = err_ty;1241 continue;1242 }1243 };12441245 let implements_from = self1246 .infcx1247 .type_implements_trait(1248 self.tcx.get_diagnostic_item(sym::From).unwrap(),1249 [self_ty, err_ty],1250 obligation.param_env,1251 )1252 .must_apply_modulo_regions();12531254 let err_ty_str = self.tcx.short_string(err_ty, err.long_ty_path());1255 let label = if !implements_from && is_last {1256 format!(1257 "this can't be annotated with `?` because it has type `Result<_, {err_ty_str}>`"1258 )1259 } else {1260 format!("this has type `Result<_, {err_ty_str}>`")1261 };12621263 if !suggested || !implements_from {1264 err.span_label(span, label);1265 }1266 prev = Some(err_ty);1267 }1268 (suggested, noted_missing_impl)1269 }12701271 fn note_missing_impl_for_question_mark(1272 &self,1273 err: &mut Diag<'_>,1274 self_ty: Ty<'_>,1275 found_ty: Option<Ty<'_>>,1276 trait_pred: ty::PolyTraitPredicate<'tcx>,1277 ) -> bool {1278 match (self_ty.kind(), found_ty) {1279 (ty::Adt(def, _), Some(ty))1280 if let ty::Adt(found, _) = ty.kind()1281 && def.did().is_local()1282 && found.did().is_local() =>1283 {1284 err.span_note(1285 self.tcx.def_span(def.did()),1286 format!("`{self_ty}` needs to implement `From<{ty}>`"),1287 );1288 }1289 (ty::Adt(def, _), None) if def.did().is_local() => {1290 let trait_path = self.tcx.short_string(1291 trait_pred.skip_binder().trait_ref.print_only_trait_path(),1292 err.long_ty_path(),1293 );1294 err.span_note(1295 self.tcx.def_span(def.did()),1296 format!("`{self_ty}` needs to implement `{trait_path}`"),1297 );1298 }1299 (ty::Adt(def, _), Some(ty)) if def.did().is_local() => {1300 err.span_note(1301 self.tcx.def_span(def.did()),1302 format!("`{self_ty}` needs to implement `From<{ty}>`"),1303 );1304 }1305 (_, Some(ty))1306 if let ty::Adt(def, _) = ty.kind()1307 && def.did().is_local() =>1308 {1309 err.span_note(1310 self.tcx.def_span(def.did()),1311 format!("`{ty}` needs to implement `Into<{self_ty}>`"),1312 );1313 }1314 _ => return false,1315 }1316 true1317 }13181319 fn report_const_param_not_wf(1320 &self,1321 ty: Ty<'tcx>,1322 obligation: &PredicateObligation<'tcx>,1323 ) -> Diag<'a> {1324 let def_id = obligation.cause.body_id;1325 let span = self.tcx.ty_span(def_id);13261327 let mut file = None;1328 let ty_str = self.tcx.short_string(ty, &mut file);1329 let mut diag = match ty.kind() {1330 ty::Float(_) => {1331 struct_span_code_err!(1332 self.dcx(),1333 span,1334 E0741,1335 "`{ty_str}` is forbidden as the type of a const generic parameter",1336 )1337 }1338 ty::FnPtr(..) => {1339 struct_span_code_err!(1340 self.dcx(),1341 span,1342 E0741,1343 "using function pointers as const generic parameters is forbidden",1344 )1345 }1346 ty::RawPtr(_, _) => {1347 struct_span_code_err!(1348 self.dcx(),1349 span,1350 E0741,1351 "using raw pointers as const generic parameters is forbidden",1352 )1353 }1354 ty::Adt(def, _) => {1355 // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...1356 let mut diag = struct_span_code_err!(1357 self.dcx(),1358 span,1359 E0741,1360 "`{ty_str}` must implement `ConstParamTy` to be used as the type of a const generic parameter",1361 );1362 // Only suggest derive if this isn't a derived obligation,1363 // and the struct is local.1364 if let Some(span) = self.tcx.hir_span_if_local(def.did())1365 && obligation.cause.code().parent().is_none()1366 {1367 if ty.is_structural_eq_shallow(self.tcx) {1368 diag.span_suggestion(1369 span.shrink_to_lo(),1370 format!("add `#[derive(ConstParamTy)]` to the {}", def.descr()),1371 "#[derive(ConstParamTy)]\n",1372 Applicability::MachineApplicable,1373 );1374 } else {1375 // FIXME(adt_const_params): We should check there's not already an1376 // overlapping `Eq`/`PartialEq` impl.1377 diag.span_suggestion(1378 span.shrink_to_lo(),1379 format!(1380 "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the {}",1381 def.descr()1382 ),1383 "#[derive(ConstParamTy, PartialEq, Eq)]\n",1384 Applicability::MachineApplicable,1385 );1386 }1387 }1388 diag1389 }1390 _ => {1391 struct_span_code_err!(1392 self.dcx(),1393 span,1394 E0741,1395 "`{ty_str}` can't be used as a const parameter type",1396 )1397 }1398 };1399 diag.long_ty_path = file;14001401 let mut code = obligation.cause.code();1402 let mut pred = obligation.predicate.as_trait_clause();1403 while let Some((next_code, next_pred)) = code.parent_with_predicate() {1404 if let Some(pred) = pred {1405 self.enter_forall(pred, |pred| {1406 let ty = self.tcx.short_string(pred.self_ty(), diag.long_ty_path());1407 let trait_path = self1408 .tcx1409 .short_string(pred.print_modifiers_and_trait_path(), diag.long_ty_path());1410 diag.note(format!("`{ty}` must implement `{trait_path}`, but it does not"));1411 })1412 }1413 code = next_code;1414 pred = next_pred;1415 }14161417 diag1418 }1419}14201421impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {1422 fn can_match_trait(1423 &self,1424 param_env: ty::ParamEnv<'tcx>,1425 goal: ty::TraitPredicate<'tcx>,1426 assumption: ty::PolyTraitPredicate<'tcx>,1427 ) -> bool {1428 // Fast path1429 if goal.polarity != assumption.polarity() {1430 return false;1431 }14321433 let trait_assumption = self.instantiate_binder_with_fresh_vars(1434 DUMMY_SP,1435 infer::BoundRegionConversionTime::HigherRankedType,1436 assumption,1437 );14381439 self.can_eq(param_env, goal.trait_ref, trait_assumption.trait_ref)1440 }14411442 fn can_match_host_effect(1443 &self,1444 param_env: ty::ParamEnv<'tcx>,1445 goal: ty::HostEffectPredicate<'tcx>,1446 assumption: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,1447 ) -> bool {1448 let assumption = self.instantiate_binder_with_fresh_vars(1449 DUMMY_SP,1450 infer::BoundRegionConversionTime::HigherRankedType,1451 assumption,1452 );14531454 assumption.constness.satisfies(goal.constness)1455 && self.can_eq(param_env, goal.trait_ref, assumption.trait_ref)1456 }14571458 fn as_host_effect_clause(1459 predicate: ty::Predicate<'tcx>,1460 ) -> Option<ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>> {1461 predicate.as_clause().and_then(|clause| match clause.kind().skip_binder() {1462 ty::ClauseKind::HostEffect(pred) => Some(clause.kind().rebind(pred)),1463 _ => None,1464 })1465 }14661467 fn can_match_projection(1468 &self,1469 param_env: ty::ParamEnv<'tcx>,1470 goal: ty::ProjectionPredicate<'tcx>,1471 assumption: ty::PolyProjectionPredicate<'tcx>,1472 ) -> bool {1473 let assumption = self.instantiate_binder_with_fresh_vars(1474 DUMMY_SP,1475 infer::BoundRegionConversionTime::HigherRankedType,1476 assumption,1477 );14781479 self.can_eq(param_env, goal.projection_term, assumption.projection_term)1480 && self.can_eq(param_env, goal.term, assumption.term)1481 }14821483 // returns if `cond` not occurring implies that `error` does not occur - i.e., that1484 // `error` occurring implies that `cond` occurs.1485 #[instrument(level = "debug", skip(self), ret)]1486 pub(super) fn error_implies(1487 &self,1488 cond: Goal<'tcx, ty::Predicate<'tcx>>,1489 error: Goal<'tcx, ty::Predicate<'tcx>>,1490 ) -> bool {1491 if cond == error {1492 return true;1493 }14941495 // FIXME: We could be smarter about this, i.e. if cond's param-env is a1496 // subset of error's param-env. This only matters when binders will carry1497 // predicates though, and obviously only matters for error reporting.1498 if cond.param_env != error.param_env {1499 return false;1500 }1501 let param_env = error.param_env;15021503 if let Some(error) = error.predicate.as_trait_clause() {1504 self.enter_forall(error, |error| {1505 elaborate(self.tcx, std::iter::once(cond.predicate))1506 .filter_map(|implied| implied.as_trait_clause())1507 .any(|implied| self.can_match_trait(param_env, error, implied))1508 })1509 } else if let Some(error) = Self::as_host_effect_clause(error.predicate) {1510 self.enter_forall(error, |error| {1511 elaborate(self.tcx, std::iter::once(cond.predicate))1512 .filter_map(Self::as_host_effect_clause)1513 .any(|implied| self.can_match_host_effect(param_env, error, implied))1514 })1515 } else if let Some(error) = error.predicate.as_projection_clause() {1516 self.enter_forall(error, |error| {1517 elaborate(self.tcx, std::iter::once(cond.predicate))1518 .filter_map(|implied| implied.as_projection_clause())1519 .any(|implied| self.can_match_projection(param_env, error, implied))1520 })1521 } else {1522 false1523 }1524 }15251526 #[instrument(level = "debug", skip_all)]1527 pub(super) fn report_projection_error(1528 &self,1529 obligation: &PredicateObligation<'tcx>,1530 error: &MismatchedProjectionTypes<'tcx>,1531 ) -> ErrorGuaranteed {1532 let predicate = self.resolve_vars_if_possible(obligation.predicate);15331534 if let Err(e) = predicate.error_reported() {1535 return e;1536 }15371538 self.probe(|_| {1539 // try to find the mismatched types to report the error with.1540 //1541 // this can fail if the problem was higher-ranked, in which1542 // cause I have no idea for a good error message.1543 let bound_predicate = predicate.kind();1544 let (values, err) = match bound_predicate.skip_binder() {1545 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {1546 let ocx = ObligationCtxt::new(self);15471548 let data = self.instantiate_binder_with_fresh_vars(1549 obligation.cause.span,1550 infer::BoundRegionConversionTime::HigherRankedType,1551 bound_predicate.rebind(data),1552 );1553 let unnormalized_term = data.projection_term.to_term(self.tcx);1554 // FIXME(-Znext-solver): For diagnostic purposes, it would be nice1555 // to deeply normalize this type.1556 let normalized_term = ocx.normalize(1557 &obligation.cause,1558 obligation.param_env,1559 Unnormalized::new_wip(unnormalized_term),1560 );15611562 // constrain inference variables a bit more to nested obligations from normalize so1563 // we can have more helpful errors.1564 //1565 // we intentionally drop errors from normalization here,1566 // since the normalization is just done to improve the error message.1567 let _ = ocx.try_evaluate_obligations();15681569 if let Err(new_err) =1570 ocx.eq(&obligation.cause, obligation.param_env, data.term, normalized_term)1571 {1572 (1573 Some((1574 data.projection_term,1575 self.resolve_vars_if_possible(normalized_term),1576 data.term,1577 )),1578 new_err,1579 )1580 } else {1581 (None, error.err)1582 }1583 }1584 ty::PredicateKind::AliasRelate(lhs, rhs, _) => {1585 let derive_better_type_error =1586 |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {1587 let ocx = ObligationCtxt::new(self);15881589 let normalized_term = ocx.normalize(1590 &ObligationCause::dummy(),1591 obligation.param_env,1592 Unnormalized::new_wip(alias_term.to_term(self.tcx)),1593 );15941595 if let Err(terr) = ocx.eq(1596 &ObligationCause::dummy(),1597 obligation.param_env,1598 expected_term,1599 normalized_term,1600 ) {1601 Some((terr, self.resolve_vars_if_possible(normalized_term)))1602 } else {1603 None1604 }1605 };16061607 if let Some(lhs) = lhs.to_alias_term(self.tcx)1608 && let ty::AliasTermKind::ProjectionTy { .. }1609 | ty::AliasTermKind::ProjectionConst { .. } = lhs.kind(self.tcx)1610 && let Some((better_type_err, expected_term)) =1611 derive_better_type_error(lhs, rhs)1612 {1613 (1614 Some((lhs, self.resolve_vars_if_possible(expected_term), rhs)),1615 better_type_err,1616 )1617 } else if let Some(rhs) = rhs.to_alias_term(self.tcx)1618 && let ty::AliasTermKind::ProjectionTy { .. }1619 | ty::AliasTermKind::ProjectionConst { .. } = rhs.kind(self.tcx)1620 && let Some((better_type_err, expected_term)) =1621 derive_better_type_error(rhs, lhs)1622 {1623 (1624 Some((rhs, self.resolve_vars_if_possible(expected_term), lhs)),1625 better_type_err,1626 )1627 } else {1628 (None, error.err)1629 }1630 }1631 _ => (None, error.err),1632 };16331634 let mut file = None;1635 let (msg, span, closure_span) = values1636 .and_then(|(predicate, normalized_term, expected_term)| {1637 self.maybe_detailed_projection_msg(1638 obligation.cause.span,1639 predicate,1640 normalized_term,1641 expected_term,1642 &mut file,1643 )1644 })1645 .unwrap_or_else(|| {1646 (1647 with_forced_trimmed_paths!(format!(1648 "type mismatch resolving `{}`",1649 self.tcx1650 .short_string(self.resolve_vars_if_possible(predicate), &mut file),1651 )),1652 obligation.cause.span,1653 None,1654 )1655 });1656 let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}");1657 *diag.long_ty_path() = file;1658 if let Some(span) = closure_span {1659 // Mark the closure decl so that it is seen even if we are pointing at the return1660 // type or expression.1661 //1662 // error[E0271]: expected `{closure@foo.rs:41:16}` to be a closure that returns1663 // `Unit3`, but it returns `Unit4`1664 // --> $DIR/foo.rs:43:171665 // |1666 // LL | let v = Unit2.m(1667 // | - required by a bound introduced by this call1668 // ...1669 // LL | f: |x| {1670 // | --- /* this span */1671 // LL | drop(x);1672 // LL | Unit41673 // | ^^^^^ expected `Unit3`, found `Unit4`1674 // |1675 diag.span_label(span, "this closure");1676 if !span.overlaps(obligation.cause.span) {1677 // Point at the binding corresponding to the closure where it is used.1678 diag.span_label(obligation.cause.span, "closure used here");1679 }1680 }16811682 let secondary_span = self.probe(|_| {1683 let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =1684 predicate.kind().skip_binder()1685 else {1686 return None;1687 };16881689 let trait_ref = self.enter_forall_and_leak_universe(1690 predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)),1691 );1692 let Ok(Some(ImplSource::UserDefined(impl_data))) =1693 SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref))1694 else {1695 return None;1696 };16971698 let Ok(node) =1699 specialization_graph::assoc_def(self.tcx, impl_data.impl_def_id, proj.def_id())1700 else {1701 return None;1702 };17031704 if !node.is_final() {1705 return None;1706 }17071708 match self.tcx.hir_get_if_local(node.item.def_id) {1709 Some(1710 hir::Node::TraitItem(hir::TraitItem {1711 kind: hir::TraitItemKind::Type(_, Some(ty)),1712 ..1713 })1714 | hir::Node::ImplItem(hir::ImplItem {1715 kind: hir::ImplItemKind::Type(ty),1716 ..1717 }),1718 ) => Some((1719 ty.span,1720 with_forced_trimmed_paths!(Cow::from(format!(1721 "type mismatch resolving `{}`",1722 self.tcx.short_string(1723 self.resolve_vars_if_possible(predicate),1724 diag.long_ty_path()1725 ),1726 ))),1727 true,1728 )),1729 _ => None,1730 }1731 });17321733 self.note_type_err(1734 &mut diag,1735 &obligation.cause,1736 secondary_span,1737 values.map(|(_, normalized_ty, expected_ty)| {1738 obligation.param_env.and(infer::ValuePairs::Terms(ExpectedFound::new(1739 expected_ty,1740 normalized_ty,1741 )))1742 }),1743 err,1744 false,1745 Some(span),1746 );1747 self.note_obligation_cause(&mut diag, obligation);1748 diag.emit()1749 })1750 }17511752 fn maybe_detailed_projection_msg(1753 &self,1754 mut span: Span,1755 projection_term: ty::AliasTerm<'tcx>,1756 normalized_ty: ty::Term<'tcx>,1757 expected_ty: ty::Term<'tcx>,1758 long_ty_path: &mut Option<PathBuf>,1759 ) -> Option<(String, Span, Option<Span>)> {1760 let trait_def_id = projection_term.trait_def_id(self.tcx);1761 let self_ty = projection_term.self_ty();17621763 with_forced_trimmed_paths! {1764 if self.tcx.is_lang_item(projection_term.def_id(), LangItem::FnOnceOutput) {1765 let (span, closure_span) = if let ty::Closure(def_id, _) = *self_ty.kind() {1766 let def_span = self.tcx.def_span(def_id);1767 if let Some(local_def_id) = def_id.as_local()1768 && let node = self.tcx.hir_node_by_def_id(local_def_id)1769 && let Some(fn_decl) = node.fn_decl()1770 && let Some(id) = node.body_id()1771 {1772 span = match fn_decl.output {1773 hir::FnRetTy::Return(ty) => ty.span,1774 hir::FnRetTy::DefaultReturn(_) => {1775 let body = self.tcx.hir_body(id);1776 match body.value.kind {1777 hir::ExprKind::Block(1778 hir::Block { expr: Some(expr), .. },1779 _,1780 ) => expr.span,1781 hir::ExprKind::Block(1782 hir::Block {1783 expr: None, stmts: [.., last], ..1784 },1785 _,1786 ) => last.span,1787 _ => body.value.span,1788 }1789 }1790 };1791 }1792 (span, Some(def_span))1793 } else {1794 (span, None)1795 };1796 let item = match self_ty.kind() {1797 ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),1798 _ => self.tcx.short_string(self_ty, long_ty_path),1799 };1800 let expected_ty = self.tcx.short_string(expected_ty, long_ty_path);1801 let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path);1802 Some((format!(1803 "expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`",1804 ), span, closure_span))1805 } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) {1806 let self_ty = self.tcx.short_string(self_ty, long_ty_path);1807 let expected_ty = self.tcx.short_string(expected_ty, long_ty_path);1808 let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path);1809 Some((format!(1810 "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \1811 resolves to `{normalized_ty}`"1812 ), span, None))1813 } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {1814 let self_ty = self.tcx.short_string(self_ty, long_ty_path);1815 let expected_ty = self.tcx.short_string(expected_ty, long_ty_path);1816 let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path);1817 Some((format!(1818 "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \1819 yields `{normalized_ty}`"1820 ), span, None))1821 } else {1822 None1823 }1824 }1825 }18261827 pub fn fuzzy_match_tys(1828 &self,1829 mut a: Ty<'tcx>,1830 mut b: Ty<'tcx>,1831 ignoring_lifetimes: bool,1832 ) -> Option<CandidateSimilarity> {1833 /// returns the fuzzy category of a given type, or None1834 /// if the type can be equated to any type.1835 fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {1836 match t.kind() {1837 ty::Bool => Some(0),1838 ty::Char => Some(1),1839 ty::Str => Some(2),1840 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => Some(2),1841 ty::Int(..)1842 | ty::Uint(..)1843 | ty::Float(..)1844 | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),1845 ty::Ref(..) | ty::RawPtr(..) => Some(5),1846 ty::Array(..) | ty::Slice(..) => Some(6),1847 ty::FnDef(..) | ty::FnPtr(..) => Some(7),1848 ty::Dynamic(..) => Some(8),1849 ty::Closure(..) => Some(9),1850 ty::Tuple(..) => Some(10),1851 ty::Param(..) => Some(11),1852 ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }) => Some(12),1853 ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => Some(13),1854 ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => Some(14),1855 ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => Some(15),1856 ty::Never => Some(16),1857 ty::Adt(..) => Some(17),1858 ty::Coroutine(..) => Some(18),1859 ty::Foreign(..) => Some(19),1860 ty::CoroutineWitness(..) => Some(20),1861 ty::CoroutineClosure(..) => Some(21),1862 ty::Pat(..) => Some(22),1863 ty::UnsafeBinder(..) => Some(23),1864 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,1865 }1866 }18671868 let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {1869 loop {1870 match t.kind() {1871 ty::Ref(_, inner, _) | ty::RawPtr(inner, _) => t = *inner,1872 _ => break t,1873 }1874 }1875 };18761877 if !ignoring_lifetimes {1878 a = strip_references(a);1879 b = strip_references(b);1880 }18811882 let cat_a = type_category(self.tcx, a)?;1883 let cat_b = type_category(self.tcx, b)?;1884 if a == b {1885 Some(CandidateSimilarity::Exact { ignoring_lifetimes })1886 } else if cat_a == cat_b {1887 match (a.kind(), b.kind()) {1888 (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,1889 (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,1890 // Matching on references results in a lot of unhelpful1891 // suggestions, so let's just not do that for now.1892 //1893 // We still upgrade successful matches to `ignoring_lifetimes: true`1894 // to prioritize that impl.1895 (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {1896 self.fuzzy_match_tys(a, b, true).is_some()1897 }1898 _ => true,1899 }1900 .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })1901 } else if ignoring_lifetimes {1902 None1903 } else {1904 self.fuzzy_match_tys(a, b, true)1905 }1906 }19071908 pub(super) fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {1909 match kind {1910 hir::ClosureKind::Closure => "a closure",1911 hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine",1912 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1913 hir::CoroutineDesugaring::Async,1914 hir::CoroutineSource::Block,1915 )) => "an async block",1916 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1917 hir::CoroutineDesugaring::Async,1918 hir::CoroutineSource::Fn,1919 )) => "an async function",1920 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1921 hir::CoroutineDesugaring::Async,1922 hir::CoroutineSource::Closure,1923 ))1924 | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {1925 "an async closure"1926 }1927 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1928 hir::CoroutineDesugaring::AsyncGen,1929 hir::CoroutineSource::Block,1930 )) => "an async gen block",1931 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1932 hir::CoroutineDesugaring::AsyncGen,1933 hir::CoroutineSource::Fn,1934 )) => "an async gen function",1935 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1936 hir::CoroutineDesugaring::AsyncGen,1937 hir::CoroutineSource::Closure,1938 ))1939 | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::AsyncGen) => {1940 "an async gen closure"1941 }1942 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1943 hir::CoroutineDesugaring::Gen,1944 hir::CoroutineSource::Block,1945 )) => "a gen block",1946 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1947 hir::CoroutineDesugaring::Gen,1948 hir::CoroutineSource::Fn,1949 )) => "a gen function",1950 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1951 hir::CoroutineDesugaring::Gen,1952 hir::CoroutineSource::Closure,1953 ))1954 | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => "a gen closure",1955 }1956 }19571958 pub(super) fn find_similar_impl_candidates(1959 &self,1960 trait_pred: ty::PolyTraitPredicate<'tcx>,1961 ) -> Vec<ImplCandidate<'tcx>> {1962 let mut candidates: Vec<_> = self1963 .tcx1964 .all_impls(trait_pred.def_id())1965 .filter_map(|def_id| {1966 let imp = self.tcx.impl_trait_header(def_id);1967 if imp.polarity != ty::ImplPolarity::Positive1968 || !self.tcx.is_user_visible_dep(def_id.krate)1969 {1970 return None;1971 }1972 let imp = imp.trait_ref.skip_binder();19731974 self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false).map(1975 |similarity| ImplCandidate { trait_ref: imp, similarity, impl_def_id: def_id },1976 )1977 })1978 .collect();1979 if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {1980 // If any of the candidates is a perfect match, we don't want to show all of them.1981 // This is particularly relevant for the case of numeric types (as they all have the1982 // same category).1983 candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));1984 }1985 candidates1986 }19871988 pub(super) fn report_similar_impl_candidates(1989 &self,1990 impl_candidates: &[ImplCandidate<'tcx>],1991 obligation: &PredicateObligation<'tcx>,1992 trait_pred: ty::PolyTraitPredicate<'tcx>,1993 body_def_id: LocalDefId,1994 err: &mut Diag<'_>,1995 other: bool,1996 param_env: ty::ParamEnv<'tcx>,1997 ) -> bool {1998 let parent_map = self.tcx.visible_parent_map(());1999 let alternative_candidates = |def_id: DefId| {2000 let mut impl_candidates: Vec<_> = self
Findings
✓ No findings reported for this file.