From 8360a40a8a2ff2098eed561dd89c577349dbbb76 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 8 Sep 2022 22:28:00 +0300 Subject: [PATCH 01/16] Migrate named_anon_conflict.rs --- .../locales/en-US/infer.ftl | 11 ++++++ compiler/rustc_infer/src/errors/mod.rs | 24 +++++++++++- .../nice_region_error/named_anon_conflict.rs | 38 +++++++------------ 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index c9d83746d54..40ca2c1cd16 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -172,3 +172,14 @@ infer_msl_unmet_req = because this has an unmet lifetime requirement infer_msl_trait_note = this has an implicit `'static` lifetime requirement infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement infer_suggest_add_let_for_letchains = consider adding `let` + +infer_explicit_lifetime_required = explicit lifetime required in {$ident_kind -> + [ident] the type of `{$simple_ident}` + *[param_type] parameter type +} + .label = lifetime `{$named}` required + +infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$ident_kind -> + [ident] the type of `{$simple_ident}` + *[param_type] type +} diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index c4f11472d55..99112397c7f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -357,8 +357,8 @@ impl AddToDiagnostic for LifetimeMismatchLabels { pub struct AddLifetimeParamsSuggestion<'a> { pub tcx: TyCtxt<'a>, pub sub: Region<'a>, - pub ty_sup: &'a Ty<'a>, - pub ty_sub: &'a Ty<'a>, + pub ty_sup: &'a hir::Ty<'a>, + pub ty_sub: &'a hir::Ty<'a>, pub add_note: bool, } @@ -520,3 +520,23 @@ pub struct MismatchedStaticLifetime<'a> { #[subdiagnostic] pub implicit_static_lifetimes: Vec, } + +#[derive(SessionDiagnostic)] +#[diag(infer::explicit_lifetime_required, code = "E0621")] +pub struct ExplicitLifetimeRequired<'a> { + #[primary_span] + #[label] + pub span: Span, + pub ident_kind: &'static str, + pub simple_ident: String, + pub named: String, + + #[suggestion( + infer::explicit_lifetime_required_sugg, + code = "{new_ty}", + applicability = "unspecified" + )] + pub new_ty_span: Span, + #[skip_arg] + pub new_ty: Ty<'a>, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 3fe7c1598fc..d7751158902 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -1,8 +1,11 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where one region is named and the other is anonymous. -use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use crate::{ + errors::ExplicitLifetimeRequired, + infer::error_reporting::nice_region_error::find_anon_type::find_anon_type, +}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_middle::ty; use rustc_span::symbol::kw; @@ -87,30 +90,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { return None; } - let (error_var, span_label_var) = match param.pat.simple_ident() { - Some(simple_ident) => ( - format!("the type of `{}`", simple_ident), - format!("the type of `{}`", simple_ident), - ), - None => ("parameter type".to_owned(), "type".to_owned()), + let simple_ident = param.pat.simple_ident(); + let (ident_kind, simple_ident) = match simple_ident { + Some(ident) => ("ident", ident.to_string()), + None => ("param_type", String::new()), }; - let mut diag = struct_span_err!( - self.tcx().sess, - span, - E0621, - "explicit lifetime required in {}", - error_var - ); + let named = named.to_string(); - diag.span_label(span, format!("lifetime `{}` required", named)); - diag.span_suggestion( - new_ty_span, - &format!("add explicit lifetime `{}` to {}", named, span_label_var), - new_ty, - Applicability::Unspecified, - ); - - Some(diag) + let err = + ExplicitLifetimeRequired { span, ident_kind, simple_ident, named, new_ty_span, new_ty }; + let err = self.tcx().sess.parse_sess.create_err(err); + Some(err) } } From 2118ff401f64789b6a9e64134d6d2797efee4be9 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 11 Sep 2022 00:45:38 +0300 Subject: [PATCH 02/16] Migrate placeholder_error.rs --- .../locales/en-US/infer.ftl | 28 ++ compiler/rustc_infer/src/errors/mod.rs | 41 +++ .../nice_region_error/placeholder_error.rs | 253 +++++++++--------- 3 files changed, 191 insertions(+), 131 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 40ca2c1cd16..a52ac133946 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -183,3 +183,31 @@ infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$id [ident] the type of `{$simple_ident}` *[param_type] type } + +infer_actual_impl_expl_1 = {$leading_ellipsis -> + [true] ... + *[false] {""} +}{$kind -> + [signature] closure with signature `{$ty_or_sig}` must implement `{$trait_path}` + [passive] `{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` + *[other] `{$ty_or_sig}` must implement `{$trait_path}` +}{$lt_kind -> + [two] , for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... + [any] , for any lifetime `'{$lifetime_1}`... + [some] , for some specific lifetime `'{lifetime_1}`... + *[nothing] {""} +} + +infer_actual_impl_expl_2 = {$kind_2 -> + [implements_trait] ...but it actually implements `{$trait_path_2}` + [implemented_for_ty] ...but `{$trait_path_2}` is actually implemented for the type `{$ty}` + *[ty_implements] ...but `{$ty}` actually implements `{$trait_path_2}` +}{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} + +infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough + .label_satisfy = doesn't satisfy where-clause + .label_where = due to a where-clause on `{$def_id}`... + .label_dup = implementation of `{$trait_def_id}` is not general enough diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 99112397c7f..f694c5ca409 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -540,3 +540,44 @@ pub struct ExplicitLifetimeRequired<'a> { #[skip_arg] pub new_ty: Ty<'a>, } + +#[derive(SessionSubdiagnostic)] +pub enum ActualImplExplNotes { + // Field names have to be different across all variants + #[note(infer::actual_impl_expl_1)] + NoteOne { + leading_ellipsis: bool, + kind: &'static str, + ty_or_sig: String, + trait_path: String, + lt_kind: &'static str, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(infer::actual_impl_expl_2)] + NoteTwo { + kind_2: &'static str, + trait_path_2: String, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, +} + +#[derive(SessionDiagnostic)] +#[diag(infer::trait_placeholder_mismatch)] +pub struct TraitPlaceholderMismatch { + #[primary_span] + pub span: Span, + #[label(infer::label_satisfy)] + pub satisfy_span: Option, + #[label(infer::label_where)] + pub where_span: Option, + #[label(infer::label_dup)] + pub dup_span: Option, + pub def_id: String, + pub trait_def_id: String, + + #[subdiagnostic] + pub actual_impl_expl_notes: Vec, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index fed9fda74bf..d9fc2ec243f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -1,10 +1,11 @@ +use crate::errors::{ActualImplExplNotes, TraitPlaceholderMismatch}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; -use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::error::ExpectedFound; @@ -12,7 +13,7 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt}; -use std::fmt::{self, Write}; +use std::fmt; impl<'tcx> NiceRegionError<'_, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and @@ -205,26 +206,21 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { actual_substs: SubstsRef<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let span = cause.span(); - let msg = format!( - "implementation of `{}` is not general enough", - self.tcx().def_path_str(trait_def_id), - ); - let mut err = self.tcx().sess.struct_span_err(span, &msg); - let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) - | ObligationCauseCode::ExprItemObligation(def_id, ..) = - *cause.code() - { - err.span_label(span, "doesn't satisfy where-clause"); - err.span_label( - self.tcx().def_span(def_id), - &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), - ); - true - } else { - err.span_label(span, &msg); - false - }; + let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = + if let ObligationCauseCode::ItemObligation(def_id) + | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code() + { + ( + true, + Some(span), + Some(self.tcx().def_span(def_id)), + None, + self.tcx().def_path_str(def_id), + ) + } else { + (false, None, None, Some(span), String::new()) + }; let expected_trait_ref = self .cx @@ -284,8 +280,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ?expected_self_ty_has_vid, ); - self.explain_actual_impl_that_was_found( - &mut err, + let actual_impl_expl_notes = self.explain_actual_impl_that_was_found( sub_placeholder, sup_placeholder, has_sub, @@ -299,7 +294,17 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { leading_ellipsis, ); - err + let diag = TraitPlaceholderMismatch { + span, + satisfy_span, + where_span, + dup_span, + def_id, + trait_def_id: self.tcx().def_path_str(trait_def_id), + actual_impl_expl_notes, + }; + + self.tcx().sess.create_err(diag) } /// Add notes with details about the expected and actual trait refs, with attention to cases @@ -309,7 +314,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { /// due to the number of combinations we have to deal with. fn explain_actual_impl_that_was_found( &self, - err: &mut Diagnostic, sub_placeholder: Option>, sup_placeholder: Option>, has_sub: Option, @@ -321,7 +325,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { actual_has_vid: Option, any_self_ty_has_vid: bool, leading_ellipsis: bool, - ) { + ) -> Vec { // HACK(eddyb) maybe move this in a more central location. #[derive(Copy, Clone)] struct Highlighted<'tcx, T> { @@ -380,120 +384,107 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref); expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub); expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup); - err.note(&{ - let passive_voice = match (has_sub, has_sup) { - (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid, - (None, None) => { - expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid); - match expected_has_vid { - Some(_) => true, - None => any_self_ty_has_vid, - } - } - }; - let mut note = if same_self_type { - let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); - self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); - - if self_ty.value.is_closure() - && self.tcx().is_fn_trait(expected_trait_ref.value.def_id) - { - let closure_sig = self_ty.map(|closure| { - if let ty::Closure(_, substs) = closure.kind() { - self.tcx().signature_unclosure( - substs.as_closure().sig(), - rustc_hir::Unsafety::Normal, - ) - } else { - bug!("type is not longer closure"); - } - }); - - format!( - "{}closure with signature `{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - closure_sig, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - } else { - format!( - "{}`{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - self_ty, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - } - } else if passive_voice { - format!( - "{}`{}` would have to be implemented for the type `{}`", - if leading_ellipsis { "..." } else { "" }, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - expected_trait_ref.map(|tr| tr.self_ty()), - ) - } else { - format!( - "{}`{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - expected_trait_ref.map(|tr| tr.self_ty()), - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - }; - - match (has_sub, has_sup) { - (Some(n1), Some(n2)) => { - let _ = write!( - note, - ", for any two lifetimes `'{}` and `'{}`...", - std::cmp::min(n1, n2), - std::cmp::max(n1, n2), - ); - } - (Some(n), _) | (_, Some(n)) => { - let _ = write!(note, ", for any lifetime `'{}`...", n,); - } - (None, None) => { - if let Some(n) = expected_has_vid { - let _ = write!(note, ", for some specific lifetime `'{}`...", n,); - } + let passive_voice = match (has_sub, has_sup) { + (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid, + (None, None) => { + expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid); + match expected_has_vid { + Some(_) => true, + None => any_self_ty_has_vid, } } + }; - note - }); + let (kind, ty_or_sig, trait_path) = if same_self_type { + let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); + self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); + + if self_ty.value.is_closure() + && self.tcx().is_fn_trait(expected_trait_ref.value.def_id) + { + let closure_sig = self_ty.map(|closure| { + if let ty::Closure(_, substs) = closure.kind() { + self.tcx().signature_unclosure( + substs.as_closure().sig(), + rustc_hir::Unsafety::Normal, + ) + } else { + bug!("type is not longer closure"); + } + }); + ( + "signature", + closure_sig.to_string(), + expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + ) + } else { + ( + "other", + self_ty.to_string(), + expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + ) + } + } else if passive_voice { + ( + "passive", + expected_trait_ref.map(|tr| tr.self_ty()).to_string(), + expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + ) + } else { + ( + "other", + expected_trait_ref.map(|tr| tr.self_ty()).to_string(), + expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + ) + }; + + let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) { + (Some(n1), Some(n2)) => ("two", std::cmp::min(n1, n2), std::cmp::max(n1, n2)), + (Some(n), _) | (_, Some(n)) => ("any", n, 0), + (None, None) => { + if let Some(n) = expected_has_vid { + ("some", n, 0) + } else { + ("nothing", 0, 0) + } + } + }; + + let note_1 = ActualImplExplNotes::NoteOne { + leading_ellipsis, + kind, + ty_or_sig, + trait_path, + lt_kind, + lifetime_1, + lifetime_2, + }; let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref); actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid); - err.note(&{ - let passive_voice = match actual_has_vid { - Some(_) => any_self_ty_has_vid, - None => true, - }; - let mut note = if same_self_type { - format!( - "...but it actually implements `{}`", - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - } else if passive_voice { - format!( - "...but `{}` is actually implemented for the type `{}`", - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - actual_trait_ref.map(|tr| tr.self_ty()), - ) - } else { - format!( - "...but `{}` actually implements `{}`", - actual_trait_ref.map(|tr| tr.self_ty()), - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - }; + let passive_voice = match actual_has_vid { + Some(_) => any_self_ty_has_vid, + None => true, + }; - if let Some(n) = actual_has_vid { - let _ = write!(note, ", for some specific lifetime `'{}`", n); - } + let trait_path_2 = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(); + let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string(); + let kind_2 = if same_self_type { + "implements_trait" + } else if passive_voice { + "implemented_for_ty" + } else { + "ty_implements" + }; - note - }); + let has_lifetime = actual_has_vid.is_some(); + let lifetime = actual_has_vid.unwrap_or_default(); + + let note_2 = + ActualImplExplNotes::NoteTwo { kind_2, trait_path_2, ty, has_lifetime, lifetime }; + + vec![note_1, note_2] } } From 3935a81d473167387123f8d48087f5ee446f92c4 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 13 Sep 2022 20:11:42 +0300 Subject: [PATCH 03/16] Migrate trait_impl_difference.rs --- .../locales/en-US/infer.ftl | 10 +++++ compiler/rustc_infer/src/errors/mod.rs | 38 +++++++++++++++++++ .../trait_impl_difference.rs | 38 ++++++------------- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index a52ac133946..d28608cf47d 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -211,3 +211,13 @@ infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not ge .label_satisfy = doesn't satisfy where-clause .label_where = due to a where-clause on `{$def_id}`... .label_dup = implementation of `{$trait_def_id}` is not general enough + +infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature + .found = found `{$found}` + .expected = expected `{$expected}` + .expected_found = expected `{$expected}` + {" "}found `{$found}` + +infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output +infer_tid_consider_borriwing = consider borrowing this type parameter in the trait +infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index f694c5ca409..e2579ab7b7c 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -581,3 +581,41 @@ pub struct TraitPlaceholderMismatch { #[subdiagnostic] pub actual_impl_expl_notes: Vec, } + +pub struct ConsiderBorrowingParamHelp { + pub spans: Vec, +} + +impl AddSubdiagnostic for ConsiderBorrowingParamHelp { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + let mut type_param_span: MultiSpan = self.spans.clone().into(); + for &span in &self.spans { + type_param_span.push_span_label(span, fluent::infer::tid_consider_borriwing); + } + diag.span_help(type_param_span, fluent::infer::tid_param_help); + } +} + +#[derive(SessionSubdiagnostic)] +#[help(infer::tid_rel_help)] +pub struct RelationshipHelp; + +#[derive(SessionDiagnostic)] +#[diag(infer::trait_impl_diff)] +pub struct TraitImplDiff { + #[primary_span] + #[label(infer::found)] + pub sp: Span, + #[label(infer::expected)] + pub trait_sp: Span, + #[note(infer::expected_found)] + pub note: (), + #[subdiagnostic] + pub param_help: ConsiderBorrowingParamHelp, + #[subdiagnostic] + // Seems like subdiagnostics are always pushed to the end, so this one + // also has to be a subdiagnostic to maintain order. + pub rel_help: Option, + pub expected: String, + pub found: String, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 5d536e982ed..bacd8894a0f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -1,10 +1,11 @@ //! Error Reporting for `impl` items that do not match the obligations from their `trait`. +use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::Subtype; use crate::traits::ObligationCauseCode::CompareImplItemObligation; -use rustc_errors::{ErrorGuaranteed, MultiSpan}; +use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; @@ -51,10 +52,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { trait_def_id: DefId, ) -> ErrorGuaranteed { let trait_sp = self.tcx().def_span(trait_def_id); - let mut err = self - .tcx() - .sess - .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); // Mark all unnamed regions in the type with a number. // This diagnostic is called in response to lifetime errors, so be informative. @@ -91,9 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let found = self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; - err.span_label(sp, &format!("found `{}`", found)); - err.span_label(trait_sp, &format!("expected `{}`", expected)); - // Get the span of all the used type parameters in the method. let assoc_item = self.tcx().associated_item(trait_def_id); let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] }; @@ -110,26 +104,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } _ => {} } - let mut type_param_span: MultiSpan = visitor.types.to_vec().into(); - for &span in &visitor.types { - type_param_span - .push_span_label(span, "consider borrowing this type parameter in the trait"); - } - err.note(&format!("expected `{}`\n found `{}`", expected, found)); + let diag = TraitImplDiff { + sp, + trait_sp, + note: (), + param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() }, + rel_help: visitor.types.is_empty().then_some(RelationshipHelp), + expected, + found, + }; - err.span_help( - type_param_span, - "the lifetime requirements from the `impl` do not correspond to the requirements in \ - the `trait`", - ); - if visitor.types.is_empty() { - err.help( - "verify the lifetime relationships in the `trait` and `impl` between the `self` \ - argument, the other inputs and its output", - ); - } - err.emit() + self.tcx().sess.emit_err(diag) } } From 0634b0119cadbf4fcc90d8a399b1c46e1442a5b5 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sat, 17 Sep 2022 02:54:59 +0300 Subject: [PATCH 04/16] Partial work on static_impl_trait.rs --- .../locales/en-US/infer.ftl | 52 +++++ compiler/rustc_infer/src/errors/mod.rs | 97 ++++++++++ .../nice_region_error/static_impl_trait.rs | 183 +++++++----------- 3 files changed, 221 insertions(+), 111 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index d28608cf47d..7a10f4b7bc5 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -221,3 +221,55 @@ infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signatu infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output infer_tid_consider_borriwing = consider borrowing this type parameter in the trait infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + +infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement +infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s 'static` requirement +infer_dtcs_has_req_note = the used `impl` has a `'static` requirement +infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement + +infer_but_calling_introduces = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$lifetime_kind -> + [named] lifetime `{lifetime}` + *[anon] an anonymous lifetime `'_` +} but calling `{assoc_item}` introduces an implicit `'static` lifetime requirement + .label1 = {$has_lifetime -> + [named] lifetime `{lifetime}` + *[anon] an anonymous lifetime `'_` + } + .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> + [named] `impl` of `{$impl_path}` + *[anon] inherent `impl` + } + +infer_but_needs_to_satisfy = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$has_lifetime -> + [named] lifetime `{lifetime}` + *[anon] an anonymous lifetime `'_` +} but it needs to satisfy a `'static` lifetime requirement + .influencer = this data with {$has_lifetime -> + [named] lifetime `{lifetime}` + *[anon] an anonymous lifetime `'_` + }... + .require = {$spans_empty -> + *[true] ...is used and required to live as long as `'static` here + [false] ...and is required to live as long as `'static` here + } + .used_here = ...is used here... + .introduced_by_bound = 'static` lifetime requirement introduced by this bound + +infer_more_targeted = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$has_lifetime -> + [named] lifetime `{lifetime}` + *[anon] an anonymous lifetime `'_` +} but calling `{$ident}` introduces an implicit `'static` lifetime requirement + +infer_ril_introduced_here = `'static` requirement introduced here +infer_ril_introduced_by = requirement introduced by this return type +infer_ril_because_of = because of this returned expression +infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index e2579ab7b7c..dc79c725951 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -8,6 +8,7 @@ use rustc_hir::{FnRetTy, Ty}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::{Region, TyCtxt}; use rustc_span::symbol::kw; +use rustc_span::Symbol; use rustc_span::{symbol::Ident, BytePos, Span}; use crate::infer::error_reporting::{ @@ -619,3 +620,99 @@ pub struct TraitImplDiff { pub expected: String, pub found: String, } + +pub struct DynTraitConstraintSuggestion { + pub span: Span, + pub ident: Ident, +} + +impl AddSubdiagnostic for DynTraitConstraintSuggestion { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + let mut multi_span: MultiSpan = vec![self.span].into(); + multi_span.push_span_label(self.span, fluent::infer::dtcs_has_lifetime_req_label); + multi_span.push_span_label(self.ident.span, fluent::infer::dtcs_introduces_requirement); + diag.span_note(multi_span, fluent::infer::dtcs_has_req_note); + diag.span_suggestion_verbose( + self.span.shrink_to_hi(), + fluent::infer::dtcs_suggestion, + " + '_", + Applicability::MaybeIncorrect, + ); + } +} + +#[derive(SessionDiagnostic)] +#[diag(infer::but_calling_introduces, code = "E0772")] +pub struct ButCallingIntroduces { + #[label(infer::label1)] + pub param_ty_span: Span, + #[primary_span] + #[label(infer::label2)] + pub cause_span: Span, + + pub has_param_name: bool, + pub param_name: String, + pub has_lifetime: bool, + pub lifetime: String, + pub assoc_item: Symbol, + pub has_impl_path: bool, + pub impl_path: String, +} + +pub struct ReqIntroducedLocations { + pub span: MultiSpan, + pub spans: Vec, + pub fn_decl_span: Span, + pub cause_span: Span, + pub add_label: bool, +} + +impl AddSubdiagnostic for ReqIntroducedLocations { + fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { + for sp in self.spans { + self.span.push_span_label(sp, fluent::infer::ril_introduced_here); + } + + if self.add_label { + self.span.push_span_label(self.fn_decl_span, fluent::infer::ril_introduced_by); + } + self.span.push_span_label(self.cause_span, fluent::infer::ril_because_of); + diag.span_note(self.span, fluent::infer::ril_static_introduced_by); + } +} + +pub struct MoreTargeted { + pub ident: Symbol, +} + +impl AddSubdiagnostic for MoreTargeted { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + diag.code(rustc_errors::error_code!(E0772)); + diag.set_primary_message(fluent::infer::more_targeted); + diag.set_arg("ident", self.ident); + } +} + +#[derive(SessionDiagnostic)] +#[diag(infer::but_needs_to_satisfy, code = "E0759")] +pub struct ButNeedsToSatisfy { + #[primary_span] + pub sp: Span, + #[label(infer::influencer)] + pub influencer_point: Span, + #[label(infer::used_here)] + pub spans: Vec, + #[label(infer::require)] + pub require_span_as_label: Option, + #[note(infer::require)] + pub require_span_as_note: Option, + #[note(infer::introduced_by_bound)] + pub bound: Option, + + #[subdiagnostic] + pub req_introduces_loc: Option, + + pub spans_empty: bool, + pub has_lifetime: bool, + pub lifetime: String, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 9bd2202d260..b76f7e7689f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -1,11 +1,15 @@ //! Error Reporting for static impl Traits. +use crate::errors::{ + ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted, + ReqIntroducedLocations, +}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{AddSubdiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; @@ -49,46 +53,33 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } let param = self.find_param_with_region(*sup_r, *sub_r)?; - let lifetime = if sup_r.has_name() { - format!("lifetime `{}`", sup_r) - } else { - "an anonymous lifetime `'_`".to_string() + let simple_ident = param.param.pat.simple_ident(); + + let (has_impl_path, impl_path) = match ctxt.assoc_item.container { + AssocItemContainer::TraitContainer => { + let id = ctxt.assoc_item.container_id(tcx); + (true, tcx.def_path_str(id)) + } + AssocItemContainer::ImplContainer => (false, String::new()), }; - let mut err = struct_span_err!( - tcx.sess, - cause.span, - E0772, - "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ - requirement", - param - .param - .pat - .simple_ident() - .map(|s| format!("`{}`", s)) - .unwrap_or_else(|| "`fn` parameter".to_string()), - lifetime, - ctxt.assoc_item.name, - ); - err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); - err.span_label( - cause.span, - &format!( - "...is used and required to live as long as `'static` here \ - because of an implicit lifetime bound on the {}", - match ctxt.assoc_item.container { - AssocItemContainer::TraitContainer => { - let id = ctxt.assoc_item.container_id(tcx); - format!("`impl` of `{}`", tcx.def_path_str(id)) - } - AssocItemContainer::ImplContainer => "inherent `impl`".to_string(), - }, - ), - ); + + let diag = ButCallingIntroduces { + param_ty_span: param.param_ty_span, + cause_span: cause.span, + has_param_name: simple_ident.is_some(), + param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), + has_lifetime: sup_r.has_name(), + lifetime: sup_r.to_string(), + assoc_item: ctxt.assoc_item.name, + has_impl_path, + impl_path, + }; + let mut err = self.tcx().sess.create_err(diag); if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { let reported = err.emit(); return Some(reported); } else { - err.cancel(); + err.cancel() } } return None; @@ -104,25 +95,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let sp = var_origin.span(); let return_sp = sub_origin.span(); let param = self.find_param_with_region(*sup_r, *sub_r)?; - let (lifetime_name, lifetime) = if sup_r.has_name() { - (sup_r.to_string(), format!("lifetime `{}`", sup_r)) - } else { - ("'_".to_owned(), "an anonymous lifetime `'_`".to_string()) - }; - let param_name = param - .param - .pat - .simple_ident() - .map(|s| format!("`{}`", s)) - .unwrap_or_else(|| "`fn` parameter".to_string()); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0759, - "{} has {} but it needs to satisfy a `'static` lifetime requirement", - param_name, - lifetime, - ); + let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() }; let (mention_influencer, influencer_point) = if sup_origin.span().overlaps(param.param_ty_span) { @@ -141,7 +114,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } else { (!sup_origin.span().overlaps(return_sp), param.param_ty_span) }; - err.span_label(influencer_point, &format!("this data with {}...", lifetime)); debug!("try_report_static_impl_trait: param_info={:?}", param); @@ -155,31 +127,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { spans.dedup_by_key(|span| (span.lo(), span.hi())); // We try to make the output have fewer overlapping spans if possible. - let require_msg = if spans.is_empty() { - "...is used and required to live as long as `'static` here" - } else { - "...and is required to live as long as `'static` here" - }; let require_span = if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; - for span in &spans { - err.span_label(*span, "...is used here..."); - } - - if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) { - // If any of the "captured here" labels appears on the same line or after - // `require_span`, we put it on a note to ensure the text flows by appearing - // always at the end. - err.span_note(require_span, require_msg); + let spans_empty = spans.is_empty(); + let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp); + let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { + Some(*bound) } else { - // We don't need a note, it's already at the end, it can be shown as a `span_label`. - err.span_label(require_span, require_msg); - } + None + }; + + let mut subdiag = None; - if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { - err.span_note(*bound, "`'static` lifetime requirement introduced by this bound"); - } if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { if let ObligationCauseCode::ReturnValue(hir_id) | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code() @@ -187,33 +147,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let parent_id = tcx.hir().get_parent_item(*hir_id); if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) { let mut span: MultiSpan = fn_decl.output.span().into(); + let mut spans = Vec::new(); let mut add_label = true; if let hir::FnRetTy::Return(ty) = fn_decl.output { let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); v.visit_ty(ty); if !v.0.is_empty() { span = v.0.clone().into(); - for sp in v.0 { - span.push_span_label(sp, "`'static` requirement introduced here"); - } + spans = v.0; add_label = false; } } - if add_label { - span.push_span_label( - fn_decl.output.span(), - "requirement introduced by this return type", - ); - } - span.push_span_label(cause.span, "because of this returned expression"); - err.span_note( + let fn_decl_span = fn_decl.output.span(); + + subdiag = Some(ReqIntroducedLocations { span, - "`'static` lifetime requirement introduced by the return type", - ); + spans, + fn_decl_span, + cause_span: cause.span, + add_label, + }); } } } + let diag = ButNeedsToSatisfy { + sp, + influencer_point, + spans: spans.clone(), + // If any of the "captured here" labels appears on the same line or after + // `require_span`, we put it on a note to ensure the text flows by appearing + // always at the end. + require_span_as_note: require_as_note.then_some(require_span), + // We don't need a note, it's already at the end, it can be shown as a `span_label`. + require_span_as_label: (!require_as_note).then_some(require_span), + req_introduces_loc: subdiag, + + has_lifetime: sup_r.has_name(), + lifetime: sup_r.to_string(), + spans_empty, + bound, + }; + + let mut err = self.tcx().sess.create_err(diag); + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); let mut override_error_code = None; @@ -247,12 +224,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { // Provide a more targeted error code and description. - err.code(rustc_errors::error_code!(E0772)); - err.set_primary_message(&format!( - "{} has {} but calling `{}` introduces an implicit `'static` lifetime \ - requirement", - param_name, lifetime, ident, - )); + let retarget_subdiag = MoreTargeted { ident }; + retarget_subdiag.add_to_diagnostic(&mut err); } let arg = match param.param.pat.simple_ident() { @@ -513,21 +486,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let mut traits = vec![]; let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did); hir_v.visit_ty(&self_ty); - for span in &traits { - let mut multi_span: MultiSpan = vec![*span].into(); - multi_span - .push_span_label(*span, "this has an implicit `'static` lifetime requirement"); - multi_span.push_span_label( - ident.span, - "calling this method introduces the `impl`'s 'static` requirement", - ); - err.span_note(multi_span, "the used `impl` has a `'static` requirement"); - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_", - Applicability::MaybeIncorrect, - ); + for &span in &traits { + let subdiag = DynTraitConstraintSuggestion { span, ident }; + subdiag.add_to_diagnostic(err); suggested = true; } } From 57fdd196aeda1e0fa5829248bd4afb8e6f06d7e5 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 22 Sep 2022 17:29:21 +0300 Subject: [PATCH 05/16] Rebase and fix --- compiler/rustc_infer/src/errors/mod.rs | 26 +++++++++---------- .../nice_region_error/static_impl_trait.rs | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index dc79c725951..55df63075d2 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -4,9 +4,9 @@ use rustc_errors::{ MultiSpan, SubdiagnosticMessage, }; use rustc_hir as hir; -use rustc_hir::{FnRetTy, Ty}; +use rustc_hir::FnRetTy; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{Region, TyCtxt}; +use rustc_middle::ty::{Region, Ty, TyCtxt}; use rustc_span::symbol::kw; use rustc_span::Symbol; use rustc_span::{symbol::Ident, BytePos, Span}; @@ -522,7 +522,7 @@ pub struct MismatchedStaticLifetime<'a> { pub implicit_static_lifetimes: Vec, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(infer::explicit_lifetime_required, code = "E0621")] pub struct ExplicitLifetimeRequired<'a> { #[primary_span] @@ -542,7 +542,7 @@ pub struct ExplicitLifetimeRequired<'a> { pub new_ty: Ty<'a>, } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] pub enum ActualImplExplNotes { // Field names have to be different across all variants #[note(infer::actual_impl_expl_1)] @@ -565,7 +565,7 @@ pub enum ActualImplExplNotes { }, } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(infer::trait_placeholder_mismatch)] pub struct TraitPlaceholderMismatch { #[primary_span] @@ -587,7 +587,7 @@ pub struct ConsiderBorrowingParamHelp { pub spans: Vec, } -impl AddSubdiagnostic for ConsiderBorrowingParamHelp { +impl AddToDiagnostic for ConsiderBorrowingParamHelp { fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { @@ -597,11 +597,11 @@ impl AddSubdiagnostic for ConsiderBorrowingParamHelp { } } -#[derive(SessionSubdiagnostic)] +#[derive(Subdiagnostic)] #[help(infer::tid_rel_help)] pub struct RelationshipHelp; -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(infer::trait_impl_diff)] pub struct TraitImplDiff { #[primary_span] @@ -626,7 +626,7 @@ pub struct DynTraitConstraintSuggestion { pub ident: Ident, } -impl AddSubdiagnostic for DynTraitConstraintSuggestion { +impl AddToDiagnostic for DynTraitConstraintSuggestion { fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer::dtcs_has_lifetime_req_label); @@ -641,7 +641,7 @@ impl AddSubdiagnostic for DynTraitConstraintSuggestion { } } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(infer::but_calling_introduces, code = "E0772")] pub struct ButCallingIntroduces { #[label(infer::label1)] @@ -667,7 +667,7 @@ pub struct ReqIntroducedLocations { pub add_label: bool, } -impl AddSubdiagnostic for ReqIntroducedLocations { +impl AddToDiagnostic for ReqIntroducedLocations { fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { for sp in self.spans { self.span.push_span_label(sp, fluent::infer::ril_introduced_here); @@ -685,7 +685,7 @@ pub struct MoreTargeted { pub ident: Symbol, } -impl AddSubdiagnostic for MoreTargeted { +impl AddToDiagnostic for MoreTargeted { fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { diag.code(rustc_errors::error_code!(E0772)); diag.set_primary_message(fluent::infer::more_targeted); @@ -693,7 +693,7 @@ impl AddSubdiagnostic for MoreTargeted { } } -#[derive(SessionDiagnostic)] +#[derive(Diagnostic)] #[diag(infer::but_needs_to_satisfy, code = "E0759")] pub struct ButNeedsToSatisfy { #[primary_span] diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index b76f7e7689f..fbc71bd7e01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -9,7 +9,7 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{AddSubdiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; From 6c19c08140b7c0c5a9f9f9a434036b460167c87d Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 25 Sep 2022 10:55:42 +0300 Subject: [PATCH 06/16] More descriptive names for ActualImplExplNotes variants --- compiler/rustc_error_messages/locales/en-US/infer.ftl | 4 ++-- compiler/rustc_infer/src/errors/mod.rs | 8 ++++---- .../nice_region_error/placeholder_error.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 7a10f4b7bc5..8cfd20c6eda 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -184,7 +184,7 @@ infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$id *[param_type] type } -infer_actual_impl_expl_1 = {$leading_ellipsis -> +infer_actual_impl_expl_expected = {$leading_ellipsis -> [true] ... *[false] {""} }{$kind -> @@ -198,7 +198,7 @@ infer_actual_impl_expl_1 = {$leading_ellipsis -> *[nothing] {""} } -infer_actual_impl_expl_2 = {$kind_2 -> +infer_actual_impl_expl_but_actually = {$kind_2 -> [implements_trait] ...but it actually implements `{$trait_path_2}` [implemented_for_ty] ...but `{$trait_path_2}` is actually implemented for the type `{$ty}` *[ty_implements] ...but `{$ty}` actually implements `{$trait_path_2}` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 55df63075d2..edd9eca24cb 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -545,8 +545,8 @@ pub struct ExplicitLifetimeRequired<'a> { #[derive(Subdiagnostic)] pub enum ActualImplExplNotes { // Field names have to be different across all variants - #[note(infer::actual_impl_expl_1)] - NoteOne { + #[note(infer::actual_impl_expl_expected)] + Expected { leading_ellipsis: bool, kind: &'static str, ty_or_sig: String, @@ -555,8 +555,8 @@ pub enum ActualImplExplNotes { lifetime_1: usize, lifetime_2: usize, }, - #[note(infer::actual_impl_expl_2)] - NoteTwo { + #[note(infer::actual_impl_expl_but_actually)] + ButActually { kind_2: &'static str, trait_path_2: String, has_lifetime: bool, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index d9fc2ec243f..cf1032f7006 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -451,7 +451,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { } }; - let note_1 = ActualImplExplNotes::NoteOne { + let note_1 = ActualImplExplNotes::Expected { leading_ellipsis, kind, ty_or_sig, @@ -483,7 +483,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let lifetime = actual_has_vid.unwrap_or_default(); let note_2 = - ActualImplExplNotes::NoteTwo { kind_2, trait_path_2, ty, has_lifetime, lifetime }; + ActualImplExplNotes::ButActually { kind_2, trait_path_2, ty, has_lifetime, lifetime }; vec![note_1, note_2] } From 71d24da665c122fe885d0f62917c01b7f8e8d77f Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 29 Sep 2022 17:10:43 +0300 Subject: [PATCH 07/16] Split into several messages --- .../locales/en-US/infer.ftl | 71 ++++++-- compiler/rustc_infer/src/errors/mod.rs | 168 +++++++++++++++++- .../nice_region_error/placeholder_error.rs | 58 +++--- 3 files changed, 250 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 8cfd20c6eda..4a43d150968 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -184,25 +184,64 @@ infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$id *[param_type] type } -infer_actual_impl_expl_expected = {$leading_ellipsis -> +infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> [true] ... *[false] {""} -}{$kind -> - [signature] closure with signature `{$ty_or_sig}` must implement `{$trait_path}` - [passive] `{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` - *[other] `{$ty_or_sig}` must implement `{$trait_path}` -}{$lt_kind -> - [two] , for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... - [any] , for any lifetime `'{$lifetime_1}`... - [some] , for some specific lifetime `'{lifetime_1}`... - *[nothing] {""} -} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`... +infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` +infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{lifetime_1}`... +infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` +infer_actual_impl_expl_expected_other_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +infer_actual_impl_expl_expected_other_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +infer_actual_impl_expl_expected_other_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{lifetime_1}`... +infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}` -infer_actual_impl_expl_but_actually = {$kind_2 -> - [implements_trait] ...but it actually implements `{$trait_path_2}` - [implemented_for_ty] ...but `{$trait_path_2}` is actually implemented for the type `{$ty}` - *[ty_implements] ...but `{$ty}` actually implements `{$trait_path_2}` -}{$has_lifetime -> +infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path_2}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} +infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path_2}` is actually implemented for the type `{$ty}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} +infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path_2}`{$has_lifetime -> [true] , for some specific lifetime `'{$lifetime}` *[false] {""} } diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index edd9eca24cb..69fc3be2bc3 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -544,25 +544,177 @@ pub struct ExplicitLifetimeRequired<'a> { #[derive(Subdiagnostic)] pub enum ActualImplExplNotes { - // Field names have to be different across all variants - #[note(infer::actual_impl_expl_expected)] - Expected { + // Field names have to be different across Expected* and ButActually variants + #[note(infer::actual_impl_expl_expected_signature_two)] + ExpectedSignatureTwo { leading_ellipsis: bool, - kind: &'static str, ty_or_sig: String, trait_path: String, - lt_kind: &'static str, lifetime_1: usize, lifetime_2: usize, }, - #[note(infer::actual_impl_expl_but_actually)] - ButActually { - kind_2: &'static str, + #[note(infer::actual_impl_expl_expected_signature_any)] + ExpectedSignatureAny { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + }, + #[note(infer::actual_impl_expl_expected_signature_some)] + ExpectedSignatureSome { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + }, + #[note(infer::actual_impl_expl_expected_signature_nothing)] + ExpectedSignatureNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, + #[note(infer::actual_impl_expl_expected_passive_two)] + ExpectedPassiveTwo { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(infer::actual_impl_expl_expected_passive_any)] + ExpectedPassiveAny { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + }, + #[note(infer::actual_impl_expl_expected_passive_some)] + ExpectedPassiveSome { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + }, + #[note(infer::actual_impl_expl_expected_passive_nothing)] + ExpectedPassiveNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, + #[note(infer::actual_impl_expl_expected_other_two)] + ExpectedOtherTwo { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(infer::actual_impl_expl_expected_other_any)] + ExpectedOtherAny { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + }, + #[note(infer::actual_impl_expl_expected_other_some)] + ExpectedOtherSome { + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + }, + #[note(infer::actual_impl_expl_expected_other_nothing)] + ExpectedOtherNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, + #[note(infer::actual_impl_expl_but_actually_implements_trait)] + ButActuallyImplementsTrait { trait_path_2: String, has_lifetime: bool, lifetime: usize }, + #[note(infer::actual_impl_expl_but_actually_implemented_for_ty)] + ButActuallyImplementedForTy { trait_path_2: String, has_lifetime: bool, lifetime: usize, ty: String, }, + #[note(infer::actual_impl_expl_but_actually_ty_implements)] + ButActuallyTyImplements { + trait_path_2: String, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, +} + +pub enum ActualImplExpectedKind { + Signature, + Passive, + Other, +} + +pub enum ActualImplExpectedLifetimeKind { + Two, + Any, + Some, + Nothing, +} + +impl ActualImplExplNotes { + pub fn new_expected( + kind: ActualImplExpectedKind, + lt_kind: ActualImplExpectedLifetimeKind, + leading_ellipsis: bool, + ty_or_sig: String, + trait_path: String, + lifetime_1: usize, + lifetime_2: usize, + ) -> Self { + match (kind, lt_kind) { + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedSignatureTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedPassiveTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedOtherTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } + } + } + } } #[derive(Diagnostic)] diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index cf1032f7006..d2fd4f6cd7c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -1,4 +1,7 @@ -use crate::errors::{ActualImplExplNotes, TraitPlaceholderMismatch}; +use crate::errors::{ + ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes, + TraitPlaceholderMismatch, +}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::ValuePairs; @@ -414,52 +417,54 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { } }); ( - "signature", + ActualImplExpectedKind::Signature, closure_sig.to_string(), expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), ) } else { ( - "other", + ActualImplExpectedKind::Other, self_ty.to_string(), expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), ) } } else if passive_voice { ( - "passive", + ActualImplExpectedKind::Passive, expected_trait_ref.map(|tr| tr.self_ty()).to_string(), expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), ) } else { ( - "other", + ActualImplExpectedKind::Other, expected_trait_ref.map(|tr| tr.self_ty()).to_string(), expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), ) }; let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) { - (Some(n1), Some(n2)) => ("two", std::cmp::min(n1, n2), std::cmp::max(n1, n2)), - (Some(n), _) | (_, Some(n)) => ("any", n, 0), + (Some(n1), Some(n2)) => { + (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2)) + } + (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0), (None, None) => { if let Some(n) = expected_has_vid { - ("some", n, 0) + (ActualImplExpectedLifetimeKind::Some, n, 0) } else { - ("nothing", 0, 0) + (ActualImplExpectedLifetimeKind::Nothing, 0, 0) } } }; - let note_1 = ActualImplExplNotes::Expected { - leading_ellipsis, + let note_1 = ActualImplExplNotes::new_expected( kind, + lt_kind, + leading_ellipsis, ty_or_sig, trait_path, - lt_kind, lifetime_1, lifetime_2, - }; + ); let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref); actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid); @@ -471,19 +476,26 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let trait_path_2 = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(); let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string(); - let kind_2 = if same_self_type { - "implements_trait" - } else if passive_voice { - "implemented_for_ty" - } else { - "ty_implements" - }; - let has_lifetime = actual_has_vid.is_some(); let lifetime = actual_has_vid.unwrap_or_default(); - let note_2 = - ActualImplExplNotes::ButActually { kind_2, trait_path_2, ty, has_lifetime, lifetime }; + let note_2 = if same_self_type { + ActualImplExplNotes::ButActuallyImplementsTrait { trait_path_2, has_lifetime, lifetime } + } else if passive_voice { + ActualImplExplNotes::ButActuallyImplementedForTy { + trait_path_2, + ty, + has_lifetime, + lifetime, + } + } else { + ActualImplExplNotes::ButActuallyTyImplements { + trait_path_2, + ty, + has_lifetime, + lifetime, + } + }; vec![note_1, note_2] } From eb7ce1703bb719c1d038be6572a349a3e70f7ca2 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Fri, 14 Oct 2022 21:50:06 +0300 Subject: [PATCH 08/16] Use eager translation --- .../locales/en-US/infer.ftl | 2 +- compiler/rustc_infer/src/errors/mod.rs | 38 +++++++++++++------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 4a43d150968..4219964a877 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -258,7 +258,7 @@ infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signatu {" "}found `{$found}` infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output -infer_tid_consider_borriwing = consider borrowing this type parameter in the trait +infer_tid_consider_borrowing = consider borrowing this type parameter in the trait infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 69fc3be2bc3..9092874dfae 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -544,7 +544,6 @@ pub struct ExplicitLifetimeRequired<'a> { #[derive(Subdiagnostic)] pub enum ActualImplExplNotes { - // Field names have to be different across Expected* and ButActually variants #[note(infer::actual_impl_expl_expected_signature_two)] ExpectedSignatureTwo { leading_ellipsis: bool, @@ -731,7 +730,7 @@ pub struct TraitPlaceholderMismatch { pub def_id: String, pub trait_def_id: String, - #[subdiagnostic] + #[subdiagnostic(eager)] pub actual_impl_expl_notes: Vec, } @@ -740,12 +739,17 @@ pub struct ConsiderBorrowingParamHelp { } impl AddToDiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { - type_param_span.push_span_label(span, fluent::infer::tid_consider_borriwing); + // Seems like we can't call f() here as Into is required + type_param_span.push_span_label(span, fluent::infer::tid_consider_borrowing); } - diag.span_help(type_param_span, fluent::infer::tid_param_help); + let msg = f(diag, fluent::infer::tid_param_help.into()); + diag.span_help(type_param_span, msg); } } @@ -779,14 +783,19 @@ pub struct DynTraitConstraintSuggestion { } impl AddToDiagnostic for DynTraitConstraintSuggestion { - fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { let mut multi_span: MultiSpan = vec![self.span].into(); multi_span.push_span_label(self.span, fluent::infer::dtcs_has_lifetime_req_label); multi_span.push_span_label(self.ident.span, fluent::infer::dtcs_introduces_requirement); - diag.span_note(multi_span, fluent::infer::dtcs_has_req_note); + let msg = f(diag, fluent::infer::dtcs_has_req_note.into()); + diag.span_note(multi_span, msg); + let msg = f(diag, fluent::infer::dtcs_suggestion.into()); diag.span_suggestion_verbose( self.span.shrink_to_hi(), - fluent::infer::dtcs_suggestion, + msg, " + '_", Applicability::MaybeIncorrect, ); @@ -820,7 +829,10 @@ pub struct ReqIntroducedLocations { } impl AddToDiagnostic for ReqIntroducedLocations { - fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { + fn add_to_diagnostic_with(mut self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { for sp in self.spans { self.span.push_span_label(sp, fluent::infer::ril_introduced_here); } @@ -829,7 +841,8 @@ impl AddToDiagnostic for ReqIntroducedLocations { self.span.push_span_label(self.fn_decl_span, fluent::infer::ril_introduced_by); } self.span.push_span_label(self.cause_span, fluent::infer::ril_because_of); - diag.span_note(self.span, fluent::infer::ril_static_introduced_by); + let msg = f(diag, fluent::infer::ril_static_introduced_by.into()); + diag.span_note(self.span, msg); } } @@ -838,7 +851,10 @@ pub struct MoreTargeted { } impl AddToDiagnostic for MoreTargeted { - fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, + { diag.code(rustc_errors::error_code!(E0772)); diag.set_primary_message(fluent::infer::more_targeted); diag.set_arg("ident", self.ident); From 40b221814ea00a9d279474188d81b9a063eb3f68 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sat, 15 Oct 2022 13:16:51 +0300 Subject: [PATCH 09/16] Rename subdiagnostic fields that do not need to be unique now --- .../rustc_error_messages/locales/en-US/infer.ftl | 6 +++--- compiler/rustc_infer/src/errors/mod.rs | 11 +++-------- .../nice_region_error/placeholder_error.rs | 13 ++++--------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 4219964a877..f74af62702e 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -233,15 +233,15 @@ infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> *[false] {""} }`{$ty_or_sig}` must implement `{$trait_path}` -infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path_2}`{$has_lifetime -> +infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> [true] , for some specific lifetime `'{$lifetime}` *[false] {""} } -infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path_2}` is actually implemented for the type `{$ty}`{$has_lifetime -> +infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> [true] , for some specific lifetime `'{$lifetime}` *[false] {""} } -infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path_2}`{$has_lifetime -> +infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> [true] , for some specific lifetime `'{$lifetime}` *[false] {""} } diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 9092874dfae..1733b6e148f 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -617,21 +617,16 @@ pub enum ActualImplExplNotes { #[note(infer::actual_impl_expl_expected_other_nothing)] ExpectedOtherNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, #[note(infer::actual_impl_expl_but_actually_implements_trait)] - ButActuallyImplementsTrait { trait_path_2: String, has_lifetime: bool, lifetime: usize }, + ButActuallyImplementsTrait { trait_path: String, has_lifetime: bool, lifetime: usize }, #[note(infer::actual_impl_expl_but_actually_implemented_for_ty)] ButActuallyImplementedForTy { - trait_path_2: String, + trait_path: String, has_lifetime: bool, lifetime: usize, ty: String, }, #[note(infer::actual_impl_expl_but_actually_ty_implements)] - ButActuallyTyImplements { - trait_path_2: String, - has_lifetime: bool, - lifetime: usize, - ty: String, - }, + ButActuallyTyImplements { trait_path: String, has_lifetime: bool, lifetime: usize, ty: String }, } pub enum ActualImplExpectedKind { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index d2fd4f6cd7c..904723c4da9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -474,27 +474,22 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { None => true, }; - let trait_path_2 = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(); + let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(); let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string(); let has_lifetime = actual_has_vid.is_some(); let lifetime = actual_has_vid.unwrap_or_default(); let note_2 = if same_self_type { - ActualImplExplNotes::ButActuallyImplementsTrait { trait_path_2, has_lifetime, lifetime } + ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime } } else if passive_voice { ActualImplExplNotes::ButActuallyImplementedForTy { - trait_path_2, + trait_path, ty, has_lifetime, lifetime, } } else { - ActualImplExplNotes::ButActuallyTyImplements { - trait_path_2, - ty, - has_lifetime, - lifetime, - } + ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime } }; vec![note_1, note_2] From 19b8579803979dd3b1e83f7aa9655920eef14b98 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Mon, 24 Oct 2022 19:06:45 +0300 Subject: [PATCH 10/16] Address changes of pr 103345 --- compiler/rustc_infer/src/errors/mod.rs | 92 +++++++++++++------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 1733b6e148f..51b04eb0df0 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -523,7 +523,7 @@ pub struct MismatchedStaticLifetime<'a> { } #[derive(Diagnostic)] -#[diag(infer::explicit_lifetime_required, code = "E0621")] +#[diag(infer_explicit_lifetime_required, code = "E0621")] pub struct ExplicitLifetimeRequired<'a> { #[primary_span] #[label] @@ -533,7 +533,7 @@ pub struct ExplicitLifetimeRequired<'a> { pub named: String, #[suggestion( - infer::explicit_lifetime_required_sugg, + infer_explicit_lifetime_required_sugg, code = "{new_ty}", applicability = "unspecified" )] @@ -544,7 +544,7 @@ pub struct ExplicitLifetimeRequired<'a> { #[derive(Subdiagnostic)] pub enum ActualImplExplNotes { - #[note(infer::actual_impl_expl_expected_signature_two)] + #[note(infer_actual_impl_expl_expected_signature_two)] ExpectedSignatureTwo { leading_ellipsis: bool, ty_or_sig: String, @@ -552,23 +552,23 @@ pub enum ActualImplExplNotes { lifetime_1: usize, lifetime_2: usize, }, - #[note(infer::actual_impl_expl_expected_signature_any)] + #[note(infer_actual_impl_expl_expected_signature_any)] ExpectedSignatureAny { leading_ellipsis: bool, ty_or_sig: String, trait_path: String, lifetime_1: usize, }, - #[note(infer::actual_impl_expl_expected_signature_some)] + #[note(infer_actual_impl_expl_expected_signature_some)] ExpectedSignatureSome { leading_ellipsis: bool, ty_or_sig: String, trait_path: String, lifetime_1: usize, }, - #[note(infer::actual_impl_expl_expected_signature_nothing)] + #[note(infer_actual_impl_expl_expected_signature_nothing)] ExpectedSignatureNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, - #[note(infer::actual_impl_expl_expected_passive_two)] + #[note(infer_actual_impl_expl_expected_passive_two)] ExpectedPassiveTwo { leading_ellipsis: bool, ty_or_sig: String, @@ -576,23 +576,23 @@ pub enum ActualImplExplNotes { lifetime_1: usize, lifetime_2: usize, }, - #[note(infer::actual_impl_expl_expected_passive_any)] + #[note(infer_actual_impl_expl_expected_passive_any)] ExpectedPassiveAny { leading_ellipsis: bool, ty_or_sig: String, trait_path: String, lifetime_1: usize, }, - #[note(infer::actual_impl_expl_expected_passive_some)] + #[note(infer_actual_impl_expl_expected_passive_some)] ExpectedPassiveSome { leading_ellipsis: bool, ty_or_sig: String, trait_path: String, lifetime_1: usize, }, - #[note(infer::actual_impl_expl_expected_passive_nothing)] + #[note(infer_actual_impl_expl_expected_passive_nothing)] ExpectedPassiveNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, - #[note(infer::actual_impl_expl_expected_other_two)] + #[note(infer_actual_impl_expl_expected_other_two)] ExpectedOtherTwo { leading_ellipsis: bool, ty_or_sig: String, @@ -600,32 +600,32 @@ pub enum ActualImplExplNotes { lifetime_1: usize, lifetime_2: usize, }, - #[note(infer::actual_impl_expl_expected_other_any)] + #[note(infer_actual_impl_expl_expected_other_any)] ExpectedOtherAny { leading_ellipsis: bool, ty_or_sig: String, trait_path: String, lifetime_1: usize, }, - #[note(infer::actual_impl_expl_expected_other_some)] + #[note(infer_actual_impl_expl_expected_other_some)] ExpectedOtherSome { leading_ellipsis: bool, ty_or_sig: String, trait_path: String, lifetime_1: usize, }, - #[note(infer::actual_impl_expl_expected_other_nothing)] + #[note(infer_actual_impl_expl_expected_other_nothing)] ExpectedOtherNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, - #[note(infer::actual_impl_expl_but_actually_implements_trait)] + #[note(infer_actual_impl_expl_but_actually_implements_trait)] ButActuallyImplementsTrait { trait_path: String, has_lifetime: bool, lifetime: usize }, - #[note(infer::actual_impl_expl_but_actually_implemented_for_ty)] + #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)] ButActuallyImplementedForTy { trait_path: String, has_lifetime: bool, lifetime: usize, ty: String, }, - #[note(infer::actual_impl_expl_but_actually_ty_implements)] + #[note(infer_actual_impl_expl_but_actually_ty_implements)] ButActuallyTyImplements { trait_path: String, has_lifetime: bool, lifetime: usize, ty: String }, } @@ -712,15 +712,15 @@ impl ActualImplExplNotes { } #[derive(Diagnostic)] -#[diag(infer::trait_placeholder_mismatch)] +#[diag(infer_trait_placeholder_mismatch)] pub struct TraitPlaceholderMismatch { #[primary_span] pub span: Span, - #[label(infer::label_satisfy)] + #[label(label_satisfy)] pub satisfy_span: Option, - #[label(infer::label_where)] + #[label(label_where)] pub where_span: Option, - #[label(infer::label_dup)] + #[label(label_dup)] pub dup_span: Option, pub def_id: String, pub trait_def_id: String, @@ -741,26 +741,26 @@ impl AddToDiagnostic for ConsiderBorrowingParamHelp { let mut type_param_span: MultiSpan = self.spans.clone().into(); for &span in &self.spans { // Seems like we can't call f() here as Into is required - type_param_span.push_span_label(span, fluent::infer::tid_consider_borrowing); + type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing); } - let msg = f(diag, fluent::infer::tid_param_help.into()); + let msg = f(diag, fluent::infer_tid_param_help.into()); diag.span_help(type_param_span, msg); } } #[derive(Subdiagnostic)] -#[help(infer::tid_rel_help)] +#[help(infer_tid_rel_help)] pub struct RelationshipHelp; #[derive(Diagnostic)] -#[diag(infer::trait_impl_diff)] +#[diag(infer_trait_impl_diff)] pub struct TraitImplDiff { #[primary_span] - #[label(infer::found)] + #[label(found)] pub sp: Span, - #[label(infer::expected)] + #[label(expected)] pub trait_sp: Span, - #[note(infer::expected_found)] + #[note(expected_found)] pub note: (), #[subdiagnostic] pub param_help: ConsiderBorrowingParamHelp, @@ -783,11 +783,11 @@ impl AddToDiagnostic for DynTraitConstraintSuggestion { F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { let mut multi_span: MultiSpan = vec![self.span].into(); - multi_span.push_span_label(self.span, fluent::infer::dtcs_has_lifetime_req_label); - multi_span.push_span_label(self.ident.span, fluent::infer::dtcs_introduces_requirement); - let msg = f(diag, fluent::infer::dtcs_has_req_note.into()); + multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); + multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); + let msg = f(diag, fluent::infer_dtcs_has_req_note.into()); diag.span_note(multi_span, msg); - let msg = f(diag, fluent::infer::dtcs_suggestion.into()); + let msg = f(diag, fluent::infer_dtcs_suggestion.into()); diag.span_suggestion_verbose( self.span.shrink_to_hi(), msg, @@ -798,12 +798,12 @@ impl AddToDiagnostic for DynTraitConstraintSuggestion { } #[derive(Diagnostic)] -#[diag(infer::but_calling_introduces, code = "E0772")] +#[diag(infer_but_calling_introduces, code = "E0772")] pub struct ButCallingIntroduces { - #[label(infer::label1)] + #[label(label1)] pub param_ty_span: Span, #[primary_span] - #[label(infer::label2)] + #[label(label2)] pub cause_span: Span, pub has_param_name: bool, @@ -829,14 +829,14 @@ impl AddToDiagnostic for ReqIntroducedLocations { F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { for sp in self.spans { - self.span.push_span_label(sp, fluent::infer::ril_introduced_here); + self.span.push_span_label(sp, fluent::infer_ril_introduced_here); } if self.add_label { - self.span.push_span_label(self.fn_decl_span, fluent::infer::ril_introduced_by); + self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by); } - self.span.push_span_label(self.cause_span, fluent::infer::ril_because_of); - let msg = f(diag, fluent::infer::ril_static_introduced_by.into()); + self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of); + let msg = f(diag, fluent::infer_ril_static_introduced_by.into()); diag.span_note(self.span, msg); } } @@ -851,25 +851,25 @@ impl AddToDiagnostic for MoreTargeted { F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { diag.code(rustc_errors::error_code!(E0772)); - diag.set_primary_message(fluent::infer::more_targeted); + diag.set_primary_message(fluent::infer_more_targeted); diag.set_arg("ident", self.ident); } } #[derive(Diagnostic)] -#[diag(infer::but_needs_to_satisfy, code = "E0759")] +#[diag(infer_but_needs_to_satisfy, code = "E0759")] pub struct ButNeedsToSatisfy { #[primary_span] pub sp: Span, - #[label(infer::influencer)] + #[label(influencer)] pub influencer_point: Span, - #[label(infer::used_here)] + #[label(used_here)] pub spans: Vec, - #[label(infer::require)] + #[label(require)] pub require_span_as_label: Option, - #[note(infer::require)] + #[note(require)] pub require_span_as_note: Option, - #[note(infer::introduced_by_bound)] + #[note(introduced_by_bound)] pub bound: Option, #[subdiagnostic] From 7ecd064bbe32419eb473b28cdc8e41dd34f20aa9 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 3 Nov 2022 20:45:14 +0300 Subject: [PATCH 11/16] Split infer_explicit_lifetime_required into several diags --- .../locales/en-US/infer.ftl | 15 +++--- compiler/rustc_infer/src/errors/mod.rs | 49 ++++++++++++------- .../nice_region_error/named_anon_conflict.rs | 23 +++++---- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index f74af62702e..52babec4f9e 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -173,16 +173,15 @@ infer_msl_trait_note = this has an implicit `'static` lifetime requirement infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement infer_suggest_add_let_for_letchains = consider adding `let` -infer_explicit_lifetime_required = explicit lifetime required in {$ident_kind -> - [ident] the type of `{$simple_ident}` - *[param_type] parameter type -} +infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` .label = lifetime `{$named}` required -infer_explicit_lifetime_required_sugg = add explicit lifetime `{$named}` to {$ident_kind -> - [ident] the type of `{$simple_ident}` - *[param_type] type -} +infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type + .label = lifetime `{$named}` required + +infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` + +infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> [true] ... diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 51b04eb0df0..9e3def93a6d 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -523,23 +523,38 @@ pub struct MismatchedStaticLifetime<'a> { } #[derive(Diagnostic)] -#[diag(infer_explicit_lifetime_required, code = "E0621")] -pub struct ExplicitLifetimeRequired<'a> { - #[primary_span] - #[label] - pub span: Span, - pub ident_kind: &'static str, - pub simple_ident: String, - pub named: String, - - #[suggestion( - infer_explicit_lifetime_required_sugg, - code = "{new_ty}", - applicability = "unspecified" - )] - pub new_ty_span: Span, - #[skip_arg] - pub new_ty: Ty<'a>, +pub enum ExplicitLifetimeRequired<'a> { + #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")] + WithIdent { + #[primary_span] + #[label] + span: Span, + simple_ident: Ident, + named: String, + #[suggestion( + infer_explicit_lifetime_required_sugg_with_ident, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, + #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")] + WithParamType { + #[primary_span] + #[label] + span: Span, + named: String, + #[suggestion( + infer_explicit_lifetime_required_sugg_with_param_type, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index d7751158902..4e13ec90228 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -89,18 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { { return None; } - - let simple_ident = param.pat.simple_ident(); - let (ident_kind, simple_ident) = match simple_ident { - Some(ident) => ("ident", ident.to_string()), - None => ("param_type", String::new()), - }; - let named = named.to_string(); - - let err = - ExplicitLifetimeRequired { span, ident_kind, simple_ident, named, new_ty_span, new_ty }; - let err = self.tcx().sess.parse_sess.create_err(err); - Some(err) + let err = match param.pat.simple_ident() { + Some(simple_ident) => ExplicitLifetimeRequired::WithIdent { + span, + simple_ident, + named, + new_ty_span, + new_ty, + }, + None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty }, + }; + Some(self.tcx().sess.parse_sess.create_err(err)) } } From 62f9962eafbf4cf1196d256cf6c559ac397261e1 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 3 Nov 2022 21:50:52 +0300 Subject: [PATCH 12/16] Made ty_or_sig and trait_path use their actual types instead of String --- compiler/rustc_infer/src/errors/mod.rs | 101 ++++++++++++------ .../error_reporting/nice_region_error/mod.rs | 2 +- .../nice_region_error/placeholder_error.rs | 92 ++++++++-------- 3 files changed, 118 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 9e3def93a6d..388ddd09905 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,16 +1,18 @@ use hir::GenericParamKind; use rustc_errors::{ fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString, - MultiSpan, SubdiagnosticMessage, + IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, }; use rustc_hir as hir; use rustc_hir::FnRetTy; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{Region, Ty, TyCtxt}; +use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; +use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt}; use rustc_span::symbol::kw; use rustc_span::Symbol; use rustc_span::{symbol::Ident, BytePos, Span}; +use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted; use crate::infer::error_reporting::{ need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, ObligationCauseAsDiagArg, @@ -557,91 +559,126 @@ pub enum ExplicitLifetimeRequired<'a> { }, } +pub enum TyOrSig<'tcx> { + Ty(Highlighted<'tcx, Ty<'tcx>>), + ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), +} + +impl IntoDiagnosticArg for TyOrSig<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + match self { + TyOrSig::Ty(ty) => ty.into_diagnostic_arg(), + TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(), + } + } +} + #[derive(Subdiagnostic)] -pub enum ActualImplExplNotes { +pub enum ActualImplExplNotes<'tcx> { #[note(infer_actual_impl_expl_expected_signature_two)] ExpectedSignatureTwo { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, lifetime_2: usize, }, #[note(infer_actual_impl_expl_expected_signature_any)] ExpectedSignatureAny { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, }, #[note(infer_actual_impl_expl_expected_signature_some)] ExpectedSignatureSome { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, }, #[note(infer_actual_impl_expl_expected_signature_nothing)] - ExpectedSignatureNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, + ExpectedSignatureNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, #[note(infer_actual_impl_expl_expected_passive_two)] ExpectedPassiveTwo { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, lifetime_2: usize, }, #[note(infer_actual_impl_expl_expected_passive_any)] ExpectedPassiveAny { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, }, #[note(infer_actual_impl_expl_expected_passive_some)] ExpectedPassiveSome { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, }, #[note(infer_actual_impl_expl_expected_passive_nothing)] - ExpectedPassiveNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, + ExpectedPassiveNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, #[note(infer_actual_impl_expl_expected_other_two)] ExpectedOtherTwo { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, lifetime_2: usize, }, #[note(infer_actual_impl_expl_expected_other_any)] ExpectedOtherAny { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, }, #[note(infer_actual_impl_expl_expected_other_some)] ExpectedOtherSome { leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, }, #[note(infer_actual_impl_expl_expected_other_nothing)] - ExpectedOtherNothing { leading_ellipsis: bool, ty_or_sig: String, trait_path: String }, + ExpectedOtherNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, #[note(infer_actual_impl_expl_but_actually_implements_trait)] - ButActuallyImplementsTrait { trait_path: String, has_lifetime: bool, lifetime: usize }, + ButActuallyImplementsTrait { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + }, #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)] ButActuallyImplementedForTy { - trait_path: String, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, has_lifetime: bool, lifetime: usize, ty: String, }, #[note(infer_actual_impl_expl_but_actually_ty_implements)] - ButActuallyTyImplements { trait_path: String, has_lifetime: bool, lifetime: usize, ty: String }, + ButActuallyTyImplements { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, } pub enum ActualImplExpectedKind { @@ -657,13 +694,13 @@ pub enum ActualImplExpectedLifetimeKind { Nothing, } -impl ActualImplExplNotes { +impl<'tcx> ActualImplExplNotes<'tcx> { pub fn new_expected( kind: ActualImplExpectedKind, lt_kind: ActualImplExpectedLifetimeKind, leading_ellipsis: bool, - ty_or_sig: String, - trait_path: String, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, lifetime_1: usize, lifetime_2: usize, ) -> Self { @@ -728,7 +765,7 @@ impl ActualImplExplNotes { #[derive(Diagnostic)] #[diag(infer_trait_placeholder_mismatch)] -pub struct TraitPlaceholderMismatch { +pub struct TraitPlaceholderMismatch<'tcx> { #[primary_span] pub span: Span, #[label(label_satisfy)] @@ -741,7 +778,7 @@ pub struct TraitPlaceholderMismatch { pub trait_def_id: String, #[subdiagnostic(eager)] - pub actual_impl_expl_notes: Vec, + pub actual_impl_expl_notes: Vec>, } pub struct ConsiderBorrowingParamHelp { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 8a0e332f9c7..59fb74eb543 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -9,7 +9,7 @@ mod different_lifetimes; pub mod find_anon_type; mod mismatched_static_lifetime; mod named_anon_conflict; -mod placeholder_error; +pub(crate) mod placeholder_error; mod placeholder_relation; mod static_impl_trait; mod trait_impl_difference; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 904723c4da9..2ff2d1926a2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -1,6 +1,6 @@ use crate::errors::{ ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes, - TraitPlaceholderMismatch, + TraitPlaceholderMismatch, TyOrSig, }; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; @@ -8,7 +8,7 @@ use crate::infer::ValuePairs; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir::def::Namespace; use rustc_hir::def_id::DefId; use rustc_middle::ty::error::ExpectedFound; @@ -18,6 +18,42 @@ use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt}; use std::fmt; +// HACK(eddyb) maybe move this in a more central location. +#[derive(Copy, Clone)] +pub struct Highlighted<'tcx, T> { + tcx: TyCtxt<'tcx>, + highlight: RegionHighlightMode<'tcx>, + value: T, +} + +impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T> +where + T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>, +{ + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + rustc_errors::DiagnosticArgValue::Str(self.to_string().into()) + } +} + +impl<'tcx, T> Highlighted<'tcx, T> { + fn map(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> { + Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) } + } +} + +impl<'tcx, T> fmt::Display for Highlighted<'tcx, T> +where + T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS); + printer.region_highlight_mode = self.highlight; + + let s = self.value.print(printer)?.into_buffer(); + f.write_str(&s) + } +} + impl<'tcx> NiceRegionError<'_, 'tcx> { /// When given a `ConcreteFailure` for a function with arguments containing a named region and /// an anonymous region, emit a descriptive diagnostic error. @@ -328,39 +364,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { actual_has_vid: Option, any_self_ty_has_vid: bool, leading_ellipsis: bool, - ) -> Vec { - // HACK(eddyb) maybe move this in a more central location. - #[derive(Copy, Clone)] - struct Highlighted<'tcx, T> { - tcx: TyCtxt<'tcx>, - highlight: RegionHighlightMode<'tcx>, - value: T, - } - - impl<'tcx, T> Highlighted<'tcx, T> { - fn map(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> { - Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) } - } - } - - impl<'tcx, T> fmt::Display for Highlighted<'tcx, T> - where - T: for<'a> Print< - 'tcx, - FmtPrinter<'a, 'tcx>, - Error = fmt::Error, - Output = FmtPrinter<'a, 'tcx>, - >, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS); - printer.region_highlight_mode = self.highlight; - - let s = self.value.print(printer)?.into_buffer(); - f.write_str(&s) - } - } - + ) -> Vec> { // The weird thing here with the `maybe_highlighting_region` calls and the // the match inside is meant to be like this: // @@ -418,27 +422,27 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { }); ( ActualImplExpectedKind::Signature, - closure_sig.to_string(), - expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + TyOrSig::ClosureSig(closure_sig), + expected_trait_ref.map(|tr| tr.print_only_trait_path()), ) } else { ( ActualImplExpectedKind::Other, - self_ty.to_string(), - expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + TyOrSig::Ty(self_ty), + expected_trait_ref.map(|tr| tr.print_only_trait_path()), ) } } else if passive_voice { ( ActualImplExpectedKind::Passive, - expected_trait_ref.map(|tr| tr.self_ty()).to_string(), - expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())), + expected_trait_ref.map(|tr| tr.print_only_trait_path()), ) } else { ( ActualImplExpectedKind::Other, - expected_trait_ref.map(|tr| tr.self_ty()).to_string(), - expected_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(), + TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())), + expected_trait_ref.map(|tr| tr.print_only_trait_path()), ) }; @@ -474,7 +478,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { None => true, }; - let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path()).to_string(); + let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path()); let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string(); let has_lifetime = actual_has_vid.is_some(); let lifetime = actual_has_vid.unwrap_or_default(); From a86173766c113fdde95c2510de5909d4f9469833 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 3 Nov 2022 21:56:15 +0300 Subject: [PATCH 13/16] Fix nits --- .../error_reporting/nice_region_error/placeholder_error.rs | 6 ++---- .../error_reporting/nice_region_error/static_impl_trait.rs | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 2ff2d1926a2..a5e5f953856 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -333,7 +333,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { leading_ellipsis, ); - let diag = TraitPlaceholderMismatch { + self.tcx().sess.create_err(TraitPlaceholderMismatch { span, satisfy_span, where_span, @@ -341,9 +341,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { def_id, trait_def_id: self.tcx().def_path_str(trait_def_id), actual_impl_expl_notes, - }; - - self.tcx().sess.create_err(diag) + }) } /// Add notes with details about the expected and actual trait refs, with attention to cases diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index fbc71bd7e01..ae3f174c72e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -63,7 +63,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { AssocItemContainer::ImplContainer => (false, String::new()), }; - let diag = ButCallingIntroduces { + let mut err = self.tcx().sess.create_err(ButCallingIntroduces { param_ty_span: param.param_ty_span, cause_span: cause.span, has_param_name: simple_ident.is_some(), @@ -73,8 +73,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { assoc_item: ctxt.assoc_item.name, has_impl_path, impl_path, - }; - let mut err = self.tcx().sess.create_err(diag); + }); if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) { let reported = err.emit(); return Some(reported); From dda3ebad0a2b26ee35e2f4f3d26f529b092edfc4 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Mon, 7 Nov 2022 15:56:52 +0300 Subject: [PATCH 14/16] Fix broken rebase --- .../error_reporting/nice_region_error/static_impl_trait.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index ae3f174c72e..8a6dadf935f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -8,7 +8,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, Visitor}; From 2a8b17dbc5489ee085cf1587cf3c63a3fd2746aa Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 29 Nov 2022 19:19:26 +0300 Subject: [PATCH 15/16] Fix formatting --- .../error_reporting/nice_region_error/placeholder_error.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index a5e5f953856..202f39521e9 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -405,8 +405,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty()); self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid); - if self_ty.value.is_closure() - && self.tcx().is_fn_trait(expected_trait_ref.value.def_id) + if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id) { let closure_sig = self_ty.map(|closure| { if let ty::Closure(_, substs) = closure.kind() { From 0c50e1f146efc594eb84146c598d577c9f8a27d2 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Wed, 28 Dec 2022 15:24:18 +0300 Subject: [PATCH 16/16] eager is the default now --- compiler/rustc_infer/src/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 388ddd09905..9cd053694fe 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -777,7 +777,7 @@ pub struct TraitPlaceholderMismatch<'tcx> { pub def_id: String, pub trait_def_id: String, - #[subdiagnostic(eager)] + #[subdiagnostic] pub actual_impl_expl_notes: Vec>, }