mirror of https://github.com/rust-lang/rust.git
Rollup merge of #100843 - IntQuant:issue-100717-infer, r=compiler-errors
Migrate part of rustc_infer to session diagnostic
This commit is contained in:
commit
a3c965f5fe
|
@ -3631,6 +3631,7 @@ dependencies = [
|
||||||
"rustc_macros",
|
"rustc_macros",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
# generator_kind may need to be translated
|
||||||
|
infer_need_type_info_in_generator =
|
||||||
|
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 ->
|
||||||
|
[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
|
|
@ -41,6 +41,7 @@ fluent_messages! {
|
||||||
driver => "../locales/en-US/driver.ftl",
|
driver => "../locales/en-US/driver.ftl",
|
||||||
expand => "../locales/en-US/expand.ftl",
|
expand => "../locales/en-US/expand.ftl",
|
||||||
interface => "../locales/en-US/interface.ftl",
|
interface => "../locales/en-US/interface.ftl",
|
||||||
|
infer => "../locales/en-US/infer.ftl",
|
||||||
lint => "../locales/en-US/lint.ftl",
|
lint => "../locales/en-US/lint.ftl",
|
||||||
parser => "../locales/en-US/parser.ftl",
|
parser => "../locales/en-US/parser.ftl",
|
||||||
passes => "../locales/en-US/passes.ftl",
|
passes => "../locales/en-US/passes.ftl",
|
||||||
|
|
|
@ -15,6 +15,7 @@ rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
rustc_serialize = { path = "../rustc_serialize" }
|
rustc_serialize = { path = "../rustc_serialize" }
|
||||||
|
rustc_session = { path = "../rustc_session" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString};
|
||||||
|
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 {
|
||||||
|
#[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<Span>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub bad_label: Option<InferenceBadError<'a>>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<Span>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub bad_label: Option<InferenceBadError<'a>>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<Span>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub bad_label: Option<InferenceBadError<'a>>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub infer_subdiags: Vec<SourceKindSubdiag<'a>>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SessionDiagnostic)]
|
||||||
|
#[diag(infer::need_type_info_in_generator, code = "E0698")]
|
||||||
|
pub struct NeedTypeInfoInGenerator<'a> {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
pub generator_kind: GeneratorKindAsDiagArg,
|
||||||
|
#[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: UnderspecifiedArgKind,
|
||||||
|
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: UnderspecifiedArgKind,
|
||||||
|
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<Span>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RegionOriginNote<'a> {
|
||||||
|
Plain {
|
||||||
|
span: Span,
|
||||||
|
msg: DiagnosticMessage,
|
||||||
|
},
|
||||||
|
WithName {
|
||||||
|
span: Span,
|
||||||
|
msg: DiagnosticMessage,
|
||||||
|
name: &'a str,
|
||||||
|
continues: bool,
|
||||||
|
},
|
||||||
|
WithRequirement {
|
||||||
|
span: Span,
|
||||||
|
requirement: ObligationCauseAsDiagArg<'a>,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,7 +58,7 @@ use crate::traits::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
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_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -78,7 +78,7 @@ use std::{cmp, fmt, iter};
|
||||||
|
|
||||||
mod note;
|
mod note;
|
||||||
|
|
||||||
mod need_type_info;
|
pub(crate) mod need_type_info;
|
||||||
pub use need_type_info::TypeAnnotationNeeded;
|
pub use need_type_info::TypeAnnotationNeeded;
|
||||||
|
|
||||||
pub mod nice_region_error;
|
pub mod nice_region_error;
|
||||||
|
@ -2886,6 +2886,30 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Newtype to allow implementing IntoDiagnosticArg
|
||||||
|
pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>);
|
||||||
|
|
||||||
|
impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
|
||||||
|
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
|
||||||
|
use crate::traits::ObligationCauseCode::*;
|
||||||
|
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",
|
||||||
|
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",
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
rustc_errors::DiagnosticArgValue::Str(kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
|
/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks
|
||||||
/// extra information about each type, but we only care about the category.
|
/// extra information about each type, but we only care about the category.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
use crate::errors::{
|
||||||
|
AmbigousImpl, AmbigousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
|
||||||
|
SourceKindMultiSuggestion, SourceKindSubdiag,
|
||||||
|
};
|
||||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
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::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::{self, DefIdTree, InferConst};
|
use rustc_middle::ty::{self, DefIdTree, InferConst};
|
||||||
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
|
use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
|
||||||
|
use rustc_session::SessionDiagnostic;
|
||||||
use rustc_span::symbol::{kw, Ident};
|
use rustc_span::symbol::{kw, Ident};
|
||||||
use rustc_span::{BytePos, Span};
|
use rustc_span::{BytePos, Span};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -60,38 +65,49 @@ pub struct InferenceDiagnosticsParentData {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum UnderspecifiedArgKind {
|
pub enum UnderspecifiedArgKind {
|
||||||
Type { prefix: Cow<'static, str> },
|
Type { prefix: Cow<'static, str> },
|
||||||
Const { is_parameter: bool },
|
Const { is_parameter: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InferenceDiagnosticsData {
|
impl InferenceDiagnosticsData {
|
||||||
/// Generate a label for a generic argument which can't be inferred. When not
|
fn can_add_more_info(&self) -> bool {
|
||||||
/// much is known about the argument, `use_diag` may be used to describe the
|
!(self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }))
|
||||||
/// 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 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() {
|
if in_type.is_ty_infer() {
|
||||||
String::new()
|
"empty"
|
||||||
} else if self.name == "_" {
|
} else if self.name == "_" {
|
||||||
// FIXME: Consider specializing this message if there is a single `_`
|
// FIXME: Consider specializing this message if there is a single `_`
|
||||||
// in the type.
|
// in the type.
|
||||||
", where the placeholders `_` are specified".to_string()
|
"underscore"
|
||||||
} else {
|
} 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.clone(),
|
||||||
|
prefix: self.kind.try_get_prefix().unwrap_or_default(),
|
||||||
|
name: self.name.clone(),
|
||||||
|
has_parent,
|
||||||
|
parent_prefix,
|
||||||
|
parent_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,18 +129,24 @@ impl InferenceDiagnosticsParentData {
|
||||||
fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
|
fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
|
||||||
Self::for_parent_def_id(tcx, tcx.parent(def_id))
|
Self::for_parent_def_id(tcx, tcx.parent(def_id))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn suffix_string(&self) -> String {
|
impl IntoDiagnosticArg for UnderspecifiedArgKind {
|
||||||
format!(" declared on the {} `{}`", self.prefix, self.name)
|
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 {
|
impl UnderspecifiedArgKind {
|
||||||
fn prefix_string(&self) -> Cow<'static, str> {
|
fn try_get_prefix(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Type { prefix } => format!("type for {}", prefix).into(),
|
Self::Type { prefix } => Some(prefix.as_ref()),
|
||||||
Self::Const { is_parameter: true } => "the value of const parameter".into(),
|
Self::Const { .. } => None,
|
||||||
Self::Const { is_parameter: false } => "the value of the constant".into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,11 +325,44 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
arg_data: InferenceDiagnosticsData,
|
arg_data: InferenceDiagnosticsData,
|
||||||
error_code: TypeAnnotationNeeded,
|
error_code: TypeAnnotationNeeded,
|
||||||
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
||||||
let error_code = error_code.into();
|
let source_kind = "other";
|
||||||
let mut err =
|
let source_name = "";
|
||||||
self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
|
let failure_span = None;
|
||||||
err.span_label(span, arg_data.cannot_infer_msg());
|
let infer_subdiags = Vec::new();
|
||||||
err
|
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(
|
pub fn emit_inference_failure_err(
|
||||||
|
@ -340,48 +395,39 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
return self.bad_inference_failure_err(failure_span, arg_data, error_code)
|
return self.bad_inference_failure_err(failure_span, arg_data, error_code)
|
||||||
};
|
};
|
||||||
|
|
||||||
let error_code = error_code.into();
|
let (source_kind, name) = kind.ty_localized_msg(self);
|
||||||
let mut err = self.tcx.sess.struct_span_err_with_code(
|
let failure_span = if should_label_span && !failure_span.overlaps(span) {
|
||||||
span,
|
Some(failure_span)
|
||||||
&format!("type annotations needed{}", kind.ty_msg(self)),
|
} else {
|
||||||
error_code,
|
None
|
||||||
);
|
};
|
||||||
|
|
||||||
if should_label_span && !failure_span.overlaps(span) {
|
|
||||||
err.span_label(failure_span, "type must be known at this point");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let mut infer_subdiags = Vec::new();
|
||||||
|
let mut multi_suggestions = Vec::new();
|
||||||
match kind {
|
match kind {
|
||||||
InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
|
InferSourceKind::LetBinding { insert_span, pattern_name, ty } => {
|
||||||
let suggestion_msg = if let Some(name) = pattern_name {
|
infer_subdiags.push(SourceKindSubdiag::LetLike {
|
||||||
format!(
|
span: insert_span,
|
||||||
"consider giving `{}` an explicit type{}",
|
name: pattern_name.map(|name| name.to_string()).unwrap_or_else(String::new),
|
||||||
name,
|
x_kind: arg_data.where_x_is_kind(ty),
|
||||||
arg_data.where_x_is_specified(ty)
|
prefix_kind: arg_data.kind.clone(),
|
||||||
)
|
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
|
||||||
} else {
|
arg_name: arg_data.name,
|
||||||
format!(
|
kind: if pattern_name.is_some() { "with_pattern" } else { "other" },
|
||||||
"consider giving this pattern a type{}",
|
type_name: ty_to_string(self, ty),
|
||||||
arg_data.where_x_is_specified(ty)
|
});
|
||||||
)
|
|
||||||
};
|
|
||||||
err.span_suggestion_verbose(
|
|
||||||
insert_span,
|
|
||||||
&suggestion_msg,
|
|
||||||
format!(": {}", ty_to_string(self, ty)),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
InferSourceKind::ClosureArg { insert_span, ty } => {
|
InferSourceKind::ClosureArg { insert_span, ty } => {
|
||||||
err.span_suggestion_verbose(
|
infer_subdiags.push(SourceKindSubdiag::LetLike {
|
||||||
insert_span,
|
span: insert_span,
|
||||||
&format!(
|
name: String::new(),
|
||||||
"consider giving this closure parameter an explicit type{}",
|
x_kind: arg_data.where_x_is_kind(ty),
|
||||||
arg_data.where_x_is_specified(ty)
|
prefix_kind: arg_data.kind.clone(),
|
||||||
),
|
prefix: arg_data.kind.try_get_prefix().unwrap_or_default(),
|
||||||
format!(": {}", ty_to_string(self, ty)),
|
arg_name: arg_data.name,
|
||||||
Applicability::HasPlaceholders,
|
kind: "closure",
|
||||||
);
|
type_name: ty_to_string(self, ty),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
InferSourceKind::GenericArg {
|
InferSourceKind::GenericArg {
|
||||||
insert_span,
|
insert_span,
|
||||||
|
@ -393,19 +439,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
let generics = self.tcx.generics_of(generics_def_id);
|
let generics = self.tcx.generics_of(generics_def_id);
|
||||||
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
|
let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
|
||||||
|
|
||||||
let cannot_infer_msg = format!(
|
let (parent_exists, parent_prefix, parent_name) =
|
||||||
"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::<T>`,
|
|
||||||
// the type parameter `T` was still declared on the enum, not on the
|
|
||||||
// variant.
|
|
||||||
InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
|
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)
|
let args = fmt_printer(self, Namespace::TypeNS)
|
||||||
.comma_sep(generic_args.iter().copied().map(|arg| {
|
.comma_sep(generic_args.iter().copied().map(|arg| {
|
||||||
|
@ -435,15 +482,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_buffer();
|
.into_buffer();
|
||||||
|
|
||||||
err.span_suggestion_verbose(
|
infer_subdiags.push(SourceKindSubdiag::GenericSuggestion {
|
||||||
insert_span,
|
span: insert_span,
|
||||||
&format!(
|
arg_count: generic_args.len(),
|
||||||
"consider specifying the generic argument{}",
|
args,
|
||||||
pluralize!(generic_args.len()),
|
});
|
||||||
),
|
|
||||||
format!("::<{}>", args),
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
|
InferSourceKind::FullyQualifiedMethodCall { receiver, successor, substs, def_id } => {
|
||||||
let printer = fmt_printer(self, Namespace::ValueNS);
|
let printer = fmt_printer(self, Namespace::ValueNS);
|
||||||
|
@ -468,37 +511,54 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
|
|
||||||
let suggestion = vec![
|
multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified {
|
||||||
(receiver.span.shrink_to_lo(), format!("{def_path}({adjustment}")),
|
span: receiver.span,
|
||||||
(receiver.span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()),
|
def_path,
|
||||||
];
|
adjustment,
|
||||||
err.multipart_suggestion_verbose(
|
successor,
|
||||||
"try using a fully qualified path to specify the expected types",
|
});
|
||||||
suggestion,
|
|
||||||
Applicability::HasPlaceholders,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
|
InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
|
||||||
let ret = ty_to_string(self, ty);
|
let ty_info = ty_to_string(self, ty);
|
||||||
let (arrow, post) = match data {
|
multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn {
|
||||||
FnRetTy::DefaultReturn(_) => ("-> ", " "),
|
ty_info,
|
||||||
_ => ("", ""),
|
data,
|
||||||
};
|
should_wrap_expr,
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err
|
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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn need_type_info_err_in_generator(
|
pub fn need_type_info_err_in_generator(
|
||||||
|
@ -510,15 +570,26 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
let ty = self.resolve_vars_if_possible(ty);
|
let ty = self.resolve_vars_if_possible(ty);
|
||||||
let data = self.extract_inference_diagnostics_data(ty.into(), None);
|
let data = self.extract_inference_diagnostics_data(ty.into(), None);
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
NeedTypeInfoInGenerator {
|
||||||
self.tcx.sess,
|
bad_label: data.make_bad_error(span),
|
||||||
span,
|
span,
|
||||||
E0698,
|
generator_kind: GeneratorKindAsDiagArg(kind),
|
||||||
"type inside {} must be known in this context",
|
}
|
||||||
kind,
|
.into_diagnostic(&self.tcx.sess.parse_sess)
|
||||||
);
|
}
|
||||||
err.span_label(span, data.cannot_infer_msg());
|
}
|
||||||
err
|
|
||||||
|
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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,22 +650,22 @@ impl<'tcx> InferSource<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> InferSourceKind<'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 {
|
match *self {
|
||||||
InferSourceKind::LetBinding { ty, .. }
|
InferSourceKind::LetBinding { ty, .. }
|
||||||
| InferSourceKind::ClosureArg { ty, .. }
|
| InferSourceKind::ClosureArg { ty, .. }
|
||||||
| InferSourceKind::ClosureReturn { ty, .. } => {
|
| InferSourceKind::ClosureReturn { ty, .. } => {
|
||||||
if ty.is_closure() {
|
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() {
|
} else if !ty.is_ty_infer() {
|
||||||
format!(" for `{}`", ty_to_string(infcx, ty))
|
("normal", ty_to_string(infcx, ty))
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
("other", String::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: We should be able to add some additional info here.
|
// FIXME: We should be able to add some additional info here.
|
||||||
InferSourceKind::GenericArg { .. }
|
InferSourceKind::GenericArg { .. }
|
||||||
| InferSourceKind::FullyQualifiedMethodCall { .. } => String::new(),
|
| InferSourceKind::FullyQualifiedMethodCall { .. } => ("other", String::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,96 +1,78 @@
|
||||||
use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
|
use crate::errors::RegionOriginNote;
|
||||||
|
use crate::infer::error_reporting::note_and_explain_region;
|
||||||
use crate::infer::{self, InferCtxt, SubregionOrigin};
|
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, ErrorGuaranteed,
|
||||||
|
};
|
||||||
use rustc_middle::traits::ObligationCauseCode;
|
use rustc_middle::traits::ObligationCauseCode;
|
||||||
use rustc_middle::ty::error::TypeError;
|
use rustc_middle::ty::error::TypeError;
|
||||||
use rustc_middle::ty::{self, Region};
|
use rustc_middle::ty::{self, Region};
|
||||||
|
|
||||||
|
use super::ObligationCauseAsDiagArg;
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
|
pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
|
||||||
let mut label_or_note = |span, msg: &str| {
|
|
||||||
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 {
|
match *origin {
|
||||||
infer::Subtype(ref trace) => {
|
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||||
if let Some((expected, found)) = self.values_str(trace.values) {
|
span: trace.cause.span,
|
||||||
label_or_note(
|
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
||||||
trace.cause.span,
|
expected_found: self.values_str(trace.values),
|
||||||
&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::Reborrow(span) => {
|
|
||||||
label_or_note(span, "...so that reference does not outlive borrowed content");
|
|
||||||
}
|
}
|
||||||
|
.add_to_diagnostic(err),
|
||||||
|
infer::Reborrow(span) => RegionOriginNote::Plain { span, msg: fluent::infer::reborrow }
|
||||||
|
.add_to_diagnostic(err),
|
||||||
infer::ReborrowUpvar(span, ref upvar_id) => {
|
infer::ReborrowUpvar(span, ref upvar_id) => {
|
||||||
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_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) => {
|
infer::RelateObjectBound(span) => {
|
||||||
label_or_note(span, "...so that it can be closed over into an object");
|
RegionOriginNote::Plain { span, msg: fluent::infer::relate_object_bound }
|
||||||
|
.add_to_diagnostic(err);
|
||||||
}
|
}
|
||||||
infer::DataBorrowed(ty, span) => {
|
infer::DataBorrowed(ty, span) => {
|
||||||
label_or_note(
|
RegionOriginNote::WithName {
|
||||||
span,
|
span,
|
||||||
&format!(
|
msg: fluent::infer::data_borrowed,
|
||||||
"...so that the type `{}` is not borrowed for too long",
|
name: &self.ty_to_string(ty),
|
||||||
self.ty_to_string(ty)
|
continues: false,
|
||||||
),
|
}
|
||||||
);
|
.add_to_diagnostic(err);
|
||||||
}
|
}
|
||||||
infer::ReferenceOutlivesReferent(ty, span) => {
|
infer::ReferenceOutlivesReferent(ty, span) => {
|
||||||
label_or_note(
|
RegionOriginNote::WithName {
|
||||||
span,
|
span,
|
||||||
&format!(
|
msg: fluent::infer::reference_outlives_referent,
|
||||||
"...so that the reference type `{}` does not outlive the data it points at",
|
name: &self.ty_to_string(ty),
|
||||||
self.ty_to_string(ty)
|
continues: false,
|
||||||
),
|
}
|
||||||
);
|
.add_to_diagnostic(err);
|
||||||
}
|
}
|
||||||
infer::RelateParamBound(span, t, opt_span) => {
|
infer::RelateParamBound(span, ty, opt_span) => {
|
||||||
label_or_note(
|
RegionOriginNote::WithName {
|
||||||
span,
|
span,
|
||||||
&format!(
|
msg: fluent::infer::relate_param_bound,
|
||||||
"...so that the type `{}` will meet its required lifetime bounds{}",
|
name: &self.ty_to_string(ty),
|
||||||
self.ty_to_string(t),
|
continues: opt_span.is_some(),
|
||||||
if opt_span.is_some() { "..." } else { "" },
|
}
|
||||||
),
|
.add_to_diagnostic(err);
|
||||||
);
|
|
||||||
if let Some(span) = opt_span {
|
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) => {
|
infer::RelateRegionParamBound(span) => {
|
||||||
label_or_note(
|
RegionOriginNote::Plain { span, msg: fluent::infer::relate_region_param_bound }
|
||||||
span,
|
.add_to_diagnostic(err);
|
||||||
"...so that the declared lifetime parameter bounds are satisfied",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
infer::CompareImplItemObligation { span, .. } => {
|
infer::CompareImplItemObligation { span, .. } => {
|
||||||
label_or_note(
|
RegionOriginNote::Plain { span, msg: fluent::infer::compare_impl_item_obligation }
|
||||||
span,
|
.add_to_diagnostic(err);
|
||||||
"...so that the definition in impl matches the definition from the trait",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
infer::CheckAssociatedTypeBounds { ref parent, .. } => {
|
||||||
self.note_region_origin(err, &parent);
|
self.note_region_origin(err, &parent);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::errors::OpaqueHiddenTypeDiag;
|
||||||
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
|
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
use hir::def_id::{DefId, LocalDefId};
|
use hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -153,22 +154,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
if let Some(OpaqueTyOrigin::TyAlias) =
|
if let Some(OpaqueTyOrigin::TyAlias) =
|
||||||
did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span))
|
did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span))
|
||||||
{
|
{
|
||||||
self.tcx
|
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
|
||||||
.sess
|
span: cause.span,
|
||||||
.struct_span_err(
|
hidden_type: self.tcx.def_span(did2),
|
||||||
cause.span,
|
opaque_type: self.tcx.def_span(def_id),
|
||||||
"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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(self.register_hidden_type(
|
Some(self.register_hidden_type(
|
||||||
|
|
|
@ -34,5 +34,6 @@ extern crate tracing;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rustc_middle;
|
extern crate rustc_middle;
|
||||||
|
|
||||||
|
mod errors;
|
||||||
pub mod infer;
|
pub mod infer;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|
Loading…
Reference in New Issue