From fa4eda8935cc902b0757815e774f11ee791af156 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 19 Jul 2016 01:02:47 +0300 Subject: [PATCH] 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 --- src/librustc/infer/error_reporting.rs | 49 +++++++++++-------- src/librustc/macros.rs | 7 +-- src/librustc/traits/error_reporting.rs | 14 ++++-- src/librustc_typeck/check/compare_method.rs | 8 ++- .../compile-fail/associated-types-eq-3.rs | 6 +-- src/test/compile-fail/issue-31173.rs | 26 ++++++++++ 6 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 src/test/compile-fail/issue-31173.rs diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index be73818c8a4e..0726d8560bab 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -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>, 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 `{}`". diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 52420475db10..190c9b665e0d 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -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)) }) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 3b9ecb882585..afbe34f89bbf 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -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(); } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 847dcc90ad39..2c4c6279076d 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -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 diff --git a/src/test/compile-fail/associated-types-eq-3.rs b/src/test/compile-fail/associated-types-eq-3.rs index 8c66160e8a36..cb952f6534f0 100644 --- a/src/test/compile-fail/associated-types-eq-3.rs +++ b/src/test/compile-fail/associated-types-eq-3.rs @@ -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` } diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs new file mode 100644 index 000000000000..62d23a99cbad --- /dev/null +++ b/src/test/compile-fail/issue-31173.rs @@ -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 or the MIT license +// , 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) { + let mut found_e = false; + + let temp: Vec = 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() {}