Skip to content

Commit 8ccc11b

Browse files
authored
Rollup merge of #35765 - KiChjang:e0053-bonus, r=jonathandturner
Additional span info for E0053 Part of #35233. Fixes #35212. r? @jonathandturner
2 parents c3601d4 + 31d56cb commit 8ccc11b

File tree

7 files changed

+158
-27
lines changed

7 files changed

+158
-27
lines changed

src/librustc/hir/map/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,13 @@ impl<'ast> Map<'ast> {
569569
}
570570
}
571571

572+
pub fn expect_impl_item(&self, id: NodeId) -> &'ast ImplItem {
573+
match self.find(id) {
574+
Some(NodeImplItem(item)) => item,
575+
_ => bug!("expected impl item, found {}", self.node_to_string(id))
576+
}
577+
}
578+
572579
pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem {
573580
match self.find(id) {
574581
Some(NodeTraitItem(item)) => item,

src/librustc/infer/error_reporting.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
523523
pub fn note_type_err(&self,
524524
diag: &mut DiagnosticBuilder<'tcx>,
525525
origin: TypeOrigin,
526+
secondary_span: Option<(Span, String)>,
526527
values: Option<ValuePairs<'tcx>>,
527528
terr: &TypeError<'tcx>)
528529
{
@@ -553,6 +554,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
553554
}
554555

555556
diag.span_label(span, &terr);
557+
if let Some((sp, msg)) = secondary_span {
558+
diag.span_label(sp, &msg);
559+
}
556560

557561
self.note_error_origin(diag, &origin);
558562
self.check_and_note_conflicting_crates(diag, terr, span);
@@ -569,7 +573,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
569573
self.tcx.sess, trace.origin.span(), E0308,
570574
"{}", trace.origin.as_failure_str()
571575
);
572-
self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
576+
self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
573577
diag
574578
}
575579

src/librustc/traits/error_reporting.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
161161
self.tcx.sess, origin.span(), E0271,
162162
"type mismatch resolving `{}`", predicate
163163
);
164-
self.note_type_err(&mut diag, origin, values, err);
164+
self.note_type_err(&mut diag, origin, None, values, err);
165165
self.note_obligation_cause(&mut diag, obligation);
166166
diag.emit();
167167
});

src/librustc_typeck/check/compare_method.rs

+85-21
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ use middle::free_region::FreeRegionMap;
1212
use rustc::infer::{self, InferOk, TypeOrigin};
1313
use rustc::ty;
1414
use rustc::traits::{self, Reveal};
15-
use rustc::ty::error::ExpectedFound;
15+
use rustc::ty::error::{ExpectedFound, TypeError};
1616
use rustc::ty::subst::{Subst, Substs};
17-
use rustc::hir::map::Node;
18-
use rustc::hir::{ImplItemKind, TraitItem_};
17+
use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
1918

2019
use syntax::ast;
2120
use syntax_pos::Span;
@@ -300,6 +299,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
300299
impl_m_span,
301300
impl_m_body_id,
302301
&impl_sig);
302+
let impl_args = impl_sig.inputs.clone();
303303
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
304304
unsafety: impl_m.fty.unsafety,
305305
abi: impl_m.fty.abi,
@@ -318,6 +318,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
318318
impl_m_span,
319319
impl_m_body_id,
320320
&trait_sig);
321+
let trait_args = trait_sig.inputs.clone();
321322
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
322323
unsafety: trait_m.fty.unsafety,
323324
abi: trait_m.fty.abi,
@@ -331,16 +332,82 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
331332
impl_fty,
332333
trait_fty);
333334

335+
let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node {
336+
ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(),
337+
_ => bug!("{:?} is not a method", impl_m)
338+
};
339+
340+
let (impl_err_span, trait_err_span) = match terr {
341+
TypeError::Mutability => {
342+
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
343+
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
344+
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
345+
trait_m_sig.decl.inputs.iter(),
346+
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
347+
};
348+
349+
impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
350+
match (&impl_arg.ty.node, &trait_arg.ty.node) {
351+
(&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
352+
(&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
353+
impl_mt.mutbl != trait_mt.mutbl,
354+
_ => false
355+
}
356+
}).map(|(ref impl_arg, ref trait_arg)| {
357+
match (impl_arg.to_self(), trait_arg.to_self()) {
358+
(Some(impl_self), Some(trait_self)) =>
359+
(impl_self.span, Some(trait_self.span)),
360+
(None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
361+
_ => bug!("impl and trait fns have different first args, \
362+
impl: {:?}, trait: {:?}", impl_arg, trait_arg)
363+
}
364+
}).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
365+
} else {
366+
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
367+
}
368+
}
369+
TypeError::Sorts(ExpectedFound { expected, found }) => {
370+
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
371+
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
372+
TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
373+
trait_m_sig.decl.inputs.iter(),
374+
_ => bug!("{:?} is not a MethodTraitItem", trait_m)
375+
};
376+
let impl_iter = impl_args.iter();
377+
let trait_iter = trait_args.iter();
378+
let arg_idx = impl_iter.zip(trait_iter)
379+
.position(|(impl_arg_ty, trait_arg_ty)| {
380+
*impl_arg_ty == found && *trait_arg_ty == expected
381+
}).unwrap();
382+
impl_m_iter.zip(trait_m_iter)
383+
.nth(arg_idx)
384+
.map(|(impl_arg, trait_arg)|
385+
(impl_arg.ty.span, Some(trait_arg.ty.span)))
386+
.unwrap_or(
387+
(origin.span(), tcx.map.span_if_local(trait_m.def_id)))
388+
} else {
389+
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
390+
}
391+
}
392+
_ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
393+
};
394+
395+
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
396+
334397
let mut diag = struct_span_err!(
335398
tcx.sess, origin.span(), E0053,
336399
"method `{}` has an incompatible type for trait", trait_m.name
337400
);
401+
338402
infcx.note_type_err(
339-
&mut diag, origin,
403+
&mut diag,
404+
origin,
405+
trait_err_span.map(|sp| (sp, format!("original trait requirement"))),
340406
Some(infer::ValuePairs::Types(ExpectedFound {
341-
expected: trait_fty,
342-
found: impl_fty
343-
})), &terr
407+
expected: trait_fty,
408+
found: impl_fty
409+
})),
410+
&terr
344411
);
345412
diag.emit();
346413
return
@@ -487,12 +554,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
487554
trait_ty);
488555

489556
// Locate the Span containing just the type of the offending impl
490-
if let Some(impl_trait_node) = tcx.map.get_if_local(impl_c.def_id) {
491-
if let Node::NodeImplItem(impl_trait_item) = impl_trait_node {
492-
if let ImplItemKind::Const(ref ty, _) = impl_trait_item.node {
493-
origin = TypeOrigin::Misc(ty.span);
494-
}
495-
}
557+
match tcx.map.expect_impl_item(impl_c_node_id).node {
558+
ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
559+
_ => bug!("{:?} is not a impl const", impl_c)
496560
}
497561

498562
let mut diag = struct_span_err!(
@@ -502,16 +566,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
502566
);
503567

504568
// Add a label to the Span containing just the type of the item
505-
if let Some(orig_trait_node) = tcx.map.get_if_local(trait_c.def_id) {
506-
if let Node::NodeTraitItem(orig_trait_item) = orig_trait_node {
507-
if let TraitItem_::ConstTraitItem(ref ty, _) = orig_trait_item.node {
508-
diag.span_label(ty.span, &format!("original trait requirement"));
509-
}
510-
}
511-
}
569+
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
570+
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
571+
TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
572+
_ => bug!("{:?} is not a trait const", trait_c)
573+
};
512574

513575
infcx.note_type_err(
514-
&mut diag, origin,
576+
&mut diag,
577+
origin,
578+
Some((trait_c_span, format!("original trait requirement"))),
515579
Some(infer::ValuePairs::Types(ExpectedFound {
516580
expected: trait_ty,
517581
found: impl_ty

src/test/compile-fail/E0053.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,21 @@
99
// except according to those terms.
1010

1111
trait Foo {
12-
fn foo(x: u16);
13-
fn bar(&self);
12+
fn foo(x: u16); //~ NOTE original trait requirement
13+
fn bar(&self); //~ NOTE original trait requirement
1414
}
1515

1616
struct Bar;
1717

1818
impl Foo for Bar {
19-
fn foo(x: i16) { } //~ ERROR E0053
20-
fn bar(&mut self) { } //~ ERROR E0053
19+
fn foo(x: i16) { }
20+
//~^ ERROR method `foo` has an incompatible type for trait
21+
//~| NOTE expected u16
22+
fn bar(&mut self) { }
23+
//~^ ERROR method `bar` has an incompatible type for trait
24+
//~| NOTE values differ in mutability
25+
//~| NOTE expected type `fn(&Bar)`
26+
//~| NOTE found type `fn(&mut Bar)`
2127
}
2228

2329
fn main() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2016 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+
// rustc-env:RUST_NEW_ERROR_FORMAT
12+
13+
trait Foo {
14+
fn foo(x: u16);
15+
fn bar(&mut self, bar: &mut Bar);
16+
}
17+
18+
struct Bar;
19+
20+
impl Foo for Bar {
21+
fn foo(x: i16) { }
22+
fn bar(&mut self, bar: &Bar) { }
23+
}
24+
25+
fn main() {
26+
}
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0053]: method `foo` has an incompatible type for trait
2+
--> $DIR/trait-impl-fn-incompatibility.rs:21:15
3+
|
4+
14 | fn foo(x: u16);
5+
| --- original trait requirement
6+
...
7+
21 | fn foo(x: i16) { }
8+
| ^^^ expected u16, found i16
9+
10+
error[E0053]: method `bar` has an incompatible type for trait
11+
--> $DIR/trait-impl-fn-incompatibility.rs:22:28
12+
|
13+
15 | fn bar(&mut self, bar: &mut Bar);
14+
| -------- original trait requirement
15+
...
16+
22 | fn bar(&mut self, bar: &Bar) { }
17+
| ^^^^ values differ in mutability
18+
|
19+
= note: expected type `fn(&mut Bar, &mut Bar)`
20+
= note: found type `fn(&mut Bar, &Bar)`
21+
22+
error: aborting due to 2 previous errors
23+

0 commit comments

Comments
 (0)