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, pub fn report_and_explain_type_error_with_code(&self,
trace: TypeTrace<'tcx>, origin: TypeOrigin,
values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>, terr: &TypeError<'tcx>,
message: &str, message: &str,
code: &str) code: &str)
-> DiagnosticBuilder<'tcx> -> DiagnosticBuilder<'tcx>
{ {
let (expected, found) = match self.values_str(&trace.values) { let expected_found = match values {
Some((expected, found)) => (expected, found), None => None,
None => return self.tcx.sess.diagnostic().struct_dummy() /* derived error */ 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 = 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 span = origin.span();
let mut err = self.tcx.sess.struct_span_err_with_code( let mut err = self.tcx.sess.struct_span_err_with_code(
trace.origin.span(), span, message, code);
message,
code);
if !is_simple_error || check_old_school() { let mut is_simple_error = false;
err.note_expected_found(&"type", &expected, &found);
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.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);
@ -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? // FIXME: do we want to use a different error code for each origin?
let failure_str = trace.origin.as_failure_str(); 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 `{}`". /// Returns a string of the form "expected `{}`, found `{}`".

View File

@ -62,11 +62,12 @@ macro_rules! span_bug {
#[macro_export] #[macro_export]
macro_rules! type_err { 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); __diagnostic_used!($code);
$infcx.report_and_explain_type_error_with_code( $infcx.report_and_explain_type_error_with_code(
$trace, $origin,
$terr, $values,
&$terr,
&format!($($message)*), &format!($($message)*),
stringify!($code)) stringify!($code))
}) })

View File

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

View File

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

View File

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