Skip to content

Commit 7c8ae60

Browse files
committed
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
2 parents 9ef923e + c65d338 commit 7c8ae60

File tree

5 files changed

+138
-12
lines changed

5 files changed

+138
-12
lines changed

src/librustc/middle/infer/error_reporting.rs

+50
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ use rustc_front::hir;
7878
use rustc_front::print::pprust;
7979

8080
use middle::def;
81+
use middle::def_id::DefId;
8182
use middle::infer;
8283
use middle::region;
8384
use middle::subst;
@@ -226,6 +227,8 @@ pub trait ErrorReporting<'tcx> {
226227

227228
fn report_type_error(&self, trace: TypeTrace<'tcx>, terr: &ty::TypeError<'tcx>);
228229

230+
fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span);
231+
229232
fn report_and_explain_type_error(&self,
230233
trace: TypeTrace<'tcx>,
231234
terr: &ty::TypeError<'tcx>);
@@ -484,13 +487,60 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
484487
expected_found_str,
485488
terr);
486489

490+
self.check_and_note_conflicting_crates(terr, trace.origin.span());
491+
487492
match trace.origin {
488493
infer::MatchExpressionArm(_, arm_span) =>
489494
self.tcx.sess.span_note(arm_span, "match arm with an incompatible type"),
490495
_ => ()
491496
}
492497
}
493498

499+
/// Adds a note if the types come from similarly named crates
500+
fn check_and_note_conflicting_crates(&self, terr: &ty::TypeError<'tcx>, sp: Span) {
501+
let report_path_match = |did1: DefId, did2: DefId| {
502+
// Only external crates, if either is from a local
503+
// module we could have false positives
504+
if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
505+
let exp_path = self.tcx.with_path(did1,
506+
|p| p.map(|x| x.to_string())
507+
.collect::<Vec<_>>());
508+
let found_path = self.tcx.with_path(did2,
509+
|p| p.map(|x| x.to_string())
510+
.collect::<Vec<_>>());
511+
// We compare strings because PathMod and PathName can be different
512+
// for imported and non-imported crates
513+
if exp_path == found_path {
514+
let crate_name = self.tcx.sess.cstore
515+
.get_crate_data(did1.krate).name();
516+
self.tcx.sess.span_note(sp, &format!("Perhaps two different versions \
517+
of crate `{}` are being used?",
518+
crate_name));
519+
}
520+
}
521+
};
522+
match *terr {
523+
ty::TypeError::Sorts(ref exp_found) => {
524+
// if they are both "path types", there's a chance of ambiguity
525+
// due to different versions of the same crate
526+
match (&exp_found.expected.sty, &exp_found.found.sty) {
527+
(&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) |
528+
(&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
529+
(&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) |
530+
(&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => {
531+
report_path_match(exp_adt.did, found_adt.did);
532+
},
533+
_ => ()
534+
}
535+
},
536+
ty::TypeError::Traits(ref exp_found) => {
537+
self.tcx.sess.note("errrr0");
538+
report_path_match(exp_found.expected, exp_found.found);
539+
},
540+
_ => () // FIXME(#22750) handle traits and stuff
541+
}
542+
}
543+
494544
fn report_and_explain_type_error(&self,
495545
trace: TypeTrace<'tcx>,
496546
terr: &ty::TypeError<'tcx>) {

src/librustc/middle/ty.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -5311,6 +5311,16 @@ impl<'tcx> TyS<'tcx> {
53115311
impl<'tcx> fmt::Display for TypeError<'tcx> {
53125312
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53135313
use self::TypeError::*;
5314+
fn report_maybe_different(f: &mut fmt::Formatter,
5315+
expected: String, found: String) -> fmt::Result {
5316+
// A naive approach to making sure that we're not reporting silly errors such as:
5317+
// (expected closure, found closure).
5318+
if expected == found {
5319+
write!(f, "expected {}, found a different {}", expected, found)
5320+
} else {
5321+
write!(f, "expected {}, found {}", expected, found)
5322+
}
5323+
}
53145324

53155325
match *self {
53165326
CyclicTy => write!(f, "cyclic type of infinite size"),
@@ -5371,20 +5381,15 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
53715381
found bound lifetime parameter {}", br)
53725382
}
53735383
Sorts(values) => tls::with(|tcx| {
5374-
// A naive approach to making sure that we're not reporting silly errors such as:
5375-
// (expected closure, found closure).
5376-
let expected_str = values.expected.sort_string(tcx);
5377-
let found_str = values.found.sort_string(tcx);
5378-
if expected_str == found_str {
5379-
write!(f, "expected {}, found a different {}", expected_str, found_str)
5380-
} else {
5381-
write!(f, "expected {}, found {}", expected_str, found_str)
5382-
}
5384+
report_maybe_different(f, values.expected.sort_string(tcx),
5385+
values.found.sort_string(tcx))
53835386
}),
53845387
Traits(values) => tls::with(|tcx| {
5385-
write!(f, "expected trait `{}`, found trait `{}`",
5386-
tcx.item_path_str(values.expected),
5387-
tcx.item_path_str(values.found))
5388+
report_maybe_different(f,
5389+
format!("trait `{}`",
5390+
tcx.item_path_str(values.expected)),
5391+
format!("trait `{}`",
5392+
tcx.item_path_str(values.found)))
53885393
}),
53895394
BuiltinBoundsMismatch(values) => {
53905395
if values.expected.is_empty() {

src/test/auxiliary/crate_a1.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub struct Foo;
12+
13+
pub trait Bar{}
14+
15+
pub fn bar() -> Box<Bar> {
16+
unimplemented!()
17+
}
18+
19+
20+
pub fn try_foo(x: Foo){}
21+
pub fn try_bar(x: Box<Bar>){}

src/test/auxiliary/crate_a2.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub struct Foo;
12+
13+
pub trait Bar{}
14+
15+
pub fn bar() -> Box<Bar> {
16+
unimplemented!()
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:crate_a1.rs
12+
// aux-build:crate_a2.rs
13+
14+
// This tests the extra note reported when a type error deals with
15+
// seemingly identical types.
16+
// The main use case of this error is when there are two crates
17+
// (generally different versions of the same crate) with the same name
18+
// causing a type mismatch. Here, we simulate that error using block-scoped
19+
// aliased `extern crate` declarations.
20+
21+
fn main() {
22+
let foo2 = {extern crate crate_a2 as a; a::Foo};
23+
let bar2 = {extern crate crate_a2 as a; a::bar()};
24+
{
25+
extern crate crate_a1 as a;
26+
a::try_foo(foo2); //~ ERROR mismatched types
27+
//~^ HELP run
28+
//~^^ NOTE Perhaps two different versions of crate `crate_a1`
29+
a::try_bar(bar2); //~ ERROR mismatched types
30+
//~^ HELP run
31+
//~^^ NOTE Perhaps two different versions of crate `crate_a1`
32+
}
33+
}

0 commit comments

Comments
 (0)