Auto merge of #38057 - KiChjang:display-formal-type-param, r=nikomatsakis

Display better error messages for E0282

Fixes #36554.
This commit is contained in:
bors 2016-12-12 00:22:30 +00:00
commit 5e2f37fca9
28 changed files with 191 additions and 76 deletions

View file

@ -13,6 +13,7 @@ use super::InferCtxt;
use super::lattice::{self, LatticeDir};
use super::Subtype;
use traits::ObligationCause;
use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
@ -83,6 +84,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
self.fields.infcx
}
fn cause(&self) -> &ObligationCause<'tcx> {
&self.fields.trace.cause
}
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(&v, &a)?;

View file

@ -30,7 +30,9 @@
//! a lattice.
use super::InferCtxt;
use super::type_variable::TypeVariableOrigin;
use traits::ObligationCause;
use ty::TyVar;
use ty::{self, Ty};
use ty::relate::{RelateResult, TypeRelation};
@ -38,6 +40,8 @@ use ty::relate::{RelateResult, TypeRelation};
pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> {
fn infcx(&self) -> &'f InferCtxt<'f, 'gcx, 'tcx>;
fn cause(&self) -> &ObligationCause<'tcx>;
// Relates the type `v` to `a` and `b` such that `v` represents
// the LUB/GLB of `a` and `b` as appropriate.
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>;
@ -64,14 +68,15 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L,
match (&a.sty, &b.sty) {
(&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..)))
if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => {
let v = infcx.next_diverging_ty_var();
let v = infcx.next_diverging_ty_var(
TypeVariableOrigin::LatticeVariable(this.cause().span));
this.relate_bound(v, a, b)?;
Ok(v)
}
(&ty::TyInfer(TyVar(..)), _) |
(_, &ty::TyInfer(TyVar(..))) => {
let v = infcx.next_ty_var();
let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span));
this.relate_bound(v, a, b)?;
Ok(v)
}

View file

@ -13,6 +13,7 @@ use super::InferCtxt;
use super::lattice::{self, LatticeDir};
use super::Subtype;
use traits::ObligationCause;
use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
@ -83,6 +84,10 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx>
self.fields.infcx
}
fn cause(&self) -> &ObligationCause<'tcx> {
&self.fields.trace.cause
}
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
let mut sub = self.fields.sub(self.a_is_expected);
sub.relate(&a, &v)?;

View file

@ -45,6 +45,7 @@ use util::nodemap::{FxHashMap, FxHashSet, NodeMap};
use self::combine::CombineFields;
use self::higher_ranked::HrMatchResult;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::type_variable::TypeVariableOrigin;
use self::unify_key::ToType;
mod bivariate;
@ -114,7 +115,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// We instantiate UnificationTable with bounds<Ty> because the
// types that might instantiate a general type variable have an
// order, represented by its upper and lower bounds.
type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
pub type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>,
// Map from integral variable to the kind of integer it represents
int_unification_table: RefCell<UnificationTable<ty::IntVid>>,
@ -1054,18 +1055,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
})
}
pub fn next_ty_var_id(&self, diverging: bool) -> TyVid {
pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
self.type_variables
.borrow_mut()
.new_var(diverging, None)
.new_var(diverging, origin, None)
}
pub fn next_ty_var(&self) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false))
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(false, origin))
}
pub fn next_diverging_ty_var(&self) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(true))
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
self.tcx.mk_var(self.next_ty_var_id(true, origin))
}
pub fn next_int_var_id(&self) -> IntVid {
@ -1118,7 +1119,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let ty_var_id = self.type_variables
.borrow_mut()
.new_var(false, default);
.new_var(false,
TypeVariableOrigin::TypeParameterDefinition(span, def.name),
default);
self.tcx.mk_var(ty_var_id)
}

View file

