Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge need_type_info_err(_const) #77093

Merged
merged 8 commits into from
Sep 26, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
207 changes: 121 additions & 86 deletions compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ fn closure_return_type_suggestion(
suggestion,
Applicability::HasPlaceholders,
);
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
err.span_label(
span,
InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr),
);
}

/// Given a closure signature, return a `String` containing a list of all its argument types.
Expand Down Expand Up @@ -220,60 +223,124 @@ impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded {
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn extract_type_name(
lcnr marked this conversation as resolved.
Show resolved Hide resolved
&self,
ty: Ty<'tcx>,
arg: GenericArg<'tcx>,
highlight: Option<ty::print::RegionHighlightMode>,
) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) {
lcnr marked this conversation as resolved.
Show resolved Hide resolved
if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
let mut inner = self.inner.borrow_mut();
let ty_vars = &inner.type_variables();
let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = 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)))
match arg.unpack() {
GenericArgKind::Type(ty) => {
if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
let mut inner = self.inner.borrow_mut();
let ty_vars = &inner.type_variables();
let var_origin = ty_vars.var_origin(ty_vid);
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
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)
};

if name != kw::SelfUpper {
return (
name.to_string(),
Some(var_origin.span),
"type parameter".into(),
parent_name,
parent_desc,
);
}
}
}

let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
let _ = ty.print(printer);
(s, None, ty.prefix_string(), None, None)
}
GenericArgKind::Const(ct) => {
let span = 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(),
parent_name,
parent_descr,
);
}

debug_assert!(!origin.span.is_dummy());
Some(origin.span)
} else {
(None, None)
bug!("unexpect const: {:?}", ct);
};

if name != kw::SelfUpper {
return (
name.to_string(),
Some(var_origin.span),
"type parameter".into(),
parent_name,
parent_desc,
);
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"),
}

let mut s = String::new();
let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS);
if let Some(highlight) = highlight {
printer.region_highlight_mode = highlight;
}
let _ = ty.print(printer);
(s, None, ty.prefix_string(), None, None)
}

// FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well.
pub fn need_type_info_err(
lcnr marked this conversation as resolved.
Show resolved Hide resolved
&self,
body_id: Option<hir::BodyId>,
span: Span,
ty: Ty<'tcx>,
ty: 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 (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(ty, 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 ty_to_string = |ty: Ty<'tcx>| -> String {
Expand Down Expand Up @@ -545,55 +612,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// Avoid multiple labels pointing at `span`.
err.span_label(
span,
InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr),
InferCtxt::missing_type_msg(kind_str, &name, &descr, parent_name, parent_descr),
);
}

err
}

// FIXME(const_generics): We should either try and merge this with `need_type_info_err`
// or improve the errors created here.
//
// Unlike for type inference variables, we don't yet store the origin of const inference variables.
// This is needed for to get a more relevant error span.
pub fn need_type_info_err_const(
&self,
body_id: Option<hir::BodyId>,
span: Span,
ct: &'tcx ty::Const<'tcx>,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> {
let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span);
if let Some(body_id) = body_id {
let expr = self.tcx.hir().expect_expr(body_id.hir_id);
local_visitor.visit_expr(expr);
}

let mut param_name = None;
let span = 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(param) = origin.kind {
param_name = Some(param);
}
origin.span
} else {
local_visitor.target_span
};

let error_code = error_code.into();
let mut err =
self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);

if let Some(param_name) = param_name {
err.note(&format!("cannot infer the value of the const parameter `{}`", param_name));
} else {
err.note("unable to infer the value of a const parameter");
}

err
}

/// If the `FnSig` for the method call can be found and type arguments are identified as
/// needed, suggest annotating the call, otherwise point out the resulting type of the call.
fn annotate_method_call(
Expand Down Expand Up @@ -647,7 +672,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, None);
let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(ty.into(), None);

let mut err = struct_span_err!(
self.tcx.sess,
Expand All @@ -656,18 +681,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"type inside {} must be known in this context",
kind,
);
err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr));
err.span_label(
span,
InferCtxt::missing_type_msg("type", &name, &descr, parent_name, parent_descr),
);
err
}

fn missing_type_msg(
lcnr marked this conversation as resolved.
Show resolved Hide resolved
kind_str: &str,
type_name: &str,
descr: &str,
parent_name: Option<String>,
parent_descr: Option<&str>,
) -> Cow<'static, str> {
) -> String {
if type_name == "_" {
"cannot infer type".into()
format!("cannot infer {}", kind_str)
} else {
let parent_desc = if let Some(parent_name) = parent_name {
let parent_type_descr = if let Some(parent_descr) = parent_descr {
Expand All @@ -681,7 +710,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
"".to_string()
};

format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into()
let preposition = if "the value" == kind_str { "of" } else { "for" };
// For example: "cannot infer type for type parameter `T`"
format!(
"cannot infer {} {} {} `{}`{}",
kind_str, preposition, descr, type_name, parent_desc
)
.into()
}
}
}
5 changes: 4 additions & 1 deletion compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
GenericParamDefKind::Const { .. } => {
let origin = ConstVariableOrigin {
kind: ConstVariableOriginKind::ConstParameterDefinition(param.name),
kind: ConstVariableOriginKind::ConstParameterDefinition(
param.name,
param.def_id,
),
span,
};
let const_var_id =
Expand Down
18 changes: 9 additions & 9 deletions compiler/rustc_middle/src/infer/unify_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify::{
self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue,
};
use rustc_span::def_id::DefId;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use rustc_span::Span;

use std::cmp;
use std::marker::PhantomData;
Expand Down Expand Up @@ -124,8 +125,7 @@ pub struct ConstVariableOrigin {
pub enum ConstVariableOriginKind {
MiscVariable,
ConstInference,
// FIXME(const_generics): Consider storing the `DefId` of the param here.
ConstParameterDefinition(Symbol),
ConstParameterDefinition(Symbol, DefId),
SubstitutionPlaceholder,
}

Expand Down Expand Up @@ -176,17 +176,17 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);

fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
let val = match (value1.val, value2.val) {
let (val, span) = match (value1.val, value2.val) {
(ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => {
bug!("equating two const variables, both of which have known values")
}

// If one side is known, prefer that one.
(ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => {
Ok(value1.val)
(value1.val, value1.origin.span)
}
(ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => {
Ok(value2.val)
(value2.val, value2.origin.span)
}

// If both sides are *unknown*, it hardly matters, does it?
Expand All @@ -200,14 +200,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
// universe is the minimum of the two universes, because that is
// the one which contains the fewest names in scope.
let universe = cmp::min(universe1, universe2);
Ok(ConstVariableValue::Unknown { universe })
(ConstVariableValue::Unknown { universe }, value1.origin.span)
}
}?;
};

Ok(ConstVarValue {
origin: ConstVariableOrigin {
kind: ConstVariableOriginKind::ConstInference,
span: DUMMY_SP,
span: span,
},
val,
})
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, Some(highlight)).0;
let type_name = self.infcx.extract_type_name(ty.into(), Some(highlight)).0;

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, Some(highlight)).0;
let type_name = self.infcx.extract_type_name(return_ty.into(), Some(highlight)).0;

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, Some(highlight)).0;
let type_name = self.infcx.extract_type_name(yield_ty.into(), Some(highlight)).0;

let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id);

Expand Down
Loading