From 225955ab71942109cc618290d439ff40ca4f9684 Mon Sep 17 00:00:00 2001 From: Christopher Vittal Date: Sun, 5 Nov 2017 16:18:13 -0500 Subject: [PATCH] Detect mismatch of impl Trait and Generics Add a function to detect the distinction between the following code ``` trait Foo { fn bar(&self, &impl Debug); } impl Foo for () { fn bar(&self, _: U) { } } ``` What is still left to do is add a new error code and explanation, and clean up extraneous function arguments. --- src/librustc_typeck/check/compare_method.rs | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index b21d48886120c..849b307f55f59 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -67,6 +67,14 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } + if let Err(ErrorReported) = compare_synthetic_generics(tcx, + impl_m, + impl_m_span, + trait_m, + trait_item_span) { + return; + } + if let Err(ErrorReported) = compare_predicate_entailment(tcx, impl_m, impl_m_span, @@ -321,6 +329,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, found: impl_fty, })), &terr); + // FIXME(chrisvittal) do not emit this error if we already have an error on the + // return value of the trait diag.emit(); return Err(ErrorReported); } @@ -707,6 +717,46 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Ok(()) } +fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + impl_m: &ty::AssociatedItem, + _impl_m_span: Span, // FIXME necessary? + trait_m: &ty::AssociatedItem, + _trait_item_span: Option) // FIXME necessary? + -> Result<(), ErrorReported> { + // FIXME(chrisvittal) Clean up this function, list of FIXME items: + // 1. New error code + // 2. Better messages for the span lables + // 3. Explination as to what is going on + // 4. Correct the function signature for what we actually use + // If we get here, we already have the same number of generics, so the zip will + // be okay. + let mut error_found = false; + let impl_m_generics = tcx.generics_of(impl_m.def_id); + let trait_m_generics = tcx.generics_of(trait_m.def_id); + for (impl_ty, trait_ty) in impl_m_generics.types.iter().zip(trait_m_generics.types.iter()) { + if impl_ty.synthetic != trait_ty.synthetic { + let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap(); + let impl_span = tcx.hir.span(impl_node_id); + let trait_node_id = tcx.hir.as_local_node_id(trait_ty.def_id).unwrap(); + let trait_span = tcx.hir.span(trait_node_id); + let mut err = struct_span_err!(tcx.sess, + impl_span, + E0053, + "method `{}` has incompatible signature for trait", + trait_m.name); + err.span_label(trait_span, "Annotation in trait"); + err.span_label(impl_span, "Annotation in impl"); + err.emit(); + error_found = true; + } + } + if error_found { + Err(ErrorReported) + } else { + Ok(()) + } +} + pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_c: &ty::AssociatedItem, impl_c_span: Span,