the two hardest things in programming, names and...
This commit is contained in:
parent
0e84b61053
commit
e5430e5306
2 changed files with 115 additions and 79 deletions
|
@ -178,7 +178,7 @@ fn closure_return_type_suggestion(
|
||||||
);
|
);
|
||||||
err.span_label(
|
err.span_label(
|
||||||
span,
|
span,
|
||||||
InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr),
|
InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,12 +220,23 @@ impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Information about a constant or a type containing inference variables.
|
||||||
|
pub struct InferDiagnosticsData {
|
||||||
|
pub name: String,
|
||||||
|
pub span: Option<Span>,
|
||||||
|
pub description: Cow<'static, str>,
|
||||||
|
pub parent_name: Option<String>,
|
||||||
|
pub parent_description: Option<&'static str>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
pub fn extract_type_name(
|
/// Extracts data used by diagnostic for either types or constants
|
||||||
|
/// which were stuck during inference.
|
||||||
|
pub fn extract_infer_data(
|
||||||
&self,
|
&self,
|
||||||
arg: GenericArg<'tcx>,
|
arg: GenericArg<'tcx>,
|
||||||
highlight: Option<ty::print::RegionHighlightMode>,
|
highlight: Option<ty::print::RegionHighlightMode>,
|
||||||
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
|
) -> InferDiagnosticsData {
|
||||||
match arg.unpack() {
|
match arg.unpack() {
|
||||||
GenericArgKind::Type(ty) => {
|
GenericArgKind::Type(ty) => {
|
||||||
if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
|
if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
|
||||||
|
@ -236,8 +247,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
var_origin.kind
|
var_origin.kind
|
||||||
{
|
{
|
||||||
let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
|
let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
|
||||||
let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id
|
let (parent_name, parent_description) =
|
||||||
{
|
if let Some(parent_def_id) = parent_def_id {
|
||||||
let parent_name = self
|
let parent_name = self
|
||||||
.tcx
|
.tcx
|
||||||
.def_key(parent_def_id)
|
.def_key(parent_def_id)
|
||||||
|
@ -255,13 +266,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if name != kw::SelfUpper {
|
if name != kw::SelfUpper {
|
||||||
return (
|
return InferDiagnosticsData {
|
||||||
name.to_string(),
|
name: name.to_string(),
|
||||||
Some(var_origin.span),
|
span: Some(var_origin.span),
|
||||||
"type parameter".into(),
|
description: "type parameter".into(),
|
||||||
parent_name,
|
parent_name,
|
||||||
parent_desc,
|
parent_description,
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,18 +283,24 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
printer.region_highlight_mode = highlight;
|
printer.region_highlight_mode = highlight;
|
||||||
}
|
}
|
||||||
let _ = ty.print(printer);
|
let _ = ty.print(printer);
|
||||||
(s, None, ty.prefix_string(), None, None)
|
InferDiagnosticsData {
|
||||||
|
name: s,
|
||||||
|
span: None,
|
||||||
|
description: ty.prefix_string(),
|
||||||
|
parent_name: None,
|
||||||
|
parent_description: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GenericArgKind::Const(ct) => {
|
GenericArgKind::Const(ct) => {
|
||||||
let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
|
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
|
||||||
let origin =
|
let origin =
|
||||||
self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
|
self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
|
||||||
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
|
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
|
||||||
origin.kind
|
origin.kind
|
||||||
{
|
{
|
||||||
let parent_def_id = self.tcx.parent(def_id);
|
let parent_def_id = self.tcx.parent(def_id);
|
||||||
let (parent_name, parent_descr) = if let Some(parent_def_id) = parent_def_id
|
let (parent_name, parent_description) =
|
||||||
{
|
if let Some(parent_def_id) = parent_def_id {
|
||||||
let parent_name = self
|
let parent_name = self
|
||||||
.tcx
|
.tcx
|
||||||
.def_key(parent_def_id)
|
.def_key(parent_def_id)
|
||||||
|
@ -300,28 +317,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
(None, None)
|
(None, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return InferDiagnosticsData {
|
||||||
name.to_string(),
|
name: name.to_string(),
|
||||||
Some(origin.span),
|
span: Some(origin.span),
|
||||||
"const parameter".into(),
|
description: "const parameter".into(),
|
||||||
parent_name,
|
parent_name,
|
||||||
parent_descr,
|
parent_description,
|
||||||
);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(!origin.span.is_dummy());
|
debug_assert!(!origin.span.is_dummy());
|
||||||
Some(origin.span)
|
|
||||||
} else {
|
|
||||||
bug!("unexpect const: {:?}", ct);
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
|
let mut printer =
|
||||||
|
ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
|
||||||
if let Some(highlight) = highlight {
|
if let Some(highlight) = highlight {
|
||||||
printer.region_highlight_mode = highlight;
|
printer.region_highlight_mode = highlight;
|
||||||
}
|
}
|
||||||
let _ = ct.print(printer);
|
let _ = ct.print(printer);
|
||||||
(s, span, "the constant".into(), None, None)
|
InferDiagnosticsData {
|
||||||
|
name: s,
|
||||||
|
span: Some(origin.span),
|
||||||
|
description: "the constant".into(),
|
||||||
|
parent_name: None,
|
||||||
|
parent_description: None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bug!("unexpect const: {:?}", ct);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
|
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
|
||||||
}
|
}
|
||||||
|
@ -331,18 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
&self,
|
&self,
|
||||||
body_id: Option<hir::BodyId>,
|
body_id: Option<hir::BodyId>,
|
||||||
span: Span,
|
span: Span,
|
||||||
ty: GenericArg<'tcx>,
|
arg: GenericArg<'tcx>,
|
||||||
error_code: TypeAnnotationNeeded,
|
error_code: TypeAnnotationNeeded,
|
||||||
) -> DiagnosticBuilder<'tcx> {
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
let ty = self.resolve_vars_if_possible(&ty);
|
let ty = self.resolve_vars_if_possible(&arg);
|
||||||
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(ty, None);
|
let arg_data = self.extract_infer_data(arg, None);
|
||||||
let kind_str = match ty.unpack() {
|
let kind_str = match ty.unpack() {
|
||||||
GenericArgKind::Type(_) => "type",
|
GenericArgKind::Type(_) => "type",
|
||||||
GenericArgKind::Const(_) => "the value",
|
GenericArgKind::Const(_) => "the value",
|
||||||
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
|
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span);
|
let mut local_visitor = FindHirNodeVisitor::new(&self, arg.into(), span);
|
||||||
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
let ty_to_string = |ty: Ty<'tcx>| -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
|
||||||
|
@ -372,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
|
let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
|
||||||
pattern.span
|
pattern.span
|
||||||
} else if let Some(span) = name_sp {
|
} else if let Some(span) = arg_data.span {
|
||||||
// `span` here lets us point at `sum` instead of the entire right hand side expr:
|
// `span` here lets us point at `sum` instead of the entire right hand side expr:
|
||||||
// error[E0282]: type annotations needed
|
// error[E0282]: type annotations needed
|
||||||
// --> file2.rs:3:15
|
// --> file2.rs:3:15
|
||||||
|
@ -419,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// When `name` corresponds to a type argument, show the path of the full type we're
|
// When `arg_data.name` corresponds to a type argument, show the path of the full type we're
|
||||||
// trying to infer. In the following example, `ty_msg` contains
|
// trying to infer. In the following example, `ty_msg` contains
|
||||||
// " in `std::result::Result<i32, E>`":
|
// " in `std::result::Result<i32, E>`":
|
||||||
// ```
|
// ```
|
||||||
|
@ -458,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
&mut err,
|
&mut err,
|
||||||
&decl.output,
|
&decl.output,
|
||||||
self.tcx.hir().body(body_id),
|
self.tcx.hir().body(body_id),
|
||||||
&descr,
|
&arg_data.description,
|
||||||
&name,
|
&arg_data.name,
|
||||||
&ret,
|
&ret,
|
||||||
parent_name,
|
arg_data.parent_name,
|
||||||
parent_descr,
|
arg_data.parent_description,
|
||||||
);
|
);
|
||||||
// We don't want to give the other suggestions when the problem is the
|
// We don't want to give the other suggestions when the problem is the
|
||||||
// closure return type.
|
// closure return type.
|
||||||
|
@ -476,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
// nudge them in the right direction.
|
// nudge them in the right direction.
|
||||||
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
|
format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret)
|
||||||
}
|
}
|
||||||
Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => {
|
Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => {
|
||||||
let ty = ty_to_string(ty);
|
let ty = ty_to_string(ty);
|
||||||
format!("the explicit type `{}`, with the type parameters specified", ty)
|
format!("the explicit type `{}`, with the type parameters specified", ty)
|
||||||
}
|
}
|
||||||
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => {
|
Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => {
|
||||||
let ty = ty_to_string(ty);
|
let ty = ty_to_string(ty);
|
||||||
format!(
|
format!(
|
||||||
"the explicit type `{}`, where the type parameter `{}` is specified",
|
"the explicit type `{}`, where the type parameter `{}` is specified",
|
||||||
ty, name,
|
ty, arg_data.name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => "a type".to_string(),
|
_ => "a type".to_string(),
|
||||||
|
@ -601,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
// | ^^^ cannot infer type for `S`
|
// | ^^^ cannot infer type for `S`
|
||||||
// |
|
// |
|
||||||
// = note: type must be known at this point
|
// = note: type must be known at this point
|
||||||
let span = name_sp.unwrap_or(err_span);
|
let span = arg_data.span.unwrap_or(err_span);
|
||||||
if !err
|
if !err
|
||||||
.span
|
.span
|
||||||
.span_labels()
|
.span_labels()
|
||||||
|
@ -612,7 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
// Avoid multiple labels pointing at `span`.
|
// Avoid multiple labels pointing at `span`.
|
||||||
err.span_label(
|
err.span_label(
|
||||||
span,
|
span,
|
||||||
InferCtxt::missing_type_msg(kind_str, &name, &descr, parent_name, parent_descr),
|
InferCtxt::cannot_infer_msg(
|
||||||
|
kind_str,
|
||||||
|
&arg_data.name,
|
||||||
|
&arg_data.description,
|
||||||
|
arg_data.parent_name,
|
||||||
|
arg_data.parent_description,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> DiagnosticBuilder<'tcx> {
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
let ty = self.resolve_vars_if_possible(&ty);
|
let ty = self.resolve_vars_if_possible(&ty);
|
||||||
let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(ty.into(), None);
|
let data = self.extract_infer_data(ty.into(), None);
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
self.tcx.sess,
|
self.tcx.sess,
|
||||||
|
@ -683,12 +711,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
err.span_label(
|
err.span_label(
|
||||||
span,
|
span,
|
||||||
InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr),
|
InferCtxt::cannot_infer_msg(
|
||||||
|
"type",
|
||||||
|
&data.name,
|
||||||
|
&data.description,
|
||||||
|
data.parent_name,
|
||||||
|
data.parent_description,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
|
||||||
fn missing_type_msg(
|
fn cannot_infer_msg(
|
||||||
kind_str: &str,
|
kind_str: &str,
|
||||||
type_name: &str,
|
type_name: &str,
|
||||||
descr: &str,
|
descr: &str,
|
||||||
|
@ -710,6 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: We really shouldn't be dealing with strings here
|
||||||
|
// but instead use a sensible enum for cases like this.
|
||||||
let preposition = if "the value" == kind_str { "of" } else { "for" };
|
let preposition = if "the value" == kind_str { "of" } else { "for" };
|
||||||
// For example: "cannot infer type for type parameter `T`"
|
// For example: "cannot infer type for type parameter `T`"
|
||||||
format!(
|
format!(
|
||||||
|
|
|
@ -396,7 +396,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||||
) -> Option<RegionNameHighlight> {
|
) -> Option<RegionNameHighlight> {
|
||||||
let mut highlight = RegionHighlightMode::default();
|
let mut highlight = RegionHighlightMode::default();
|
||||||
highlight.highlighting_region_vid(needle_fr, counter);
|
highlight.highlighting_region_vid(needle_fr, counter);
|
||||||
let type_name = self.infcx.extract_type_name(ty.into(), Some(highlight)).0;
|
let type_name = self.infcx.extract_infer_data(ty.into(), Some(highlight)).name;
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
|
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
|
||||||
|
@ -646,7 +646,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
let mut highlight = RegionHighlightMode::default();
|
let mut highlight = RegionHighlightMode::default();
|
||||||
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
||||||
let type_name = self.infcx.extract_type_name(return_ty.into(), Some(highlight)).0;
|
let type_name = self.infcx.extract_infer_data(return_ty.into(), Some(highlight)).name;
|
||||||
|
|
||||||
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
|
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
|
||||||
|
|
||||||
|
@ -698,7 +698,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
let mut highlight = RegionHighlightMode::default();
|
let mut highlight = RegionHighlightMode::default();
|
||||||
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
|
||||||
let type_name = self.infcx.extract_type_name(yield_ty.into(), Some(highlight)).0;
|
let type_name = self.infcx.extract_infer_data(yield_ty.into(), Some(highlight)).name;
|
||||||
|
|
||||||
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
|
let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue