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
This commit is contained in:
bors 2015-09-09 10:54:05 +00:00
commit 7c8ae608dc
5 changed files with 138 additions and 12 deletions

View File

@ -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>) {

View File

@ -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() {

View File

@ -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>){}

View File

@ -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!()
}

View File

@ -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`
}
}