]> git.lizzy.rs Git - rust.git/blob - src/librustc_typeck/check/compare_method.rs
Rollup merge of #62557 - taiki-e:typo, r=Centril
[rust.git] / src / librustc_typeck / check / compare_method.rs
1 use rustc::hir::{self, GenericParamKind, ImplItemKind, TraitItemKind};
2 use rustc::hir::def::{Res, DefKind};
3 use rustc::infer::{self, InferOk};
4 use rustc::ty::{self, TyCtxt, GenericParamDefKind};
5 use rustc::ty::util::ExplicitSelf;
6 use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
7 use rustc::ty::error::{ExpectedFound, TypeError};
8 use rustc::ty::subst::{Subst, InternalSubsts, SubstsRef};
9 use rustc::util::common::ErrorReported;
10 use errors::{Applicability, DiagnosticId};
11
12 use syntax_pos::Span;
13
14 use super::{Inherited, FnCtxt, potentially_plural_count};
15
16 /// Checks that a method from an impl conforms to the signature of
17 /// the same method as declared in the trait.
18 ///
19 /// # Parameters
20 ///
21 /// - `impl_m`: type of the method we are checking
22 /// - `impl_m_span`: span to use for reporting errors
23 /// - `trait_m`: the method in the trait
24 /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
25
26 pub fn compare_impl_method<'tcx>(
27     tcx: TyCtxt<'tcx>,
28     impl_m: &ty::AssocItem,
29     impl_m_span: Span,
30     trait_m: &ty::AssocItem,
31     impl_trait_ref: ty::TraitRef<'tcx>,
32     trait_item_span: Option<Span>,
33 ) {
34     debug!("compare_impl_method(impl_trait_ref={:?})",
35            impl_trait_ref);
36
37     let impl_m_span = tcx.sess.source_map().def_span(impl_m_span);
38
39     if let Err(ErrorReported) = compare_self_type(tcx,
40                                                   impl_m,
41                                                   impl_m_span,
42                                                   trait_m,
43                                                   impl_trait_ref) {
44         return;
45     }
46
47     if let Err(ErrorReported) = compare_number_of_generics(tcx,
48                                                            impl_m,
49                                                            impl_m_span,
50                                                            trait_m,
51                                                            trait_item_span) {
52         return;
53     }
54
55     if let Err(ErrorReported) = compare_number_of_method_arguments(tcx,
56                                                                    impl_m,
57                                                                    impl_m_span,
58                                                                    trait_m,
59                                                                    trait_item_span) {
60         return;
61     }
62
63     if let Err(ErrorReported) = compare_synthetic_generics(tcx,
64                                                            impl_m,
65                                                            trait_m) {
66         return;
67     }
68
69     if let Err(ErrorReported) = compare_predicate_entailment(tcx,
70                                                              impl_m,
71                                                              impl_m_span,
72                                                              trait_m,
73                                                              impl_trait_ref) {
74         return;
75     }
76 }
77
78 fn compare_predicate_entailment<'tcx>(
79     tcx: TyCtxt<'tcx>,
80     impl_m: &ty::AssocItem,
81     impl_m_span: Span,
82     trait_m: &ty::AssocItem,
83     impl_trait_ref: ty::TraitRef<'tcx>,
84 ) -> Result<(), ErrorReported> {
85     let trait_to_impl_substs = impl_trait_ref.substs;
86
87     // This node-id should be used for the `body_id` field on each
88     // `ObligationCause` (and the `FnCtxt`). This is what
89     // `regionck_item` expects.
90     let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap();
91
92     let cause = ObligationCause {
93         span: impl_m_span,
94         body_id: impl_m_hir_id,
95         code: ObligationCauseCode::CompareImplMethodObligation {
96             item_name: impl_m.ident.name,
97             impl_item_def_id: impl_m.def_id,
98             trait_item_def_id: trait_m.def_id,
99         },
100     };
101
102     // This code is best explained by example. Consider a trait:
103     //
104     //     trait Trait<'t,T> {
105     //          fn method<'a,M>(t: &'t T, m: &'a M) -> Self;
106     //     }
107     //
108     // And an impl:
109     //
110     //     impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
111     //          fn method<'b,N>(t: &'j &'i U, m: &'b N) -> Foo;
112     //     }
113     //
114     // We wish to decide if those two method types are compatible.
115     //
116     // We start out with trait_to_impl_substs, that maps the trait
117     // type parameters to impl type parameters. This is taken from the
118     // impl trait reference:
119     //
120     //     trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
121     //
122     // We create a mapping `dummy_substs` that maps from the impl type
123     // parameters to fresh types and regions. For type parameters,
124     // this is the identity transform, but we could as well use any
125     // placeholder types. For regions, we convert from bound to free
126     // regions (Note: but only early-bound regions, i.e., those
127     // declared on the impl or used in type parameter bounds).
128     //
129     //     impl_to_skol_substs = {'i => 'i0, U => U0, N => N0 }
130     //
131     // Now we can apply skol_substs to the type of the impl method
132     // to yield a new function type in terms of our fresh, placeholder
133     // types:
134     //
135     //     <'b> fn(t: &'i0 U0, m: &'b) -> Foo
136     //
137     // We now want to extract and substitute the type of the *trait*
138     // method and compare it. To do so, we must create a compound
139     // substitution by combining trait_to_impl_substs and
140     // impl_to_skol_substs, and also adding a mapping for the method
141     // type parameters. We extend the mapping to also include
142     // the method parameters.
143     //
144     //     trait_to_skol_substs = { T => &'i0 U0, Self => Foo, M => N0 }
145     //
146     // Applying this to the trait method type yields:
147     //
148     //     <'a> fn(t: &'i0 U0, m: &'a) -> Foo
149     //
150     // This type is also the same but the name of the bound region ('a
151     // vs 'b).  However, the normal subtyping rules on fn types handle
152     // this kind of equivalency just fine.
153     //
154     // We now use these substitutions to ensure that all declared bounds are
155     // satisfied by the implementation's method.
156     //
157     // We do this by creating a parameter environment which contains a
158     // substitution corresponding to impl_to_skol_substs. We then build
159     // trait_to_skol_substs and use it to convert the predicates contained
160     // in the trait_m.generics to the placeholder form.
161     //
162     // Finally we register each of these predicates as an obligation in
163     // a fresh FulfillmentCtxt, and invoke select_all_or_error.
164
165     // Create mapping from impl to placeholder.
166     let impl_to_skol_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
167
168     // Create mapping from trait to placeholder.
169     let trait_to_skol_substs = impl_to_skol_substs.rebase_onto(tcx,
170                                                                impl_m.container.id(),
171                                                                trait_to_impl_substs);
172     debug!("compare_impl_method: trait_to_skol_substs={:?}",
173            trait_to_skol_substs);
174
175     let impl_m_generics = tcx.generics_of(impl_m.def_id);
176     let trait_m_generics = tcx.generics_of(trait_m.def_id);
177     let impl_m_predicates = tcx.predicates_of(impl_m.def_id);
178     let trait_m_predicates = tcx.predicates_of(trait_m.def_id);
179
180     // Check region bounds.
181     check_region_bounds_on_impl_method(tcx,
182                                        impl_m_span,
183                                        impl_m,
184                                        trait_m,
185                                        &trait_m_generics,
186                                        &impl_m_generics,
187                                        trait_to_skol_substs)?;
188
189     // Create obligations for each predicate declared by the impl
190     // definition in the context of the trait's parameter
191     // environment. We can't just use `impl_env.caller_bounds`,
192     // however, because we want to replace all late-bound regions with
193     // region variables.
194     let impl_predicates = tcx.predicates_of(impl_m_predicates.parent.unwrap());
195     let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
196
197     debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
198
199     // This is the only tricky bit of the new way we check implementation methods
200     // We need to build a set of predicates where only the method-level bounds
201     // are from the trait and we assume all other bounds from the implementation
202     // to be previously satisfied.
203     //
204     // We then register the obligations from the impl_m and check to see
205     // if all constraints hold.
206     hybrid_preds.predicates.extend(
207         trait_m_predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
208
209     // Construct trait parameter environment and then shift it into the placeholder viewpoint.
210     // The key step here is to update the caller_bounds's predicates to be
211     // the new hybrid bounds we computed.
212     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id);
213     let param_env = ty::ParamEnv::new(
214         tcx.intern_predicates(&hybrid_preds.predicates),
215         Reveal::UserFacing,
216         None
217     );
218     let param_env = traits::normalize_param_env_or_error(tcx,
219                                                          impl_m.def_id,
220                                                          param_env,
221                                                          normalize_cause.clone());
222
223     tcx.infer_ctxt().enter(|infcx| {
224         let inh = Inherited::new(infcx, impl_m.def_id);
225         let infcx = &inh.infcx;
226
227         debug!("compare_impl_method: caller_bounds={:?}",
228                param_env.caller_bounds);
229
230         let mut selcx = traits::SelectionContext::new(&infcx);
231
232         let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs);
233         let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars(
234             impl_m_span,
235             infer::HigherRankedType,
236             &ty::Binder::bind(impl_m_own_bounds.predicates)
237         );
238         for predicate in impl_m_own_bounds {
239             let traits::Normalized { value: predicate, obligations } =
240                 traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate);
241
242             inh.register_predicates(obligations);
243             inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
244         }
245
246         // We now need to check that the signature of the impl method is
247         // compatible with that of the trait method. We do this by
248         // checking that `impl_fty <: trait_fty`.
249         //
250         // FIXME. Unfortunately, this doesn't quite work right now because
251         // associated type normalization is not integrated into subtype
252         // checks. For the comparison to be valid, we need to
253         // normalize the associated types in the impl/trait methods
254         // first. However, because function types bind regions, just
255         // calling `normalize_associated_types_in` would have no effect on
256         // any associated types appearing in the fn arguments or return
257         // type.
258
259         // Compute placeholder form of impl and trait method tys.
260         let tcx = infcx.tcx;
261
262         let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
263             impl_m_span,
264             infer::HigherRankedType,
265             &tcx.fn_sig(impl_m.def_id)
266         );
267         let impl_sig =
268             inh.normalize_associated_types_in(impl_m_span,
269                                               impl_m_hir_id,
270                                               param_env,
271                                               &impl_sig);
272         let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig));
273         debug!("compare_impl_method: impl_fty={:?}", impl_fty);
274
275         let trait_sig = tcx.liberate_late_bound_regions(
276             impl_m.def_id,
277             &tcx.fn_sig(trait_m.def_id));
278         let trait_sig =
279             trait_sig.subst(tcx, trait_to_skol_substs);
280         let trait_sig =
281             inh.normalize_associated_types_in(impl_m_span,
282                                               impl_m_hir_id,
283                                               param_env,
284                                               &trait_sig);
285         let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig));
286
287         debug!("compare_impl_method: trait_fty={:?}", trait_fty);
288
289         let sub_result = infcx.at(&cause, param_env)
290                               .sup(trait_fty, impl_fty)
291                               .map(|InferOk { obligations, .. }| {
292                                   inh.register_predicates(obligations);
293                               });
294
295         if let Err(terr) = sub_result {
296             debug!("sub_types failed: impl ty {:?}, trait ty {:?}",
297                    impl_fty,
298                    trait_fty);
299
300             let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
301                                                                                     param_env,
302                                                                                     &terr,
303                                                                                     &cause,
304                                                                                     impl_m,
305                                                                                     impl_sig,
306                                                                                     trait_m,
307                                                                                     trait_sig);
308
309             let cause = ObligationCause {
310                 span: impl_err_span,
311                 ..cause.clone()
312             };
313
314             let mut diag = struct_span_err!(tcx.sess,
315                                             cause.span(tcx),
316                                             E0053,
317                                             "method `{}` has an incompatible type for trait",
318                                             trait_m.ident);
319             if let TypeError::Mutability = terr {
320                 if let Some(trait_err_span) = trait_err_span {
321                     if let Ok(trait_err_str) = tcx.sess.source_map()
322                                                        .span_to_snippet(trait_err_span) {
323                         diag.span_suggestion(
324                             impl_err_span,
325                             "consider change the type to match the mutability in trait",
326                             trait_err_str,
327                             Applicability::MachineApplicable,
328                         );
329                     }
330                 }
331             }
332
333             infcx.note_type_err(&mut diag,
334                                 &cause,
335                                 trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
336                                 Some(infer::ValuePairs::Types(ExpectedFound {
337                                     expected: trait_fty,
338                                     found: impl_fty,
339                                 })),
340                                 &terr);
341             diag.emit();
342             return Err(ErrorReported);
343         }
344
345         // Check that all obligations are satisfied by the implementation's
346         // version.
347         if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
348             infcx.report_fulfillment_errors(errors, None, false);
349             return Err(ErrorReported);
350         }
351
352         // Finally, resolve all regions. This catches wily misuses of
353         // lifetime parameters.
354         let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
355         fcx.regionck_item(impl_m_hir_id, impl_m_span, &[]);
356
357         Ok(())
358     })
359 }
360
361 fn check_region_bounds_on_impl_method<'tcx>(
362     tcx: TyCtxt<'tcx>,
363     span: Span,
364     impl_m: &ty::AssocItem,
365     trait_m: &ty::AssocItem,
366     trait_generics: &ty::Generics,
367     impl_generics: &ty::Generics,
368     trait_to_skol_substs: SubstsRef<'tcx>,
369 ) -> Result<(), ErrorReported> {
370     let trait_params = trait_generics.own_counts().lifetimes;
371     let impl_params = impl_generics.own_counts().lifetimes;
372
373     debug!("check_region_bounds_on_impl_method: \
374             trait_generics={:?} \
375             impl_generics={:?} \
376             trait_to_skol_substs={:?}",
377            trait_generics,
378            impl_generics,
379            trait_to_skol_substs);
380
381     // Must have same number of early-bound lifetime parameters.
382     // Unfortunately, if the user screws up the bounds, then this
383     // will change classification between early and late.  E.g.,
384     // if in trait we have `<'a,'b:'a>`, and in impl we just have
385     // `<'a,'b>`, then we have 2 early-bound lifetime parameters
386     // in trait but 0 in the impl. But if we report "expected 2
387     // but found 0" it's confusing, because it looks like there
388     // are zero. Since I don't quite know how to phrase things at
389     // the moment, give a kind of vague error message.
390     if trait_params != impl_params {
391         let def_span = tcx.sess.source_map().def_span(span);
392         let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span);
393         let mut err = struct_span_err!(
394             tcx.sess,
395             span,
396             E0195,
397             "lifetime parameters or bounds on method `{}` do not match the trait declaration",
398             impl_m.ident,
399         );
400         err.span_label(span, "lifetimes do not match method in trait");
401         if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) {
402             let def_sp = tcx.sess.source_map().def_span(sp);
403             let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp);
404             err.span_label(sp, "lifetimes in impl do not match this method in trait");
405         }
406         err.emit();
407         return Err(ErrorReported);
408     }
409
410     Ok(())
411 }
412
413 fn extract_spans_for_error_reporting<'a, 'tcx>(
414     infcx: &infer::InferCtxt<'a, 'tcx>,
415     param_env: ty::ParamEnv<'tcx>,
416     terr: &TypeError<'_>,
417     cause: &ObligationCause<'tcx>,
418     impl_m: &ty::AssocItem,
419     impl_sig: ty::FnSig<'tcx>,
420     trait_m: &ty::AssocItem,
421     trait_sig: ty::FnSig<'tcx>,
422 ) -> (Span, Option<Span>) {
423     let tcx = infcx.tcx;
424     let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap();
425     let (impl_m_output, impl_m_iter) = match tcx.hir()
426                                                 .expect_impl_item(impl_m_hir_id)
427                                                 .node {
428         ImplItemKind::Method(ref impl_m_sig, _) => {
429             (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
430         }
431         _ => bug!("{:?} is not a method", impl_m),
432     };
433
434     match *terr {
435         TypeError::Mutability => {
436             if let Some(trait_m_hir_id) = tcx.hir().as_local_hir_id(trait_m.def_id) {
437                 let trait_m_iter = match tcx.hir()
438                                             .expect_trait_item(trait_m_hir_id)
439                                             .node {
440                     TraitItemKind::Method(ref trait_m_sig, _) => {
441                         trait_m_sig.decl.inputs.iter()
442                     }
443                     _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
444                 };
445
446                 impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
447                     match (&impl_arg.node, &trait_arg.node) {
448                         (&hir::TyKind::Rptr(_, ref impl_mt), &hir::TyKind::Rptr(_, ref trait_mt)) |
449                         (&hir::TyKind::Ptr(ref impl_mt), &hir::TyKind::Ptr(ref trait_mt)) => {
450                             impl_mt.mutbl != trait_mt.mutbl
451                         }
452                         _ => false,
453                     }
454                 }).map(|(ref impl_arg, ref trait_arg)| {
455                     (impl_arg.span, Some(trait_arg.span))
456                 })
457                 .unwrap_or_else(|| (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)))
458             } else {
459                 (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
460             }
461         }
462         TypeError::Sorts(ExpectedFound { .. }) => {
463             if let Some(trait_m_hir_id) = tcx.hir().as_local_hir_id(trait_m.def_id) {
464                 let (trait_m_output, trait_m_iter) =
465                     match tcx.hir().expect_trait_item(trait_m_hir_id).node {
466                         TraitItemKind::Method(ref trait_m_sig, _) => {
467                             (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
468                         }
469                         _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
470                     };
471
472                 let impl_iter = impl_sig.inputs().iter();
473                 let trait_iter = trait_sig.inputs().iter();
474                 impl_iter.zip(trait_iter)
475                          .zip(impl_m_iter)
476                          .zip(trait_m_iter)
477                          .filter_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)|
478                              match infcx.at(&cause, param_env).sub(trait_arg_ty, impl_arg_ty) {
479                                  Ok(_) => None,
480                                  Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
481                              }
482                          )
483                          .next()
484                          .unwrap_or_else(||
485                              if
486                                  infcx.at(&cause, param_env)
487                                       .sup(trait_sig.output(), impl_sig.output())
488                                       .is_err()
489                              {
490                                  (impl_m_output.span(), Some(trait_m_output.span()))
491                              } else {
492                                  (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
493                              }
494                          )
495             } else {
496                 (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id))
497             }
498         }
499         _ => (cause.span(tcx), tcx.hir().span_if_local(trait_m.def_id)),
500     }
501 }
502
503 fn compare_self_type<'tcx>(
504     tcx: TyCtxt<'tcx>,
505     impl_m: &ty::AssocItem,
506     impl_m_span: Span,
507     trait_m: &ty::AssocItem,
508     impl_trait_ref: ty::TraitRef<'tcx>,
509 ) -> Result<(), ErrorReported> {
510     // Try to give more informative error messages about self typing
511     // mismatches.  Note that any mismatch will also be detected
512     // below, where we construct a canonical function type that
513     // includes the self parameter as a normal parameter.  It's just
514     // that the error messages you get out of this code are a bit more
515     // inscrutable, particularly for cases where one method has no
516     // self.
517
518     let self_string = |method: &ty::AssocItem| {
519         let untransformed_self_ty = match method.container {
520             ty::ImplContainer(_) => impl_trait_ref.self_ty(),
521             ty::TraitContainer(_) => tcx.mk_self_type()
522         };
523         let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
524         let param_env = ty::ParamEnv::reveal_all();
525
526         tcx.infer_ctxt().enter(|infcx| {
527             let self_arg_ty = tcx.liberate_late_bound_regions(
528                 method.def_id,
529                 &ty::Binder::bind(self_arg_ty)
530             );
531             let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok();
532             match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
533                 ExplicitSelf::ByValue => "self".to_owned(),
534                 ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_owned(),
535                 ExplicitSelf::ByReference(_, hir::MutMutable) => "&mut self".to_owned(),
536                 _ => format!("self: {}", self_arg_ty)
537             }
538         })
539     };
540
541     match (trait_m.method_has_self_argument, impl_m.method_has_self_argument) {
542         (false, false) | (true, true) => {}
543
544         (false, true) => {
545             let self_descr = self_string(impl_m);
546             let mut err = struct_span_err!(tcx.sess,
547                                            impl_m_span,
548                                            E0185,
549                                            "method `{}` has a `{}` declaration in the impl, but \
550                                             not in the trait",
551                                            trait_m.ident,
552                                            self_descr);
553             err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
554             if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
555                 err.span_label(span, format!("trait method declared without `{}`", self_descr));
556             } else {
557                 err.note_trait_signature(trait_m.ident.to_string(),
558                                          trait_m.signature(tcx));
559             }
560             err.emit();
561             return Err(ErrorReported);
562         }
563
564         (true, false) => {
565             let self_descr = self_string(trait_m);
566             let mut err = struct_span_err!(tcx.sess,
567                                            impl_m_span,
568                                            E0186,
569                                            "method `{}` has a `{}` declaration in the trait, but \
570                                             not in the impl",
571                                            trait_m.ident,
572                                            self_descr);
573             err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
574             if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
575                 err.span_label(span, format!("`{}` used in trait", self_descr));
576             } else {
577                 err.note_trait_signature(trait_m.ident.to_string(),
578                                          trait_m.signature(tcx));
579             }
580             err.emit();
581             return Err(ErrorReported);
582         }
583     }
584
585     Ok(())
586 }
587
588 fn compare_number_of_generics<'tcx>(
589     tcx: TyCtxt<'tcx>,
590     impl_: &ty::AssocItem,
591     _impl_span: Span,
592     trait_: &ty::AssocItem,
593     trait_span: Option<Span>,
594 ) -> Result<(), ErrorReported> {
595     let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
596     let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
597
598     let matchings = [
599         ("type", trait_own_counts.types, impl_own_counts.types),
600         ("const", trait_own_counts.consts, impl_own_counts.consts),
601     ];
602
603     let mut err_occurred = false;
604     for &(kind, trait_count, impl_count) in &matchings {
605         if impl_count != trait_count {
606             err_occurred = true;
607
608             let (
609                 trait_spans,
610                 impl_trait_spans,
611             ) = if let Some(trait_hir_id) = tcx.hir().as_local_hir_id(trait_.def_id) {
612                 let trait_item = tcx.hir().expect_trait_item(trait_hir_id);
613                 if trait_item.generics.params.is_empty() {
614                     (Some(vec![trait_item.generics.span]), vec![])
615                 } else {
616                     let arg_spans: Vec<Span> = trait_item.generics.params.iter()
617                         .map(|p| p.span)
618                         .collect();
619                     let impl_trait_spans: Vec<Span> = trait_item.generics.params.iter()
620                         .filter_map(|p| match p.kind {
621                             GenericParamKind::Type {
622                                 synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
623                             } => Some(p.span),
624                             _ => None,
625                         }).collect();
626                     (Some(arg_spans), impl_trait_spans)
627                 }
628             } else {
629                 (trait_span.map(|s| vec![s]), vec![])
630             };
631
632             let impl_hir_id = tcx.hir().as_local_hir_id(impl_.def_id).unwrap();
633             let impl_item = tcx.hir().expect_impl_item(impl_hir_id);
634             let impl_item_impl_trait_spans: Vec<Span> = impl_item.generics.params.iter()
635                 .filter_map(|p| match p.kind {
636                     GenericParamKind::Type {
637                         synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), ..
638                     } => Some(p.span),
639                     _ => None,
640                 }).collect();
641             let spans = impl_item.generics.spans();
642             let span = spans.primary_span();
643
644             let mut err = tcx.sess.struct_span_err_with_code(
645                 spans,
646                 &format!(
647                     "method `{}` has {} {kind} parameter{} but its trait \
648                      declaration has {} {kind} parameter{}",
649                     trait_.ident,
650                     impl_count,
651                     if impl_count != 1 { "s" } else { "" },
652                     trait_count,
653                     if trait_count != 1 { "s" } else { "" },
654                     kind = kind,
655                 ),
656                 DiagnosticId::Error("E0049".into()),
657             );
658
659             let mut suffix = None;
660
661             if let Some(spans) = trait_spans {
662                 let mut spans = spans.iter();
663                 if let Some(span) = spans.next() {
664                     err.span_label(*span, format!(
665                         "expected {} {} parameter{}",
666                         trait_count,
667                         kind,
668                         if trait_count != 1 { "s" } else { "" },
669                     ));
670                 }
671                 for span in spans {
672                     err.span_label(*span, "");
673                 }
674             } else {
675                 suffix = Some(format!(", expected {}", trait_count));
676             }
677
678             if let Some(span) = span {
679                 err.span_label(span, format!(
680                     "found {} {} parameter{}{}",
681                     impl_count,
682                     kind,
683                     if impl_count != 1 { "s" } else { "" },
684                     suffix.unwrap_or_else(|| String::new()),
685                 ));
686             }
687
688             for span in impl_trait_spans.iter().chain(impl_item_impl_trait_spans.iter()) {
689                 err.span_label(*span, "`impl Trait` introduces an implicit type parameter");
690             }
691
692             err.emit();
693         }
694     }
695
696     if err_occurred {
697         Err(ErrorReported)
698     } else {
699         Ok(())
700     }
701 }
702
703 fn compare_number_of_method_arguments<'tcx>(
704     tcx: TyCtxt<'tcx>,
705     impl_m: &ty::AssocItem,
706     impl_m_span: Span,
707     trait_m: &ty::AssocItem,
708     trait_item_span: Option<Span>,
709 ) -> Result<(), ErrorReported> {
710     let impl_m_fty = tcx.fn_sig(impl_m.def_id);
711     let trait_m_fty = tcx.fn_sig(trait_m.def_id);
712     let trait_number_args = trait_m_fty.inputs().skip_binder().len();
713     let impl_number_args = impl_m_fty.inputs().skip_binder().len();
714     if trait_number_args != impl_number_args {
715         let trait_m_hir_id = tcx.hir().as_local_hir_id(trait_m.def_id);
716         let trait_span = if let Some(trait_id) = trait_m_hir_id {
717             match tcx.hir().expect_trait_item(trait_id).node {
718                 TraitItemKind::Method(ref trait_m_sig, _) => {
719                     let pos = if trait_number_args > 0 {
720                         trait_number_args - 1
721                     } else {
722                         0
723                     };
724                     if let Some(arg) = trait_m_sig.decl.inputs.get(pos) {
725                         Some(if pos == 0 {
726                             arg.span
727                         } else {
728                             Span::new(trait_m_sig.decl.inputs[0].span.lo(),
729                                       arg.span.hi(),
730                                       arg.span.ctxt())
731                         })
732                     } else {
733                         trait_item_span
734                     }
735                 }
736                 _ => bug!("{:?} is not a method", impl_m),
737             }
738         } else {
739             trait_item_span
740         };
741         let impl_m_hir_id = tcx.hir().as_local_hir_id(impl_m.def_id).unwrap();
742         let impl_span = match tcx.hir().expect_impl_item(impl_m_hir_id).node {
743             ImplItemKind::Method(ref impl_m_sig, _) => {
744                 let pos = if impl_number_args > 0 {
745                     impl_number_args - 1
746                 } else {
747                     0
748                 };
749                 if let Some(arg) = impl_m_sig.decl.inputs.get(pos) {
750                     if pos == 0 {
751                         arg.span
752                     } else {
753                         Span::new(impl_m_sig.decl.inputs[0].span.lo(),
754                                   arg.span.hi(),
755                                   arg.span.ctxt())
756                     }
757                 } else {
758                     impl_m_span
759                 }
760             }
761             _ => bug!("{:?} is not a method", impl_m),
762         };
763         let mut err = struct_span_err!(tcx.sess,
764                                        impl_span,
765                                        E0050,
766                                        "method `{}` has {} but the declaration in \
767                                         trait `{}` has {}",
768                                        trait_m.ident,
769                                        potentially_plural_count(impl_number_args, "parameter"),
770                                        tcx.def_path_str(trait_m.def_id),
771                                        trait_number_args);
772         if let Some(trait_span) = trait_span {
773             err.span_label(trait_span, format!("trait requires {}",
774                 potentially_plural_count(trait_number_args, "parameter")));
775         } else {
776             err.note_trait_signature(trait_m.ident.to_string(),
777                                      trait_m.signature(tcx));
778         }
779         err.span_label(impl_span, format!("expected {}, found {}",
780             potentially_plural_count(trait_number_args, "parameter"), impl_number_args));
781         err.emit();
782         return Err(ErrorReported);
783     }
784
785     Ok(())
786 }
787
788 fn compare_synthetic_generics<'tcx>(
789     tcx: TyCtxt<'tcx>,
790     impl_m: &ty::AssocItem,
791     trait_m: &ty::AssocItem,
792 ) -> Result<(), ErrorReported> {
793     // FIXME(chrisvittal) Clean up this function, list of FIXME items:
794     //     1. Better messages for the span labels
795     //     2. Explanation as to what is going on
796     // If we get here, we already have the same number of generics, so the zip will
797     // be okay.
798     let mut error_found = false;
799     let impl_m_generics = tcx.generics_of(impl_m.def_id);
800     let trait_m_generics = tcx.generics_of(trait_m.def_id);
801     let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
802         GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
803         GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
804     });
805     let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| {
806         match param.kind {
807             GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
808             GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
809         }
810     });
811     for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic))
812         in impl_m_type_params.zip(trait_m_type_params)
813     {
814         if impl_synthetic != trait_synthetic {
815             let impl_hir_id = tcx.hir().as_local_hir_id(impl_def_id).unwrap();
816             let impl_span = tcx.hir().span(impl_hir_id);
817             let trait_span = tcx.def_span(trait_def_id);
818             let mut err = struct_span_err!(tcx.sess,
819                                            impl_span,
820                                            E0643,
821                                            "method `{}` has incompatible signature for trait",
822                                            trait_m.ident);
823             err.span_label(trait_span, "declaration in trait here");
824             match (impl_synthetic, trait_synthetic) {
825                 // The case where the impl method uses `impl Trait` but the trait method uses
826                 // explicit generics
827                 (Some(hir::SyntheticTyParamKind::ImplTrait), None) => {
828                     err.span_label(impl_span, "expected generic parameter, found `impl Trait`");
829                     (|| {
830                         // try taking the name from the trait impl
831                         // FIXME: this is obviously suboptimal since the name can already be used
832                         // as another generic argument
833                         let new_name = tcx
834                             .sess
835                             .source_map()
836                             .span_to_snippet(trait_span)
837                             .ok()?;
838                         let trait_m = tcx.hir().as_local_hir_id(trait_m.def_id)?;
839                         let trait_m = tcx.hir().trait_item(hir::TraitItemId { hir_id: trait_m });
840
841                         let impl_m = tcx.hir().as_local_hir_id(impl_m.def_id)?;
842                         let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m });
843
844                         // in case there are no generics, take the spot between the function name
845                         // and the opening paren of the argument list
846                         let new_generics_span = tcx
847                             .sess
848                             .source_map()
849                             .generate_fn_name_span(impl_span)?
850                             .shrink_to_hi();
851                         // in case there are generics, just replace them
852                         let generics_span = impl_m
853                             .generics
854                             .span
855                             .substitute_dummy(new_generics_span);
856                         // replace with the generics from the trait
857                         let new_generics = tcx
858                             .sess
859                             .source_map()
860                             .span_to_snippet(trait_m.generics.span)
861                             .ok()?;
862
863                         err.multipart_suggestion(
864                             "try changing the `impl Trait` argument to a generic parameter",
865                             vec![
866                                 // replace `impl Trait` with `T`
867                                 (impl_span, new_name),
868                                 // replace impl method generics with trait method generics
869                                 // This isn't quite right, as users might have changed the names
870                                 // of the generics, but it works for the common case
871                                 (generics_span, new_generics),
872                             ],
873                             Applicability::MaybeIncorrect,
874                         );
875                         Some(())
876                     })();
877                 },
878                 // The case where the trait method uses `impl Trait`, but the impl method uses
879                 // explicit generics.
880                 (None, Some(hir::SyntheticTyParamKind::ImplTrait)) => {
881                     err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
882                     (|| {
883                         let impl_m = tcx.hir().as_local_hir_id(impl_m.def_id)?;
884                         let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m });
885                         let input_tys = match impl_m.node {
886                             hir::ImplItemKind::Method(ref sig, _) => &sig.decl.inputs,
887                             _ => unreachable!(),
888                         };
889                         struct Visitor(Option<Span>, hir::def_id::DefId);
890                         impl<'v> hir::intravisit::Visitor<'v> for Visitor {
891                             fn visit_ty(&mut self, ty: &'v hir::Ty) {
892                                 hir::intravisit::walk_ty(self, ty);
893                                 if let hir::TyKind::Path(
894                                     hir::QPath::Resolved(None, ref path)) = ty.node
895                                 {
896                                     if let Res::Def(DefKind::TyParam, def_id) = path.res {
897                                         if def_id == self.1 {
898                                             self.0 = Some(ty.span);
899                                         }
900                                     }
901                                 }
902                             }
903                             fn nested_visit_map<'this>(
904                                 &'this mut self
905                             ) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
906                                 hir::intravisit::NestedVisitorMap::None
907                             }
908                         }
909                         let mut visitor = Visitor(None, impl_def_id);
910                         for ty in input_tys {
911                             hir::intravisit::Visitor::visit_ty(&mut visitor, ty);
912                         }
913                         let span = visitor.0?;
914
915                         let bounds = impl_m.generics.params.iter().find_map(|param| {
916                             match param.kind {
917                                 GenericParamKind::Lifetime { .. } => None,
918                                 GenericParamKind::Type { .. } |
919                                 GenericParamKind::Const { .. } => {
920                                     if param.hir_id == impl_hir_id {
921                                         Some(&param.bounds)
922                                     } else {
923                                         None
924                                     }
925                                 }
926                             }
927                         })?;
928                         let bounds = bounds.first()?.span().to(bounds.last()?.span());
929                         let bounds = tcx
930                             .sess
931                             .source_map()
932                             .span_to_snippet(bounds)
933                             .ok()?;
934
935                         err.multipart_suggestion(
936                             "try removing the generic parameter and using `impl Trait` instead",
937                             vec![
938                                 // delete generic parameters
939                                 (impl_m.generics.span, String::new()),
940                                 // replace param usage with `impl Trait`
941                                 (span, format!("impl {}", bounds)),
942                             ],
943                             Applicability::MaybeIncorrect,
944                         );
945                         Some(())
946                     })();
947                 },
948                 _ => unreachable!(),
949             }
950             err.emit();
951             error_found = true;
952         }
953     }
954     if error_found {
955         Err(ErrorReported)
956     } else {
957         Ok(())
958     }
959 }
960
961 pub fn compare_const_impl<'tcx>(
962     tcx: TyCtxt<'tcx>,
963     impl_c: &ty::AssocItem,
964     impl_c_span: Span,
965     trait_c: &ty::AssocItem,
966     impl_trait_ref: ty::TraitRef<'tcx>,
967 ) {
968     debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
969
970     tcx.infer_ctxt().enter(|infcx| {
971         let param_env = tcx.param_env(impl_c.def_id);
972         let inh = Inherited::new(infcx, impl_c.def_id);
973         let infcx = &inh.infcx;
974
975         // The below is for the most part highly similar to the procedure
976         // for methods above. It is simpler in many respects, especially
977         // because we shouldn't really have to deal with lifetimes or
978         // predicates. In fact some of this should probably be put into
979         // shared functions because of DRY violations...
980         let trait_to_impl_substs = impl_trait_ref.substs;
981
982         // Create a parameter environment that represents the implementation's
983         // method.
984         let impl_c_hir_id = tcx.hir().as_local_hir_id(impl_c.def_id).unwrap();
985
986         // Compute placeholder form of impl and trait const tys.
987         let impl_ty = tcx.type_of(impl_c.def_id);
988         let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs);
989         let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id);
990
991         // There is no "body" here, so just pass dummy id.
992         let impl_ty = inh.normalize_associated_types_in(impl_c_span,
993                                                         impl_c_hir_id,
994                                                         param_env,
995                                                         &impl_ty);
996
997         debug!("compare_const_impl: impl_ty={:?}", impl_ty);
998
999         let trait_ty = inh.normalize_associated_types_in(impl_c_span,
1000                                                          impl_c_hir_id,
1001                                                          param_env,
1002                                                          &trait_ty);
1003
1004         debug!("compare_const_impl: trait_ty={:?}", trait_ty);
1005
1006         let err = infcx.at(&cause, param_env)
1007                        .sup(trait_ty, impl_ty)
1008                        .map(|ok| inh.register_infer_ok_obligations(ok));
1009
1010         if let Err(terr) = err {
1011             debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
1012                    impl_ty,
1013                    trait_ty);
1014
1015             // Locate the Span containing just the type of the offending impl
1016             match tcx.hir().expect_impl_item(impl_c_hir_id).node {
1017                 ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
1018                 _ => bug!("{:?} is not a impl const", impl_c),
1019             }
1020
1021             let mut diag = struct_span_err!(tcx.sess,
1022                                             cause.span,
1023                                             E0326,
1024                                             "implemented const `{}` has an incompatible type for \
1025                                              trait",
1026                                             trait_c.ident);
1027
1028             let trait_c_hir_id = tcx.hir().as_local_hir_id(trait_c.def_id);
1029             let trait_c_span = trait_c_hir_id.map(|trait_c_hir_id| {
1030                 // Add a label to the Span containing just the type of the const
1031                 match tcx.hir().expect_trait_item(trait_c_hir_id).node {
1032                     TraitItemKind::Const(ref ty, _) => ty.span,
1033                     _ => bug!("{:?} is not a trait const", trait_c),
1034                 }
1035             });
1036
1037             infcx.note_type_err(&mut diag,
1038                                 &cause,
1039                                 trait_c_span.map(|span| (span, "type in trait".to_owned())),
1040                                 Some(infer::ValuePairs::Types(ExpectedFound {
1041                                     expected: trait_ty,
1042                                     found: impl_ty,
1043                                 })),
1044                                 &terr);
1045             diag.emit();
1046         }
1047
1048         // Check that all obligations are satisfied by the implementation's
1049         // version.
1050         if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
1051             infcx.report_fulfillment_errors(errors, None, false);
1052             return;
1053         }
1054
1055         let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id);
1056         fcx.regionck_item(impl_c_hir_id, impl_c_span, &[]);
1057     });
1058 }