@ -13,6 +13,7 @@ use self::TypeVariableValue::*;
use self::UndoEntry::*;
use hir::def_id::{DefId};
use syntax::util::small_vector::SmallVector;
use syntax::ast;
use syntax_pos::Span;
use ty::{self, Ty};
@ -28,8 +29,24 @@ pub struct TypeVariableTable<'tcx> {
eq_relations: ut::UnificationTable<ty::TyVid>,
}
/// Reasons to create a type inference variable
pub enum TypeVariableOrigin {
MiscVariable(Span),
NormalizeProjectionType(Span),
TypeInference(Span),
TypeParameterDefinition(Span, ast::Name),
TransformedUpvar(Span),
SubstitutionPlaceholder(Span),
AutoDeref(Span),
AdjustmentType(Span),
DivergingStmt(Span),
DivergingBlockExpr(Span),
LatticeVariable(Span),
}
struct TypeVariableData<'tcx> {
value: TypeVariableValue<'tcx>,
origin: TypeVariableOrigin,
diverging: bool
}
@ -107,6 +124,10 @@ impl<'tcx> TypeVariableTable<'tcx> {
self.values.get(vid.index as usize).diverging
}
pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin {
&self.values.get(vid.index as usize).origin
}
/// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`.
///
/// Precondition: neither `a` nor `b` are known.
@ -173,10 +194,12 @@ impl<'tcx> TypeVariableTable<'tcx> {
pub fn new_var(&mut self,
diverging: bool,
default: Option<Default<'tcx>>) -> ty::TyVid {
origin: TypeVariableOrigin,
default: Option<Default<'tcx>>,) -> ty::TyVid {
self.eq_relations.new_key(());
let index = self.values.push(TypeVariableData {
value: Bounded { relations: vec![], default: default },
origin: origin,
diverging: diverging
});
let v = ty::TyVid { index: index as u32 };

View file

@ -27,6 +27,7 @@ use super::{
use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin;
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::error::ExpectedFound;
@ -38,7 +39,7 @@ use util::nodemap::{FxHashMap, FxHashSet};
use std::cmp;
use std::fmt;
use syntax::ast;
use syntax_pos::Span;
use syntax_pos::{DUMMY_SP, Span};
use errors::DiagnosticBuilder;
#[derive(Debug, PartialEq, Eq, Hash)]
@ -790,9 +791,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if let ty::TyParam(..) = ty.sty {
if let ty::TyParam(ty::ParamTy {name, ..}) = ty.sty {
let infcx = self.infcx;
self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var())
self.var_map.entry(ty).or_insert_with(||
infcx.next_ty_var(
TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name)))
} else {
ty.super_fold_with(self)
}
@ -824,12 +827,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn need_type_info(&self, span: Span, ty: Ty<'tcx>) {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = if let ty::TyInfer(ty::TyVar(ty_vid)) = ty.sty {
let ty_vars = self.type_variables.borrow();
if let TypeVariableOrigin::TypeParameterDefinition(_, name) =
*ty_vars.var_origin(ty_vid)
{
name.to_string()
} else {
ty.to_string()
}
} else {
ty.to_string()
};
let mut err = struct_span_err!(self.tcx.sess, span, E0282,
"unable to infer enough type information about `{}`",
ty);
name);
err.note("type annotations or generic parameter binding required");
err.span_label(span, &format!("cannot infer type for `{}`", ty));
err.emit()
err.span_label(span, &format!("cannot infer type for `{}`", name));
err.emit();
}
fn note_obligation_cause<T>(&self,

View file

@ -25,6 +25,7 @@ use super::util;
use hir::def_id::DefId;
use infer::InferOk;
use infer::type_variable::TypeVariableOrigin;
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::ast;
use syntax::symbol::Symbol;
@ -382,7 +383,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
// and a deferred predicate to resolve this when more type
// information is available.
let ty_var = selcx.infcx().next_ty_var();
let tcx = selcx.infcx().tcx;
let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
i.name == projection_ty.item_name && i.kind == ty::AssociatedKind::Type
).map(|i| i.def_id).unwrap();
let ty_var = selcx.infcx().next_ty_var(
TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
let projection = ty::Binder(ty::ProjectionPredicate {
projection_ty: projection_ty,
ty: ty_var
@ -596,7 +602,12 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
let trait_obligation = Obligation { cause: cause,
recursion_depth: depth,
predicate: trait_ref.to_predicate() };
let new_value = selcx.infcx().next_ty_var();
let tcx = selcx.infcx().tcx;
let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
i.name == projection_ty.item_name && i.kind == ty::AssociatedKind::Type
).map(|i| i.def_id).unwrap();
let new_value = selcx.infcx().next_ty_var(
TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id)));
Normalized {
value: new_value,
obligations: vec![trait_obligation]