refactor type error reporting
This commit is contained in:
parent
8eb12d91aa
commit
cea88ebb39
8 changed files with 140 additions and 202 deletions
|
@ -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> {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue