1
Fork 0

refactor type error reporting

This commit is contained in:
Ariel Ben-Yehuda 2016-07-16 23:18:20 +03:00
parent 8eb12d91aa
commit cea88ebb39
8 changed files with 140 additions and 202 deletions

View file

@ -83,7 +83,7 @@ use hir::def_id::DefId;
use infer::{self, TypeOrigin}; use infer::{self, TypeOrigin};
use middle::region; use middle::region;
use ty::subst; use ty::subst;
use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, ReFree}; use ty::{Region, ReFree};
use ty::error::TypeError; use ty::error::TypeError;
@ -462,52 +462,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
} }
fn report_type_error(&self,
trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>)
-> DiagnosticBuilder<'tcx> {
let (expected, found) = match self.values_str(&trace.values) {
Some(v) => v,
None => {
return self.tcx.sess.diagnostic().struct_dummy(); /* derived error */
}
};
let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
values.expected.is_primitive() && values.found.is_primitive()
} else {
false
};
let mut err = struct_span_err!(self.tcx.sess,
trace.origin.span(),
E0308,
"{}",
trace.origin);
if !is_simple_error || check_old_school() {
err.note_expected_found(&"type", &expected, &found);
}
err.span_label(trace.origin.span(), &terr);
self.check_and_note_conflicting_crates(&mut err, terr, trace.origin.span());
match trace.origin {
TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
hir::MatchSource::IfLetDesugar{..} => {
err.span_note(arm_span, "`if let` arm with an incompatible type");
}
_ => {
err.span_note(arm_span, "match arm with an incompatible type");
}
},
_ => ()
}
err
}
/// Adds a note if the types come from similarly named crates /// Adds a note if the types come from similarly named crates
fn check_and_note_conflicting_crates(&self, fn check_and_note_conflicting_crates(&self,
err: &mut DiagnosticBuilder, err: &mut DiagnosticBuilder,
@ -550,43 +504,91 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
} }
pub fn report_and_explain_type_error(&self, fn note_error_origin(&self,
trace: TypeTrace<'tcx>, err: &mut DiagnosticBuilder<'tcx>,
terr: &TypeError<'tcx>) origin: &TypeOrigin)
-> DiagnosticBuilder<'tcx> { {
let trace = self.resolve_type_vars_if_possible(&trace); match origin {
&TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
hir::MatchSource::IfLetDesugar {..} => {
err.span_note(arm_span, "`if let` arm with an incompatible type");
}
_ => {
err.span_note(arm_span, "match arm with an incompatible type");
}
},
_ => ()
}
}
pub fn report_and_explain_type_error_with_code(&self,
trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>,
message: &str,
code: &str)
-> DiagnosticBuilder<'tcx>
{
let (expected, found) = match self.values_str(&trace.values) {
Some((expected, found)) => (expected, found),
None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */
};
let span = trace.origin.span(); let span = trace.origin.span();
let mut err = self.report_type_error(trace, terr);
let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
values.expected.is_primitive() && values.found.is_primitive()
} else {
false
};
let mut err = self.tcx.sess.struct_span_err_with_code(
trace.origin.span(),
message,
code);
if !is_simple_error || check_old_school() {
err.note_expected_found(&"type", &expected, &found);
}
err.span_label(span, &terr);
self.note_error_origin(&mut err, &trace.origin);
self.check_and_note_conflicting_crates(&mut err, terr, span);
self.tcx.note_and_explain_type_err(&mut err, terr, span); self.tcx.note_and_explain_type_err(&mut err, terr, span);
err err
} }
/// Returns a string of the form "expected `{}`, found `{}`", or None if this is a derived pub fn report_and_explain_type_error(&self,
/// error. trace: TypeTrace<'tcx>,
terr: &TypeError<'tcx>)
-> DiagnosticBuilder<'tcx>
{
// FIXME: do we want to use a different error code for each origin?
let failure_str = trace.origin.as_failure_str();
type_err!(self, trace, terr, E0308, "{}", failure_str)
}
/// Returns a string of the form "expected `{}`, found `{}`".
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> {
match *values { match *values {
infer::Types(ref exp_found) => self.expected_found_str(exp_found), infer::Types(ref exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found) infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
} }
} }
fn expected_found_str<T: fmt::Display + Resolvable<'tcx> + TypeFoldable<'tcx>>( fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
&self, &self,
exp_found: &ty::error::ExpectedFound<T>) exp_found: &ty::error::ExpectedFound<T>)
-> Option<(String, String)> -> Option<(String, String)>
{ {
let expected = exp_found.expected.resolve(self); let exp_found = self.resolve_type_vars_if_possible(exp_found);
if expected.references_error() { if exp_found.references_error() {
return None; return None;
} }
let found = exp_found.found.resolve(self); Some((format!("{}", exp_found.expected), format!("{}", exp_found.found)))
if found.references_error() {
return None;
}
Some((format!("{}", expected), format!("{}", found)))
} }
fn report_generic_bound_failure(&self, fn report_generic_bound_failure(&self,
@ -1609,68 +1611,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) { fn note_region_origin(&self, err: &mut DiagnosticBuilder, origin: &SubregionOrigin<'tcx>) {
match *origin { match *origin {
infer::Subtype(ref trace) => { infer::Subtype(ref trace) => {
let desc = match trace.origin { if let Some((expected, found)) = self.values_str(&trace.values) {
TypeOrigin::Misc(_) => { // FIXME: do we want a "the" here?
"types are compatible" err.span_note(
} trace.origin.span(),
TypeOrigin::MethodCompatCheck(_) => { &format!("...so that {} (expected {}, found {})",
"method type is compatible with trait" trace.origin.as_requirement_str(), expected, found));
} } else {
TypeOrigin::ExprAssignable(_) => { // FIXME: this really should be handled at some earlier stage. Our
"expression is assignable" // handling of region checking when type errors are present is
} // *terrible*.
TypeOrigin::RelateTraitRefs(_) => {
"traits are compatible"
}
TypeOrigin::RelateSelfType(_) => {
"self type matches impl self type"
}
TypeOrigin::RelateOutputImplTypes(_) => {
"trait type parameters matches those \
specified on the impl"
}
TypeOrigin::MatchExpressionArm(_, _, _) => {
"match arms have compatible types"
}
TypeOrigin::IfExpression(_) => {
"if and else have compatible types"
}
TypeOrigin::IfExpressionWithNoElse(_) => {
"if may be missing an else clause"
}
TypeOrigin::RangeExpression(_) => {
"start and end of range have compatible types"
}
TypeOrigin::EquatePredicate(_) => {
"equality where clause is satisfied"
}
TypeOrigin::MainFunctionType(_) => {
"the `main` function has the correct type"
}
TypeOrigin::StartFunctionType(_) => {
"the `start` function has the correct type"
}
TypeOrigin::IntrinsicType(_) => {
"the intrinsic has the correct type"
}
};
match self.values_str(&trace.values) { err.span_note(
Some((expected, found)) => { trace.origin.span(),
err.span_note( &format!("...so that {}",
trace.origin.span(), trace.origin.as_requirement_str()));
&format!("...so that {} (expected {}, found {})",
desc, expected, found));
}
None => {
// Really should avoid printing this error at
// all, since it is derived, but that would
// require more refactoring than I feel like
// doing right now. - nmatsakis
err.span_note(
trace.origin.span(),
&format!("...so that {}", desc));
}
} }
} }
infer::Reborrow(span) => { infer::Reborrow(span) => {
@ -1813,32 +1768,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
} }
} }
pub trait Resolvable<'tcx> {
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self;
}
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
infcx.resolve_type_vars_if_possible(self)
}
}
impl<'tcx> Resolvable<'tcx> for ty::TraitRef<'tcx> {
fn resolve<'a, 'gcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-> ty::TraitRef<'tcx> {
infcx.resolve_type_vars_if_possible(self)
}
}
impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> {
fn resolve<'a, 'gcx>(&self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-> ty::PolyTraitRef<'tcx>
{
infcx.resolve_type_vars_if_possible(self)
}
}
fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
scope_id: ast::NodeId) scope_id: ast::NodeId)
-> Vec<hir::LifetimeDef> { -> Vec<hir::LifetimeDef> {

View file

@ -231,7 +231,7 @@ pub enum TypeOrigin {
} }
impl TypeOrigin { impl TypeOrigin {
fn as_str(&self) -> &'static str { fn as_failure_str(&self) -> &'static str {
match self { match self {
&TypeOrigin::Misc(_) | &TypeOrigin::Misc(_) |
&TypeOrigin::RelateSelfType(_) | &TypeOrigin::RelateSelfType(_) |
@ -252,11 +252,26 @@ impl TypeOrigin {
&TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type", &TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
} }
} }
}
impl fmt::Display for TypeOrigin { fn as_requirement_str(&self) -> &'static str {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> { match self {
fmt::Display::fmt(self.as_str(), f) &TypeOrigin::Misc(_) => "types are compatible",
&TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
&TypeOrigin::ExprAssignable(_) => "expression is assignable",
&TypeOrigin::RelateTraitRefs(_) => "traits are compatible",
&TypeOrigin::RelateSelfType(_) => "self type matches impl self type",
&TypeOrigin::RelateOutputImplTypes(_) => {
"trait type parameters matches those specified on the impl"
}
&TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
&TypeOrigin::IfExpression(_) => "if and else have compatible types",
&TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
&TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
&TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
&TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
&TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
&TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
}
} }
} }
@ -1489,22 +1504,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn type_error_message<M>(&self, pub fn type_error_message<M>(&self,
sp: Span, sp: Span,
mk_msg: M, mk_msg: M,
actual_ty: Ty<'tcx>, actual_ty: Ty<'tcx>)
err: Option<&TypeError<'tcx>>)
where M: FnOnce(String) -> String, where M: FnOnce(String) -> String,
{ {
self.type_error_struct(sp, mk_msg, actual_ty, err).emit(); self.type_error_struct(sp, mk_msg, actual_ty).emit();
} }
pub fn type_error_struct<M>(&self, pub fn type_error_struct<M>(&self,
sp: Span, sp: Span,
mk_msg: M, mk_msg: M,
actual_ty: Ty<'tcx>, actual_ty: Ty<'tcx>)
err: Option<&TypeError<'tcx>>)
-> DiagnosticBuilder<'tcx> -> DiagnosticBuilder<'tcx>
where M: FnOnce(String) -> String, where M: FnOnce(String) -> String,
{ {
debug!("type_error_struct({:?}, {:?}, {:?})", sp, actual_ty, err); debug!("type_error_struct({:?}, {:?})", sp, actual_ty);
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty); let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
@ -1513,21 +1526,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
return self.tcx.sess.diagnostic().struct_dummy(); return self.tcx.sess.diagnostic().struct_dummy();
} }
let error_str = err.map_or("".to_string(), |t_err| {
format!(" ({})", t_err)
});
let msg = mk_msg(self.ty_to_string(actual_ty)); let msg = mk_msg(self.ty_to_string(actual_ty));
// FIXME: use an error code. // FIXME: use an error code.
let mut db = self.tcx.sess.struct_span_err( self.tcx.sess.struct_span_err(sp, &msg)
sp, &format!("{} {}", msg, error_str));
if let Some(err) = err {
self.tcx.note_and_explain_type_err(&mut db, err, sp);
}
db
} }
pub fn report_mismatched_types(&self, pub fn report_mismatched_types(&self,

View file

@ -59,3 +59,15 @@ macro_rules! span_bug {
$crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
}) })
} }
#[macro_export]
macro_rules! type_err {
($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
$infcx.report_and_explain_type_error_with_code(
$trace,
$terr,
&format!($($message)*),
stringify!($code))
})
}

