From 8fc5ba65e1a6f2e7600c98579d4a0f488560c5bf Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Wed, 18 Jan 2023 16:34:08 +0300 Subject: [PATCH 01/11] Port OutlivesContent, OutlivesBound, FUllfillReqLifetime, LfBoundNotSatisfied diagnostics --- .../locales/en-US/infer.ftl | 14 ++ compiler/rustc_infer/src/errors/mod.rs | 37 ++++++ .../src/errors/note_and_explain.rs | 36 +++++- .../src/infer/error_reporting/note.rs | 120 ++++++++---------- 4 files changed, 131 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index bcc1d9002dfde..505dd98049444 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -140,6 +140,14 @@ infer_lifetime_param_suggestion_elided = each elided lifetime in input position infer_region_explanation = {$pref_kind -> *[should_not_happen] [{$pref_kind}] + [ref_valid_for] ...the reference is valid for + [content_valid_for] ...but the borrowed content is only valid for + [type_valid_for] object type is valid for + [source_pointer_valid_for] source pointer is only valid for + [type_satisfy] type must satisfy + [type_outlive] type must outlive + [lf_instantiated_with] lifetime parameter instantiated with + [lf_must_outlive] but lifetime parameter must outlive [empty] {""} }{$pref_kind -> [empty] {""} @@ -158,8 +166,14 @@ infer_region_explanation = {$pref_kind -> *[should_not_happen] [{$suff_kind}] [empty]{""} [continues] ... + [req_by_binding] {" "}as required by this binding } +infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... +infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type +infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime +infer_lf_bound_not_satisfied = lifetime bound not satisfied + infer_mismatched_static_lifetime = incompatible lifetime on type infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` infer_implicit_static_lifetime_note = 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 8bf3a160abbb4..ae2985d456b79 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -933,3 +933,40 @@ pub struct ButNeedsToSatisfy { pub has_lifetime: bool, pub lifetime: String, } + +#[derive(Diagnostic)] +#[diag(infer_outlives_content, code = "E0312")] +pub struct OutlivesContent<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec>, +} + +#[derive(Diagnostic)] +#[diag(infer_outlives_bound, code = "E0476")] +pub struct OutlivesBound<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec>, +} + +#[derive(Diagnostic)] +#[diag(infer_fullfill_req_lifetime, code = "E0477")] +pub struct FullfillReqLifetime<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub note: Option>, +} + +#[derive(Diagnostic)] +#[diag(infer_lf_bound_not_satisfied, code = "E0478")] +pub struct LfBoundNotSatisfied<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec>, +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 5d861a78af800..c60eee609946b 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -121,16 +121,34 @@ impl<'a> DescriptionCtx<'a> { pub enum PrefixKind { Empty, + RefValidFor, + ContentValidFor, + TypeValidFor, + SourcePointerValidFor, + TypeSatisfy, + TypeOutlive, + LfInstantiatedWith, + LfMustOutlive, } pub enum SuffixKind { + Empty, Continues, + ReqByBinding, } impl IntoDiagnosticArg for PrefixKind { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { let kind = match self { Self::Empty => "empty", + Self::RefValidFor => "ref_valid_for", + Self::ContentValidFor => "content_valid_for", + Self::TypeValidFor => "type_valid_for", + Self::SourcePointerValidFor => "source_pointer_valid_for", + Self::TypeSatisfy => "type_satisfy", + Self::TypeOutlive => "type_outlive", + Self::LfInstantiatedWith => "lf_instantiated_with", + Self::LfMustOutlive => "lf_must_outlive", } .into(); rustc_errors::DiagnosticArgValue::Str(kind) @@ -140,7 +158,9 @@ impl IntoDiagnosticArg for PrefixKind { impl IntoDiagnosticArg for SuffixKind { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { let kind = match self { + Self::Empty => "empty", Self::Continues => "continues", + Self::ReqByBinding => "req_by_binding", } .into(); rustc_errors::DiagnosticArgValue::Str(kind) @@ -166,17 +186,19 @@ impl RegionExplanation<'_> { } impl AddToDiagnostic for RegionExplanation<'_> { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) where F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, { - if let Some(span) = self.desc.span { - diag.span_note(span, fluent::infer_region_explanation); - } else { - diag.note(fluent::infer_region_explanation); - } - self.desc.add_to(diag); diag.set_arg("pref_kind", self.prefix); diag.set_arg("suff_kind", self.suffix); + let desc_span = self.desc.span; + self.desc.add_to(diag); + let msg = f(diag, fluent::infer_region_explanation.into()); + if let Some(span) = desc_span { + diag.span_note(span, msg); + } else { + diag.note(msg); + } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index bdd09a995dc23..c2b936c3402a2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,9 +1,12 @@ -use crate::errors::RegionOriginNote; +use crate::errors::{ + note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, + RegionOriginNote, +}; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; use rustc_errors::{ fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, + ErrorGuaranteed, IntoDiagnostic, }; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; @@ -119,104 +122,83 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err } infer::Reborrow(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0312, - "lifetime of reference outlives lifetime of borrowed content..." - ); - note_and_explain_region( + let reference_valid = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "...the reference is valid for ", sub, - "...", None, + note_and_explain::PrefixKind::RefValidFor, + note_and_explain::SuffixKind::Continues, ); - note_and_explain_region( + let content_valid = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "...but the borrowed content is only valid for ", sup, - "", None, + note_and_explain::PrefixKind::ContentValidFor, + note_and_explain::SuffixKind::Empty, ); - err + OutlivesContent { + span, + notes: reference_valid.into_iter().chain(content_valid).collect(), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateObjectBound(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0476, - "lifetime of the source pointer does not outlive lifetime bound of the \ - object type" - ); - note_and_explain_region( + let object_valid = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "object type is valid for ", sub, - "", None, + note_and_explain::PrefixKind::TypeValidFor, + note_and_explain::SuffixKind::Empty, ); - note_and_explain_region( + let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "source pointer is only valid for ", sup, - "", None, + note_and_explain::PrefixKind::SourcePointerValidFor, + note_and_explain::SuffixKind::Empty, ); - err + OutlivesBound { + span, + notes: object_valid.into_iter().chain(pointer_valid).collect(), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateParamBound(span, ty, opt_span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0477, - "the type `{}` does not fulfill the required lifetime", - self.ty_to_string(ty) + let prefix = match *sub { + ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, + _ => note_and_explain::PrefixKind::TypeOutlive, + }; + let suffix = if opt_span.is_some() { + note_and_explain::SuffixKind::ReqByBinding + } else { + note_and_explain::SuffixKind::Empty + }; + let note = note_and_explain::RegionExplanation::new( + self.tcx, sub, opt_span, prefix, suffix, ); - match *sub { - ty::ReStatic => note_and_explain_region( - self.tcx, - &mut err, - "type must satisfy ", - sub, - if opt_span.is_some() { " as required by this binding" } else { "" }, - opt_span, - ), - _ => note_and_explain_region( - self.tcx, - &mut err, - "type must outlive ", - sub, - if opt_span.is_some() { " as required by this binding" } else { "" }, - opt_span, - ), - } - err + FullfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::RelateRegionParamBound(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - note_and_explain_region( + let param_instantiated = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "lifetime parameter instantiated with ", sup, - "", None, + note_and_explain::PrefixKind::LfInstantiatedWith, + note_and_explain::SuffixKind::Empty, ); - note_and_explain_region( + let param_must_outlive = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "but lifetime parameter must outlive ", sub, - "", None, + note_and_explain::PrefixKind::LfMustOutlive, + note_and_explain::SuffixKind::Empty, ); - err + LfBoundNotSatisfied { + span, + notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::ReferenceOutlivesReferent(ty, span) => { let mut err = struct_span_err!( From 58e901b6fd1163172149fd422565523b17eed5f0 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Thu, 19 Jan 2023 17:35:09 +0300 Subject: [PATCH 02/11] Port "BorrowedTooLong" diagnostic --- .../locales/en-US/infer.ftl | 6 ++-- compiler/rustc_infer/src/errors/mod.rs | 10 +++++++ .../src/errors/note_and_explain.rs | 8 ++++-- .../src/infer/error_reporting/note.rs | 28 +++++++++++++++++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 505dd98049444..0fcde81174038 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -142,12 +142,14 @@ infer_region_explanation = {$pref_kind -> *[should_not_happen] [{$pref_kind}] [ref_valid_for] ...the reference is valid for [content_valid_for] ...but the borrowed content is only valid for - [type_valid_for] object type is valid for + [type_obj_valid_for] object type is valid for [source_pointer_valid_for] source pointer is only valid for [type_satisfy] type must satisfy [type_outlive] type must outlive [lf_instantiated_with] lifetime parameter instantiated with [lf_must_outlive] but lifetime parameter must outlive + [type_valid_for] the type is valid for + [borrow_lasts_for] but the borrow lasts for [empty] {""} }{$pref_kind -> [empty] {""} @@ -156,7 +158,6 @@ infer_region_explanation = {$pref_kind -> *[should_not_happen] [{$desc_kind}] [restatic] the static lifetime [revar] lifetime {$desc_arg} - [as_defined] the lifetime `{$desc_arg}` as defined here [as_defined_anon] the anonymous lifetime as defined here [defined_here] the anonymous lifetime defined here @@ -173,6 +174,7 @@ infer_outlives_content = lifetime of reference outlives lifetime of borrowed con infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime infer_lf_bound_not_satisfied = lifetime bound not satisfied +infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long infer_mismatched_static_lifetime = incompatible lifetime on type infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index ae2985d456b79..6efe72bfc365b 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -970,3 +970,13 @@ pub struct LfBoundNotSatisfied<'a> { #[subdiagnostic] pub notes: Vec>, } + +#[derive(Diagnostic)] +#[diag(infer_borrowed_too_long, code = "E0490")] +pub struct BorrowedTooLong<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub notes: Vec>, +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index c60eee609946b..e779fdd6e5509 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -123,12 +123,14 @@ pub enum PrefixKind { Empty, RefValidFor, ContentValidFor, - TypeValidFor, + TypeObjValidFor, SourcePointerValidFor, TypeSatisfy, TypeOutlive, LfInstantiatedWith, LfMustOutlive, + TypeValidFor, + BorrowLastsFor, } pub enum SuffixKind { @@ -143,12 +145,14 @@ impl IntoDiagnosticArg for PrefixKind { Self::Empty => "empty", Self::RefValidFor => "ref_valid_for", Self::ContentValidFor => "content_valid_for", - Self::TypeValidFor => "type_valid_for", + Self::TypeObjValidFor => "type_obj_valid_for", Self::SourcePointerValidFor => "source_pointer_valid_for", Self::TypeSatisfy => "type_satisfy", Self::TypeOutlive => "type_outlive", Self::LfInstantiatedWith => "lf_instantiated_with", Self::LfMustOutlive => "lf_must_outlive", + Self::TypeValidFor => "type_valid_for", + Self::BorrowLastsFor => "borrow_lasts_for", } .into(); rustc_errors::DiagnosticArgValue::Str(kind) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index c2b936c3402a2..e470d9d905371 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,6 +1,6 @@ use crate::errors::{ - note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, - RegionOriginNote, + note_and_explain, BorrowedTooLong, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, + OutlivesContent, RegionOriginNote, }; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; @@ -147,7 +147,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.tcx, sub, None, - note_and_explain::PrefixKind::TypeValidFor, + note_and_explain::PrefixKind::TypeObjValidFor, note_and_explain::SuffixKind::Empty, ); let pointer_valid = note_and_explain::RegionExplanation::new( @@ -200,6 +200,28 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } + infer::DataBorrowed(ty, span) => { + let type_valid = note_and_explain::RegionExplanation::new( + self.tcx, + sub, + None, + note_and_explain::PrefixKind::TypeValidFor, + note_and_explain::SuffixKind::Empty, + ); + let borrow_lasts_for = note_and_explain::RegionExplanation::new( + self.tcx, + sup, + None, + note_and_explain::PrefixKind::BorrowLastsFor, + note_and_explain::SuffixKind::Empty, + ); + BorrowedTooLong { + span, + ty: self.resolve_vars_if_possible(ty), + notes: type_valid.into_iter().chain(borrow_lasts_for).collect(), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) + } infer::ReferenceOutlivesReferent(ty, span) => { let mut err = struct_span_err!( self.tcx.sess, From cb8ea01096fb14ea25bbe69fd0b92f7e7752cb78 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sat, 21 Jan 2023 18:16:53 +0300 Subject: [PATCH 03/11] Port RefLongerThanData --- .../locales/en-US/infer.ftl | 3 ++ compiler/rustc_infer/src/errors/mod.rs | 10 +++++++ .../src/errors/note_and_explain.rs | 4 +++ .../src/infer/error_reporting/note.rs | 30 ++++++++----------- 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 0fcde81174038..c012973f1ddc3 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -150,6 +150,8 @@ infer_region_explanation = {$pref_kind -> [lf_must_outlive] but lifetime parameter must outlive [type_valid_for] the type is valid for [borrow_lasts_for] but the borrow lasts for + [pointer_valid_for] the pointer is valid for + [data_valid_for] but the referenced data is only valid for [empty] {""} }{$pref_kind -> [empty] {""} @@ -175,6 +177,7 @@ infer_outlives_bound = lifetime of the source pointer does not outlive lifetime infer_fullfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime infer_lf_bound_not_satisfied = lifetime bound not satisfied infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long +infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references infer_mismatched_static_lifetime = incompatible lifetime on type infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 6efe72bfc365b..7088be05ef78d 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -980,3 +980,13 @@ pub struct BorrowedTooLong<'a> { #[subdiagnostic] pub notes: Vec>, } + +#[derive(Diagnostic)] +#[diag(infer_ref_longer_than_data, code = "E0491")] +pub struct RefLongerThanData<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub notes: Vec>, +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index e779fdd6e5509..3516517dcc3ab 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -131,6 +131,8 @@ pub enum PrefixKind { LfMustOutlive, TypeValidFor, BorrowLastsFor, + PointerValidFor, + DataValidFor, } pub enum SuffixKind { @@ -153,6 +155,8 @@ impl IntoDiagnosticArg for PrefixKind { Self::LfMustOutlive => "lf_must_outlive", Self::TypeValidFor => "type_valid_for", Self::BorrowLastsFor => "borrow_lasts_for", + Self::PointerValidFor => "pointer_valid_for", + Self::DataValidFor => "data_valid_for", } .into(); rustc_errors::DiagnosticArgValue::Str(kind) diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index e470d9d905371..4c07cc0b6a252 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,6 +1,6 @@ use crate::errors::{ note_and_explain, BorrowedTooLong, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, - OutlivesContent, RegionOriginNote, + OutlivesContent, RefLongerThanData, RegionOriginNote, }; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; @@ -223,30 +223,26 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::ReferenceOutlivesReferent(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0491, - "in type `{}`, reference has a longer lifetime than the data it references", - self.ty_to_string(ty) - ); - note_and_explain_region( + let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "the pointer is valid for ", sub, - "", None, + note_and_explain::PrefixKind::PointerValidFor, + note_and_explain::SuffixKind::Empty, ); - note_and_explain_region( + let data_valid = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "but the referenced data is only valid for ", sup, - "", None, + note_and_explain::PrefixKind::DataValidFor, + note_and_explain::SuffixKind::Empty, ); - err + RefLongerThanData { + span, + ty: self.resolve_vars_if_possible(ty), + notes: pointer_valid.into_iter().chain(data_valid).collect(), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { let mut err = self.report_extra_impl_obligation( From 35dbec338ac837c533843ff7cf0441c3b6052b5e Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sat, 21 Jan 2023 19:45:45 +0300 Subject: [PATCH 04/11] Port another diagnostic --- .../locales/en-US/infer.ftl | 6 ++-- .../src/errors/note_and_explain.rs | 4 +++ .../src/infer/error_reporting/note.rs | 30 +++++++++---------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index c012973f1ddc3..c257bf739d11a 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -146,8 +146,10 @@ infer_region_explanation = {$pref_kind -> [source_pointer_valid_for] source pointer is only valid for [type_satisfy] type must satisfy [type_outlive] type must outlive - [lf_instantiated_with] lifetime parameter instantiated with - [lf_must_outlive] but lifetime parameter must outlive + [lf_param_instantiated_with] lifetime parameter instantiated with + [lf_param_must_outlive] but lifetime parameter must outlive + [lf_instantiated_with] lifetime instantiated with + [lf_must_outlive] but lifetime must outlive [type_valid_for] the type is valid for [borrow_lasts_for] but the borrow lasts for [pointer_valid_for] the pointer is valid for diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 3516517dcc3ab..b212a5a09c01d 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -127,6 +127,8 @@ pub enum PrefixKind { SourcePointerValidFor, TypeSatisfy, TypeOutlive, + LfParamInstantiatedWith, + LfParamMustOutlive, LfInstantiatedWith, LfMustOutlive, TypeValidFor, @@ -151,6 +153,8 @@ impl IntoDiagnosticArg for PrefixKind { Self::SourcePointerValidFor => "source_pointer_valid_for", Self::TypeSatisfy => "type_satisfy", Self::TypeOutlive => "type_outlive", + Self::LfParamInstantiatedWith => "lf_param_instantiated_with", + Self::LfParamMustOutlive => "lf_param_must_outlive", Self::LfInstantiatedWith => "lf_instantiated_with", Self::LfMustOutlive => "lf_must_outlive", Self::TypeValidFor => "type_valid_for", diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 4c07cc0b6a252..adf240e7ce5d7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -5,8 +5,8 @@ use crate::errors::{ use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; use rustc_errors::{ - fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, IntoDiagnostic, + fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, + IntoDiagnostic, }; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; @@ -184,14 +184,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.tcx, sup, None, - note_and_explain::PrefixKind::LfInstantiatedWith, + note_and_explain::PrefixKind::LfParamInstantiatedWith, note_and_explain::SuffixKind::Empty, ); let param_must_outlive = note_and_explain::RegionExplanation::new( self.tcx, sub, None, - note_and_explain::PrefixKind::LfMustOutlive, + note_and_explain::PrefixKind::LfParamMustOutlive, note_and_explain::SuffixKind::Empty, ); LfBoundNotSatisfied { @@ -279,25 +279,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err } infer::AscribeUserTypeProvePredicate(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - note_and_explain_region( + let instantiated = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "lifetime instantiated with ", sup, - "", None, + note_and_explain::PrefixKind::LfInstantiatedWith, + note_and_explain::SuffixKind::Empty, ); - note_and_explain_region( + let must_outlive = note_and_explain::RegionExplanation::new( self.tcx, - &mut err, - "but lifetime must outlive ", sub, - "", None, + note_and_explain::PrefixKind::LfMustOutlive, + note_and_explain::SuffixKind::Empty, ); - err + LfBoundNotSatisfied { + span, + notes: instantiated.into_iter().chain(must_outlive).collect(), + } + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } }; if sub.is_error() || sup.is_error() { From 8d590dc3039d49cb8b54f3aec380d43b3ed5e2dd Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sat, 21 Jan 2023 20:55:37 +0300 Subject: [PATCH 05/11] Resolve rebase --- .../locales/en-US/infer.ftl | 2 -- compiler/rustc_infer/src/errors/mod.rs | 10 ------- .../src/errors/note_and_explain.rs | 4 --- .../src/infer/error_reporting/note.rs | 26 ++----------------- 4 files changed, 2 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index c257bf739d11a..0398634da021e 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -150,8 +150,6 @@ infer_region_explanation = {$pref_kind -> [lf_param_must_outlive] but lifetime parameter must outlive [lf_instantiated_with] lifetime instantiated with [lf_must_outlive] but lifetime must outlive - [type_valid_for] the type is valid for - [borrow_lasts_for] but the borrow lasts for [pointer_valid_for] the pointer is valid for [data_valid_for] but the referenced data is only valid for [empty] {""} diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 7088be05ef78d..49b6a325f68e3 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -971,16 +971,6 @@ pub struct LfBoundNotSatisfied<'a> { pub notes: Vec>, } -#[derive(Diagnostic)] -#[diag(infer_borrowed_too_long, code = "E0490")] -pub struct BorrowedTooLong<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, - #[subdiagnostic] - pub notes: Vec>, -} - #[derive(Diagnostic)] #[diag(infer_ref_longer_than_data, code = "E0491")] pub struct RefLongerThanData<'a> { diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index b212a5a09c01d..cb96aeec5f34f 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -131,8 +131,6 @@ pub enum PrefixKind { LfParamMustOutlive, LfInstantiatedWith, LfMustOutlive, - TypeValidFor, - BorrowLastsFor, PointerValidFor, DataValidFor, } @@ -157,8 +155,6 @@ impl IntoDiagnosticArg for PrefixKind { Self::LfParamMustOutlive => "lf_param_must_outlive", Self::LfInstantiatedWith => "lf_instantiated_with", Self::LfMustOutlive => "lf_must_outlive", - Self::TypeValidFor => "type_valid_for", - Self::BorrowLastsFor => "borrow_lasts_for", Self::PointerValidFor => "pointer_valid_for", Self::DataValidFor => "data_valid_for", } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index adf240e7ce5d7..c43e5713283ad 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,6 +1,6 @@ use crate::errors::{ - note_and_explain, BorrowedTooLong, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, - OutlivesContent, RefLongerThanData, RegionOriginNote, + note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, + RefLongerThanData, RegionOriginNote, }; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; @@ -200,28 +200,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } - infer::DataBorrowed(ty, span) => { - let type_valid = note_and_explain::RegionExplanation::new( - self.tcx, - sub, - None, - note_and_explain::PrefixKind::TypeValidFor, - note_and_explain::SuffixKind::Empty, - ); - let borrow_lasts_for = note_and_explain::RegionExplanation::new( - self.tcx, - sup, - None, - note_and_explain::PrefixKind::BorrowLastsFor, - note_and_explain::SuffixKind::Empty, - ); - BorrowedTooLong { - span, - ty: self.resolve_vars_if_possible(ty), - notes: type_valid.into_iter().chain(borrow_lasts_for).collect(), - } - .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) - } infer::ReferenceOutlivesReferent(ty, span) => { let pointer_valid = note_and_explain::RegionExplanation::new( self.tcx, From b8feb63345b70f98c33ce68e844d9334b9a6f847 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 22 Jan 2023 18:16:47 +0300 Subject: [PATCH 06/11] Port WhereClauseSuggestions --- .../locales/en-US/infer.ftl | 3 ++ compiler/rustc_infer/src/errors/mod.rs | 26 +++++++++++++++++ .../src/infer/error_reporting/note.rs | 28 ++++++++----------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 0398634da021e..f7e1420d76c43 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -327,3 +327,6 @@ 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 + +infer_where_remove = remove the `where` clause +infer_where_copy_predicates = copy the `where` clause predicates from the trait diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 49b6a325f68e3..7fa04043edf4d 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -980,3 +980,29 @@ pub struct RefLongerThanData<'a> { #[subdiagnostic] pub notes: Vec>, } + +#[derive(Subdiagnostic)] +pub enum WhereClauseSuggestions { + #[suggestion( + infer_where_remove, + code = "", + applicability = "machine-applicable", + style = "verbose" + )] + Remove { + #[primary_span] + span: Span, + }, + #[suggestion( + infer_where_copy_predicates, + code = "{space}where {}", + applicability = "machine-applicable", + style = "verbose" + )] + CopyPredicates { + #[primary_span] + span: Span, + space: &'static str, + trait_predicates: String, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index c43e5713283ad..e0e89158a5838 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,12 +1,11 @@ use crate::errors::{ note_and_explain, FullfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, - RefLongerThanData, RegionOriginNote, + RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, }; use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt}; use crate::infer::{self, SubregionOrigin}; use rustc_errors::{ - fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - IntoDiagnostic, + fluent, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, }; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::traits::ObligationCauseCode; @@ -325,22 +324,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; }; - if trait_predicates.is_empty() { - err.span_suggestion_verbose( - generics.where_clause_span, - "remove the `where` clause", - String::new(), - Applicability::MachineApplicable, - ); + let suggestion = if trait_predicates.is_empty() { + WhereClauseSuggestions::Remove { span: generics.where_clause_span } } else { let space = if generics.where_clause_span.is_empty() { " " } else { "" }; - err.span_suggestion_verbose( - generics.where_clause_span, - "copy the `where` clause predicates from the trait", - format!("{space}where {}", trait_predicates.join(", ")), - Applicability::MachineApplicable, - ); - } + WhereClauseSuggestions::CopyPredicates { + span: generics.where_clause_span, + space, + trait_predicates: trait_predicates.join(", "), + } + }; + err.subdiagnostic(suggestion); } pub(super) fn report_placeholder_failure( From 6fa4c7d89c48146af0b246c7640ad3a611412a23 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 22 Jan 2023 18:54:47 +0300 Subject: [PATCH 07/11] Make sure tests pass --- 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 7fa04043edf4d..83c5178751696 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -995,7 +995,7 @@ pub enum WhereClauseSuggestions { }, #[suggestion( infer_where_copy_predicates, - code = "{space}where {}", + code = "{space}where {trait_predicates}", applicability = "machine-applicable", style = "verbose" )] From 9f06c3d87f5a40078319e60ebe91bba279bf3f76 Mon Sep 17 00:00:00 2001 From: IQuant Date: Sat, 28 Jan 2023 19:41:14 +0300 Subject: [PATCH 08/11] Port SuggestRemoveSemiOrReturnBinding --- .../locales/en-US/infer.ftl | 5 ++ compiler/rustc_infer/src/errors/mod.rs | 44 ++++++++++ .../src/infer/error_reporting/mod.rs | 14 ++-- .../src/infer/error_reporting/suggest.rs | 80 +++++++++---------- 4 files changed, 97 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index f7e1420d76c43..1019b6114641c 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -330,3 +330,8 @@ infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by t infer_where_remove = remove the `where` clause infer_where_copy_predicates = copy the `where` clause predicates from the trait + +infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions +infer_srs_remove = consider removing this semicolon +infer_srs_add = consider returning the local binding `{$ident}` +infer_srs_add_one = consider returning one of these bindings diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 83c5178751696..41691ff4f72bc 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1006,3 +1006,47 @@ pub enum WhereClauseSuggestions { trait_predicates: String, }, } + +#[derive(Subdiagnostic)] +pub enum SuggestRemoveSemiOrReturnBinding { + #[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")] + RemoveAndBox { + #[suggestion_part(code = "Box::new(")] + first_lo: Span, + #[suggestion_part(code = ")")] + first_hi: Span, + #[suggestion_part(code = "Box::new(")] + second_lo: Span, + #[suggestion_part(code = ")")] + second_hi: Span, + #[suggestion_part(code = "")] + sp: Span, + }, + #[suggestion( + infer_srs_remove, + style = "short", + code = "", + applicability = "machine-applicable" + )] + Remove { + #[primary_span] + sp: Span, + }, + #[suggestion( + infer_srs_add, + style = "verbose", + code = "{code}", + applicability = "maybe-incorrect" + )] + Add { + #[primary_span] + sp: Span, + code: String, + ident: Ident, + }, + #[note(infer_srs_add_one)] + AddOne { + #[primary_span] + spans: MultiSpan, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c56149c114920..ae231b1188d3c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -750,15 +750,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let msg = "`match` arms have incompatible types"; err.span_label(outer, msg); - self.suggest_remove_semi_or_return_binding( - err, + if let Some(subdiag) = self.suggest_remove_semi_or_return_binding( prior_arm_block_id, prior_arm_ty, prior_arm_span, arm_block_id, arm_ty, arm_span, - ); + ) { + err.subdiagnostic(subdiag); + } if let Some(ret_sp) = opt_suggest_box_span { // Get return type span and point to it. self.suggest_boxing_for_return_impl_trait( @@ -783,15 +784,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let Some(sp) = outer_span { err.span_label(sp, "`if` and `else` have incompatible types"); } - self.suggest_remove_semi_or_return_binding( - err, + if let Some(subdiag) = self.suggest_remove_semi_or_return_binding( Some(then_id), then_ty, then_span, Some(else_id), else_ty, else_span, - ); + ) { + err.subdiagnostic(subdiag); + } if let Some(ret_sp) = opt_suggest_box_span { self.suggest_boxing_for_return_impl_trait( err, diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 7d9a53d1c025f..8d84264ee8c0d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -11,21 +11,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable}; use rustc_span::{sym, BytePos, Span}; -use crate::errors::SuggAddLetForLetChains; +use crate::errors::{SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding}; use super::TypeErrCtxt; impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub(super) fn suggest_remove_semi_or_return_binding( &self, - err: &mut Diagnostic, first_id: Option, first_ty: Ty<'tcx>, first_span: Span, second_id: Option, second_ty: Ty<'tcx>, second_span: Span, - ) { + ) -> Option { let remove_semicolon = [ (first_id, self.resolve_vars_if_possible(second_ty)), (second_id, self.resolve_vars_if_possible(first_ty)), @@ -37,35 +36,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }); match remove_semicolon { Some((sp, StatementAsExpression::NeedsBoxing)) => { - err.multipart_suggestion( - "consider removing this semicolon and boxing the expressions", - vec![ - (first_span.shrink_to_lo(), "Box::new(".to_string()), - (first_span.shrink_to_hi(), ")".to_string()), - (second_span.shrink_to_lo(), "Box::new(".to_string()), - (second_span.shrink_to_hi(), ")".to_string()), - (sp, String::new()), - ], - Applicability::MachineApplicable, - ); + Some(SuggestRemoveSemiOrReturnBinding::RemoveAndBox { + first_lo: first_span.shrink_to_lo(), + first_hi: first_span.shrink_to_hi(), + second_lo: second_span.shrink_to_lo(), + second_hi: second_span.shrink_to_hi(), + sp, + }) } Some((sp, StatementAsExpression::CorrectType)) => { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - "", - Applicability::MachineApplicable, - ); + Some(SuggestRemoveSemiOrReturnBinding::Remove { sp }) } None => { + let mut ret = None; for (id, ty) in [(first_id, second_ty), (second_id, first_ty)] { if let Some(id) = id && let hir::Node::Block(blk) = self.tcx.hir().get(id) - && self.consider_returning_binding(blk, ty, err) + && let Some(diag) = self.consider_returning_binding_diag(blk, ty) { + ret = Some(diag); break; } } + ret } } } @@ -655,16 +648,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// Suggest returning a local binding with a compatible type if the block /// has no return expression. - pub fn consider_returning_binding( + pub fn consider_returning_binding_diag( &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, - err: &mut Diagnostic, - ) -> bool { + ) -> Option { let blk = blk.innermost_block(); // Do not suggest if we have a tail expr. if blk.expr.is_some() { - return false; + return None; } let mut shadowed = FxIndexSet::default(); let mut candidate_idents = vec![]; @@ -733,7 +725,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match &candidate_idents[..] { [(ident, _ty)] => { let sm = self.tcx.sess.source_map(); - if let Some(stmt) = blk.stmts.last() { + let (span, sugg) = if let Some(stmt) = blk.stmts.last() { let stmt_span = sm.stmt_span(stmt.span, blk.span); let sugg = if sm.is_multiline(blk.span) && let Some(spacing) = sm.indentation_before(stmt_span) @@ -742,12 +734,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } else { format!(" {ident}") }; - err.span_suggestion_verbose( - stmt_span.shrink_to_hi(), - format!("consider returning the local binding `{ident}`"), - sugg, - Applicability::MaybeIncorrect, - ); + (stmt_span.shrink_to_hi(), sugg) } else { let sugg = if sm.is_multiline(blk.span) && let Some(spacing) = sm.indentation_before(blk.span.shrink_to_lo()) @@ -757,21 +744,34 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!(" {ident} ") }; let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); - err.span_suggestion_verbose( + ( sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), - format!("consider returning the local binding `{ident}`"), sugg, - Applicability::MaybeIncorrect, - ); - } - true + ) + }; + Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident }) } values if (1..3).contains(&values.len()) => { let spans = values.iter().map(|(ident, _)| ident.span).collect::>(); - err.span_note(spans, "consider returning one of these bindings"); + Some(SuggestRemoveSemiOrReturnBinding::AddOne { spans: spans.into() }) + } + _ => None, + } + } + + pub fn consider_returning_binding( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut Diagnostic, + ) -> bool { + let diag = self.consider_returning_binding_diag(blk, expected_ty); + match diag { + Some(diag) => { + err.subdiagnostic(diag); true } - _ => false, + None => false, } } } From fdbec623c42ef022bd9461fef7639358a7b2968f Mon Sep 17 00:00:00 2001 From: IQuant Date: Tue, 31 Jan 2023 19:12:48 +0300 Subject: [PATCH 09/11] Port ConsiderAddingAwait --- .../locales/en-US/infer.ftl | 4 ++ compiler/rustc_infer/src/errors/mod.rs | 43 ++++++++++++ .../src/infer/error_reporting/suggest.rs | 65 ++++++++----------- 3 files changed, 74 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 1019b6114641c..8f4ac5234ce33 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -335,3 +335,7 @@ infer_srs_remove_and_box = consider removing this semicolon and boxing the expre infer_srs_remove = consider removing this semicolon infer_srs_add = consider returning the local binding `{$ident}` infer_srs_add_one = consider returning one of these bindings + +infer_await_both_futures = consider `await`ing on both `Future`s +infer_await_future = consider `await`ing on the `Future` +infer_await_note = calling an async function returns a future \ No newline at end of file diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 41691ff4f72bc..ba9821b2151bb 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1050,3 +1050,46 @@ pub enum SuggestRemoveSemiOrReturnBinding { spans: MultiSpan, }, } + +#[derive(Subdiagnostic)] +pub enum ConsiderAddingAwait { + #[help(infer_await_both_futures)] + BothFuturesHelp, + #[multipart_suggestion(infer_await_both_futures, applicability = "maybe-incorrect")] + BothFuturesSugg { + #[suggestion_part(code = ".await")] + first: Span, + #[suggestion_part(code = ".await")] + second: Span, + }, + #[suggestion( + infer_await_future, + code = ".await", + style = "verbose", + applicability = "maybe-incorrect" + )] + FutureSugg { + #[primary_span] + span: Span, + }, + #[suggestion( + infer_await_future, + code = ".await", + style = "verbose", + applicability = "maybe-incorrect" + )] + #[note(infer_await_note)] + FutureSuggWithNote { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + infer_await_future, + style = "verbose", + applicability = "maybe-incorrect" + )] + FutureSuggMultiple { + #[suggestion_part(code = ".await")] + spans: Vec, + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 8d84264ee8c0d..b183abf977f4d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -11,7 +11,9 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitable}; use rustc_span::{sym, BytePos, Span}; -use crate::errors::{SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding}; +use crate::errors::{ + ConsiderAddingAwait, SuggAddLetForLetChains, SuggestRemoveSemiOrReturnBinding, +}; use super::TypeErrCtxt; @@ -191,7 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return; } - match ( + let subdiag = match ( self.get_impl_future_output_ty(exp_found.expected), self.get_impl_future_output_ty(exp_found.found), ) { @@ -200,65 +202,52 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { let then_span = self.find_block_span_from_hir_id(*then_id); - diag.multipart_suggestion( - "consider `await`ing on both `Future`s", - vec![ - (then_span.shrink_to_hi(), ".await".to_string()), - (exp_span.shrink_to_hi(), ".await".to_string()), - ], - Applicability::MaybeIncorrect, - ); + Some(ConsiderAddingAwait::BothFuturesSugg { + first: then_span.shrink_to_hi(), + second: exp_span.shrink_to_hi(), + }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { prior_arms, .. }) => { if let [.., arm_span] = &prior_arms[..] { - diag.multipart_suggestion( - "consider `await`ing on both `Future`s", - vec![ - (arm_span.shrink_to_hi(), ".await".to_string()), - (exp_span.shrink_to_hi(), ".await".to_string()), - ], - Applicability::MaybeIncorrect, - ); + Some(ConsiderAddingAwait::BothFuturesSugg { + first: arm_span.shrink_to_hi(), + second: exp_span.shrink_to_hi(), + }) } else { - diag.help("consider `await`ing on both `Future`s"); + Some(ConsiderAddingAwait::BothFuturesHelp) } } - _ => { - diag.help("consider `await`ing on both `Future`s"); - } + _ => Some(ConsiderAddingAwait::BothFuturesHelp), }, (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { - self.suggest_await_on_future(diag, exp_span); - diag.span_note(exp_span, "calling an async function returns a future"); + Some(ConsiderAddingAwait::FutureSuggWithNote { span: exp_span.shrink_to_hi() }) } (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() { ObligationCauseCode::Pattern { span: Some(then_span), .. } => { - self.suggest_await_on_future(diag, then_span.shrink_to_hi()); + Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::IfExpression(box IfExpressionCause { then_id, .. }) => { let then_span = self.find_block_span_from_hir_id(*then_id); - self.suggest_await_on_future(diag, then_span.shrink_to_hi()); + Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { ref prior_arms, .. - }) => { - diag.multipart_suggestion_verbose( - "consider `await`ing on the `Future`", - prior_arms - .iter() - .map(|arm| (arm.shrink_to_hi(), ".await".to_string())) - .collect(), - Applicability::MaybeIncorrect, - ); - } - _ => {} + }) => Some({ + ConsiderAddingAwait::FutureSuggMultiple { + spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(), + } + }), + _ => None, }, - _ => {} + _ => None, + }; + if let Some(subdiag) = subdiag { + diag.subdiagnostic(subdiag); } } From 5c7afde6f2729963b06477f25ef66680e68e434f Mon Sep 17 00:00:00 2001 From: IQuant Date: Fri, 3 Feb 2023 17:24:53 +0300 Subject: [PATCH 10/11] Port PlaceholderRelationLfNotSatisfied diagnostic --- .../locales/en-US/infer.ftl | 8 ++- compiler/rustc_infer/src/errors/mod.rs | 59 +++++++++++++++++ .../nice_region_error/placeholder_relation.rs | 66 +++++++++++-------- 3 files changed, 103 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 8f4ac5234ce33..c5b2b6c2d7357 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -338,4 +338,10 @@ infer_srs_add_one = consider returning one of these bindings infer_await_both_futures = consider `await`ing on both `Future`s infer_await_future = consider `await`ing on the `Future` -infer_await_note = calling an async function returns a future \ No newline at end of file +infer_await_note = calling an async function returns a future + +infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... +infer_prlf_defined_without_sub = the lifetime defined here... +infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here +infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here +infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 for more information) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index ba9821b2151bb..f4af251d11fc8 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1093,3 +1093,62 @@ pub enum ConsiderAddingAwait { spans: Vec, }, } + +#[derive(Diagnostic)] +pub enum PlaceholderRelationLfNotSatisfied { + #[diag(infer_lf_bound_not_satisfied)] + HasBoth { + #[primary_span] + span: Span, + #[note(infer_prlf_defined_with_sub)] + sub_span: Span, + #[note(infer_prlf_must_oultive_with_sup)] + sup_span: Span, + sub_symbol: Symbol, + sup_symbol: Symbol, + #[note(infer_prlf_known_limitation)] + note: (), + }, + #[diag(infer_lf_bound_not_satisfied)] + HasSub { + #[primary_span] + span: Span, + #[note(infer_prlf_defined_with_sub)] + sub_span: Span, + #[note(infer_prlf_must_oultive_without_sup)] + sup_span: Span, + sub_symbol: Symbol, + #[note(infer_prlf_known_limitation)] + note: (), + }, + #[diag(infer_lf_bound_not_satisfied)] + HasSup { + #[primary_span] + span: Span, + #[note(infer_prlf_defined_without_sub)] + sub_span: Span, + #[note(infer_prlf_must_oultive_with_sup)] + sup_span: Span, + sup_symbol: Symbol, + #[note(infer_prlf_known_limitation)] + note: (), + }, + #[diag(infer_lf_bound_not_satisfied)] + HasNone { + #[primary_span] + span: Span, + #[note(infer_prlf_defined_without_sub)] + sub_span: Span, + #[note(infer_prlf_must_oultive_without_sup)] + sup_span: Span, + #[note(infer_prlf_known_limitation)] + note: (), + }, + #[diag(infer_lf_bound_not_satisfied)] + OnlyPrimarySpan { + #[primary_span] + span: Span, + #[note(infer_prlf_known_limitation)] + note: (), + }, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs index 9534bce54ef0e..e8d94f0c04eaa 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs @@ -1,5 +1,8 @@ -use crate::infer::{ - error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin, +use crate::{ + errors::PlaceholderRelationLfNotSatisfied, + infer::{ + error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin, + }, }; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; @@ -16,8 +19,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)), Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)), )) => { - let msg = "lifetime bound not satisfied"; - let mut err = self.tcx().sess.struct_span_err(*span, msg); + let span = *span; let (sub_span, sub_symbol) = match sub_name { ty::BrNamed(def_id, symbol) => { (Some(self.tcx().def_span(def_id)), Some(symbol)) @@ -32,41 +34,47 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { ty::BrAnon(_, span) => (*span, None), ty::BrEnv => (None, None), }; - match (sub_span, sup_span, sub_symbol, sup_symbol) { - (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => { - err.span_note( + let diag = match (sub_span, sup_span, sub_symbol, sup_symbol) { + (Some(sub_span), Some(sup_span), Some(&sub_symbol), Some(&sup_symbol)) => { + PlaceholderRelationLfNotSatisfied::HasBoth { + span, sub_span, - format!("the lifetime `{sub_symbol}` defined here..."), - ); - err.span_note( sup_span, - format!("...must outlive the lifetime `{sup_symbol}` defined here"), - ); + sub_symbol, + sup_symbol, + note: (), + } } - (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => { - err.span_note(sub_span, "the lifetime defined here..."); - err.span_note( + (Some(sub_span), Some(sup_span), _, Some(&sup_symbol)) => { + PlaceholderRelationLfNotSatisfied::HasSup { + span, + sub_span, sup_span, - format!("...must outlive the lifetime `{sup_symbol}` defined here"), - ); + sup_symbol, + note: (), + } } - (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => { - err.span_note( + (Some(sub_span), Some(sup_span), Some(&sub_symbol), _) => { + PlaceholderRelationLfNotSatisfied::HasSub { + span, sub_span, - format!("the lifetime `{sub_symbol}` defined here..."), - ); - err.span_note(sup_span, "...must outlive the lifetime defined here"); + sup_span, + sub_symbol, + note: (), + } } (Some(sub_span), Some(sup_span), _, _) => { - err.span_note(sub_span, "the lifetime defined here..."); - err.span_note(sup_span, "...must outlive the lifetime defined here"); + PlaceholderRelationLfNotSatisfied::HasNone { + span, + sub_span, + sup_span, + note: (), + } } - _ => {} - } - err.note("this is a known limitation that will be removed in the future (see issue #100013 for more information)"); - Some(err) + _ => PlaceholderRelationLfNotSatisfied::OnlyPrimarySpan { span, note: () }, + }; + Some(self.tcx().sess.create_err(diag)) } - _ => None, } } From 58939b9520e71b6caa2ccc5ca28071e6379d39c0 Mon Sep 17 00:00:00 2001 From: IQuant Date: Tue, 14 Feb 2023 23:16:29 +0300 Subject: [PATCH 11/11] Specify correct spans in suggest_await_on_expect_found --- compiler/rustc_infer/src/errors/mod.rs | 8 +------- compiler/rustc_infer/src/infer/error_reporting/suggest.rs | 6 +++++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index f4af251d11fc8..0c2713fb1a7c8 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1072,14 +1072,8 @@ pub enum ConsiderAddingAwait { #[primary_span] span: Span, }, - #[suggestion( - infer_await_future, - code = ".await", - style = "verbose", - applicability = "maybe-incorrect" - )] #[note(infer_await_note)] - FutureSuggWithNote { + FutureSuggNote { #[primary_span] span: Span, }, diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index b183abf977f4d..18c5097a26289 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -223,7 +223,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ => Some(ConsiderAddingAwait::BothFuturesHelp), }, (_, Some(ty)) if self.same_type_modulo_infer(exp_found.expected, ty) => { - Some(ConsiderAddingAwait::FutureSuggWithNote { span: exp_span.shrink_to_hi() }) + // FIXME: Seems like we can't have a suggestion and a note with different spans in a single subdiagnostic + diag.subdiagnostic(ConsiderAddingAwait::FutureSugg { + span: exp_span.shrink_to_hi(), + }); + Some(ConsiderAddingAwait::FutureSuggNote { span: exp_span }) } (Some(ty), _) if self.same_type_modulo_infer(ty, exp_found.found) => match cause.code() {