about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-09-09 10:54:05 +0000
committerbors <bors@rust-lang.org>2015-09-09 10:54:05 +0000
commit7c8ae608dc65665039f3aeb01548d675953a2a68 (patch)
tree66dffaac82f0b1a3fafdc823078562c63d049433
parent9ef923e380009a7075dfb57017952ce45f5fa327 (diff)
parentc65d33819ccf141d40bd9bf30784b36bf83c124b (diff)
downloadrust-7c8ae608dc65665039f3aeb01548d675953a2a68.tar.gz
rust-7c8ae608dc65665039f3aeb01548d675953a2a68.zip
Auto merge of #28300 - Manishearth:crate_err, r=eddyb
Partially fixes #22750

I'll write a test for this when I figure out how to.

r? @eddyb

cc @steveklabnik
-rw-r--r--src/librustc/middle/infer/error_reporting.rs50
-rw-r--r--src/librustc/middle/ty.rs29
-rw-r--r--src/test/auxiliary/crate_a1.rs21
-rw-r--r--src/test/auxiliary/crate_a2.rs17
-rw-r--r--src/test/compile-fail/type-mismatch-same-crate-name.rs33
5 files changed, 138 insertions, 12 deletions
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 8197ccf4be7..7ec39ac8515 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -78,6 +78,7 @@ use rustc_front::hir;
 use rustc_front::print::pprust;
 
 use middle::def;
+use middle::def_id::DefId;
 use middle::infer;
 use middle::region;
 use middle::subst;
@@ -226,6 +227,8 @@ pub trait ErrorReporting<'tcx> {
 
     fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>);
 
+    fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span);
+
     fn report_and_explain_type_error(&self,
                                      trace: TypeTrace<'tcx>,
                                      terr: &ty::TypeError<'tcx>);
@@ -484,6 +487,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                  expected_found_str,
                  terr);
 
+        self.check_and_note_conflicting_crates(terr, trace.origin.span());
+
         match trace.origin {
             infer::MatchExpressionArm(_, arm_span) =>
                 self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"),
@@ -491,6 +496,51 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
+    /// Adds a note if the types come from similarly named crates
+    fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span) {
+        let report_path_match = |did1: DefId, did2: DefId| {
+            // Only external crates, if either is from a local
+            // module we could have false positives
+            if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
+                let exp_path = self.tcx.with_path(did1,
+                                                  |p| p.map(|x| x.to_string())
+                                                       .collect::<Vec<_>>());
+                let found_path = self.tcx.with_path(did2,
+                                                    |p| p.map(|x| x.to_string())
+                                                         .collect::<Vec<_>>());
+                // We compare strings because PathMod and PathName can be different
+                // for imported and non-imported crates
+                if exp_path == found_path {
+                    let crate_name = self.tcx.sess.cstore
+                                         .get_crate_data(did1.krate).name();
+                    self.tcx.sess.span_note(sp, &format!("Perhaps two different versions \
+                                                          of crate `{}` are being used?",
+                                                          crate_name));
+                }
+            }
+        };
+        match *terr {
+            ty::TypeError::Sorts(ref exp_found) => {
+                // if they are both "path types", there's a chance of ambiguity
+                // due to different versions of the same crate
+                match (&exp_found.expected.sty, &exp_found.found.sty) {
+                    (&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) |
+                    (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
+                    (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
+                    (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => {
+                        report_path_match(exp_adt.did, found_adt.did);
+                    },
+                    _ => ()
+                }
+            },
+            ty::TypeError::Traits(ref exp_found) => {
+                self.tcx.sess.note("errrr0");
+                report_path_match(exp_found.expected, exp_found.found);
+            },
+            _ => () // FIXME(#22750) handle traits and stuff
+        }
+    }
+
     fn report_and_explain_type_error(&self,
                                      trace: TypeTrace<'tcx>,
                                      terr: &ty::TypeError<'tcx>) {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 9f2c87b1a0a..99d8c5c9301 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -5311,6 +5311,16 @@ impl<'tcx> TyS<'tcx> {
 impl<'tcx> fmt::Display for TypeError<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use self::TypeError::*;
+        fn report_maybe_different(f: &mut fmt::Formatter,
+                                  expected: String, found: String) -> fmt::Result {
+            // A naive approach to making sure that we're not reporting silly errors such as:
+            // (expected closure, found closure).
+            if expected == found {
+                write!(f, "expected {}, found a different {}", expected, found)
+            } else {
+                write!(f, "expected {}, found {}", expected, found)
+            }
+        }
 
         match *self {
             CyclicTy => write!(f, "cyclic type of infinite size"),
@@ -5371,20 +5381,15 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
                            found bound lifetime parameter {}", br)
             }
             Sorts(values) => tls::with(|tcx| {
-                // A naive approach to making sure that we're not reporting silly errors such as:
-                // (expected closure, found closure).
-                let expected_str = values.expected.sort_string(tcx);
-                let found_str = values.found.sort_string(tcx);
-                if expected_str == found_str {
-                    write!(f, "expected {}, found a different {}", expected_str, found_str)
-                } else {
-                    write!(f, "expected {}, found {}", expected_str, found_str)
-                }
+                report_maybe_different(f, values.expected.sort_string(tcx),
+                                       values.found.sort_string(tcx))
             }),
             Traits(values) => tls::with(|tcx| {
-                write!(f, "expected trait `{}`, found trait `{}`",
-                       tcx.item_path_str(values.expected),
-                       tcx.item_path_str(values.found))
+                report_maybe_different(f,
+                                       format!("trait `{}`",
+                                               tcx.item_path_str(values.expected)),
+                                       format!("trait `{}`",
+                                               tcx.item_path_str(values.found)))
             }),
             BuiltinBoundsMismatch(values) => {
                 if values.expected.is_empty() {
diff --git a/src/test/auxiliary/crate_a1.rs b/src/test/auxiliary/crate_a1.rs
new file mode 100644
index 00000000000..70f7cac94de
--- /dev/null
+++ b/src/test/auxiliary/crate_a1.rs
@@ -0,0 +1,21 @@
+// Copyright 2015 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.
+
+pub struct Foo;
+
+pub trait Bar{}
+
+pub fn bar() -> Box<Bar> {
+    unimplemented!()
+}
+
+
+pub fn try_foo(x: Foo){}
+pub fn try_bar(x: Box<Bar>){}
diff --git a/src/test/auxiliary/crate_a2.rs b/src/test/auxiliary/crate_a2.rs
new file mode 100644
index 00000000000..d801f25ba2e
--- /dev/null
+++ b/src/test/auxiliary/crate_a2.rs
@@ -0,0 +1,17 @@
+// Copyright 2015 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.
+
+pub struct Foo;
+
+pub trait Bar{}
+
+pub fn bar() -> Box<Bar> {
+    unimplemented!()
+}
diff --git a/src/test/compile-fail/type-mismatch-same-crate-name.rs b/src/test/compile-fail/type-mismatch-same-crate-name.rs
new file mode 100644
index 00000000000..014fa35c309
--- /dev/null
+++ b/src/test/compile-fail/type-mismatch-same-crate-name.rs
@@ -0,0 +1,33 @@
+// Copyright 2014 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.
+
+// aux-build:crate_a1.rs
+// aux-build:crate_a2.rs
+
+// This tests the extra note reported when a type error deals with
+// seemingly identical types.
+// The main use case of this error is when there are two crates
+// (generally different versions of the same crate) with the same name
+// causing a type mismatch. Here, we simulate that error using block-scoped
+// aliased `extern crate` declarations.
+
+fn main() {
+    let foo2 = {extern crate crate_a2 as a; a::Foo};
+    let bar2 = {extern crate crate_a2 as a; a::bar()};
+    {
+        extern crate crate_a1 as a;
+        a::try_foo(foo2); //~ ERROR mismatched types
+                          //~^ HELP run
+                          //~^^ NOTE Perhaps two different versions of crate `crate_a1`
+        a::try_bar(bar2); //~ ERROR mismatched types
+                          //~^ HELP run
+                          //~^^ NOTE Perhaps two different versions of crate `crate_a1`
+    }
+}