View file

@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => { _ => {
let mut err = self.type_error_struct(call_expr.span, |actual| { let mut err = self.type_error_struct(call_expr.span, |actual| {
format!("expected function, found `{}`", actual) format!("expected function, found `{}`", actual)
}, callee_ty, None); }, callee_ty);
if let hir::ExprCall(ref expr, _) = call_expr.node { if let hir::ExprCall(ref expr, _) = call_expr.node {
let tcx = self.tcx; let tcx = self.tcx;

View file

@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
format!("casting `{}` as `{}` is invalid", format!("casting `{}` as `{}` is invalid",
actual, actual,
fcx.ty_to_string(self.cast_ty)) fcx.ty_to_string(self.cast_ty))
}, self.expr_ty, None) }, self.expr_ty)
.help(&format!("cast through {} first", match e { .help(&format!("cast through {} first", match e {
CastError::NeedViaPtr => "a raw pointer", CastError::NeedViaPtr => "a raw pointer",
CastError::NeedViaThinPtr => "a thin pointer", CastError::NeedViaThinPtr => "a thin pointer",
@ -167,35 +167,35 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
CastError::CastToChar => { CastError::CastToChar => {
fcx.type_error_message(self.span, |actual| { fcx.type_error_message(self.span, |actual| {
format!("only `u8` can be cast as `char`, not `{}`", actual) format!("only `u8` can be cast as `char`, not `{}`", actual)
}, self.expr_ty, None); }, self.expr_ty);
} }
CastError::NonScalar => { CastError::NonScalar => {
fcx.type_error_message(self.span, |actual| { fcx.type_error_message(self.span, |actual| {
format!("non-scalar cast: `{}` as `{}`", format!("non-scalar cast: `{}` as `{}`",
actual, actual,
fcx.ty_to_string(self.cast_ty)) fcx.ty_to_string(self.cast_ty))
}, self.expr_ty, None); }, self.expr_ty);
} }
CastError::IllegalCast => { CastError::IllegalCast => {
fcx.type_error_message(self.span, |actual| { fcx.type_error_message(self.span, |actual| {
format!("casting `{}` as `{}` is invalid", format!("casting `{}` as `{}` is invalid",
actual, actual,
fcx.ty_to_string(self.cast_ty)) fcx.ty_to_string(self.cast_ty))
}, self.expr_ty, None); }, self.expr_ty);
} }
CastError::SizedUnsizedCast => { CastError::SizedUnsizedCast => {
fcx.type_error_message(self.span, |actual| { fcx.type_error_message(self.span, |actual| {
format!("cannot cast thin pointer `{}` to fat pointer `{}`", format!("cannot cast thin pointer `{}` to fat pointer `{}`",
actual, actual,
fcx.ty_to_string(self.cast_ty)) fcx.ty_to_string(self.cast_ty))
}, self.expr_ty, None) }, self.expr_ty)
} }
CastError::DifferingKinds => { CastError::DifferingKinds => {
fcx.type_error_struct(self.span, |actual| { fcx.type_error_struct(self.span, |actual| {
format!("casting `{}` as `{}` is invalid", format!("casting `{}` as `{}` is invalid",
actual, actual,
fcx.ty_to_string(self.cast_ty)) fcx.ty_to_string(self.cast_ty))
}, self.expr_ty, None) }, self.expr_ty)
.note("vtable kinds may not match") .note("vtable kinds may not match")
.emit(); .emit();
} }
@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
let tstr = fcx.ty_to_string(self.cast_ty); let tstr = fcx.ty_to_string(self.cast_ty);
let mut err = fcx.type_error_struct(self.span, |actual| { let mut err = fcx.type_error_struct(self.span, |actual| {
format!("cast to unsized type: `{}` as `{}`", actual, tstr) format!("cast to unsized type: `{}` as `{}`", actual, tstr)
}, self.expr_ty, None); }, self.expr_ty);
match self.expr_ty.sty { match self.expr_ty.sty {
ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => { ty::TyRef(_, ty::TypeAndMut { mutbl: mt, .. }) => {
let mtstr = match mt { let mtstr = match mt {
@ -484,4 +484,3 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span) traits::type_known_to_meet_builtin_bound(self, ty, ty::BoundSized, span)
} }
} }

View file

@ -160,8 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
item_name, item_name,
actual) actual)
}, },
rcvr_ty, rcvr_ty);
None);
// If the item has the name of a field, give a help note // If the item has the name of a field, give a help note
if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) { if let (&ty::TyStruct(def, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {

View file

@ -2541,21 +2541,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.type_error_message(arg.span, |t| { self.type_error_message(arg.span, |t| {
format!("can't pass an `{}` to variadic \ format!("can't pass an `{}` to variadic \
function, cast to `c_double`", t) function, cast to `c_double`", t)
}, arg_ty, None); }, arg_ty);
} }
ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => {
self.type_error_message(arg.span, |t| { self.type_error_message(arg.span, |t| {
format!("can't pass `{}` to variadic \ format!("can't pass `{}` to variadic \
function, cast to `c_int`", function, cast to `c_int`",
t) t)
}, arg_ty, None); }, arg_ty);
} }
ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
self.type_error_message(arg.span, |t| { self.type_error_message(arg.span, |t| {
format!("can't pass `{}` to variadic \ format!("can't pass `{}` to variadic \
function, cast to `c_uint`", function, cast to `c_uint`",
t) t)
}, arg_ty, None); }, arg_ty);
} }
ty::TyFnDef(_, _, f) => { ty::TyFnDef(_, _, f) => {
let ptr_ty = self.tcx.mk_fn_ptr(f); let ptr_ty = self.tcx.mk_fn_ptr(f);
@ -2564,7 +2564,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|t| { |t| {
format!("can't pass `{}` to variadic \ format!("can't pass `{}` to variadic \
function, cast to `{}`", t, ptr_ty) function, cast to `{}`", t, ptr_ty)
}, arg_ty, None); }, arg_ty);
} }
_ => {} _ => {}
} }
@ -2908,9 +2908,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.type_error_struct(field.span, |actual| { self.type_error_struct(field.span, |actual| {
format!("attempted to take value of method `{}` on type \ format!("attempted to take value of method `{}` on type \
`{}`", field.node, actual) `{}`", field.node, actual)
}, expr_t, None) }, expr_t)
.help( .help("maybe a `()` to call it is missing? \
"maybe a `()` to call it is missing? \
If not, try an anonymous function") If not, try an anonymous function")
.emit(); .emit();
self.write_error(expr.id); self.write_error(expr.id);
@ -2919,7 +2918,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
format!("attempted access of field `{}` on type `{}`, \ format!("attempted access of field `{}` on type `{}`, \
but no field with that name was found", but no field with that name was found",
field.node, actual) field.node, actual)
}, expr_t, None); }, expr_t);
if let ty::TyStruct(def, _) = expr_t.sty { if let ty::TyStruct(def, _) = expr_t.sty {
Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
} }
@ -3019,7 +3018,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
actual) actual)
} }
}, },
expr_t, None); expr_t);
self.write_error(expr.id); self.write_error(expr.id);
} }
@ -3038,8 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
format!("structure `{}` has no field named `{}`", format!("structure `{}` has no field named `{}`",
actual, field.name.node) actual, field.name.node)
}, },
ty, ty);
None);
// prevent all specified fields from being suggested // prevent all specified fields from being suggested
let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str()); let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect()); Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
@ -3272,7 +3270,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.type_error_message(expr.span, |actual| { self.type_error_message(expr.span, |actual| {
format!("type `{}` cannot be \ format!("type `{}` cannot be \
dereferenced", actual) dereferenced", actual)
}, oprnd_t, None); }, oprnd_t);
oprnd_t = tcx.types.err; oprnd_t = tcx.types.err;
} }
} }
@ -3647,8 +3645,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
format!("cannot index a value of type `{}`", format!("cannot index a value of type `{}`",
actual) actual)
}, },
base_t, base_t);
None);
// Try to give some advice about indexing tuples. // Try to give some advice about indexing tuples.
if let ty::TyTuple(_) = base_t.sty { if let ty::TyTuple(_) = base_t.sty {
let mut needs_note = true; let mut needs_note = true;
@ -4523,7 +4520,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if !self.is_tainted_by_errors() { if !self.is_tainted_by_errors() {
self.type_error_message(sp, |_actual| { self.type_error_message(sp, |_actual| {
"the type of this value must be known in this context".to_string() "the type of this value must be known in this context".to_string()
}, ty, None); }, ty);
} }
self.demand_suptype(sp, self.tcx.types.err, ty); self.demand_suptype(sp, self.tcx.types.err, ty);
ty = self.tcx.types.err; ty = self.tcx.types.err;

View file

@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.type_error_message(ex.span, |actual| { self.type_error_message(ex.span, |actual| {
format!("cannot apply unary operator `{}` to type `{}`", format!("cannot apply unary operator `{}` to type `{}`",
op_str, actual) op_str, actual)
}, operand_ty, None); }, operand_ty);
self.tcx.types.err self.tcx.types.err
} }
} }