From 313d474b35fd6e60302324f75622d77765e1cbf8 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 21 Aug 2022 20:56:00 +0300 Subject: [PATCH 1/7] Migrate OpaqueHiddenType, E0282, E0283, E0284, E0698 --- Cargo.lock | 1 + .../locales/en-US/infer.ftl | 65 ++++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_infer/Cargo.toml | 1 + compiler/rustc_infer/src/errors.rs | 187 +++++++++++ .../infer/error_reporting/need_type_info.rs | 312 ++++++++++-------- compiler/rustc_infer/src/lib.rs | 3 + 7 files changed, 440 insertions(+), 130 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/infer.ftl create mode 100644 compiler/rustc_infer/src/errors.rs diff --git a/Cargo.lock b/Cargo.lock index ebacd32db4fc7..853a2976bc61d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3983,6 +3983,7 @@ dependencies = [ "rustc_macros", "rustc_middle", "rustc_serialize", + "rustc_session", "rustc_span", "rustc_target", "smallvec", diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl new file mode 100644 index 0000000000000..9250363551dbb --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -0,0 +1,65 @@ +infer_opaque_hidden_type = + opaque type's hidden type cannot be another opaque type from the same scope + .label = one of the two opaque types used here has to be outside its defining scope + .opaque_type = opaque type whose hidden type is being assigned + .hidden_type = opaque type being used as hidden type + +infer_type_annotations_needed = {$source_kind -> + [closure] type annotations needed for the closure `{$source_name}` + [normal] type annotations needed for `{$source_name}` + *[other] type annotations needed +} + .label = type must be known at this point + +infer_label_bad = {$bad_kind -> + *[other] cannot infer type + [more_info] cannot infer {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$name}`{$has_parent -> + [true] {" "}declared on the {$parent_prefix} `{$parent_name}` + *[false] {""} + } +} + +infer_source_kind_subdiag_let = {$kind -> + [with_pattern] consider giving `{$name}` an explicit type + [closure] consider giving this closure parameter an explicit type + *[other] consider giving this pattern a type +}{$x_kind -> + [has_name] , where the {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$arg_name}` is specified + [underscore] , where the placeholders `_` are specified + *[empty] {""} +} + +infer_source_kind_subdiag_generic_label = + cannot infer {$is_type -> + [true] type + *[false] the value + } of the {$is_type -> + [true] type + *[false] const + } {$parent_exists -> + [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` + *[false] parameter {$param_name} + } + +infer_source_kind_subdiag_generic_suggestion = + consider specifying the generic {$arg_count -> + [one] argument + *[other] arguments + } + +infer_source_kind_fully_qualified = + try using a fully qualified path to specify the expected types + +infer_source_kind_closure_return = + try giving this closure an explicit return type + +infer_need_type_info_in_generator = + type inside {$generator_kind} must be known in this context diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 3569c7f063064..a24ab3072925f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -38,6 +38,7 @@ fluent_messages! { const_eval => "../locales/en-US/const_eval.ftl", expand => "../locales/en-US/expand.ftl", interface => "../locales/en-US/interface.ftl", + infer => "../locales/en-US/infer.ftl", lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 02ac83a5e8b25..aced787d67116 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs new file mode 100644 index 0000000000000..7bd418ddf5f4c --- /dev/null +++ b/compiler/rustc_infer/src/errors.rs @@ -0,0 +1,187 @@ +use rustc_errors::{fluent, AddSubdiagnostic}; +use rustc_hir::FnRetTy; +use rustc_macros::SessionDiagnostic; +use rustc_span::{BytePos, Span}; + +#[derive(SessionDiagnostic)] +#[diag(infer::opaque_hidden_type)] +pub struct OpaqueHiddenTypeDiag { + #[primary_span] + #[label] + pub span: Span, + #[note(infer::opaque_type)] + pub opaque_type: Span, + #[note(infer::hidden_type)] + pub hidden_type: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(infer::type_annotations_needed, code = "E0282")] +pub struct AnnotationRequired<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, +} + +// Copy of `AnnotationRequired` for E0283 +#[derive(SessionDiagnostic)] +#[diag(infer::type_annotations_needed, code = "E0283")] +pub struct AmbigousImpl<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, +} + +// Copy of `AnnotationRequired` for E0284 +#[derive(SessionDiagnostic)] +#[diag(infer::type_annotations_needed, code = "E0284")] +pub struct AmbigousReturn<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option, + #[subdiagnostic] + pub bad_label: Option>, + #[subdiagnostic] + pub infer_subdiags: Vec>, + #[subdiagnostic] + pub multi_suggestions: Vec>, +} + +#[derive(SessionDiagnostic)] +#[diag(infer::need_type_info_in_generator, code = "E0698")] +pub struct NeedTypeInfoInGenerator<'a> { + #[primary_span] + pub span: Span, + pub generator_kind: String, + #[subdiagnostic] + pub bad_label: InferenceBadError<'a>, +} + +// Used when a better one isn't available +#[derive(SessionSubdiagnostic)] +#[label(infer::label_bad)] +pub struct InferenceBadError<'a> { + #[primary_span] + pub span: Span, + pub bad_kind: &'static str, + pub prefix_kind: &'static str, + pub has_parent: bool, + pub prefix: &'a str, + pub parent_prefix: &'a str, + pub parent_name: String, + pub name: String, +} + +#[derive(SessionSubdiagnostic)] +pub enum SourceKindSubdiag<'a> { + #[suggestion_verbose( + infer::source_kind_subdiag_let, + code = ": {type_name}", + applicability = "has-placeholders" + )] + LetLike { + #[primary_span] + span: Span, + name: String, + type_name: String, + kind: &'static str, + x_kind: &'static str, + prefix_kind: &'static str, + prefix: &'a str, + arg_name: String, + }, + #[label(infer::source_kind_subdiag_generic_label)] + GenericLabel { + #[primary_span] + span: Span, + is_type: bool, + param_name: String, + parent_exists: bool, + parent_prefix: String, + parent_name: String, + }, + #[suggestion_verbose( + infer::source_kind_subdiag_generic_suggestion, + code = "::<{args}>", + applicability = "has-placeholders" + )] + GenericSuggestion { + #[primary_span] + span: Span, + arg_count: usize, + args: String, + }, +} + +// Has to be implemented manually because multipart suggestions are not supported by the derive macro. +// Would be a part of `SourceKindSubdiag` otherwise. +pub enum SourceKindMultiSuggestion<'a> { + FullyQualified { + span: Span, + def_path: String, + adjustment: &'a str, + successor: (&'a str, BytePos), + }, + ClosureReturn { + ty_info: String, + data: &'a FnRetTy<'a>, + should_wrap_expr: Option, + }, +} + +impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + Self::FullyQualified { span, def_path, adjustment, successor } => { + let suggestion = vec![ + (span.shrink_to_lo(), format!("{def_path}({adjustment}")), + (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()), + ]; + diag.multipart_suggestion_verbose( + fluent::infer::source_kind_fully_qualified, + suggestion, + rustc_errors::Applicability::HasPlaceholders, + ); + } + Self::ClosureReturn { ty_info, data, should_wrap_expr } => { + let (arrow, post) = match data { + FnRetTy::DefaultReturn(_) => ("-> ", " "), + _ => ("", ""), + }; + let suggestion = match should_wrap_expr { + Some(end_span) => vec![ + (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)), + (end_span, " }".to_string()), + ], + None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))], + }; + diag.multipart_suggestion_verbose( + fluent::infer::source_kind_closure_return, + suggestion, + rustc_errors::Applicability::HasPlaceholders, + ); + } + } + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 561d1354edd21..da0035d2519f1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1,6 +1,10 @@ +use crate::errors::{ + AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator, + SourceKindMultiSuggestion, SourceKindSubdiag, +}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -14,6 +18,7 @@ use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{self, DefIdTree, InferConst}; use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; +use rustc_session::SessionDiagnostic; use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span}; use std::borrow::Cow; @@ -66,32 +71,42 @@ pub enum UnderspecifiedArgKind { } impl InferenceDiagnosticsData { - /// Generate a label for a generic argument which can't be inferred. When not - /// much is known about the argument, `use_diag` may be used to describe the - /// labeled value. - fn cannot_infer_msg(&self) -> String { - if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) { - return "cannot infer type".to_string(); - } - - let suffix = match &self.parent { - Some(parent) => parent.suffix_string(), - None => String::new(), - }; - - // For example: "cannot infer type for type parameter `T`" - format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix) + fn can_add_more_info(&self) -> bool { + !(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. })) } - fn where_x_is_specified(&self, in_type: Ty<'_>) -> String { + fn where_x_is_kind(&self, in_type: Ty<'_>) -> &'static str { if in_type.is_ty_infer() { - String::new() + "empty" } else if self.name == "_" { // FIXME: Consider specializing this message if there is a single `_` // in the type. - ", where the placeholders `_` are specified".to_string() + "underscore" } else { - format!(", where the {} `{}` is specified", self.kind.prefix_string(), self.name) + "has_name" + } + } + + /// Generate a label for a generic argument which can't be inferred. When not + /// much is known about the argument, `use_diag` may be used to describe the + /// labeled value. + fn make_bad_error(&self, span: Span) -> InferenceBadError<'_> { + let has_parent = self.parent.is_some(); + let bad_kind = if self.can_add_more_info() { "more_info" } else { "other" }; + let (parent_prefix, parent_name) = self + .parent + .as_ref() + .map(|parent| (parent.prefix, parent.name.clone())) + .unwrap_or_default(); + InferenceBadError { + span, + bad_kind, + prefix_kind: self.kind.prefix_kind(), + prefix: self.kind.try_get_prefix().unwrap_or_default(), + name: self.name.clone(), + has_parent, + parent_prefix, + parent_name, } } } @@ -113,18 +128,20 @@ impl InferenceDiagnosticsParentData { fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option { Self::for_parent_def_id(tcx, tcx.parent(def_id)) } - - fn suffix_string(&self) -> String { - format!(" declared on the {} `{}`", self.prefix, self.name) - } } impl UnderspecifiedArgKind { - fn prefix_string(&self) -> Cow<'static, str> { + fn prefix_kind(&self) -> &'static str { + match self { + Self::Type { .. } => "type", + Self::Const { is_parameter: true } => "const_with_param", + Self::Const { is_parameter: false } => "const", + } + } + fn try_get_prefix(&self) -> Option<&str> { match self { - Self::Type { prefix } => format!("type for {}", prefix).into(), - Self::Const { is_parameter: true } => "the value of const parameter".into(), - Self::Const { is_parameter: false } => "the value of the constant".into(), + Self::Type { prefix } => Some(prefix.as_ref()), + Self::Const { .. } => None, } } } @@ -303,11 +320,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let error_code = error_code.into(); - let mut err = - self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code); - err.span_label(span, arg_data.cannot_infer_msg()); - err + let source_kind = "other"; + let source_name = ""; + let failure_span = None; + let infer_subdiags = Vec::new(); + let multi_suggestions = Vec::new(); + let bad_label = Some(arg_data.make_bad_error(span)); + match error_code { + TypeAnnotationNeeded::E0282 => AnnotationRequired { + span, + source_kind, + source_name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label, + } + .into_diagnostic(&self.tcx.sess.parse_sess), + TypeAnnotationNeeded::E0283 => AmbigousImpl { + span, + source_kind, + source_name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label, + } + .into_diagnostic(&self.tcx.sess.parse_sess), + TypeAnnotationNeeded::E0284 => AmbigousReturn { + span, + source_kind, + source_name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label, + } + .into_diagnostic(&self.tcx.sess.parse_sess), + } } pub fn emit_inference_failure_err( @@ -340,48 +390,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return self.bad_inference_failure_err(failure_span, arg_data, error_code) }; - let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - span, - &format!("type annotations needed{}", kind.ty_msg(self)), - error_code, - ); - - if should_label_span && !failure_span.overlaps(span) { - err.span_label(failure_span, "type must be known at this point"); - } + let (source_kind, name) = kind.ty_localized_msg(self); + let failure_span = if should_label_span && !failure_span.overlaps(span) { + Some(failure_span) + } else { + None + }; + let mut infer_subdiags = Vec::new(); + let mut multi_suggestions = Vec::new(); match kind { InferSourceKind::LetBinding { insert_span, pattern_name, ty } => { - let suggestion_msg = if let Some(name) = pattern_name { - format!( - "consider giving `{}` an explicit type{}", - name, - arg_data.where_x_is_specified(ty) - ) - } else { - format!( - "consider giving this pattern a type{}", - arg_data.where_x_is_specified(ty) - ) - }; - err.span_suggestion_verbose( - insert_span, - &suggestion_msg, - format!(": {}", ty_to_string(self, ty)), - Applicability::HasPlaceholders, - ); + infer_subdiags.push(SourceKindSubdiag::LetLike { + span: insert_span, + name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), + x_kind: arg_data.where_x_is_kind(ty), + prefix_kind: arg_data.kind.prefix_kind(), + prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), + arg_name: arg_data.name, + kind: if pattern_name.is_some() { "with_pattern" } else { "other" }, + type_name: ty_to_string(self, ty), + }); } InferSourceKind::ClosureArg { insert_span, ty } => { - err.span_suggestion_verbose( - insert_span, - &format!( - "consider giving this closure parameter an explicit type{}", - arg_data.where_x_is_specified(ty) - ), - format!(": {}", ty_to_string(self, ty)), - Applicability::HasPlaceholders, - ); + infer_subdiags.push(SourceKindSubdiag::LetLike { + span: insert_span, + name: String::new(), + x_kind: arg_data.where_x_is_kind(ty), + prefix_kind: arg_data.kind.prefix_kind(), + prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), + arg_name: arg_data.name, + kind: "closure", + type_name: ty_to_string(self, ty), + }); } InferSourceKind::GenericArg { insert_span, @@ -393,19 +434,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(generics_def_id); let is_type = matches!(arg.unpack(), GenericArgKind::Type(_)); - let cannot_infer_msg = format!( - "cannot infer {} of the {} parameter `{}`{}", - if is_type { "type" } else { "the value" }, - if is_type { "type" } else { "const" }, - generics.params[argument_index].name, - // We use the `generics_def_id` here, as even when suggesting `None::`, - // the type parameter `T` was still declared on the enum, not on the - // variant. + let (parent_exists, parent_prefix, parent_name) = InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id) - .map_or(String::new(), |parent| parent.suffix_string()), - ); + .map_or((false, String::new(), String::new()), |parent| { + (true, parent.prefix.to_string(), parent.name) + }); - err.span_label(span, cannot_infer_msg); + infer_subdiags.push(SourceKindSubdiag::GenericLabel { + span, + is_type, + param_name: generics.params[argument_index].name.to_string(), + parent_exists, + parent_prefix, + parent_name, + }); let args = fmt_printer(self, Namespace::TypeNS) .comma_sep(generic_args.iter().copied().map(|arg| { @@ -435,15 +477,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .unwrap() .into_buffer(); - err.span_suggestion_verbose( - insert_span, - &format!( - "consider specifying the generic argument{}", - pluralize!(generic_args.len()), - ), - format!("::<{}>", args), - Applicability::HasPlaceholders, - ); + infer_subdiags.push(SourceKindSubdiag::GenericSuggestion { + span: insert_span, + arg_count: generic_args.len(), + args, + }); } InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => { let printer = fmt_printer(self, Namespace::ValueNS); @@ -468,37 +506,54 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => "", }; - let suggestion = vec![ - (receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")), - (receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()), - ]; - err.multipart_suggestion_verbose( - "try using a fully qualified path to specify the expected types", - suggestion, - Applicability::HasPlaceholders, - ); + multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified { + span: receiver.span, + def_path, + adjustment, + successor, + }); } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let ret = ty_to_string(self, ty); - let (arrow, post) = match data { - FnRetTy::DefaultReturn(_) => ("-> ", " "), - _ => ("", ""), - }; - let suggestion = match should_wrap_expr { - Some(end_span) => vec![ - (data.span(), format!("{}{}{}{{ ", arrow, ret, post)), - (end_span, " }".to_string()), - ], - None => vec![(data.span(), format!("{}{}{}", arrow, ret, post))], - }; - err.multipart_suggestion_verbose( - "try giving this closure an explicit return type", - suggestion, - Applicability::HasPlaceholders, - ); + let ty_info = ty_to_string(self, ty); + multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn { + ty_info, + data, + should_wrap_expr, + }); + } + } + match error_code { + TypeAnnotationNeeded::E0282 => AnnotationRequired { + span, + source_kind, + source_name: &name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label: None, } + .into_diagnostic(&self.tcx.sess.parse_sess), + TypeAnnotationNeeded::E0283 => AmbigousImpl { + span, + source_kind, + source_name: &name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label: None, + } + .into_diagnostic(&self.tcx.sess.parse_sess), + TypeAnnotationNeeded::E0284 => AmbigousReturn { + span, + source_kind, + source_name: &name, + failure_span, + infer_subdiags, + multi_suggestions, + bad_label: None, + } + .into_diagnostic(&self.tcx.sess.parse_sess), } - err } pub fn need_type_info_err_in_generator( @@ -510,15 +565,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty = self.resolve_vars_if_possible(ty); let data = self.extract_inference_diagnostics_data(ty.into(), None); - let mut err = struct_span_err!( - self.tcx.sess, + NeedTypeInfoInGenerator { + bad_label: data.make_bad_error(span), span, - E0698, - "type inside {} must be known in this context", - kind, - ); - err.span_label(span, data.cannot_infer_msg()); - err + generator_kind: kind.to_string(), + } + .into_diagnostic(&self.tcx.sess.parse_sess) } } @@ -579,22 +631,22 @@ impl<'tcx> InferSource<'tcx> { } impl<'tcx> InferSourceKind<'tcx> { - fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String { + fn ty_localized_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> (&'static str, String) { match *self { InferSourceKind::LetBinding { ty, .. } | InferSourceKind::ClosureArg { ty, .. } | InferSourceKind::ClosureReturn { ty, .. } => { if ty.is_closure() { - format!(" for the closure `{}`", closure_as_fn_str(infcx, ty)) + ("closure", closure_as_fn_str(infcx, ty)) } else if !ty.is_ty_infer() { - format!(" for `{}`", ty_to_string(infcx, ty)) + ("normal", ty_to_string(infcx, ty)) } else { - String::new() + ("other", String::new()) } } // FIXME: We should be able to add some additional info here. InferSourceKind::GenericArg { .. } - | InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(), + | InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()), } } } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 1c515f5ee5722..2c1d339b578fe 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -23,6 +23,8 @@ #![feature(never_type)] #![feature(try_blocks)] #![recursion_limit = "512"] // For rustdoc +// #![deny(rustc::untranslatable_diagnostic)] +// #![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; @@ -34,5 +36,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; +mod errors; pub mod infer; pub mod traits; From 7e4f4337203b247bdbfbb0661e59ab1aa3bee3f1 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 21 Aug 2022 22:39:46 +0300 Subject: [PATCH 2/7] Actually migrate OpaqueHiddenType --- .../rustc_infer/src/infer/opaque_types.rs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index e579afbf38954..233a5004a3931 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -1,3 +1,4 @@ +use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{DefiningAnchor, InferCtxt, InferOk}; use crate::traits; use hir::def_id::{DefId, LocalDefId}; @@ -153,22 +154,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(OpaqueTyOrigin::TyAlias) = did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span)) { - self.tcx - .sess - .struct_span_err( - cause.span, - "opaque type's hidden type cannot be another opaque type from the same scope", - ) - .span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope") - .span_note( - self.tcx.def_span(def_id), - "opaque type whose hidden type is being assigned", - ) - .span_note( - self.tcx.def_span(did2), - "opaque type being used as hidden type", - ) - .emit(); + self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { + span: cause.span, + hidden_type: self.tcx.def_span(did2), + opaque_type: self.tcx.def_span(def_id), + }); } } Some(self.register_hidden_type( From 3f6cb475f7aa1f4475fdb313316a7df644113376 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Mon, 22 Aug 2022 00:17:46 +0300 Subject: [PATCH 3/7] Use GeneratorKind::descr() instead of it's Display impl Those are basically the same but the first one seems to fit better --- compiler/rustc_infer/src/errors.rs | 2 +- .../rustc_infer/src/infer/error_reporting/need_type_info.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs index 7bd418ddf5f4c..51993f37bb3a7 100644 --- a/compiler/rustc_infer/src/errors.rs +++ b/compiler/rustc_infer/src/errors.rs @@ -73,7 +73,7 @@ pub struct AmbigousReturn<'a> { pub struct NeedTypeInfoInGenerator<'a> { #[primary_span] pub span: Span, - pub generator_kind: String, + pub generator_kind: &'static str, #[subdiagnostic] pub bad_label: InferenceBadError<'a>, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index da0035d2519f1..daf64aeb053d3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -568,7 +568,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { NeedTypeInfoInGenerator { bad_label: data.make_bad_error(span), span, - generator_kind: kind.to_string(), + generator_kind: kind.descr(), } .into_diagnostic(&self.tcx.sess.parse_sess) } From f50d1713fd4aab1ff9d160e9fa4b20cd2f71e68a Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 23 Aug 2022 13:48:14 +0300 Subject: [PATCH 4/7] Migrate note_region_origin function --- .../locales/en-US/infer.ftl | 43 ++++++++ compiler/rustc_infer/src/errors.rs | 64 ++++++++++- .../src/infer/error_reporting/mod.rs | 18 ++++ .../src/infer/error_reporting/note.rs | 101 +++++++++--------- 4 files changed, 173 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 9250363551dbb..770eaa62b4118 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -61,5 +61,48 @@ infer_source_kind_fully_qualified = infer_source_kind_closure_return = try giving this closure an explicit return type +# generator_kind may need to be translated infer_need_type_info_in_generator = type inside {$generator_kind} must be known in this context + + +infer_subtype = ...so that the {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] #[start]` function has the correct type + [intristic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} +infer_subtype_2 = ...so that {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [if_else_different] `if` and `else` have incompatible types + [no_else] `if` missing an `else` returns `()` + [fn_main_correct_type] `main` function has the correct type + [fn_start_correct_type] #[start]` function has the correct type + [intristic_correct_type] intrinsic has the correct type + [method_correct_type] method receiver has the correct type + *[other] types are compatible +} + +infer_reborrow = ...so that reference does not outlive borrowed content +infer_reborrow_upvar = ...so that closure can access `{$name}` +infer_relate_object_bound = ...so that it can be closed over into an object +infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long +infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at +infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> +[true] ... +*[false] {""} +} +infer_relate_param_bound_2 = ...that is required by this bound +infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied +infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait + diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs index 51993f37bb3a7..1db8763e4996d 100644 --- a/compiler/rustc_infer/src/errors.rs +++ b/compiler/rustc_infer/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{fluent, AddSubdiagnostic}; +use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString}; use rustc_hir::FnRetTy; use rustc_macros::SessionDiagnostic; use rustc_span::{BytePos, Span}; @@ -185,3 +185,65 @@ impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> { } } } + +pub enum RegionOriginNote<'a> { + Plain { + span: Span, + msg: DiagnosticMessage, + }, + WithName { + span: Span, + msg: DiagnosticMessage, + name: &'a str, + continues: bool, + }, + WithRequirement { + span: Span, + requirement: &'static str, + expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>, + }, +} + +impl AddSubdiagnostic for RegionOriginNote<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + let mut label_or_note = |span, msg: DiagnosticMessage| { + let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); + let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); + let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span); + if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { + diag.span_label(span, msg); + } else if span_is_primary && expanded_sub_count == 0 { + diag.note(msg); + } else { + diag.span_note(span, msg); + } + }; + match self { + RegionOriginNote::Plain { span, msg } => { + label_or_note(span, msg); + } + RegionOriginNote::WithName { span, msg, name, continues } => { + label_or_note(span, msg); + diag.set_arg("name", name); + diag.set_arg("continues", continues); + } + RegionOriginNote::WithRequirement { + span, + requirement, + expected_found: Some((expected, found)), + } => { + label_or_note(span, fluent::infer::subtype); + diag.set_arg("requirement", requirement); + + diag.note_expected_found(&"", expected, &"", found); + } + RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. + label_or_note(span, fluent::infer::subtype_2); + diag.set_arg("requirement", requirement); + } + }; + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 59ea1f3f9de45..13951326665d7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2811,6 +2811,7 @@ pub enum FailureCode { pub trait ObligationCauseExt<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; fn as_requirement_str(&self) -> &'static str; + fn as_requirement_localised(&self) -> &'static str; } impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { @@ -2879,6 +2880,23 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { _ => "types are compatible", } } + + fn as_requirement_localised(&self) -> &'static str { + use crate::traits::ObligationCauseCode::*; + match self.code() { + CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", + CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", + CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", + ExprAssignable => "expr_assignable", + IfExpression { .. } => "if_else_different", + IfExpressionWithNoElse => "no_else", + MainFunctionType => "fn_main_correct_type", + StartFunctionType => "fn_start_correct_type", + IntrinsicType => "intristic_correct_type", + MethodReceiver => "method_correct_type", + _ => "other", + } + } } /// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 8c465b0876002..36efbd6824a77 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,13 +1,17 @@ +use crate::errors::RegionOriginNote; use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; use crate::infer::{self, InferCtxt, SubregionOrigin}; -use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticMessage, + ErrorGuaranteed, +}; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Region}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { - let mut label_or_note = |span, msg: &str| { + let mut label_or_note = |span, msg: DiagnosticMessage| { let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span); @@ -20,77 +24,70 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } }; match *origin { - infer::Subtype(ref trace) => { - if let Some((expected, found)) = self.values_str(trace.values) { - label_or_note( - trace.cause.span, - &format!("...so that the {}", trace.cause.as_requirement_str()), - ); - - err.note_expected_found(&"", expected, &"", found); - } else { - // FIXME: this really should be handled at some earlier stage. Our - // handling of region checking when type errors are present is - // *terrible*. - - label_or_note( - trace.cause.span, - &format!("...so that {}", trace.cause.as_requirement_str()), - ); - } + infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { + span: trace.cause.span, + requirement: trace.cause.as_requirement_localised(), + expected_found: self.values_str(trace.values), } + .add_to_diagnostic(err), infer::Reborrow(span) => { - label_or_note(span, "...so that reference does not outlive borrowed content"); + label_or_note(span, fluent::infer::reborrow); + RegionOriginNote::Plain { span, msg: fluent::infer::reborrow } + .add_to_diagnostic(err) } infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - label_or_note(span, &format!("...so that closure can access `{}`", var_name)); + RegionOriginNote::WithName { + span, + msg: fluent::infer::reborrow, + name: &var_name.to_string(), + continues: false, + } + .add_to_diagnostic(err); } infer::RelateObjectBound(span) => { - label_or_note(span, "...so that it can be closed over into an object"); + label_or_note(span, fluent::infer::relate_object_bound); + RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound } + .add_to_diagnostic(err); } infer::DataBorrowed(ty, span) => { - label_or_note( + RegionOriginNote::WithName { span, - &format!( - "...so that the type `{}` is not borrowed for too long", - self.ty_to_string(ty) - ), - ); + msg: fluent::infer::data_borrowed, + name: &self.ty_to_string(ty), + continues: false, + } + .add_to_diagnostic(err); } infer::ReferenceOutlivesReferent(ty, span) => { - label_or_note( + RegionOriginNote::WithName { span, - &format!( - "...so that the reference type `{}` does not outlive the data it points at", - self.ty_to_string(ty) - ), - ); + msg: fluent::infer::reference_outlives_referent, + name: &self.ty_to_string(ty), + continues: false, + } + .add_to_diagnostic(err); } - infer::RelateParamBound(span, t, opt_span) => { - label_or_note( + infer::RelateParamBound(span, ty, opt_span) => { + RegionOriginNote::WithName { span, - &format!( - "...so that the type `{}` will meet its required lifetime bounds{}", - self.ty_to_string(t), - if opt_span.is_some() { "..." } else { "" }, - ), - ); + msg: fluent::infer::relate_param_bound, + name: &self.ty_to_string(ty), + continues: opt_span.is_some(), + } + .add_to_diagnostic(err); if let Some(span) = opt_span { - err.span_note(span, "...that is required by this bound"); + RegionOriginNote::Plain { span, msg: fluent::infer::relate_param_bound_2 } + .add_to_diagnostic(err); } } infer::RelateRegionParamBound(span) => { - label_or_note( - span, - "...so that the declared lifetime parameter bounds are satisfied", - ); + RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound } + .add_to_diagnostic(err); } infer::CompareImplItemObligation { span, .. } => { - label_or_note( - span, - "...so that the definition in impl matches the definition from the trait", - ); + RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation } + .add_to_diagnostic(err); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, &parent); From 74f99738244fc9ba2f6ad93b8c891d44d638b0f8 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 23 Aug 2022 15:33:06 +0300 Subject: [PATCH 5/7] Fix formating in infer.ftl to make tidy happy --- .../rustc_error_messages/locales/en-US/infer.ftl | 15 +++++++-------- 1 file changed, 7 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 770eaa62b4118..6ae60d92e26ee 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -1,4 +1,4 @@ -infer_opaque_hidden_type = +infer_opaque_hidden_type = opaque type's hidden type cannot be another opaque type from the same scope .label = one of the two opaque types used here has to be outside its defining scope .opaque_type = opaque type whose hidden type is being assigned @@ -8,7 +8,7 @@ infer_type_annotations_needed = {$source_kind -> [closure] type annotations needed for the closure `{$source_name}` [normal] type annotations needed for `{$source_name}` *[other] type annotations needed -} +} .label = type must be known at this point infer_label_bad = {$bad_kind -> @@ -38,24 +38,24 @@ infer_source_kind_subdiag_let = {$kind -> } infer_source_kind_subdiag_generic_label = - cannot infer {$is_type -> + cannot infer {$is_type -> [true] type *[false] the value - } of the {$is_type -> + } of the {$is_type -> [true] type *[false] const } {$parent_exists -> [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` - *[false] parameter {$param_name} + *[false] parameter {$param_name} } infer_source_kind_subdiag_generic_suggestion = - consider specifying the generic {$arg_count -> + consider specifying the generic {$arg_count -> [one] argument *[other] arguments } -infer_source_kind_fully_qualified = +infer_source_kind_fully_qualified = try using a fully qualified path to specify the expected types infer_source_kind_closure_return = @@ -105,4 +105,3 @@ infer_relate_param_bound = ...so that the type `{$name}` will meet its required infer_relate_param_bound_2 = ...that is required by this bound infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait - From 3fae3904b130272c782255066f79a13fa9fcdad6 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Wed, 24 Aug 2022 15:46:29 +0300 Subject: [PATCH 6/7] Use `IntoDiagnosticArg` where it makes sense --- .../locales/en-US/infer.ftl | 7 +++- compiler/rustc_infer/src/errors.rs | 13 +++++-- .../src/infer/error_reporting/mod.rs | 16 +++++--- .../infer/error_reporting/need_type_info.rs | 37 ++++++++++++++----- .../src/infer/error_reporting/note.rs | 29 ++++----------- 5 files changed, 61 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 6ae60d92e26ee..60086cd6e477f 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -63,7 +63,12 @@ infer_source_kind_closure_return = # generator_kind may need to be translated infer_need_type_info_in_generator = - type inside {$generator_kind} must be known in this context + type inside {$generator_kind -> + [async_block] `async` block + [async_closure] `async` closure + [async_fn] `async fn` body + *[generator] generator + } must be known in this context infer_subtype = ...so that the {$requirement -> diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs index 1db8763e4996d..938f8aa77a5b4 100644 --- a/compiler/rustc_infer/src/errors.rs +++ b/compiler/rustc_infer/src/errors.rs @@ -3,6 +3,11 @@ use rustc_hir::FnRetTy; use rustc_macros::SessionDiagnostic; use rustc_span::{BytePos, Span}; +use crate::infer::error_reporting::{ + need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, + ObligationCauseAsDiagArg, +}; + #[derive(SessionDiagnostic)] #[diag(infer::opaque_hidden_type)] pub struct OpaqueHiddenTypeDiag { @@ -73,7 +78,7 @@ pub struct AmbigousReturn<'a> { pub struct NeedTypeInfoInGenerator<'a> { #[primary_span] pub span: Span, - pub generator_kind: &'static str, + pub generator_kind: GeneratorKindAsDiagArg, #[subdiagnostic] pub bad_label: InferenceBadError<'a>, } @@ -85,7 +90,7 @@ pub struct InferenceBadError<'a> { #[primary_span] pub span: Span, pub bad_kind: &'static str, - pub prefix_kind: &'static str, + pub prefix_kind: UnderspecifiedArgKind, pub has_parent: bool, pub prefix: &'a str, pub parent_prefix: &'a str, @@ -107,7 +112,7 @@ pub enum SourceKindSubdiag<'a> { type_name: String, kind: &'static str, x_kind: &'static str, - prefix_kind: &'static str, + prefix_kind: UnderspecifiedArgKind, prefix: &'a str, arg_name: String, }, @@ -199,7 +204,7 @@ pub enum RegionOriginNote<'a> { }, WithRequirement { span: Span, - requirement: &'static str, + requirement: ObligationCauseAsDiagArg<'a>, expected_found: Option<(DiagnosticStyledString, DiagnosticStyledString)>, }, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 13951326665d7..c7e258578e4de 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,7 +58,7 @@ use crate::traits::{ }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -78,7 +78,7 @@ use std::{cmp, fmt, iter}; mod note; -mod need_type_info; +pub(crate) mod need_type_info; pub use need_type_info::TypeAnnotationNeeded; pub mod nice_region_error; @@ -2811,7 +2811,6 @@ pub enum FailureCode { pub trait ObligationCauseExt<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode; fn as_requirement_str(&self) -> &'static str; - fn as_requirement_localised(&self) -> &'static str; } impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { @@ -2880,10 +2879,15 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { _ => "types are compatible", } } +} + +/// Newtype to allow implementing IntoDiagnosticArg +pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); - fn as_requirement_localised(&self) -> &'static str { +impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { use crate::traits::ObligationCauseCode::*; - match self.code() { + let kind = match self.0.code() { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", @@ -2896,6 +2900,8 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { MethodReceiver => "method_correct_type", _ => "other", } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index daf64aeb053d3..e990fe7ecb504 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -4,7 +4,7 @@ use crate::errors::{ }; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxt; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorOf, DefKind, Namespace}; @@ -65,6 +65,7 @@ pub struct InferenceDiagnosticsParentData { name: String, } +#[derive(Clone)] pub enum UnderspecifiedArgKind { Type { prefix: Cow<'static, str> }, Const { is_parameter: bool }, @@ -101,7 +102,7 @@ impl InferenceDiagnosticsData { InferenceBadError { span, bad_kind, - prefix_kind: self.kind.prefix_kind(), + prefix_kind: self.kind.clone(), prefix: self.kind.try_get_prefix().unwrap_or_default(), name: self.name.clone(), has_parent, @@ -130,14 +131,18 @@ impl InferenceDiagnosticsParentData { } } -impl UnderspecifiedArgKind { - fn prefix_kind(&self) -> &'static str { - match self { +impl IntoDiagnosticArg for UnderspecifiedArgKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self { Self::Type { .. } => "type", Self::Const { is_parameter: true } => "const_with_param", Self::Const { is_parameter: false } => "const", - } + }; + rustc_errors::DiagnosticArgValue::Str(kind.into()) } +} + +impl UnderspecifiedArgKind { fn try_get_prefix(&self) -> Option<&str> { match self { Self::Type { prefix } => Some(prefix.as_ref()), @@ -405,7 +410,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: insert_span, name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new), x_kind: arg_data.where_x_is_kind(ty), - prefix_kind: arg_data.kind.prefix_kind(), + prefix_kind: arg_data.kind.clone(), prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, kind: if pattern_name.is_some() { "with_pattern" } else { "other" }, @@ -417,7 +422,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span: insert_span, name: String::new(), x_kind: arg_data.where_x_is_kind(ty), - prefix_kind: arg_data.kind.prefix_kind(), + prefix_kind: arg_data.kind.clone(), prefix: arg_data.kind.try_get_prefix().unwrap_or_default(), arg_name: arg_data.name, kind: "closure", @@ -568,12 +573,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { NeedTypeInfoInGenerator { bad_label: data.make_bad_error(span), span, - generator_kind: kind.descr(), + generator_kind: GeneratorKindAsDiagArg(kind), } .into_diagnostic(&self.tcx.sess.parse_sess) } } +pub struct GeneratorKindAsDiagArg(pub hir::GeneratorKind); + +impl IntoDiagnosticArg for GeneratorKindAsDiagArg { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self.0 { + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure", + hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn", + hir::GeneratorKind::Gen => "generator", + }; + rustc_errors::DiagnosticArgValue::Str(kind.into()) + } +} + #[derive(Debug)] struct InferSource<'tcx> { span: Span, diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 36efbd6824a77..cffdf56bb6d48 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -1,40 +1,26 @@ use crate::errors::RegionOriginNote; -use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt}; +use crate::infer::error_reporting::note_and_explain_region; use crate::infer::{self, InferCtxt, SubregionOrigin}; use rustc_errors::{ - fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticMessage, - ErrorGuaranteed, + fluent, struct_span_err, AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, }; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Region}; +use super::ObligationCauseAsDiagArg; + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) { - let mut label_or_note = |span, msg: DiagnosticMessage| { - let sub_count = err.children.iter().filter(|d| d.span.is_dummy()).count(); - let expanded_sub_count = err.children.iter().filter(|d| !d.span.is_dummy()).count(); - let span_is_primary = err.span.primary_spans().iter().all(|&sp| sp == span); - if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { - err.span_label(span, msg); - } else if span_is_primary && expanded_sub_count == 0 { - err.note(msg); - } else { - err.span_note(span, msg); - } - }; match *origin { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, - requirement: trace.cause.as_requirement_localised(), + requirement: ObligationCauseAsDiagArg(trace.cause.clone()), expected_found: self.values_str(trace.values), } .add_to_diagnostic(err), - infer::Reborrow(span) => { - label_or_note(span, fluent::infer::reborrow); - RegionOriginNote::Plain { span, msg: fluent::infer::reborrow } - .add_to_diagnostic(err) - } + infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow } + .add_to_diagnostic(err), infer::ReborrowUpvar(span, ref upvar_id) => { let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); RegionOriginNote::WithName { @@ -46,7 +32,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .add_to_diagnostic(err); } infer::RelateObjectBound(span) => { - label_or_note(span, fluent::infer::relate_object_bound); RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound } .add_to_diagnostic(err); } From e1765a9c56d8d9b235bc5b8fda2a0f1d4e92ff49 Mon Sep 17 00:00:00 2001 From: IQuant Date: Wed, 24 Aug 2022 17:09:07 +0300 Subject: [PATCH 7/7] Remove commented lines --- compiler/rustc_infer/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 2c1d339b578fe..eed2efd3ee0c0 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -23,8 +23,6 @@ #![feature(never_type)] #![feature(try_blocks)] #![recursion_limit = "512"] // For rustdoc -// #![deny(rustc::untranslatable_diagnostic)] -// #![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros;