Skip to content

Commit

Permalink
try to recover the non-matching types in projection errors
Browse files Browse the repository at this point in the history
The type equation in projection takes place under a binder and a snapshot, which
we can't easily take types out of. Instead, when encountering a projection error,
try to re-do the projection and find the type error then.

This fails to produce a sane type error when the failure was a "leak_check" failure.
I can't think of a sane way to show *these*, so I just left them use the old crappy
representation, and added a test to make sure we don't break them.
  • Loading branch information
arielb1 committed Jul 22, 2016
1 parent 712c5ca commit f3ee99b
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 22 deletions.
81 changes: 60 additions & 21 deletions src/librustc/traits/error_reporting.rs
Expand Up @@ -26,8 +26,9 @@ use super::{

use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
use infer::{InferCtxt, TypeOrigin};
use infer::{self, InferCtxt, TypeOrigin};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::fold::TypeFolder;
use ty::subst::{self, Subst, TypeSpace};
Expand Down Expand Up @@ -107,28 +108,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let predicate =
self.resolve_type_vars_if_possible(&obligation.predicate);

if !predicate.references_error() {
if let Some(warning_node_id) = warning_node_id {
self.tcx.sess.add_lint(
::lint::builtin::UNSIZED_IN_TUPLE,
warning_node_id,
if predicate.references_error() {
return
}
if let Some(warning_node_id) = warning_node_id {
self.tcx.sess.add_lint(
::lint::builtin::UNSIZED_IN_TUPLE,
warning_node_id,
obligation.cause.span,
format!("type mismatch resolving `{}`: {}",
predicate,
error.err));
return
}
self.probe(|_| {
let origin = TypeOrigin::Misc(obligation.cause.span);
let err_buf;
let mut err = &error.err;
let mut values = None;

// try to find the mismatched types to report the error with.
//
// this can fail if the problem was higher-ranked, in which
// cause I have no idea for a good error message.
if let ty::Predicate::Projection(ref data) = predicate {
let mut selcx = SelectionContext::new(self);
let (data, _) = self.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
format!("type mismatch resolving `{}`: {}",
predicate,
error.err));
} else {
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();
infer::LateBoundRegionConversionTime::HigherRankedType,
data);
let normalized = super::normalize_projection_type(
&mut selcx,
data.projection_ty,
obligation.cause.clone(),
0
);
let origin = TypeOrigin::Misc(obligation.cause.span);
if let Err(error) = self.eq_types(
false, origin,
data.ty, normalized.value
) {
values = Some(infer::ValuePairs::Types(ExpectedFound {
expected: normalized.value,
found: data.ty,
}));
err_buf = error;
err = &err_buf;
}
}
}

let mut diag = type_err!(
self,
origin,
values,
err,
E0271,
"type mismatch resolving `{}`",
predicate);
self.note_obligation_cause(&mut diag, obligation);
diag.emit();
});
}

fn impl_substs(&self,
Expand Down
38 changes: 38 additions & 0 deletions src/test/compile-fail/associated-types/higher-ranked-projection.rs
@@ -0,0 +1,38 @@
// 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.

#![feature(rustc_attrs)]

// revisions: good bad

trait Mirror {
type Image;
}

impl<T> Mirror for T {
type Image = T;
}

#[cfg(bad)]
fn foo<U, T>(_t: T)
where for<'a> &'a T: Mirror<Image=U>
{}

#[cfg(good)]
fn foo<U, T>(_t: T)
where for<'a> &'a T: Mirror<Image=&'a U>
{}

#[rustc_error]
fn main() { //[good]~ ERROR compilation successful
foo(());
//[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _`
//[bad]~| expected bound lifetime parameter 'a, found concrete lifetime
}
3 changes: 2 additions & 1 deletion src/test/compile-fail/issue-31173.rs
Expand Up @@ -19,7 +19,8 @@ pub fn get_tok(it: &mut IntoIter<u8>) {
})
.cloned()
//~^ ERROR type mismatch resolving
//~| expected u8, found &-ptr
//~| expected type `u8`
//~| found type `&_`
.collect(); //~ ERROR no method named `collect`
}

Expand Down

0 comments on commit f3ee99b

Please sign in to comment.