about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-07-21 02:13:14 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-07-22 14:32:56 +0300
commitf3ee99bd4d9d282c33127449073c521f29b07c21 (patch)
tree5628ddb3c510048143500c5228f93e3cb64c3e82
parent712c5cadbbb460a0b313a2fbcdaa9d6e10a25b6b (diff)
downloadrust-f3ee99bd4d9d282c33127449073c521f29b07c21.tar.gz
rust-f3ee99bd4d9d282c33127449073c521f29b07c21.zip
try to recover the non-matching types in projection errors
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.
-rw-r--r--src/librustc/traits/error_reporting.rs81
-rw-r--r--src/test/compile-fail/associated-types/higher-ranked-projection.rs38
-rw-r--r--src/test/compile-fail/issue-31173.rs3
3 files changed, 100 insertions, 22 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index afbe34f89bb..33ca1d05cad 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -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};
@@ -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,
diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs
new file mode 100644
index 00000000000..12341fa8db3
--- /dev/null
+++ b/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
+}
diff --git a/src/test/compile-fail/issue-31173.rs b/src/test/compile-fail/issue-31173.rs
index 62d23a99cba..fb1e3cc87e8 100644
--- a/src/test/compile-fail/issue-31173.rs
+++ b/src/test/compile-fail/issue-31173.rs
@@ -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`
 }