diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 59766e7e47d..32640d7d9a8 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -6,7 +6,7 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::error::{ExpectedFound, TypeError}; use rustc::ty::subst::{Subst, InternalSubsts, SubstsRef}; use rustc::util::common::ErrorReported; -use errors::Applicability; +use errors::{Applicability, DiagnosticId}; use syntax_pos::Span; @@ -576,55 +576,78 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } -fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_m: &ty::AssociatedItem, - impl_m_span: Span, - trait_m: &ty::AssociatedItem, - trait_item_span: Option) - -> Result<(), ErrorReported> { - let impl_m_generics = tcx.generics_of(impl_m.def_id); - let trait_m_generics = tcx.generics_of(trait_m.def_id); - let num_impl_m_type_params = impl_m_generics.own_counts().types; - let num_trait_m_type_params = trait_m_generics.own_counts().types; +fn compare_number_of_generics<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_: &ty::AssociatedItem, + impl_span: Span, + trait_: &ty::AssociatedItem, + trait_span: Option, +) -> Result<(), ErrorReported> { + let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts(); + let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts(); - if num_impl_m_type_params != num_trait_m_type_params { - let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap(); - let impl_m_item = tcx.hir().expect_impl_item(impl_m_node_id); - let span = if impl_m_item.generics.params.is_empty() - || impl_m_item.generics.span.is_dummy() // impl Trait in argument position (#55374) - { - impl_m_span - } else { - impl_m_item.generics.span - }; + let matchings = [ + ("type", trait_own_counts.types, impl_own_counts.types), + ("const", trait_own_counts.consts, impl_own_counts.consts), + ]; - let mut err = struct_span_err!(tcx.sess, span, E0049, - "method `{}` has {} but its trait declaration has {}", - trait_m.ident, - potentially_plural_count(num_impl_m_type_params, "type parameter"), - potentially_plural_count(num_trait_m_type_params, "type parameter") - ); + let mut err_occurred = false; + for &(kind, trait_count, impl_count) in &matchings { + if impl_count != trait_count { + err_occurred = true; - let mut suffix = None; + let impl_node_id = tcx.hir().as_local_node_id(impl_.def_id).unwrap(); + let impl_item = tcx.hir().expect_impl_item(impl_node_id); + let span = if impl_item.generics.params.is_empty() + || impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374) + impl_span + } else { + impl_item.generics.span + }; - if let Some(span) = trait_item_span { - err.span_label(span, format!("expected {}", - potentially_plural_count(num_trait_m_type_params, "type parameter"))); - } else { - suffix = Some(format!(", expected {}", num_trait_m_type_params)); + let mut err = tcx.sess.struct_span_err_with_code( + span, + &format!( + "method `{}` has {} {kind} parameter{} but its trait \ + declaration has {} {kind} parameter{}", + trait_.ident, + impl_count, + if impl_count != 1 { "s" } else { "" }, + trait_count, + if trait_count != 1 { "s" } else { "" }, + kind = kind, + ), + DiagnosticId::Error("E0049".into()), + ); + + 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 { "" }) + ); + } else { + suffix = Some(format!(", expected {}", trait_count)); + } + + err.span_label( + span, + format!("found {} {} parameter{}{}", impl_count, kind, + if impl_count != 1 { "s" } else { "" }, + suffix.unwrap_or_else(|| String::new())), + ); + + err.emit(); } - - err.span_label(span, - format!("found {}{}", - potentially_plural_count(num_impl_m_type_params, "type parameter"), - suffix.as_ref().map(|s| &s[..]).unwrap_or(""))); - - err.emit(); - - return Err(ErrorReported); } - Ok(()) + if err_occurred { + Err(ErrorReported) + } else { + Ok(()) + } } fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -725,12 +748,12 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_m_generics = tcx.generics_of(trait_m.def_id); let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, }); let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| { match param.kind { GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None, } }); for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic))