From 622217da59ae7b4d1d5128255c9517aeb2174ea6 Mon Sep 17 00:00:00 2001 From: AndyJado <101876416+AndyJado@users.noreply.github.com> Date: Fri, 26 Aug 2022 10:32:59 +0800 Subject: [PATCH] diag-mig --- .../src/diagnostics/region_errors.rs | 93 ++++++-------- compiler/rustc_borrowck/src/lib.rs | 18 +-- .../src/region_infer/opaque_types.rs | 17 +-- .../rustc_borrowck/src/session_diagnostics.rs | 117 +++++++++++++++++- .../locales/en-US/borrowck.ftl | 42 +++++++ 5 files changed, 211 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 0dce5be953e1a..00fdf331ca60c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,3 +1,5 @@ +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] //! Error reporting machinery for lifetime errors. use rustc_data_structures::fx::FxHashSet; @@ -23,7 +25,10 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use crate::borrowck_errors; -use crate::session_diagnostics::GenericDoesNotLiveLongEnough; +use crate::session_diagnostics::{ + FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr, + LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote, +}; use super::{OutlivesSuggestionBuilder, RegionName}; use crate::region_infer::BlameConstraint; @@ -488,12 +493,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let ErrorConstraintInfo { outlived_fr, span, .. } = errci; - let mut diag = self - .infcx - .tcx - .sess - .struct_span_err(*span, "captured variable cannot escape `FnMut` closure body"); - let mut output_ty = self.regioncx.universal_regions().unnormalized_output_ty; if let ty::Opaque(def_id, _) = *output_ty.kind() { output_ty = self.infcx.tcx.type_of(def_id) @@ -501,19 +500,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { debug!("report_fnmut_error: output_ty={:?}", output_ty); - let message = match output_ty.kind() { - ty::Closure(_, _) => { - "returns a closure that contains a reference to a captured variable, which then \ - escapes the closure body" - } - ty::Adt(def, _) if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => { - "returns an `async` block that contains a reference to a captured variable, which then \ - escapes the closure body" - } - _ => "returns a reference to a captured variable which escapes the closure body", + let err = FnMutError { + span: *span, + ty_err: match output_ty.kind() { + ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span }, + ty::Adt(def, _) + if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => + { + FnMutReturnTypeErr::ReturnAsyncBlock { span: *span } + } + _ => FnMutReturnTypeErr::ReturnRef { span: *span }, + }, }; - diag.span_label(*span, message); + let mut diag = self.infcx.tcx.sess.create_err(err); if let ReturnConstraint::ClosureUpvar(upvar_field) = kind { let def_id = match self.regioncx.universal_regions().defining_ty { @@ -532,20 +532,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvars_map = self.infcx.tcx.upvars_mentioned(def_id).unwrap(); let upvar_def_span = self.infcx.tcx.hir().span(def_hir); let upvar_span = upvars_map.get(&def_hir).unwrap().span; - diag.span_label(upvar_def_span, "variable defined here"); - diag.span_label(upvar_span, "variable captured here"); + diag.subdiagnostic(VarHereDenote::Defined { span: upvar_def_span }); + diag.subdiagnostic(VarHereDenote::Captured { span: upvar_span }); } } if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() { - diag.span_label(fr_span, "inferred to be a `FnMut` closure"); + diag.subdiagnostic(VarHereDenote::FnMutInferred { span: fr_span }); } - diag.note( - "`FnMut` closures only have access to their captured variables while they are \ - executing...", - ); - diag.note("...therefore, they cannot allow references to captured variables to escape"); self.suggest_move_on_borrowing_closure(&mut diag); diag @@ -681,39 +676,33 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. } = errci; - let mut diag = - self.infcx.tcx.sess.struct_span_err(*span, "lifetime may not live long enough"); - let (_, mir_def_name) = self.infcx.tcx.article_and_description(self.mir_def_id().to_def_id()); + let err = LifetimeOutliveErr { span: *span }; + let mut diag = self.infcx.tcx.sess.create_err(err); + let fr_name = self.give_region_a_name(*fr).unwrap(); fr_name.highlight_region_name(&mut diag); let outlived_fr_name = self.give_region_a_name(*outlived_fr).unwrap(); outlived_fr_name.highlight_region_name(&mut diag); - match (category, outlived_fr_is_local, fr_is_local) { - (ConstraintCategory::Return(_), true, _) => { - diag.span_label( - *span, - format!( - "{mir_def_name} was supposed to return data with lifetime `{outlived_fr_name}` but it is returning \ - data with lifetime `{fr_name}`", - ), - ); - } - _ => { - diag.span_label( - *span, - format!( - "{}requires that `{}` must outlive `{}`", - category.description(), - fr_name, - outlived_fr_name, - ), - ); - } - } + let err_category = match (category, outlived_fr_is_local, fr_is_local) { + (ConstraintCategory::Return(_), true, _) => LifetimeReturnCategoryErr::WrongReturn { + span: *span, + mir_def_name, + outlived_fr_name, + fr_name: &fr_name, + }, + _ => LifetimeReturnCategoryErr::ShortReturn { + span: *span, + category_desc: category.description(), + free_region_name: &fr_name, + outlived_fr_name, + }, + }; + + diag.subdiagnostic(err_category); self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); @@ -862,7 +851,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ident.span, "calling this method introduces the `impl`'s 'static` requirement", ); - err.span_note(multi_span, "the used `impl` has a `'static` requirement"); + err.subdiagnostic(RequireStaticErr::UsedImpl { multi_span }); err.span_suggestion_verbose( span.shrink_to_hi(), "consider relaxing the implicit `'static` requirement", diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4ad9a970bc1be..0f8afb038f455 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -18,7 +18,7 @@ extern crate tracing; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::ChunkedBitSet; @@ -50,6 +50,8 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveE use rustc_mir_dataflow::Analysis; use rustc_mir_dataflow::MoveDataParamEnv; +use crate::session_diagnostics::VarNeedNotMut; + use self::diagnostics::{AccessKind, RegionName}; use self::location::LocationTable; use self::prefixes::PrefixSet; @@ -424,17 +426,9 @@ fn do_mir_borrowck<'a, 'tcx>( continue; } - tcx.struct_span_lint_hir(UNUSED_MUT, lint_root, span, |lint| { - let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); - lint.build("variable does not need to be mutable") - .span_suggestion_short( - mut_span, - "remove this `mut`", - "", - Applicability::MachineApplicable, - ) - .emit(); - }) + let mut_span = tcx.sess.source_map().span_until_non_whitespace(span); + + tcx.emit_spanned_lint(UNUSED_MUT, lint_root, span, VarNeedNotMut { span: mut_span }) } let tainted_by_errors = mbcx.emit_errors(); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index d6712b6a4799c..127cb4e408372 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -16,6 +16,8 @@ use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::TraitEngineExt as _; +use crate::session_diagnostics::ConstNotUsedTraitAlias; + use super::RegionInferenceContext; impl<'tcx> RegionInferenceContext<'tcx> { @@ -639,17 +641,10 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { Some(GenericArgKind::Const(c1)) => c1, Some(u) => panic!("const mapped to unexpected kind: {:?}", u), None => { - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ct - ), - ) - .emit(); + self.tcx.sess.emit_err(ConstNotUsedTraitAlias { + ct: ct.to_string(), + span: self.span, + }); self.tcx().const_error(ct.ty()) } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 8c9676e4bfa85..5d750c6ca8c7b 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -1,7 +1,10 @@ -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_errors::{IntoDiagnosticArg, MultiSpan}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; +use crate::diagnostics::RegionName; + #[derive(SessionDiagnostic)] #[diag(borrowck::move_unsized, code = "E0161")] pub(crate) struct MoveUnsized<'tcx> { @@ -42,3 +45,115 @@ pub(crate) struct GenericDoesNotLiveLongEnough { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[diag(borrowck::var_does_not_need_mut)] +pub(crate) struct VarNeedNotMut { + #[suggestion_short(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(borrowck::const_not_used_in_type_alias)] +pub(crate) struct ConstNotUsedTraitAlias { + pub ct: String, + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(borrowck::var_cannot_escape_closure)] +#[note] +#[note(borrowck::cannot_escape)] +pub(crate) struct FnMutError { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub ty_err: FnMutReturnTypeErr, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum VarHereDenote { + #[label(borrowck::var_here_captured)] + Captured { + #[primary_span] + span: Span, + }, + #[label(borrowck::var_here_defined)] + Defined { + #[primary_span] + span: Span, + }, + #[label(borrowck::closure_inferred_mut)] + FnMutInferred { + #[primary_span] + span: Span, + }, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum FnMutReturnTypeErr { + #[label(borrowck::returned_closure_escaped)] + ReturnClosure { + #[primary_span] + span: Span, + }, + #[label(borrowck::returned_async_block_escaped)] + ReturnAsyncBlock { + #[primary_span] + span: Span, + }, + #[label(borrowck::returned_ref_escaped)] + ReturnRef { + #[primary_span] + span: Span, + }, +} + +#[derive(SessionDiagnostic)] +#[diag(borrowck::lifetime_constraints_error)] +pub(crate) struct LifetimeOutliveErr { + #[primary_span] + pub span: Span, +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum LifetimeReturnCategoryErr<'a> { + #[label(borrowck::returned_lifetime_wrong)] + WrongReturn { + #[primary_span] + span: Span, + mir_def_name: &'a str, + outlived_fr_name: RegionName, + fr_name: &'a RegionName, + }, + #[label(borrowck::returned_lifetime_short)] + ShortReturn { + #[primary_span] + span: Span, + category_desc: &'static str, + free_region_name: &'a RegionName, + outlived_fr_name: RegionName, + }, +} + +impl IntoDiagnosticArg for &RegionName { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{}", self).into_diagnostic_arg() + } +} + +impl IntoDiagnosticArg for RegionName { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{}", self).into_diagnostic_arg() + } +} + +#[derive(SessionSubdiagnostic)] +pub(crate) enum RequireStaticErr { + #[note(borrowck::used_impl_require_static)] + UsedImpl { + #[primary_span] + multi_span: MultiSpan, + }, +} diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl index a96fe7c8a05d5..67f2156f32e50 100644 --- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -16,3 +16,45 @@ borrowck_higher_ranked_subtype_error = borrowck_generic_does_not_live_long_enough = `{$kind}` does not live long enough + +borrowck_move_borrowed = + cannot move out of `{$desc}` beacause it is borrowed + +borrowck_var_does_not_need_mut = + variable does not need to be mutable + .suggestion = remove this `mut` + +borrowck_const_not_used_in_type_alias = + const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias + +borrowck_var_cannot_escape_closure = + captured variable cannot escape `FnMut` closure body + .note = `FnMut` closures only have access to their captured variables while they are executing... + .cannot_escape = ...therefore, they cannot allow references to captured variables to escape + +borrowck_var_here_defined = variable defined here + +borrowck_var_here_captured = variable captured here + +borrowck_closure_inferred_mut = inferred to be a `FnMut` closure + +borrowck_returned_closure_escaped = + returns a closure that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_async_block_escaped = + returns an `async` block that contains a reference to a captured variable, which then escapes the closure body + +borrowck_returned_ref_escaped = + returns a reference to a captured variable which escapes the closure body + +borrowck_lifetime_constraints_error = + lifetime may not live long enough + +borrowck_returned_lifetime_wrong = + {$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}` + +borrowck_returned_lifetime_short = + {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}` + +borrowck_used_impl_require_static = + the used `impl` has a `'static` requirement