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::diagnostics::{43 ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn,44};45use crate::error_reporting::TypeErrCtxt;46use crate::error_reporting::infer::TyCategory;47use crate::error_reporting::traits::report_dyn_incompatibility;48use crate::infer::{self, InferCtxt, InferCtxtExt as _};49use crate::traits::query::evaluate_obligation::InferCtxtExt as _;50use crate::traits::{51 MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode,52 ObligationCtxt, PredicateObligation, SelectionContext, SelectionError, elaborate,53 specialization_graph,54};5556impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {57 /// The `root_obligation` parameter should be the `root_obligation` field58 /// from a `FulfillmentError`. If no `FulfillmentError` is available,59 /// then it should be the same as `obligation`.60 pub fn report_selection_error(61 &self,62 mut obligation: PredicateObligation<'tcx>,63 root_obligation: &PredicateObligation<'tcx>,64 error: &SelectionError<'tcx>,65 ) -> ErrorGuaranteed {66 let tcx = self.tcx;67 let mut span = obligation.cause.span;68 let mut long_ty_file = None;6970 let mut err = match *error {71 SelectionError::Unimplemented => {72 // If this obligation was generated as a result of well-formedness checking, see if we73 // can get a better error message by performing HIR-based well-formedness checking.74 if let ObligationCauseCode::WellFormed(Some(wf_loc)) =75 root_obligation.cause.code().peel_derives()76 && !obligation.predicate.has_non_region_infer()77 {78 if let Some(cause) = self.tcx.diagnostic_hir_wf_check((79 tcx.erase_and_anonymize_regions(obligation.predicate),80 *wf_loc,81 )) {82 obligation.cause = cause.clone();83 span = obligation.cause.span;84 }85 }8687 if let ObligationCauseCode::CompareImplItem {88 impl_item_def_id,89 trait_item_def_id,90 kind: _,91 } = *obligation.cause.code()92 {93 debug!("ObligationCauseCode::CompareImplItemObligation");94 return self95 .report_extra_impl_obligation(96 span,97 impl_item_def_id,98 trait_item_def_id,99 &format!("`{}`", obligation.predicate),100 )101 .emit();102 }103104 // Report a const-param specific error105 if let ObligationCauseCode::ConstParam(ty) = *obligation.cause.code().peel_derives()106 {107 return self.report_const_param_not_wf(ty, &obligation).emit();108 }109110 let bound_predicate = obligation.predicate.kind();111 match bound_predicate.skip_binder() {112 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {113 let leaf_trait_predicate =114 self.resolve_vars_if_possible(bound_predicate.rebind(trait_predicate));115116 // Let's use the root obligation as the main message, when we care about the117 // most general case ("X doesn't implement Pattern<'_>") over the case that118 // happened to fail ("char doesn't implement Fn(&mut char)").119 //120 // We rely on a few heuristics to identify cases where this root121 // obligation is more important than the leaf obligation:122 let (main_trait_predicate, main_obligation) =123 if let ty::PredicateKind::Clause(124 ty::ClauseKind::Trait(root_pred)125 ) = root_obligation.predicate.kind().skip_binder()126 && !leaf_trait_predicate.self_ty().skip_binder().has_escaping_bound_vars()127 && !root_pred.self_ty().has_escaping_bound_vars()128 // The type of the leaf predicate is (roughly) the same as the type129 // from the root predicate, as a proxy for "we care about the root"130 // FIXME: this doesn't account for trivial derefs, but works as a first131 // approximation.132 && (133 // `T: Trait` && `&&T: OtherTrait`, we want `OtherTrait`134 self.can_eq(135 obligation.param_env,136 leaf_trait_predicate.self_ty().skip_binder(),137 root_pred.self_ty().peel_refs(),138 )139 // `&str: Iterator` && `&str: IntoIterator`, we want `IntoIterator`140 || self.can_eq(141 obligation.param_env,142 leaf_trait_predicate.self_ty().skip_binder(),143 root_pred.self_ty(),144 )145 )146 // The leaf trait and the root trait are different, so as to avoid147 // talking about `&mut T: Trait` and instead remain talking about148 // `T: Trait` instead149 && leaf_trait_predicate.def_id() != root_pred.def_id()150 // The root trait is not `Unsize`, as to avoid talking about it in151 // `tests/ui/coercion/coerce-issue-49593-box-never.rs`.152 && !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize)153 {154 (155 self.resolve_vars_if_possible(156 root_obligation.predicate.kind().rebind(root_pred),157 ),158 root_obligation,159 )160 } else {161 (leaf_trait_predicate, &obligation)162 };163164 if let Some(guar) = self165 .emit_specialized_closure_kind_error(&obligation, leaf_trait_predicate)166 {167 return guar;168 }169170 if let Err(guar) = leaf_trait_predicate.error_reported() {171 return guar;172 }173 // Silence redundant errors on binding access that are already174 // reported on the binding definition (#56607).175 if let Err(guar) = self.fn_arg_obligation(&obligation) {176 return guar;177 }178 let (post_message, pre_message, type_def) = self179 .get_parent_trait_ref(obligation.cause.code())180 .map(|(t, s)| {181 let t = self.tcx.short_string(t, &mut long_ty_file);182 (183 format!(" in `{t}`"),184 format!("within `{t}`, "),185 s.map(|s| (format!("within this `{t}`"), s)),186 )187 })188 .unwrap_or_default();189190 let CustomDiagnostic { message, label, notes, parent_label } = self191 .on_unimplemented_note(192 main_trait_predicate,193 main_obligation,194 &mut long_ty_file,195 );196197 let have_alt_message = message.is_some() || label.is_some();198199 let message = message.unwrap_or_else(|| {200 self.get_standard_error_message(201 main_trait_predicate,202 None,203 post_message,204 &mut long_ty_file,205 )206 });207 let is_try_conversion =208 self.is_try_conversion(span, main_trait_predicate.def_id());209 let is_question_mark = matches!(210 root_obligation.cause.code().peel_derives(),211 ObligationCauseCode::QuestionMark,212 ) && !(self213 .tcx214 .is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id())215 || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try));216 let is_unsize =217 self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);218 let question_mark_message = "the question mark operation (`?`) implicitly \219 performs a conversion on the error value \220 using the `From` trait";221 let (message, notes) = if is_try_conversion {222 let ty = self.tcx.short_string(223 main_trait_predicate.skip_binder().self_ty(),224 &mut long_ty_file,225 );226 // We have a `-> Result<_, E1>` and `gives_E2()?`.227 (228 format!("`?` couldn't convert the error to `{ty}`"),229 vec![question_mark_message.to_owned()],230 )231 } else if is_question_mark {232 let main_trait_predicate =233 self.tcx.short_string(main_trait_predicate, &mut long_ty_file);234 // Similar to the case above, but in this case the conversion is for a235 // trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when236 // `E: Error` isn't met.237 (238 format!(239 "`?` couldn't convert the error: `{main_trait_predicate}` is \240 not satisfied",241 ),242 vec![question_mark_message.to_owned()],243 )244 } else {245 (message, notes)246 };247248 let (err_msg, safe_transmute_explanation) = if self249 .tcx250 .is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)251 {252 // Recompute the safe transmute reason and use that for the error reporting253 let (report_obligation, report_pred) = self254 .select_transmute_obligation_for_reporting(255 &obligation,256 main_trait_predicate,257 root_obligation,258 );259260 match self.get_safe_transmute_error_and_reason(261 report_obligation,262 report_pred,263 span,264 ) {265 GetSafeTransmuteErrorAndReason::Silent => {266 return self267 .dcx()268 .span_delayed_bug(span, "silent safe transmute error");269 }270 GetSafeTransmuteErrorAndReason::Default => (message, None),271 GetSafeTransmuteErrorAndReason::Error {272 err_msg,273 safe_transmute_explanation,274 } => (err_msg, safe_transmute_explanation),275 }276 } else {277 (message, None)278 };279280 let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);281282 let trait_def_id = main_trait_predicate.def_id();283 let leaf_trait_def_id = leaf_trait_predicate.def_id();284 if (self.tcx.is_diagnostic_item(sym::From, trait_def_id)285 || self.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id))286 && (self.tcx.is_diagnostic_item(sym::From, leaf_trait_def_id)287 || self.tcx.is_diagnostic_item(sym::TryFrom, leaf_trait_def_id))288 {289 let trait_ref = leaf_trait_predicate.skip_binder().trait_ref;290291 if let Some(found_ty) =292 trait_ref.args.get(1).and_then(|arg| arg.as_type())293 {294 let ty = main_trait_predicate.skip_binder().self_ty();295296 if let Some(cast_ty) =297 self.find_explicit_cast_type(obligation.param_env, found_ty, ty)298 {299 let found_ty_str =300 self.tcx.short_string(found_ty, &mut long_ty_file);301 let cast_ty_str =302 self.tcx.short_string(cast_ty, &mut long_ty_file);303304 err.help(format!(305 "consider casting the `{found_ty_str}` value to `{cast_ty_str}`",306 ));307 }308 }309 }310311 *err.long_ty_path() = long_ty_file;312313 let mut suggested = false;314 let mut noted_missing_impl = false;315 if is_try_conversion || is_question_mark {316 (suggested, noted_missing_impl) = self.try_conversion_context(317 &obligation,318 main_trait_predicate,319 &mut err,320 );321 }322323 suggested |= self.detect_negative_literal(324 &obligation,325 main_trait_predicate,326 &mut err,327 );328329 if let Some(ret_span) = self.return_type_span(&obligation) {330 if is_try_conversion {331 let ty = self.tcx.short_string(332 main_trait_predicate.skip_binder().self_ty(),333 err.long_ty_path(),334 );335 err.span_label(336 ret_span,337 format!("expected `{ty}` because of this"),338 );339 } else if is_question_mark {340 let main_trait_predicate =341 self.tcx.short_string(main_trait_predicate, err.long_ty_path());342 err.span_label(343 ret_span,344 format!("required `{main_trait_predicate}` because of this"),345 );346 }347 }348349 if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {350 self.add_tuple_trait_message(351 obligation.cause.code().peel_derives(),352 &mut err,353 );354 }355356 let explanation = get_explanation_based_on_obligation(357 self.tcx,358 &obligation,359 leaf_trait_predicate,360 pre_message,361 err.long_ty_path(),362 );363364 self.check_for_binding_assigned_block_without_tail_expression(365 &obligation,366 &mut err,367 leaf_trait_predicate,368 );369 self.suggest_add_result_as_return_type(370 &obligation,371 &mut err,372 leaf_trait_predicate,373 );374375 if self.suggest_add_reference_to_arg(376 &obligation,377 &mut err,378 leaf_trait_predicate,379 have_alt_message,380 ) {381 self.note_obligation_cause(&mut err, &obligation);382 return err.emit();383 }384385 let ty_span = match leaf_trait_predicate.self_ty().skip_binder().kind() {386 ty::Adt(def, _)387 if def.did().is_local()388 && !self389 .can_suggest_derive(&obligation, leaf_trait_predicate) =>390 {391 self.tcx.def_span(def.did())392 }393 _ => DUMMY_SP,394 };395 if let Some(s) = label {396 // If it has a custom `#[rustc_on_unimplemented]`397 // error message, let's display it as the label!398 err.span_label(span, s);399 if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_))400 // When the self type is a type param We don't need to "the trait401 // `std::marker::Sized` is not implemented for `T`" as we will point402 // at the type param with a label to suggest constraining it.403 && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id())404 // Don't say "the trait `FromResidual<Option<Infallible>>` is405 // not implemented for `Result<T, E>`".406 {407 // We do this just so that the JSON output's `help` position is the408 // right one and not `file.rs:1:1`. The render is the same.409 if ty_span == DUMMY_SP {410 err.help(explanation);411 } else {412 err.span_help(ty_span, explanation);413 }414 }415 } else if let Some(custom_explanation) = safe_transmute_explanation {416 err.span_label(span, custom_explanation);417 } else if (explanation.len() > self.tcx.sess.diagnostic_width()418 || ty_span != DUMMY_SP)419 && !noted_missing_impl420 {421 // Really long types don't look good as span labels, instead move it422 // to a `help`.423 err.span_label(span, "unsatisfied trait bound");424425 // We do this just so that the JSON output's `help` position is the426 // right one and not `file.rs:1:1`. The render is the same.427 if ty_span == DUMMY_SP {428 err.help(explanation);429 } else {430 err.span_help(ty_span, explanation);431 }432 } else {433 err.span_label(span, explanation);434 }435436 if let ObligationCauseCode::Coercion { source, target } =437 *obligation.cause.code().peel_derives()438 {439 if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized)440 {441 self.suggest_borrowing_for_object_cast(442 &mut err,443 root_obligation,444 source,445 target,446 );447 }448 }449450 if let Some((msg, span)) = type_def {451 err.span_label(span, msg);452 }453 // `#[rustc_on_unimplemented]` notes for derivable traits (e.g. `Debug`'s454 // "add `#[derive(Debug)]` to `X` or manually `impl Debug for X`") duplicate455 // the `consider annotating X with #[derive(..)]` suggestion that456 // `suggest_derive` emits below, so skip them when that suggestion will be457 // shown. We keep the note otherwise (e.g. when a field isn't `Debug`, so458 // the derive can't be suggested) to avoid leaving the diagnostic without459 // actionable guidance.460 let derive_suggestion_will_be_shown = main_trait_predicate461 == leaf_trait_predicate462 && self.can_suggest_derive(&obligation, leaf_trait_predicate);463 if !derive_suggestion_will_be_shown {464 for note in notes {465 // If it has a custom `#[rustc_on_unimplemented]` note, let's display466 // it.467 err.note(note);468 }469 }470 if let Some(s) = parent_label {471 let body = obligation.cause.body_id;472 err.span_label(tcx.def_span(body), s);473 }474475 self.suggest_floating_point_literal(476 &obligation,477 &mut err,478 leaf_trait_predicate,479 );480 self.suggest_dereferencing_index(481 &obligation,482 &mut err,483 leaf_trait_predicate,484 );485 suggested |=486 self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate);487 suggested |=488 self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate);489 suggested |= self.suggest_cast_to_fn_pointer(490 &obligation,491 &mut err,492 leaf_trait_predicate,493 main_trait_predicate,494 span,495 );496 suggested |= self.suggest_remove_reference(497 &obligation,498 &mut err,499 leaf_trait_predicate,500 );501 suggested |= self.suggest_semicolon_removal(502 &obligation,503 &mut err,504 span,505 leaf_trait_predicate,506 );507 self.note_different_trait_with_same_name(508 &mut err,509 &obligation,510 leaf_trait_predicate,511 );512 self.note_adt_version_mismatch(&mut err, leaf_trait_predicate);513 self.suggest_remove_await(&obligation, &mut err);514 self.suggest_derive(&obligation, &mut err, leaf_trait_predicate);515516 if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Try) {517 self.suggest_await_before_try(518 &mut err,519 &obligation,520 leaf_trait_predicate,521 span,522 );523 }524525 if self.suggest_add_clone_to_arg(526 &obligation,527 &mut err,528 leaf_trait_predicate,529 ) {530 return err.emit();531 }532533 if self.suggest_impl_trait(&mut err, &obligation, leaf_trait_predicate) {534 return err.emit();535 }536537 if is_unsize {538 // If the obligation failed due to a missing implementation of the539 // `Unsize` trait, give a pointer to why that might be the case540 err.note(541 "all implementations of `Unsize` are provided \542 automatically by the compiler, see \543 <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> \544 for more information",545 );546 }547548 let is_fn_trait = tcx.is_fn_trait(leaf_trait_predicate.def_id());549 let is_target_feature_fn = if let ty::FnDef(def_id, _) =550 *leaf_trait_predicate.skip_binder().self_ty().kind()551 {552 !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()553 } else {554 false555 };556 if is_fn_trait && is_target_feature_fn {557 err.note(558 "`#[target_feature]` functions do not implement the `Fn` traits",559 );560 err.note(561 "try casting the function to a `fn` pointer or wrapping it in a closure",562 );563 }564565 self.note_field_shadowed_by_private_candidate_in_cause(566 &mut err,567 &obligation.cause,568 obligation.param_env,569 );570 self.try_to_add_help_message(571 &root_obligation,572 &obligation,573 leaf_trait_predicate,574 &mut err,575 span,576 is_fn_trait,577 suggested,578 );579580 // Changing mutability doesn't make a difference to whether we have581 // an `Unsize` impl (Fixes ICE in #71036)582 if !is_unsize {583 self.suggest_change_mut(&obligation, &mut err, leaf_trait_predicate);584 }585586 // If this error is due to `!: Trait` not implemented but `(): Trait` is587 // implemented, and fallback has occurred, then it could be due to a588 // variable that used to fallback to `()` now falling back to `!`. Issue a589 // note informing about the change in behaviour.590 if leaf_trait_predicate.skip_binder().self_ty().is_never()591 && self.diverging_fallback_has_occurred592 {593 let predicate = leaf_trait_predicate.map_bound(|trait_pred| {594 trait_pred.with_replaced_self_ty(self.tcx, tcx.types.unit)595 });596 let unit_obligation = obligation.with(tcx, predicate);597 if self.predicate_may_hold(&unit_obligation) {598 err.note(599 "this error might have been caused by changes to \600 Rust's type-inference algorithm (see issue #148922 \601 <https://github.com/rust-lang/rust/issues/148922> \602 for more information)",603 );604 err.help(605 "you might have intended to use the type `()` here instead",606 );607 }608 }609610 self.explain_hrtb_projection(611 &mut err,612 leaf_trait_predicate,613 obligation.param_env,614 &obligation.cause,615 );616 self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate);617618 // Return early if the trait is Debug or Display and the invocation619 // originates within a standard library macro, because the output620 // is otherwise overwhelming and unhelpful (see #85844 for an621 // example).622623 let in_std_macro =624 match obligation.cause.span.ctxt().outer_expn_data().macro_def_id {625 Some(macro_def_id) => {626 let crate_name = tcx.crate_name(macro_def_id.krate);627 STDLIB_STABLE_CRATES.contains(&crate_name)628 }629 None => false,630 };631632 if in_std_macro633 && matches!(634 self.tcx.get_diagnostic_name(leaf_trait_predicate.def_id()),635 Some(sym::Debug | sym::Display)636 )637 {638 return err.emit();639 }640641 err642 }643644 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(predicate)) => self645 .report_host_effect_error(646 bound_predicate.rebind(predicate),647 &obligation,648 span,649 ),650651 ty::PredicateKind::Subtype(predicate) => {652 // Errors for Subtype predicates show up as653 // `FulfillmentErrorCode::SubtypeError`,654 // not selection error.655 span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)656 }657658 ty::PredicateKind::Coerce(predicate) => {659 // Errors for Coerce predicates show up as660 // `FulfillmentErrorCode::SubtypeError`,661 // not selection error.662 span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)663 }664665 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))666 | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) => {667 span_bug!(668 span,669 "outlives clauses should not error outside borrowck. obligation: `{:?}`",670 obligation671 )672 }673674 ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) => {675 span_bug!(676 span,677 "projection clauses should be implied from elsewhere. obligation: `{:?}`",678 obligation679 )680 }681682 ty::PredicateKind::DynCompatible(trait_def_id) => {683 let violations = self.tcx.dyn_compatibility_violations(trait_def_id);684 let mut err = report_dyn_incompatibility(685 self.tcx,686 span,687 None,688 trait_def_id,689 violations,690 );691 if let hir::Node::Item(item) =692 self.tcx.hir_node_by_def_id(obligation.cause.body_id)693 && let hir::ItemKind::Impl(impl_) = item.kind694 && let None = impl_.of_trait695 && let hir::TyKind::TraitObject(_, tagged_ptr) = impl_.self_ty.kind696 && let TraitObjectSyntax::None = tagged_ptr.tag()697 && impl_.self_ty.span.edition().at_least_rust_2021()698 {699 // Silence the dyn-compatibility error in favor of the missing dyn on700 // self type error. #131051.701 err.downgrade_to_delayed_bug();702 }703 err704 }705706 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {707 let ty = self.resolve_vars_if_possible(ty);708 if self.next_trait_solver() {709 if let Err(guar) = ty.error_reported() {710 return guar;711 }712713 // FIXME: we'll need a better message which takes into account714 // which bounds actually failed to hold.715 self.dcx().struct_span_err(716 span,717 format!("the type `{ty}` is not well-formed"),718 )719 } else {720 // WF predicates cannot themselves make721 // errors. They can only block due to722 // ambiguity; otherwise, they always723 // degenerate into other obligations724 // (which may fail).725 span_bug!(span, "WF predicate not satisfied for {:?}", ty);726 }727 }728729 // Errors for `ConstEvaluatable`, `ConstEquate` predicates show up as730 // `SelectionError::ConstEvalFailure`, not `Unimplemented`.731 // Ambiguous predicates should never error.732 // We never return `Err` when proving `UnstableFeature` goal.733 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))734 | ty::PredicateKind::ConstEquate { .. }735 | ty::PredicateKind::Ambiguous736 | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature { .. })737 | ty::PredicateKind::NormalizesTo { .. }738 | ty::PredicateKind::AliasRelate(..)739 | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => {740 span_bug!(741 span,742 "Unexpected `Predicate` for `SelectionError`: `{:?}`",743 obligation744 )745 }746 }747 }748749 SelectionError::SignatureMismatch(SignatureMismatchData {750 found_trait_ref,751 expected_trait_ref,752 terr: terr @ TypeError::CyclicTy(_),753 }) => self.report_cyclic_signature_error(754 &obligation,755 found_trait_ref,756 expected_trait_ref,757 terr,758 ),759 SelectionError::SignatureMismatch(SignatureMismatchData {760 found_trait_ref,761 expected_trait_ref,762 terr: _,763 }) => {764 match self.report_signature_mismatch_error(765 &obligation,766 span,767 found_trait_ref,768 expected_trait_ref,769 ) {770 Ok(err) => err,771 Err(guar) => return guar,772 }773 }774775 SelectionError::TraitDynIncompatible(did) => {776 let violations = self.tcx.dyn_compatibility_violations(did);777 report_dyn_incompatibility(self.tcx, span, None, did, violations)778 }779780 SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => {781 bug!(782 "MentionsInfer should have been handled in `traits/fulfill.rs` or `traits/select/mod.rs`"783 )784 }785 SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {786 match self.report_not_const_evaluatable_error(&obligation, span) {787 Ok(err) => err,788 Err(guar) => return guar,789 }790 }791792 // Already reported in the query.793 SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(guar))794 | SelectionError::Overflow(OverflowError::Error(guar)) => {795 self.set_tainted_by_errors(guar);796 return guar;797 }798799 SelectionError::Overflow(_) => {800 bug!("overflow should be handled before the `report_selection_error` path");801 }802803 SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => {804 let expected_ty_str = self.tcx.short_string(expected_ty, &mut long_ty_file);805 let ct_str = self.tcx.short_string(ct, &mut long_ty_file);806 let mut diag = self.dcx().struct_span_err(807 span,808 format!("the constant `{ct_str}` is not of type `{expected_ty_str}`"),809 );810 diag.long_ty_path = long_ty_file;811812 self.note_type_err(813 &mut diag,814 &obligation.cause,815 None,816 None,817 TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)),818 false,819 None,820 );821 diag822 }823 };824825 self.note_obligation_cause(&mut err, &obligation);826 err.emit()827 }828}829830impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {831 pub(super) fn apply_do_not_recommend(832 &self,833 obligation: &mut PredicateObligation<'tcx>,834 root_obligation: &PredicateObligation<'tcx>,835 ) -> bool {836 let mut base_cause = obligation.cause.code().clone();837 let mut applied_do_not_recommend = false;838 loop {839 if let ObligationCauseCode::ImplDerived(ref c) = base_cause {840 if self.tcx.do_not_recommend_impl(c.impl_or_alias_def_id) {841 let code = (*c.derived.parent_code).clone();842 // Keep more precise spans that still point within the parent obligation,843 // but do not let hidden impl details move the span outside of it.844 if code == *root_obligation.cause.code()845 && root_obligation.cause.span.eq_ctxt(obligation.cause.span)846 && !root_obligation.cause.span.contains(obligation.cause.span)847 {848 obligation.cause.span = root_obligation.cause.span;849 }850 obligation.cause.map_code(|_| code);851 obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);852 applied_do_not_recommend = true;853 }854 }855 if let Some(parent_cause) = base_cause.parent() {856 base_cause = parent_cause.clone();857 } else {858 break;859 }860 }861862 applied_do_not_recommend863 }864865 fn report_host_effect_error(866 &self,867 predicate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,868 main_obligation: &PredicateObligation<'tcx>,869 span: Span,870 ) -> Diag<'a> {871 // FIXME(const_trait_impl): We should recompute the predicate with `[const]`872 // if it's `const`, and if it holds, explain that this bound only873 // *conditionally* holds.874 let trait_ref = predicate.map_bound(|predicate| ty::TraitPredicate {875 trait_ref: predicate.trait_ref,876 polarity: ty::PredicatePolarity::Positive,877 });878 let mut file = None;879880 let err_msg = self.get_standard_error_message(881 trait_ref,882 Some(predicate.constness()),883 String::new(),884 &mut file,885 );886 let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg);887 *diag.long_ty_path() = file;888 let obligation = Obligation::new(889 self.tcx,890 ObligationCause::dummy(),891 main_obligation.param_env,892 trait_ref,893 );894 if !self.predicate_may_hold(&obligation) {895 diag.downgrade_to_delayed_bug();896 }897898 if let Ok(Some(ImplSource::UserDefined(impl_data))) =899 self.enter_forall(trait_ref, |trait_ref_for_select| {900 SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref_for_select))901 })902 {903 let impl_did = impl_data.impl_def_id;904 let trait_did = trait_ref.def_id();905 let impl_span = self.tcx.def_span(impl_did);906 let trait_name = self.tcx.item_name(trait_did);907908 if self.tcx.is_const_trait(trait_did) && !self.tcx.is_const_trait_impl(impl_did) {909 if !impl_did.is_local() {910 diag.span_note(911 impl_span,912 format!("trait `{trait_name}` is implemented but not `const`"),913 );914 }915916 if let Some(command) =917 find_attr!(self.tcx, impl_did, OnConst {directive, ..} => directive.as_deref())918 .flatten()919 {920 let (_, format_args) = self.on_unimplemented_components(921 trait_ref,922 main_obligation,923 diag.long_ty_path(),924 );925 let CustomDiagnostic { message, label, notes, parent_label: _ } =926 command.eval(None, &format_args);927928 if let Some(message) = message {929 diag.primary_message(message);930 }931 if let Some(label) = label {932 diag.span_label(span, label);933 }934 for note in notes {935 diag.note(note);936 }937 } else if let Some(impl_did) = impl_did.as_local()938 && let item = self.tcx.hir_expect_item(impl_did)939 && let hir::ItemKind::Impl(item) = item.kind940 && let Some(of_trait) = item.of_trait941 {942 // trait is const, impl is local and not const943 diag.span_suggestion_verbose(944 of_trait.trait_ref.path.span.shrink_to_lo(),945 format!("make the `impl` of trait `{trait_name}` `const`"),946 "const ".to_string(),947 Applicability::MaybeIncorrect,948 );949 }950 }951 } else if let ty::Param(param) = trait_ref.self_ty().skip_binder().kind()952 && let Some(generics) =953 self.tcx.hir_node_by_def_id(main_obligation.cause.body_id).generics()954 {955 let constraint = ty::print::with_no_trimmed_paths!(format!(956 "[const] {}",957 trait_ref.map_bound(|tr| tr.trait_ref).print_trait_sugared(),958 ));959 ty::suggest_constraining_type_param(960 self.tcx,961 generics,962 &mut diag,963 param.name.as_str(),964 &constraint,965 Some(trait_ref.def_id()),966 None,967 );968 }969 diag970 }971972 fn emit_specialized_closure_kind_error(973 &self,974 obligation: &PredicateObligation<'tcx>,975 mut trait_pred: ty::PolyTraitPredicate<'tcx>,976 ) -> Option<ErrorGuaranteed> {977 // If we end up on an `AsyncFnKindHelper` goal, try to unwrap the parent978 // `AsyncFn*` goal.979 if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) {980 let mut code = obligation.cause.code();981 // Unwrap a `FunctionArg` cause, which has been refined from a derived obligation.982 if let ObligationCauseCode::FunctionArg { parent_code, .. } = code {983 code = &**parent_code;984 }985 // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.986 if let Some((_, Some(parent))) = code.parent_with_predicate() {987 trait_pred = parent;988 }989 }990991 let self_ty = trait_pred.self_ty().skip_binder();992993 let (expected_kind, trait_prefix) =994 if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {995 (expected_kind, "")996 } else if let Some(expected_kind) =997 self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id())998 {999 (expected_kind, "Async")1000 } else {1001 return None;1002 };10031004 let (closure_def_id, found_args, has_self_borrows) = match *self_ty.kind() {1005 ty::Closure(def_id, args) => {1006 (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), false)1007 }1008 ty::CoroutineClosure(def_id, args) => (1009 def_id,1010 args.as_coroutine_closure()1011 .coroutine_closure_sig()1012 .map_bound(|sig| sig.tupled_inputs_ty),1013 !args.as_coroutine_closure().tupled_upvars_ty().is_ty_var()1014 && args.as_coroutine_closure().has_self_borrows(),1015 ),1016 _ => return None,1017 };10181019 let expected_args = trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));10201021 // Verify that the arguments are compatible. If the signature is1022 // mismatched, then we have a totally different error to report.1023 if self.enter_forall(found_args, |found_args| {1024 self.enter_forall(expected_args, |expected_args| {1025 !self.can_eq(obligation.param_env, expected_args, found_args)1026 })1027 }) {1028 return None;1029 }10301031 if let Some(found_kind) = self.closure_kind(self_ty)1032 && !found_kind.extends(expected_kind)1033 {1034 let mut err = self.report_closure_error(1035 &obligation,1036 closure_def_id,1037 found_kind,1038 expected_kind,1039 trait_prefix,1040 );1041 self.note_obligation_cause(&mut err, &obligation);1042 return Some(err.emit());1043 }10441045 // If the closure has captures, then perhaps the reason that the trait1046 // is unimplemented is because async closures don't implement `Fn`/`FnMut`1047 // if they have captures.1048 if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce {1049 let coro_kind = match self1050 .tcx1051 .coroutine_kind(self.tcx.coroutine_for_closure(closure_def_id))1052 .unwrap()1053 {1054 rustc_hir::CoroutineKind::Desugared(desugaring, _) => desugaring.to_string(),1055 coro => coro.to_string(),1056 };1057 let mut err = self.dcx().create_err(CoroClosureNotFn {1058 span: self.tcx.def_span(closure_def_id),1059 kind: expected_kind.as_str(),1060 coro_kind,1061 });1062 self.note_obligation_cause(&mut err, &obligation);1063 return Some(err.emit());1064 }10651066 None1067 }10681069 fn fn_arg_obligation(1070 &self,1071 obligation: &PredicateObligation<'tcx>,1072 ) -> Result<(), ErrorGuaranteed> {1073 if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()1074 && let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id)1075 && let arg = arg.peel_borrows()1076 && let hir::ExprKind::Path(hir::QPath::Resolved(1077 None,1078 hir::Path { res: hir::def::Res::Local(hir_id), .. },1079 )) = arg.kind1080 && let Node::Pat(pat) = self.tcx.hir_node(*hir_id)1081 && let Some((preds, guar)) = self.reported_trait_errors.borrow().get(&pat.span)1082 && preds.contains(&obligation.as_goal())1083 {1084 return Err(*guar);1085 }1086 Ok(())1087 }10881089 fn detect_negative_literal(1090 &self,1091 obligation: &PredicateObligation<'tcx>,1092 trait_pred: ty::PolyTraitPredicate<'tcx>,1093 err: &mut Diag<'_>,1094 ) -> bool {1095 if let ObligationCauseCode::UnOp { hir_id, .. } = obligation.cause.code()1096 && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)1097 && let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = expr.kind1098 && let hir::ExprKind::Lit(lit) = inner.kind1099 && let LitKind::Int(_, LitIntType::Unsuffixed) = lit.node1100 {1101 err.span_suggestion_verbose(1102 lit.span.shrink_to_hi(),1103 "consider specifying an integer type that can be negative",1104 match trait_pred.skip_binder().self_ty().kind() {1105 ty::Uint(ty::UintTy::Usize) => "isize",1106 ty::Uint(ty::UintTy::U8) => "i8",1107 ty::Uint(ty::UintTy::U16) => "i16",1108 ty::Uint(ty::UintTy::U32) => "i32",1109 ty::Uint(ty::UintTy::U64) => "i64",1110 ty::Uint(ty::UintTy::U128) => "i128",1111 _ => "i64",1112 }1113 .to_string(),1114 Applicability::MaybeIncorrect,1115 );1116 return true;1117 }1118 false1119 }11201121 /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,1122 /// identify those method chain sub-expressions that could or could not have been annotated1123 /// with `?`.1124 fn try_conversion_context(1125 &self,1126 obligation: &PredicateObligation<'tcx>,1127 trait_pred: ty::PolyTraitPredicate<'tcx>,1128 err: &mut Diag<'_>,1129 ) -> (bool, bool) {1130 let span = obligation.cause.span;1131 /// Look for the (direct) sub-expr of `?`, and return it if it's a `.` method call.1132 struct FindMethodSubexprOfTry {1133 search_span: Span,1134 }1135 impl<'v> Visitor<'v> for FindMethodSubexprOfTry {1136 type Result = ControlFlow<&'v hir::Expr<'v>>;1137 fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {1138 if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind1139 && ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span)1140 && let hir::ExprKind::Call(_, [expr, ..]) = expr.kind1141 {1142 ControlFlow::Break(expr)1143 } else {1144 hir::intravisit::walk_expr(self, ex)1145 }1146 }1147 }1148 let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);1149 let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return (false, false) };1150 let ControlFlow::Break(expr) =1151 (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id))1152 else {1153 return (false, false);1154 };1155 let Some(typeck) = &self.typeck_results else {1156 return (false, false);1157 };1158 let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else {1159 return (false, false);1160 };1161 let self_ty = trait_pred.skip_binder().self_ty();1162 let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());1163 let noted_missing_impl =1164 self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);11651166 let mut prev_ty = self.resolve_vars_if_possible(1167 typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),1168 );11691170 // We always look at the `E` type, because that's the only one affected by `?`. If the1171 // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole1172 // expression, after the `?` has "unwrapped" the `T`.1173 let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> {1174 let ty::Adt(def, args) = prev_ty.kind() else {1175 return None;1176 };1177 let Some(arg) = args.get(1) else {1178 return None;1179 };1180 if !self.tcx.is_diagnostic_item(sym::Result, def.did()) {1181 return None;1182 }1183 arg.as_type()1184 };11851186 let mut suggested = false;1187 let mut chain = vec![];11881189 // The following logic is similar to `point_at_chain`, but that's focused on associated types1190 let mut expr = expr;1191 while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind {1192 // Point at every method call in the chain with the `Result` type.1193 // let foo = bar.iter().map(mapper)?;1194 // ------ -----------1195 expr = rcvr_expr;1196 chain.push((span, prev_ty));11971198 let next_ty = self.resolve_vars_if_possible(1199 typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),1200 );12011202 let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| {1203 let ty::Adt(def, _) = ty.kind() else {1204 return false;1205 };1206 self.tcx.is_diagnostic_item(symbol, def.did())1207 };1208 // For each method in the chain, see if this is `Result::map_err` or1209 // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect1210 // trailing `;`.1211 if let Some(ty) = get_e_type(prev_ty)1212 && let Some(found_ty) = found_ty1213 // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100%1214 // accurate check, but we are in the wrong stage to do that and looking for1215 // `Result::map_err` by checking the Self type and the path segment is enough.1216 // sym::ok_or_else1217 && (1218 ( // Result::map_err1219 path_segment.ident.name == sym::map_err1220 && is_diagnostic_item(sym::Result, next_ty)1221 ) || ( // Option::ok_or_else1222 path_segment.ident.name == sym::ok_or_else1223 && is_diagnostic_item(sym::Option, next_ty)1224 )1225 )1226 // Found `Result<_, ()>?`1227 && let ty::Tuple(tys) = found_ty.kind()1228 && tys.is_empty()1229 // The current method call returns `Result<_, ()>`1230 && self.can_eq(obligation.param_env, ty, found_ty)1231 // There's a single argument in the method call and it is a closure1232 && let [arg] = args1233 && let hir::ExprKind::Closure(closure) = arg.kind1234 // The closure has a block for its body with no tail expression1235 && let body = self.tcx.hir_body(closure.body)1236 && let hir::ExprKind::Block(block, _) = body.value.kind1237 && let None = block.expr1238 // The last statement is of a type that can be converted to the return error type1239 && let [.., stmt] = block.stmts1240 && let hir::StmtKind::Semi(expr) = stmt.kind1241 && let expr_ty = self.resolve_vars_if_possible(1242 typeck.expr_ty_adjusted_opt(expr)1243 .unwrap_or(Ty::new_misc_error(self.tcx)),1244 )1245 && self1246 .infcx1247 .type_implements_trait(1248 self.tcx.get_diagnostic_item(sym::From).unwrap(),1249 [self_ty, expr_ty],1250 obligation.param_env,1251 )1252 .must_apply_modulo_regions()1253 {1254 suggested = true;1255 err.span_suggestion_short(1256 stmt.span.with_lo(expr.span.hi()),1257 "remove this semicolon",1258 String::new(),1259 Applicability::MachineApplicable,1260 );1261 }12621263 prev_ty = next_ty;12641265 if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind1266 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path1267 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)1268 {1269 let parent = self.tcx.parent_hir_node(binding.hir_id);1270 // We've reached the root of the method call chain...1271 if let hir::Node::LetStmt(local) = parent1272 && let Some(binding_expr) = local.init1273 {1274 // ...and it is a binding. Get the binding creation and continue the chain.1275 expr = binding_expr;1276 }1277 if let hir::Node::Param(_param) = parent {1278 // ...and it is an fn argument.1279 break;1280 }1281 }1282 }1283 // `expr` is now the "root" expression of the method call chain, which can be any1284 // expression kind, like a method call or a path. If this expression is `Result<T, E>` as1285 // well, then we also point at it.1286 prev_ty = self.resolve_vars_if_possible(1287 typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),1288 );1289 chain.push((expr.span, prev_ty));12901291 let mut prev = None;1292 let mut iter = chain.into_iter().rev().peekable();1293 while let Some((span, err_ty)) = iter.next() {1294 let is_last = iter.peek().is_none();1295 let err_ty = get_e_type(err_ty);1296 let err_ty = match (err_ty, prev) {1297 (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => {1298 err_ty1299 }1300 (Some(err_ty), None) => err_ty,1301 _ => {1302 prev = err_ty;1303 continue;1304 }1305 };13061307 let implements_from = self1308 .infcx1309 .type_implements_trait(1310 self.tcx.get_diagnostic_item(sym::From).unwrap(),1311 [self_ty, err_ty],1312 obligation.param_env,1313 )1314 .must_apply_modulo_regions();13151316 let err_ty_str = self.tcx.short_string(err_ty, err.long_ty_path());1317 let label = if !implements_from && is_last {1318 format!(1319 "this can't be annotated with `?` because it has type `Result<_, {err_ty_str}>`"1320 )1321 } else {1322 format!("this has type `Result<_, {err_ty_str}>`")1323 };13241325 if !suggested || !implements_from {1326 err.span_label(span, label);1327 }1328 prev = Some(err_ty);1329 }1330 (suggested, noted_missing_impl)1331 }13321333 fn note_missing_impl_for_question_mark(1334 &self,1335 err: &mut Diag<'_>,1336 self_ty: Ty<'_>,1337 found_ty: Option<Ty<'_>>,1338 trait_pred: ty::PolyTraitPredicate<'tcx>,1339 ) -> bool {1340 match (self_ty.kind(), found_ty) {1341 (ty::Adt(def, _), Some(ty))1342 if let ty::Adt(found, _) = ty.kind()1343 && def.did().is_local()1344 && found.did().is_local() =>1345 {1346 err.span_note(1347 self.tcx.def_span(def.did()),1348 format!("`{self_ty}` needs to implement `From<{ty}>`"),1349 );1350 }1351 (ty::Adt(def, _), None) if def.did().is_local() => {1352 let trait_path = self.tcx.short_string(1353 trait_pred.skip_binder().trait_ref.print_only_trait_path(),1354 err.long_ty_path(),1355 );1356 err.span_note(1357 self.tcx.def_span(def.did()),1358 format!("`{self_ty}` needs to implement `{trait_path}`"),1359 );1360 }1361 (ty::Adt(def, _), Some(ty)) if def.did().is_local() => {1362 err.span_note(1363 self.tcx.def_span(def.did()),1364 format!("`{self_ty}` needs to implement `From<{ty}>`"),1365 );1366 }1367 (_, Some(ty))1368 if let ty::Adt(def, _) = ty.kind()1369 && def.did().is_local() =>1370 {1371 err.span_note(1372 self.tcx.def_span(def.did()),1373 format!("`{ty}` needs to implement `Into<{self_ty}>`"),1374 );1375 }1376 _ => return false,1377 }1378 true1379 }13801381 fn report_const_param_not_wf(1382 &self,1383 ty: Ty<'tcx>,1384 obligation: &PredicateObligation<'tcx>,1385 ) -> Diag<'a> {1386 let def_id = obligation.cause.body_id;1387 let span = self.tcx.ty_span(def_id);13881389 let mut file = None;1390 let ty_str = self.tcx.short_string(ty, &mut file);1391 let mut diag = match ty.kind() {1392 ty::Float(_) => {1393 struct_span_code_err!(1394 self.dcx(),1395 span,1396 E0741,1397 "`{ty_str}` is forbidden as the type of a const generic parameter",1398 )1399 }1400 ty::FnPtr(..) => {1401 struct_span_code_err!(1402 self.dcx(),1403 span,1404 E0741,1405 "using function pointers as const generic parameters is forbidden",1406 )1407 }1408 ty::RawPtr(_, _) => {1409 struct_span_code_err!(1410 self.dcx(),1411 span,1412 E0741,1413 "using raw pointers as const generic parameters is forbidden",1414 )1415 }1416 ty::Adt(def, _) => {1417 // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...1418 let mut diag = struct_span_code_err!(1419 self.dcx(),1420 span,1421 E0741,1422 "`{ty_str}` must implement `ConstParamTy` to be used as the type of a const generic parameter",1423 );1424 // Only suggest derive if this isn't a derived obligation,1425 // and the struct is local.1426 if let Some(span) = self.tcx.hir_span_if_local(def.did())1427 && obligation.cause.code().parent().is_none()1428 {1429 if ty.is_structural_eq_shallow(self.tcx) {1430 diag.span_suggestion(1431 span.shrink_to_lo(),1432 format!("add `#[derive(ConstParamTy)]` to the {}", def.descr()),1433 "#[derive(ConstParamTy)]\n",1434 Applicability::MachineApplicable,1435 );1436 } else {1437 // FIXME(adt_const_params): We should check there's not already an1438 // overlapping `Eq`/`PartialEq` impl.1439 diag.span_suggestion(1440 span.shrink_to_lo(),1441 format!(1442 "add `#[derive(ConstParamTy, PartialEq, Eq)]` to the {}",1443 def.descr()1444 ),1445 "#[derive(ConstParamTy, PartialEq, Eq)]\n",1446 Applicability::MachineApplicable,1447 );1448 }1449 }1450 diag1451 }1452 _ => {1453 struct_span_code_err!(1454 self.dcx(),1455 span,1456 E0741,1457 "`{ty_str}` can't be used as a const parameter type",1458 )1459 }1460 };1461 diag.long_ty_path = file;14621463 let mut code = obligation.cause.code();1464 let mut pred = obligation.predicate.as_trait_clause();1465 while let Some((next_code, next_pred)) = code.parent_with_predicate() {1466 if let Some(pred) = pred {1467 self.enter_forall(pred, |pred| {1468 let ty = self.tcx.short_string(pred.self_ty(), diag.long_ty_path());1469 let trait_path = self1470 .tcx1471 .short_string(pred.print_modifiers_and_trait_path(), diag.long_ty_path());1472 diag.note(format!("`{ty}` must implement `{trait_path}`, but it does not"));1473 })1474 }1475 code = next_code;1476 pred = next_pred;1477 }14781479 diag1480 }1481}14821483impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {1484 fn can_match_trait(1485 &self,1486 param_env: ty::ParamEnv<'tcx>,1487 goal: ty::TraitPredicate<'tcx>,1488 assumption: ty::PolyTraitPredicate<'tcx>,1489 ) -> bool {1490 // Fast path1491 if goal.polarity != assumption.polarity() {1492 return false;1493 }14941495 let trait_assumption = self.instantiate_binder_with_fresh_vars(1496 DUMMY_SP,1497 infer::BoundRegionConversionTime::HigherRankedType,1498 assumption,1499 );15001501 self.can_eq(param_env, goal.trait_ref, trait_assumption.trait_ref)1502 }15031504 fn can_match_host_effect(1505 &self,1506 param_env: ty::ParamEnv<'tcx>,1507 goal: ty::HostEffectPredicate<'tcx>,1508 assumption: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,1509 ) -> bool {1510 let assumption = self.instantiate_binder_with_fresh_vars(1511 DUMMY_SP,1512 infer::BoundRegionConversionTime::HigherRankedType,1513 assumption,1514 );15151516 assumption.constness.satisfies(goal.constness)1517 && self.can_eq(param_env, goal.trait_ref, assumption.trait_ref)1518 }15191520 fn as_host_effect_clause(1521 predicate: ty::Predicate<'tcx>,1522 ) -> Option<ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>> {1523 predicate.as_clause().and_then(|clause| match clause.kind().skip_binder() {1524 ty::ClauseKind::HostEffect(pred) => Some(clause.kind().rebind(pred)),1525 _ => None,1526 })1527 }15281529 fn can_match_projection(1530 &self,1531 param_env: ty::ParamEnv<'tcx>,1532 goal: ty::ProjectionPredicate<'tcx>,1533 assumption: ty::PolyProjectionPredicate<'tcx>,1534 ) -> bool {1535 let assumption = self.instantiate_binder_with_fresh_vars(1536 DUMMY_SP,1537 infer::BoundRegionConversionTime::HigherRankedType,1538 assumption,1539 );15401541 self.can_eq(param_env, goal.projection_term, assumption.projection_term)1542 && self.can_eq(param_env, goal.term, assumption.term)1543 }15441545 // returns if `cond` not occurring implies that `error` does not occur - i.e., that1546 // `error` occurring implies that `cond` occurs.1547 #[instrument(level = "debug", skip(self), ret)]1548 pub(super) fn error_implies(1549 &self,1550 cond: Goal<'tcx, ty::Predicate<'tcx>>,1551 error: Goal<'tcx, ty::Predicate<'tcx>>,1552 ) -> bool {1553 if cond == error {1554 return true;1555 }15561557 // FIXME: We could be smarter about this, i.e. if cond's param-env is a1558 // subset of error's param-env. This only matters when binders will carry1559 // predicates though, and obviously only matters for error reporting.1560 if cond.param_env != error.param_env {1561 return false;1562 }1563 let param_env = error.param_env;15641565 if let Some(error) = error.predicate.as_trait_clause() {1566 self.enter_forall(error, |error| {1567 elaborate(self.tcx, std::iter::once(cond.predicate))1568 .filter_map(|implied| implied.as_trait_clause())1569 .any(|implied| self.can_match_trait(param_env, error, implied))1570 })1571 } else if let Some(error) = Self::as_host_effect_clause(error.predicate) {1572 self.enter_forall(error, |error| {1573 elaborate(self.tcx, std::iter::once(cond.predicate))1574 .filter_map(Self::as_host_effect_clause)1575 .any(|implied| self.can_match_host_effect(param_env, error, implied))1576 })1577 } else if let Some(error) = error.predicate.as_projection_clause() {1578 self.enter_forall(error, |error| {1579 elaborate(self.tcx, std::iter::once(cond.predicate))1580 .filter_map(|implied| implied.as_projection_clause())1581 .any(|implied| self.can_match_projection(param_env, error, implied))1582 })1583 } else {1584 false1585 }1586 }15871588 #[instrument(level = "debug", skip_all)]1589 pub(super) fn report_projection_error(1590 &self,1591 obligation: &PredicateObligation<'tcx>,1592 error: &MismatchedProjectionTypes<'tcx>,1593 ) -> ErrorGuaranteed {1594 let predicate = self.resolve_vars_if_possible(obligation.predicate);15951596 if let Err(e) = predicate.error_reported() {1597 return e;1598 }15991600 self.probe(|_| {1601 // try to find the mismatched types to report the error with.1602 //1603 // this can fail if the problem was higher-ranked, in which1604 // cause I have no idea for a good error message.1605 let bound_predicate = predicate.kind();1606 let (values, err) = match bound_predicate.skip_binder() {1607 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {1608 let ocx = ObligationCtxt::new(self);16091610 let data = self.instantiate_binder_with_fresh_vars(1611 obligation.cause.span,1612 infer::BoundRegionConversionTime::HigherRankedType,1613 bound_predicate.rebind(data),1614 );1615 let unnormalized_term = data.projection_term.to_term(self.tcx);1616 // FIXME(-Znext-solver): For diagnostic purposes, it would be nice1617 // to deeply normalize this type.1618 let normalized_term = ocx.normalize(1619 &obligation.cause,1620 obligation.param_env,1621 Unnormalized::new_wip(unnormalized_term),1622 );16231624 // constrain inference variables a bit more to nested obligations from normalize so1625 // we can have more helpful errors.1626 //1627 // we intentionally drop errors from normalization here,1628 // since the normalization is just done to improve the error message.1629 let _ = ocx.try_evaluate_obligations();16301631 if let Err(new_err) =1632 ocx.eq(&obligation.cause, obligation.param_env, data.term, normalized_term)1633 {1634 (1635 Some((1636 data.projection_term,1637 self.resolve_vars_if_possible(normalized_term),1638 data.term,1639 )),1640 new_err,1641 )1642 } else {1643 (None, error.err)1644 }1645 }1646 ty::PredicateKind::AliasRelate(lhs, rhs, _) => {1647 let derive_better_type_error =1648 |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {1649 let ocx = ObligationCtxt::new(self);16501651 let normalized_term = ocx.normalize(1652 &ObligationCause::dummy(),1653 obligation.param_env,1654 Unnormalized::new_wip(alias_term.to_term(self.tcx)),1655 );16561657 if let Err(terr) = ocx.eq(1658 &ObligationCause::dummy(),1659 obligation.param_env,1660 expected_term,1661 normalized_term,1662 ) {1663 Some((terr, self.resolve_vars_if_possible(normalized_term)))1664 } else {1665 None1666 }1667 };16681669 if let Some(lhs) = lhs.to_alias_term()1670 && let ty::AliasTermKind::ProjectionTy { .. }1671 | ty::AliasTermKind::ProjectionConst { .. } = lhs.kind1672 && let Some((better_type_err, expected_term)) =1673 derive_better_type_error(lhs, rhs)1674 {1675 (1676 Some((lhs, self.resolve_vars_if_possible(expected_term), rhs)),1677 better_type_err,1678 )1679 } else if let Some(rhs) = rhs.to_alias_term()1680 && let ty::AliasTermKind::ProjectionTy { .. }1681 | ty::AliasTermKind::ProjectionConst { .. } = rhs.kind1682 && let Some((better_type_err, expected_term)) =1683 derive_better_type_error(rhs, lhs)1684 {1685 (1686 Some((rhs, self.resolve_vars_if_possible(expected_term), lhs)),1687 better_type_err,1688 )1689 } else {1690 (None, error.err)1691 }1692 }1693 _ => (None, error.err),1694 };16951696 let mut file = None;1697 let (msg, span, closure_span) = values1698 .and_then(|(predicate, normalized_term, expected_term)| {1699 self.maybe_detailed_projection_msg(1700 obligation.cause.span,1701 predicate,1702 normalized_term,1703 expected_term,1704 &mut file,1705 )1706 })1707 .unwrap_or_else(|| {1708 (1709 with_forced_trimmed_paths!(format!(1710 "type mismatch resolving `{}`",1711 self.tcx1712 .short_string(self.resolve_vars_if_possible(predicate), &mut file),1713 )),1714 obligation.cause.span,1715 None,1716 )1717 });1718 let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}");1719 *diag.long_ty_path() = file;1720 if let Some(span) = closure_span {1721 // Mark the closure decl so that it is seen even if we are pointing at the return1722 // type or expression.1723 //1724 // error[E0271]: expected `{closure@foo.rs:41:16}` to be a closure that returns1725 // `Unit3`, but it returns `Unit4`1726 // --> $DIR/foo.rs:43:171727 // |1728 // LL | let v = Unit2.m(1729 // | - required by a bound introduced by this call1730 // ...1731 // LL | f: |x| {1732 // | --- /* this span */1733 // LL | drop(x);1734 // LL | Unit41735 // | ^^^^^ expected `Unit3`, found `Unit4`1736 // |1737 diag.span_label(span, "this closure");1738 if !span.overlaps(obligation.cause.span) {1739 // Point at the binding corresponding to the closure where it is used.1740 diag.span_label(obligation.cause.span, "closure used here");1741 }1742 }17431744 let secondary_span = self.probe(|_| {1745 let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =1746 predicate.kind().skip_binder()1747 else {1748 return None;1749 };1750 if !proj.projection_term.kind.is_trait_projection() {1751 return None;1752 }17531754 let trait_ref = self.enter_forall_and_leak_universe(1755 predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)),1756 );1757 let Ok(Some(ImplSource::UserDefined(impl_data))) =1758 SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref))1759 else {1760 return None;1761 };17621763 let Ok(node) =1764 specialization_graph::assoc_def(self.tcx, impl_data.impl_def_id, proj.def_id())1765 else {1766 return None;1767 };17681769 if !node.is_final() {1770 return None;1771 }17721773 match self.tcx.hir_get_if_local(node.item.def_id) {1774 Some(1775 hir::Node::TraitItem(hir::TraitItem {1776 kind: hir::TraitItemKind::Type(_, Some(ty)),1777 ..1778 })1779 | hir::Node::ImplItem(hir::ImplItem {1780 kind: hir::ImplItemKind::Type(ty),1781 ..1782 }),1783 ) => Some((1784 ty.span,1785 with_forced_trimmed_paths!(Cow::from(format!(1786 "type mismatch resolving `{}`",1787 self.tcx.short_string(1788 self.resolve_vars_if_possible(predicate),1789 diag.long_ty_path()1790 ),1791 ))),1792 true,1793 )),1794 _ => None,1795 }1796 });17971798 self.note_type_err(1799 &mut diag,1800 &obligation.cause,1801 secondary_span,1802 values.map(|(_, normalized_ty, expected_ty)| {1803 obligation.param_env.and(infer::ValuePairs::Terms(ExpectedFound::new(1804 expected_ty,1805 normalized_ty,1806 )))1807 }),1808 err,1809 false,1810 Some(span),1811 );1812 self.note_obligation_cause(&mut diag, obligation);1813 diag.emit()1814 })1815 }18161817 fn maybe_detailed_projection_msg(1818 &self,1819 mut span: Span,1820 projection_term: ty::AliasTerm<'tcx>,1821 normalized_ty: ty::Term<'tcx>,1822 expected_ty: ty::Term<'tcx>,1823 long_ty_path: &mut Option<PathBuf>,1824 ) -> Option<(String, Span, Option<Span>)> {1825 if !projection_term.kind.is_trait_projection() {1826 return None;1827 }18281829 let projection_def_id = projection_term.expect_projection_def_id();1830 let trait_def_id = projection_term.trait_def_id(self.tcx);1831 let self_ty = projection_term.self_ty();18321833 with_forced_trimmed_paths! {1834 if self.tcx.is_lang_item(projection_def_id, LangItem::FnOnceOutput) {1835 let (span, closure_span) = if let ty::Closure(def_id, _) = *self_ty.kind() {1836 let def_span = self.tcx.def_span(def_id);1837 if let Some(local_def_id) = def_id.as_local()1838 && let node = self.tcx.hir_node_by_def_id(local_def_id)1839 && let Some(fn_decl) = node.fn_decl()1840 && let Some(id) = node.body_id()1841 {1842 span = match fn_decl.output {1843 hir::FnRetTy::Return(ty) => ty.span,1844 hir::FnRetTy::DefaultReturn(_) => {1845 let body = self.tcx.hir_body(id);1846 match body.value.kind {1847 hir::ExprKind::Block(1848 hir::Block { expr: Some(expr), .. },1849 _,1850 ) => expr.span,1851 hir::ExprKind::Block(1852 hir::Block {1853 expr: None, stmts: [.., last], ..1854 },1855 _,1856 ) => last.span,1857 _ => body.value.span,1858 }1859 }1860 };1861 }1862 (span, Some(def_span))1863 } else {1864 (span, None)1865 };1866 let item = match self_ty.kind() {1867 ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),1868 _ => self.tcx.short_string(self_ty, long_ty_path),1869 };1870 let expected_ty = self.tcx.short_string(expected_ty, long_ty_path);1871 let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path);1872 Some((format!(1873 "expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`",1874 ), span, closure_span))1875 } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) {1876 let self_ty = self.tcx.short_string(self_ty, long_ty_path);1877 let expected_ty = self.tcx.short_string(expected_ty, long_ty_path);1878 let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path);1879 Some((format!(1880 "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \1881 resolves to `{normalized_ty}`"1882 ), span, None))1883 } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {1884 let self_ty = self.tcx.short_string(self_ty, long_ty_path);1885 let expected_ty = self.tcx.short_string(expected_ty, long_ty_path);1886 let normalized_ty = self.tcx.short_string(normalized_ty, long_ty_path);1887 Some((format!(1888 "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \1889 yields `{normalized_ty}`"1890 ), span, None))1891 } else {1892 None1893 }1894 }1895 }18961897 pub fn fuzzy_match_tys(1898 &self,1899 mut a: Ty<'tcx>,1900 mut b: Ty<'tcx>,1901 ignoring_lifetimes: bool,1902 ) -> Option<CandidateSimilarity> {1903 /// returns the fuzzy category of a given type, or None1904 /// if the type can be equated to any type.1905 fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {1906 match t.kind() {1907 ty::Bool => Some(0),1908 ty::Char => Some(1),1909 ty::Str => Some(2),1910 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => Some(2),1911 ty::Int(..)1912 | ty::Uint(..)1913 | ty::Float(..)1914 | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),1915 ty::Ref(..) | ty::RawPtr(..) => Some(5),1916 ty::Array(..) | ty::Slice(..) => Some(6),1917 ty::FnDef(..) | ty::FnPtr(..) => Some(7),1918 ty::Dynamic(..) => Some(8),1919 ty::Closure(..) => Some(9),1920 ty::Tuple(..) => Some(10),1921 ty::Param(..) => Some(11),1922 ty::Alias(ty::AliasTy { kind: ty::Projection { .. }, .. }) => Some(12),1923 ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => Some(13),1924 ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => Some(14),1925 ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => Some(15),1926 ty::Never => Some(16),1927 ty::Adt(..) => Some(17),1928 ty::Coroutine(..) => Some(18),1929 ty::Foreign(..) => Some(19),1930 ty::CoroutineWitness(..) => Some(20),1931 ty::CoroutineClosure(..) => Some(21),1932 ty::Pat(..) => Some(22),1933 ty::UnsafeBinder(..) => Some(23),1934 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,1935 }1936 }19371938 let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {1939 loop {1940 match t.kind() {1941 ty::Ref(_, inner, _) | ty::RawPtr(inner, _) => t = *inner,1942 _ => break t,1943 }1944 }1945 };19461947 if !ignoring_lifetimes {1948 a = strip_references(a);1949 b = strip_references(b);1950 }19511952 let cat_a = type_category(self.tcx, a)?;1953 let cat_b = type_category(self.tcx, b)?;1954 if a == b {1955 Some(CandidateSimilarity::Exact { ignoring_lifetimes })1956 } else if cat_a == cat_b {1957 match (a.kind(), b.kind()) {1958 (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,1959 (ty::Foreign(def_a), ty::Foreign(def_b)) => def_a == def_b,1960 // Matching on references results in a lot of unhelpful1961 // suggestions, so let's just not do that for now.1962 //1963 // We still upgrade successful matches to `ignoring_lifetimes: true`1964 // to prioritize that impl.1965 (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {1966 self.fuzzy_match_tys(a, b, true).is_some()1967 }1968 _ => true,1969 }1970 .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })1971 } else if ignoring_lifetimes {1972 None1973 } else {1974 self.fuzzy_match_tys(a, b, true)1975 }1976 }19771978 pub(super) fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str {1979 match kind {1980 hir::ClosureKind::Closure => "a closure",1981 hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine",1982 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1983 hir::CoroutineDesugaring::Async,1984 hir::CoroutineSource::Block,1985 )) => "an async block",1986 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1987 hir::CoroutineDesugaring::Async,1988 hir::CoroutineSource::Fn,1989 )) => "an async function",1990 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1991 hir::CoroutineDesugaring::Async,1992 hir::CoroutineSource::Closure,1993 ))1994 | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {1995 "an async closure"1996 }1997 hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(1998 hir::CoroutineDesugaring::AsyncGen,1999 hir::CoroutineSource::Block,2000 )) => "an async gen block",
Findings
✓ No findings reported for this file.