switch projection errors to use the new type error messages

Unfortunately, projection errors do not come with a nice set of
mismatched types. This is because the type equality check occurs
within a higher-ranked context. Therefore, only the type error
is reported. This is ugly but was always the situation.

I will introduce better errors for the lower-ranked case in
another commit.

Fixes the last known occurence of #31173
This commit is contained in:
Ariel Ben-Yehuda 2016-07-19 01:02:47 +03:00
parent b7b2db4da7
commit fa4eda8935
6 changed files with 76 additions and 34 deletions

View File

@ -522,37 +522,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
pub fn report_and_explain_type_error_with_code(&self,
trace: TypeTrace<'tcx>,
origin: TypeOrigin,
values: Option<ValuePairs<'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 is_simple_error = if let &TypeError::Sorts(ref values) = terr {
values.expected.is_primitive() && values.found.is_primitive()
} else {
false
let expected_found = match values {
None => None,
Some(values) => match self.values_str(&values) {
Some((expected, found)) => Some((expected, found)),
None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */
}
};
let span = origin.span();
let mut err = self.tcx.sess.struct_span_err_with_code(
trace.origin.span(),
message,
code);
span, message, code);
if !is_simple_error || check_old_school() {
err.note_expected_found(&"type", &expected, &found);
let mut is_simple_error = false;
if let Some((expected, found)) = expected_found {
is_simple_error = if let &TypeError::Sorts(ref values) = terr {
values.expected.is_primitive() && values.found.is_primitive()
} else {
false
};
if !is_simple_error || check_old_school() {
err.note_expected_found(&"type", &expected, &found);
}
}
err.span_label(span, &terr);
if !is_simple_error && check_old_school() {
err.span_note(span, &format!("{}", terr));
} else {
err.span_label(span, &terr);
}
self.note_error_origin(&mut err, &trace.origin);
self.note_error_origin(&mut err, &origin);
self.check_and_note_conflicting_crates(&mut err, terr, span);
self.tcx.note_and_explain_type_err(&mut err, terr, span);
@ -566,7 +575,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, '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)
type_err!(self, trace.origin, Some(trace.values), terr, E0308, "{}", failure_str)
}
/// Returns a string of the form "expected `{}`, found `{}`".

View File

@ -62,11 +62,12 @@ macro_rules! span_bug {
#[macro_export]
macro_rules! type_err {
($infcx:expr, $trace: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
($infcx:expr, $origin: expr, $values: expr, $terr: expr, $code:ident, $($message:tt)*) => ({
__diagnostic_used!($code);
$infcx.report_and_explain_type_error_with_code(
$trace,
$terr,
$origin,
$values,
&$terr,
&format!($($message)*),
stringify!($code))
})

View File

@ -26,7 +26,7 @@ use super::{
use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
use infer::{InferCtxt};
use infer::{InferCtxt, TypeOrigin};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::fast_reject;
use ty::fold::TypeFolder;
@ -117,10 +117,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
predicate,
error.err));
} else {
let mut err = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`: {}",
predicate,
error.err);
let mut err = type_err!(
self,
TypeOrigin::Misc(obligation.cause.span),
None, // FIXME: be smarter
error.err,
E0271,
"type mismatch resolving `{}`",
predicate);
self.note_obligation_cause(&mut err, obligation);
err.emit();
}

View File

@ -12,6 +12,7 @@ use middle::free_region::FreeRegionMap;
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::ty;
use rustc::traits::{self, ProjectionMode};
use rustc::ty::error::ExpectedFound;
use rustc::ty::subst::{self, Subst, Substs, VecPerParamSpace};
use syntax::ast;
@ -324,8 +325,11 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
impl_fty,
trait_fty);
let trace = infer::TypeTrace::types(origin, false, impl_fty, trait_fty);
type_err!(infcx, trace, &terr, E0053,
let values = Some(infer::ValuePairs::Types(ExpectedFound {
expected: trait_fty,
found: impl_fty
}));
type_err!(infcx, origin, values, terr, E0053,
"method `{}` has an incompatible type for trait",
trait_m.name).emit();
return

View File

@ -47,10 +47,8 @@ pub fn main() {
let a = 42;
foo1(a);
//~^ ERROR type mismatch resolving
//~| expected usize
//~| found struct `Bar`
//~| expected usize, found struct `Bar`
baz(&a);
//~^ ERROR type mismatch resolving
//~| expected usize
//~| found struct `Bar`
//~| expected usize, found struct `Bar`
}

View File

@ -0,0 +1,26 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::vec::IntoIter;
pub fn get_tok(it: &mut IntoIter<u8>) {
let mut found_e = false;
let temp: Vec<u8> = it.take_while(|&x| {
found_e = true;
false
})
.cloned()
//~^ ERROR type mismatch resolving
//~| expected u8, found &-ptr
.collect(); //~ ERROR no method named `collect`
}
fn main() {}