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:
commit
7c8ae608dc
@ -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>) {
|
||||
|
@ -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() {
|
||||
|
21
src/test/auxiliary/crate_a1.rs
Normal file
21
src/test/auxiliary/crate_a1.rs
Normal 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>){}
|
17
src/test/auxiliary/crate_a2.rs
Normal file
17
src/test/auxiliary/crate_a2.rs
Normal 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!()
|
||||
}
|
33
src/test/compile-fail/type-mismatch-same-crate-name.rs
Normal file
33
src/test/compile-fail/type-mismatch-same-crate-name.rs
Normal 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`
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user