Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
the two hardest things in programming, names and...
  • Loading branch information
lcnr committed Sep 24, 2020
commit e5430e5306a2f3706797d5e453860875abe463ed
194 changes: 115 additions & 79 deletions compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ fn closure_return_type_suggestion(
);
err.span_label(
span,
InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr),
InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
);
}

Expand Down Expand Up @@ -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> {
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,
arg: GenericArg<'tcx>,
highlight: Option<ty::print::RegionHighlightMode>,
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
) -> InferDiagnosticsData {
match arg.unpack() {
GenericArgKind::Type(ty) => {
if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
Expand All @@ -236,32 +247,32 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
var_origin.kind
{
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 = self
.tcx
.def_key(parent_def_id)
.disambiguated_data
.data
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());

(
parent_name,
Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
)
} else {
(None, None)
};
let (parent_name, parent_description) =
if let Some(parent_def_id) = parent_def_id {
let parent_name = self
.tcx
.def_key(parent_def_id)
.disambiguated_data
.data
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());

(
parent_name,
Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
)
} else {
(None, None)
};

if name != kw::SelfUpper {
return (
name.to_string(),
Some(var_origin.span),
"type parameter".into(),
return InferDiagnosticsData {
name: name.to_string(),
span: Some(var_origin.span),
description: "type parameter".into(),
parent_name,
parent_desc,
);
parent_description,
};
}
}
}
Expand All @@ -272,56 +283,67 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
printer.region_highlight_mode = highlight;
}
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) => {
let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
let origin =
self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
origin.kind
{
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 = self
.tcx
.def_key(parent_def_id)
.disambiguated_data
.data
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());

(
parent_name,
Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
)
} else {
(None, None)
};

return (
name.to_string(),
Some(origin.span),
"const parameter".into(),
let (parent_name, parent_description) =
if let Some(parent_def_id) = parent_def_id {
let parent_name = self
.tcx
.def_key(parent_def_id)
.disambiguated_data
.data
.get_opt_name()
.map(|parent_symbol| parent_symbol.to_string());

(
parent_name,
Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
)
} else {
(None, None)
};

return InferDiagnosticsData {
name: name.to_string(),
span: Some(origin.span),
description: "const parameter".into(),
parent_name,
parent_descr,
);
parent_description,
};
}

debug_assert!(!origin.span.is_dummy());
Some(origin.span)
let mut s = String::new();
let mut printer =
ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
let _ = ct.print(printer);
InferDiagnosticsData {
name: s,
span: Some(origin.span),
description: "the constant".into(),
parent_name: None,
parent_description: None,
}
} else {
bug!("unexpect const: {:?}", ct);
};

let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS);
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
let _ = ct.print(printer);
(s, span, "the constant".into(), None, None)
}
GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
}
Expand All @@ -331,18 +353,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&self,
body_id: Option<hir::BodyId>,
span: Span,
ty: GenericArg<'tcx>,
arg: GenericArg<'tcx>,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> {
let ty = self.resolve_vars_if_possible(&ty);
let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(ty, None);
let ty = self.resolve_vars_if_possible(&arg);
let arg_data = self.extract_infer_data(arg, None);
let kind_str = match ty.unpack() {
GenericArgKind::Type(_) => "type",
GenericArgKind::Const(_) => "the value",
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 mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
Expand Down Expand Up @@ -372,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
let err_span = if let Some(pattern) = local_visitor.found_arg_pattern {
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:
// error[E0282]: type annotations needed
// --> file2.rs:3:15
Expand Down Expand Up @@ -419,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
_ => 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
// " in `std::result::Result<i32, E>`":
// ```
Expand Down Expand Up @@ -458,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&mut err,
&decl.output,
self.tcx.hir().body(body_id),
&descr,
&name,
&arg_data.description,
&arg_data.name,
&ret,
parent_name,
parent_descr,
arg_data.parent_name,
arg_data.parent_description,
);
// We don't want to give the other suggestions when the problem is the
// closure return type.
Expand All @@ -476,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// nudge them in the right direction.
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);
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);
format!(
"the explicit type `{}`, where the type parameter `{}` is specified",
ty, name,
ty, arg_data.name,
)
}
_ => "a type".to_string(),
Expand Down Expand Up @@ -601,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// | ^^^ cannot infer type for `S`
// |
// = 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
.span
.span_labels()
Expand All @@ -612,7 +634,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// Avoid multiple labels pointing at `span`.
err.span_label(
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,
),
);
}

Expand Down Expand Up @@ -672,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
) -> DiagnosticBuilder<'tcx> {
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!(
self.tcx.sess,
Expand All @@ -683,12 +711,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
err.span_label(
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
}

fn missing_type_msg(
fn cannot_infer_msg(
kind_str: &str,
type_name: &str,
descr: &str,
Expand All @@ -710,6 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"".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" };
// For example: "cannot infer type for type parameter `T`"
format!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
) -> Option<RegionNameHighlight> {
let mut highlight = RegionHighlightMode::default();
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!(
"highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
Expand Down Expand Up @@ -646,7 +646,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {

let mut highlight = RegionHighlightMode::default();
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);

Expand Down Expand Up @@ -698,7 +698,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {

let mut highlight = RegionHighlightMode::default();
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);

Expand Down