Skip to content

Commit

Permalink
Auto merge of #38057 - KiChjang:display-formal-type-param, r=nikomats…
Browse files Browse the repository at this point in the history
…akis

Display better error messages for E0282

Fixes #36554.
  • Loading branch information
bors committed Dec 12, 2016
2 parents 3db197a + d24028b commit 5e2f37f
Show file tree
Hide file tree
Showing 28 changed files with 191 additions and 76 deletions.
5 changes: 5 additions & 0 deletions src/librustc/infer/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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)?;
Expand Down
9 changes: 7 additions & 2 deletions src/librustc/infer/lattice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@
//! 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};

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, ()>;
Expand All @@ -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)
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/infer/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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)?;
Expand Down
19 changes: 11 additions & 8 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>>,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
Expand Down
25 changes: 24 additions & 1 deletion src/librustc/infer/type_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 };
Expand Down
29 changes: 23 additions & 6 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)]
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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,
Expand Down
15 changes: 13 additions & 2 deletions src/librustc/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down
8 changes: 5 additions & 3 deletions src/librustc_driver/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use rustc::ty::subst::{Kind, Subst};
use rustc::traits::{ObligationCause, Reveal};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::infer::{self, InferOk, InferResult};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc_metadata::cstore::CStore;
use rustc::hir::map as hir_map;
use rustc::session::{self, config};
Expand All @@ -36,6 +37,7 @@ use errors::emitter::Emitter;
use errors::{Level, DiagnosticBuilder};
use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
use syntax_pos::DUMMY_SP;

use rustc::hir;

Expand Down Expand Up @@ -489,7 +491,7 @@ fn sub_free_bound_false_infer() {
//! does NOT hold for any instantiation of `_#1`.
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
let t_infer1 = env.infcx.next_ty_var();
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
let t_rptr_bound1 = env.t_rptr_late_bound(1);
env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize),
env.t_fn(&[t_rptr_bound1], env.tcx().types.isize));
Expand All @@ -508,7 +510,7 @@ fn lub_free_bound_infer() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
env.create_simple_region_hierarchy();
let t_infer1 = env.infcx.next_ty_var();
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));
let t_rptr_bound1 = env.t_rptr_late_bound(1);
let t_rptr_free1 = env.t_rptr_free(1, 1);
env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize),
Expand Down Expand Up @@ -628,7 +630,7 @@ fn glb_bound_free() {
fn glb_bound_free_infer() {
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
let t_rptr_bound1 = env.t_rptr_late_bound(1);
let t_infer1 = env.infcx.next_ty_var();
let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP));

// compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize),
// which should yield for<'b> fn(&'b isize) -> isize
Expand Down
16 changes: 11 additions & 5 deletions src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc::hir::{self, PatKind};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::infer;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::ObligationCauseCode;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
use check::{FnCtxt, Expectation, Diverges};
Expand Down Expand Up @@ -162,7 +163,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
let max_len = cmp::max(expected_len, elements.len());

let element_tys_iter = (0..max_len).map(|_| self.next_ty_var());
let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(
// FIXME: MiscVariable for now, obtaining the span and name information
// from all tuple elements isn't trivial.
TypeVariableOrigin::TypeInference(pat.span)));
let element_tys = tcx.mk_type_list(element_tys_iter);
let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys));
self.demand_eqtype(pat.span, expected, pat_ty);
Expand All @@ -172,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pat_ty
}
PatKind::Box(ref inner) => {
let inner_ty = self.next_ty_var();
let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span));
let uniq_ty = tcx.mk_box(inner_ty);

if self.check_dereferencable(pat.span, expected, &inner) {
Expand Down Expand Up @@ -203,7 +207,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
(expected, mt.ty)
}
_ => {
let inner_ty = self.next_ty_var();
let inner_ty = self.next_ty_var(
TypeVariableOrigin::TypeInference(inner.span));
let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
let region = self.next_region_var(infer::PatternRegion(pat.span));
let rptr_ty = tcx.mk_ref(region, mt);
Expand Down Expand Up @@ -379,7 +384,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// ...but otherwise we want to use any supertype of the
// discriminant. This is sort of a workaround, see note (*) in
// `check_pat` for some details.
discrim_ty = self.next_ty_var();
discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
self.check_expr_has_type(discrim, discrim_ty);
};
let discrim_diverges = self.diverges.get();
Expand Down Expand Up @@ -407,7 +412,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// of execution reach it, we will panic, so bottom is an appropriate
// type in that case)
let expected = expected.adjust_for_branches(self);
let mut result_ty = self.next_diverging_ty_var();
let mut result_ty = self.next_diverging_ty_var(
TypeVariableOrigin::DivergingBlockExpr(expr.span));
let mut all_arms_diverge = Diverges::WarnedAlways;
let coerce_first = match expected {
// We don't coerce to `()` so that if the match expression is a
Expand Down
Loading

0 comments on commit 5e2f37f

Please sign in to comment.