From 28859472f71cea497dbea12523e69dc23daaff76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 1 Jun 2019 10:35:31 -0700 Subject: [PATCH] Point at individual type arguments on arg count mismatch --- src/librustc/hir/mod.rs | 10 +++- src/librustc_typeck/check/compare_method.rs | 56 ++++++++++++------- src/test/ui/error-codes/E0049.rs | 10 ++++ src/test/ui/error-codes/E0049.stderr | 19 +++++-- src/test/ui/issues/issue-36708.stderr | 4 +- ...type-arg-mismatch-due-to-impl-trait.stderr | 6 +- 6 files changed, 76 insertions(+), 29 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f03a8ddc9082..d9c98d60b958 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -16,7 +16,7 @@ use crate::util::nodemap::{NodeMap, FxHashSet}; use crate::mir::mono::Linkage; use errors::FatalError; -use syntax_pos::{Span, DUMMY_SP, symbol::InternedString}; +use syntax_pos::{Span, DUMMY_SP, symbol::InternedString, MultiSpan}; use syntax::source_map::Spanned; use rustc_target::spec::abi::Abi; use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect}; @@ -624,6 +624,14 @@ impl Generics { } None } + + pub fn spans(&self) -> MultiSpan { + if self.params.is_empty() { + self.span.into() + } else { + self.params.iter().map(|p| p.span).collect::>().into() + } + } } /// Synthetic type parameters are converted to another form during lowering; this allows diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index cc074b64cc01..742f6ed5215c 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -583,7 +583,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn compare_number_of_generics<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_: &ty::AssocItem, - impl_span: Span, + _impl_span: Span, trait_: &ty::AssocItem, trait_span: Option, ) -> Result<(), ErrorReported> { @@ -600,17 +600,25 @@ fn compare_number_of_generics<'a, 'tcx>( if impl_count != trait_count { err_occurred = true; - let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); - let impl_item = tcx.hir().expect_impl_item(impl_hir_id); - let span = if impl_item.generics.params.is_empty() - || impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374) - impl_span + let trait_spans = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) { + let trait_item = tcx.hir().expect_trait_item(trait_hir_id); + Some(if trait_item.generics.params.is_empty() { + vec![trait_item.generics.span] + } else { + trait_item.generics.params.iter().map(|p| p.span).collect::>() + }) } else { - impl_item.generics.span + trait_span.map(|s| vec![s]) }; + let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap(); + let impl_item = tcx.hir().expect_impl_item(impl_hir_id); + // let span = impl_item.generics.span; + let spans = impl_item.generics.spans(); + let span = spans.primary_span(); + let mut err = tcx.sess.struct_span_err_with_code( - span, + spans, &format!( "method `{}` has {} {kind} parameter{} but its trait \ declaration has {} {kind} parameter{}", @@ -626,22 +634,32 @@ fn compare_number_of_generics<'a, 'tcx>( let mut suffix = None; - if let Some(span) = trait_span { - err.span_label( - span, - format!("expected {} {} parameter{}", trait_count, kind, - if trait_count != 1 { "s" } else { "" }) - ); + if let Some(spans) = trait_spans { + let mut spans = spans.iter(); + if let Some(span) = spans.next() { + err.span_label(*span, format!( + "expected {} {} parameter{}", + trait_count, + kind, + if trait_count != 1 { "s" } else { "" }, + )); + } + for span in spans { + err.span_label(*span, ""); + } } else { suffix = Some(format!(", expected {}", trait_count)); } - err.span_label( - span, - format!("found {} {} parameter{}{}", impl_count, kind, + if let Some(span) = span { + err.span_label(span, format!( + "found {} {} parameter{}{}", + impl_count, + kind, if impl_count != 1 { "s" } else { "" }, - suffix.unwrap_or_else(|| String::new())), - ); + suffix.unwrap_or_else(|| String::new()), + )); + } err.emit(); } diff --git a/src/test/ui/error-codes/E0049.rs b/src/test/ui/error-codes/E0049.rs index c141f8a88282..3dd910019bfd 100644 --- a/src/test/ui/error-codes/E0049.rs +++ b/src/test/ui/error-codes/E0049.rs @@ -8,5 +8,15 @@ impl Foo for Bar { fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 } +trait Fuzz { + fn fuzz(x: A, y: B) -> Self; +} + +struct Baz; + +impl Fuzz for Baz { + fn fuzz(x: bool, y: bool) -> Self { Baz } //~ ERROR E0049 +} + fn main() { } diff --git a/src/test/ui/error-codes/E0049.stderr b/src/test/ui/error-codes/E0049.stderr index 7e9b9e8efb9a..c0cd31faa90d 100644 --- a/src/test/ui/error-codes/E0049.stderr +++ b/src/test/ui/error-codes/E0049.stderr @@ -1,12 +1,23 @@ error[E0049]: method `foo` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/E0049.rs:8:5 + --> $DIR/E0049.rs:8:11 | LL | fn foo(x: T) -> Self; - | --------------------------------- expected 1 type parameter + | - expected 1 type parameter ... LL | fn foo(x: bool) -> Self { Bar } - | ^^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters + | ^ found 0 type parameters -error: aborting due to previous error +error[E0049]: method `fuzz` has 0 type parameters but its trait declaration has 2 type parameters + --> $DIR/E0049.rs:18:12 + | +LL | fn fuzz(x: A, y: B) -> Self; + | - - + | | + | expected 2 type parameters +... +LL | fn fuzz(x: bool, y: bool) -> Self { Baz } + | ^ found 0 type parameters + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0049`. diff --git a/src/test/ui/issues/issue-36708.stderr b/src/test/ui/issues/issue-36708.stderr index 835094c4fdc5..140f19f1ff77 100644 --- a/src/test/ui/issues/issue-36708.stderr +++ b/src/test/ui/issues/issue-36708.stderr @@ -1,8 +1,8 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/issue-36708.rs:8:11 + --> $DIR/issue-36708.rs:8:12 | LL | fn foo() {} - | ^^^ found 1 type parameter, expected 0 + | ^ found 1 type parameter, expected 0 error: aborting due to previous error diff --git a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr index 3f1b10fab27f..953284735553 100644 --- a/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr +++ b/src/test/ui/issues/type-arg-mismatch-due-to-impl-trait.stderr @@ -1,11 +1,11 @@ error[E0049]: method `foo` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:11 + --> $DIR/type-arg-mismatch-due-to-impl-trait.rs:10:22 | LL | fn foo(&self, t: Self::T); - | -------------------------- expected 0 type parameters + | - expected 0 type parameters ... LL | fn foo(&self, t: impl Clone) {} - | ^ found 1 type parameter + | ^^^^^^^^^^ found 1 type parameter error: aborting due to previous error