Skip to content

Commit

Permalink
switch projection errors to use the new type error messages
Browse files Browse the repository at this point in the history
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 rust-lang#31173
  • Loading branch information
arielb1 committed Jul 20, 2016
1 parent 620d4cb commit 7724455
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 32 deletions.
44 changes: 26 additions & 18 deletions src/librustc/infer/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,37 +522,45 @@ 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 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 = trace.origin.span();
let span = origin.span();
let mut err = self.tcx.sess.struct_span_err_with_code(
span, message, code);

let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
values.expected.is_primitive() && values.found.is_primitive()
} else {
false
};
let mut is_simple_error = false;

let mut err = self.tcx.sess.struct_span_err_with_code(
trace.origin.span(),
message,
code);
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);
if !is_simple_error || check_old_school() {
err.note_expected_found(&"type", &expected, &found);
}
}

if !is_simple_error && check_old_school() {
err.span_note(span, &format!("{}", terr));
}
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);

Expand All @@ -566,7 +574,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 `{}`".
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
})
Expand Down
14 changes: 9 additions & 5 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down
8 changes: 6 additions & 2 deletions src/librustc_typeck/check/compare_method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions src/test/compile-fail/associated-types-eq-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
}
26 changes: 26 additions & 0 deletions src/test/compile-fail/issue-31173.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 7724455

Please sign in to comment.