1 use rustc_errors
::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}
;
3 use rustc_hir
::def
::{DefKind, Res}
;
4 use rustc_hir
::intravisit
;
5 use rustc_hir
::{GenericParamKind, ImplItemKind, TraitItemKind}
;
6 use rustc_infer
::infer
::{self, InferOk, TyCtxtInferExt}
;
8 use rustc_middle
::ty
::error
::{ExpectedFound, TypeError}
;
9 use rustc_middle
::ty
::subst
::{InternalSubsts, Subst}
;
10 use rustc_middle
::ty
::util
::ExplicitSelf
;
11 use rustc_middle
::ty
::{GenericParamDefKind, ToPredicate, TyCtxt}
;
13 use rustc_trait_selection
::traits
::error_reporting
::InferCtxtExt
;
14 use rustc_trait_selection
::traits
::{self, ObligationCause, ObligationCauseCode, Reveal}
;
16 use super::{potentially_plural_count, FnCtxt, Inherited}
;
18 /// Checks that a method from an impl conforms to the signature of
19 /// the same method as declared in the trait.
23 /// - `impl_m`: type of the method we are checking
24 /// - `impl_m_span`: span to use for reporting errors
25 /// - `trait_m`: the method in the trait
26 /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
28 crate fn compare_impl_method
<'tcx
>(
30 impl_m
: &ty
::AssocItem
,
32 trait_m
: &ty
::AssocItem
,
33 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
34 trait_item_span
: Option
<Span
>,
36 debug
!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref
);
38 let impl_m_span
= tcx
.sess
.source_map().guess_head_span(impl_m_span
);
40 if let Err(ErrorReported
) = compare_self_type(tcx
, impl_m
, impl_m_span
, trait_m
, impl_trait_ref
)
45 if let Err(ErrorReported
) =
46 compare_number_of_generics(tcx
, impl_m
, impl_m_span
, trait_m
, trait_item_span
)
51 if let Err(ErrorReported
) =
52 compare_number_of_method_arguments(tcx
, impl_m
, impl_m_span
, trait_m
, trait_item_span
)
57 if let Err(ErrorReported
) = compare_synthetic_generics(tcx
, impl_m
, trait_m
) {
61 if let Err(ErrorReported
) =
62 compare_predicate_entailment(tcx
, impl_m
, impl_m_span
, trait_m
, impl_trait_ref
)
68 fn compare_predicate_entailment
<'tcx
>(
70 impl_m
: &ty
::AssocItem
,
72 trait_m
: &ty
::AssocItem
,
73 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
74 ) -> Result
<(), ErrorReported
> {
75 let trait_to_impl_substs
= impl_trait_ref
.substs
;
77 // This node-id should be used for the `body_id` field on each
78 // `ObligationCause` (and the `FnCtxt`). This is what
79 // `regionck_item` expects.
80 let impl_m_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_m
.def_id
.expect_local());
82 // We sometimes modify the span further down.
83 let mut cause
= ObligationCause
::new(
86 ObligationCauseCode
::CompareImplMethodObligation
{
87 item_name
: impl_m
.ident
.name
,
88 impl_item_def_id
: impl_m
.def_id
,
89 trait_item_def_id
: trait_m
.def_id
,
93 // This code is best explained by example. Consider a trait:
95 // trait Trait<'t, T> {
96 // fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
101 // impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
102 // fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
105 // We wish to decide if those two method types are compatible.
107 // We start out with trait_to_impl_substs, that maps the trait
108 // type parameters to impl type parameters. This is taken from the
109 // impl trait reference:
111 // trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
113 // We create a mapping `dummy_substs` that maps from the impl type
114 // parameters to fresh types and regions. For type parameters,
115 // this is the identity transform, but we could as well use any
116 // placeholder types. For regions, we convert from bound to free
117 // regions (Note: but only early-bound regions, i.e., those
118 // declared on the impl or used in type parameter bounds).
120 // impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
122 // Now we can apply placeholder_substs to the type of the impl method
123 // to yield a new function type in terms of our fresh, placeholder
126 // <'b> fn(t: &'i0 U0, m: &'b) -> Foo
128 // We now want to extract and substitute the type of the *trait*
129 // method and compare it. To do so, we must create a compound
130 // substitution by combining trait_to_impl_substs and
131 // impl_to_placeholder_substs, and also adding a mapping for the method
132 // type parameters. We extend the mapping to also include
133 // the method parameters.
135 // trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
137 // Applying this to the trait method type yields:
139 // <'a> fn(t: &'i0 U0, m: &'a) -> Foo
141 // This type is also the same but the name of the bound region ('a
142 // vs 'b). However, the normal subtyping rules on fn types handle
143 // this kind of equivalency just fine.
145 // We now use these substitutions to ensure that all declared bounds are
146 // satisfied by the implementation's method.
148 // We do this by creating a parameter environment which contains a
149 // substitution corresponding to impl_to_placeholder_substs. We then build
150 // trait_to_placeholder_substs and use it to convert the predicates contained
151 // in the trait_m.generics to the placeholder form.
153 // Finally we register each of these predicates as an obligation in
154 // a fresh FulfillmentCtxt, and invoke select_all_or_error.
156 // Create mapping from impl to placeholder.
157 let impl_to_placeholder_substs
= InternalSubsts
::identity_for_item(tcx
, impl_m
.def_id
);
159 // Create mapping from trait to placeholder.
160 let trait_to_placeholder_substs
=
161 impl_to_placeholder_substs
.rebase_onto(tcx
, impl_m
.container
.id(), trait_to_impl_substs
);
162 debug
!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs
);
164 let impl_m_generics
= tcx
.generics_of(impl_m
.def_id
);
165 let trait_m_generics
= tcx
.generics_of(trait_m
.def_id
);
166 let impl_m_predicates
= tcx
.predicates_of(impl_m
.def_id
);
167 let trait_m_predicates
= tcx
.predicates_of(trait_m
.def_id
);
169 // Check region bounds.
170 check_region_bounds_on_impl_item(
179 // Create obligations for each predicate declared by the impl
180 // definition in the context of the trait's parameter
181 // environment. We can't just use `impl_env.caller_bounds`,
182 // however, because we want to replace all late-bound regions with
184 let impl_predicates
= tcx
.predicates_of(impl_m_predicates
.parent
.unwrap());
185 let mut hybrid_preds
= impl_predicates
.instantiate_identity(tcx
);
187 debug
!("compare_impl_method: impl_bounds={:?}", hybrid_preds
);
189 // This is the only tricky bit of the new way we check implementation methods
190 // We need to build a set of predicates where only the method-level bounds
191 // are from the trait and we assume all other bounds from the implementation
192 // to be previously satisfied.
194 // We then register the obligations from the impl_m and check to see
195 // if all constraints hold.
198 .extend(trait_m_predicates
.instantiate_own(tcx
, trait_to_placeholder_substs
).predicates
);
200 // Construct trait parameter environment and then shift it into the placeholder viewpoint.
201 // The key step here is to update the caller_bounds's predicates to be
202 // the new hybrid bounds we computed.
203 let normalize_cause
= traits
::ObligationCause
::misc(impl_m_span
, impl_m_hir_id
);
204 let param_env
= ty
::ParamEnv
::new(
205 tcx
.intern_predicates(&hybrid_preds
.predicates
),
209 let param_env
= traits
::normalize_param_env_or_error(
213 normalize_cause
.clone(),
216 tcx
.infer_ctxt().enter(|infcx
| {
217 let inh
= Inherited
::new(infcx
, impl_m
.def_id
.expect_local());
218 let infcx
= &inh
.infcx
;
220 debug
!("compare_impl_method: caller_bounds={:?}", param_env
.caller_bounds());
222 let mut selcx
= traits
::SelectionContext
::new(&infcx
);
224 let impl_m_own_bounds
= impl_m_predicates
.instantiate_own(tcx
, impl_to_placeholder_substs
);
225 let (impl_m_own_bounds
, _
) = infcx
.replace_bound_vars_with_fresh_vars(
227 infer
::HigherRankedType
,
228 &ty
::Binder
::bind(impl_m_own_bounds
.predicates
),
230 for predicate
in impl_m_own_bounds
{
231 let traits
::Normalized { value: predicate, obligations }
=
232 traits
::normalize(&mut selcx
, param_env
, normalize_cause
.clone(), &predicate
);
234 inh
.register_predicates(obligations
);
235 inh
.register_predicate(traits
::Obligation
::new(cause
.clone(), param_env
, predicate
));
238 // We now need to check that the signature of the impl method is
239 // compatible with that of the trait method. We do this by
240 // checking that `impl_fty <: trait_fty`.
242 // FIXME. Unfortunately, this doesn't quite work right now because
243 // associated type normalization is not integrated into subtype
244 // checks. For the comparison to be valid, we need to
245 // normalize the associated types in the impl/trait methods
246 // first. However, because function types bind regions, just
247 // calling `normalize_associated_types_in` would have no effect on
248 // any associated types appearing in the fn arguments or return
251 // Compute placeholder form of impl and trait method tys.
254 let (impl_sig
, _
) = infcx
.replace_bound_vars_with_fresh_vars(
256 infer
::HigherRankedType
,
257 &tcx
.fn_sig(impl_m
.def_id
),
260 inh
.normalize_associated_types_in(impl_m_span
, impl_m_hir_id
, param_env
, &impl_sig
);
261 let impl_fty
= tcx
.mk_fn_ptr(ty
::Binder
::bind(impl_sig
));
262 debug
!("compare_impl_method: impl_fty={:?}", impl_fty
);
264 let trait_sig
= tcx
.liberate_late_bound_regions(impl_m
.def_id
, &tcx
.fn_sig(trait_m
.def_id
));
265 let trait_sig
= trait_sig
.subst(tcx
, trait_to_placeholder_substs
);
267 inh
.normalize_associated_types_in(impl_m_span
, impl_m_hir_id
, param_env
, &trait_sig
);
268 let trait_fty
= tcx
.mk_fn_ptr(ty
::Binder
::bind(trait_sig
));
270 debug
!("compare_impl_method: trait_fty={:?}", trait_fty
);
272 let sub_result
= infcx
.at(&cause
, param_env
).sup(trait_fty
, impl_fty
).map(
273 |InferOk { obligations, .. }
| {
274 inh
.register_predicates(obligations
);
278 if let Err(terr
) = sub_result
{
279 debug
!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty
, trait_fty
);
281 let (impl_err_span
, trait_err_span
) = extract_spans_for_error_reporting(
282 &infcx
, param_env
, &terr
, &cause
, impl_m
, impl_sig
, trait_m
, trait_sig
,
285 cause
.make_mut().span
= impl_err_span
;
287 let mut diag
= struct_span_err
!(
291 "method `{}` has an incompatible type for trait",
294 if let TypeError
::Mutability
= terr
{
295 if let Some(trait_err_span
) = trait_err_span
{
296 if let Ok(trait_err_str
) = tcx
.sess
.source_map().span_to_snippet(trait_err_span
)
298 diag
.span_suggestion(
300 "consider change the type to match the mutability in trait",
302 Applicability
::MachineApplicable
,
311 trait_err_span
.map(|sp
| (sp
, "type in trait".to_owned())),
312 Some(infer
::ValuePairs
::Types(ExpectedFound
{
319 return Err(ErrorReported
);
322 // Check that all obligations are satisfied by the implementation's
324 if let Err(ref errors
) = inh
.fulfillment_cx
.borrow_mut().select_all_or_error(&infcx
) {
325 infcx
.report_fulfillment_errors(errors
, None
, false);
326 return Err(ErrorReported
);
329 // Finally, resolve all regions. This catches wily misuses of
330 // lifetime parameters.
331 let fcx
= FnCtxt
::new(&inh
, param_env
, impl_m_hir_id
);
332 fcx
.regionck_item(impl_m_hir_id
, impl_m_span
, &[]);
338 fn check_region_bounds_on_impl_item
<'tcx
>(
341 impl_m
: &ty
::AssocItem
,
342 trait_m
: &ty
::AssocItem
,
343 trait_generics
: &ty
::Generics
,
344 impl_generics
: &ty
::Generics
,
345 ) -> Result
<(), ErrorReported
> {
346 let trait_params
= trait_generics
.own_counts().lifetimes
;
347 let impl_params
= impl_generics
.own_counts().lifetimes
;
350 "check_region_bounds_on_impl_item: \
351 trait_generics={:?} \
353 trait_generics
, impl_generics
356 // Must have same number of early-bound lifetime parameters.
357 // Unfortunately, if the user screws up the bounds, then this
358 // will change classification between early and late. E.g.,
359 // if in trait we have `<'a,'b:'a>`, and in impl we just have
360 // `<'a,'b>`, then we have 2 early-bound lifetime parameters
361 // in trait but 0 in the impl. But if we report "expected 2
362 // but found 0" it's confusing, because it looks like there
363 // are zero. Since I don't quite know how to phrase things at
364 // the moment, give a kind of vague error message.
365 if trait_params
!= impl_params
{
366 let item_kind
= assoc_item_kind_str(impl_m
);
367 let def_span
= tcx
.sess
.source_map().guess_head_span(span
);
368 let span
= tcx
.hir().get_generics(impl_m
.def_id
).map(|g
| g
.span
).unwrap_or(def_span
);
369 let mut err
= struct_span_err
!(
373 "lifetime parameters or bounds on {} `{}` do not match the trait declaration",
377 err
.span_label(span
, &format
!("lifetimes do not match {} in trait", item_kind
));
378 if let Some(sp
) = tcx
.hir().span_if_local(trait_m
.def_id
) {
379 let def_sp
= tcx
.sess
.source_map().guess_head_span(sp
);
380 let sp
= tcx
.hir().get_generics(trait_m
.def_id
).map(|g
| g
.span
).unwrap_or(def_sp
);
383 &format
!("lifetimes in impl do not match this {} in trait", item_kind
),
387 return Err(ErrorReported
);
393 fn extract_spans_for_error_reporting
<'a
, 'tcx
>(
394 infcx
: &infer
::InferCtxt
<'a
, 'tcx
>,
395 param_env
: ty
::ParamEnv
<'tcx
>,
396 terr
: &TypeError
<'_
>,
397 cause
: &ObligationCause
<'tcx
>,
398 impl_m
: &ty
::AssocItem
,
399 impl_sig
: ty
::FnSig
<'tcx
>,
400 trait_m
: &ty
::AssocItem
,
401 trait_sig
: ty
::FnSig
<'tcx
>,
402 ) -> (Span
, Option
<Span
>) {
404 let impl_m_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_m
.def_id
.expect_local());
405 let (impl_m_output
, impl_m_iter
) = match tcx
.hir().expect_impl_item(impl_m_hir_id
).kind
{
406 ImplItemKind
::Fn(ref impl_m_sig
, _
) => {
407 (&impl_m_sig
.decl
.output
, impl_m_sig
.decl
.inputs
.iter())
409 _
=> bug
!("{:?} is not a method", impl_m
),
413 TypeError
::Mutability
=> {
414 if let Some(def_id
) = trait_m
.def_id
.as_local() {
415 let trait_m_hir_id
= tcx
.hir().local_def_id_to_hir_id(def_id
);
416 let trait_m_iter
= match tcx
.hir().expect_trait_item(trait_m_hir_id
).kind
{
417 TraitItemKind
::Fn(ref trait_m_sig
, _
) => trait_m_sig
.decl
.inputs
.iter(),
418 _
=> bug
!("{:?} is not a TraitItemKind::Fn", trait_m
),
423 .find(|&(ref impl_arg
, ref trait_arg
)| {
424 match (&impl_arg
.kind
, &trait_arg
.kind
) {
426 &hir
::TyKind
::Rptr(_
, ref impl_mt
),
427 &hir
::TyKind
::Rptr(_
, ref trait_mt
),
429 | (&hir
::TyKind
::Ptr(ref impl_mt
), &hir
::TyKind
::Ptr(ref trait_mt
)) => {
430 impl_mt
.mutbl
!= trait_mt
.mutbl
435 .map(|(ref impl_arg
, ref trait_arg
)| (impl_arg
.span
, Some(trait_arg
.span
)))
436 .unwrap_or_else(|| (cause
.span(tcx
), tcx
.hir().span_if_local(trait_m
.def_id
)))
438 (cause
.span(tcx
), tcx
.hir().span_if_local(trait_m
.def_id
))
441 TypeError
::Sorts(ExpectedFound { .. }
) => {
442 if let Some(def_id
) = trait_m
.def_id
.as_local() {
443 let trait_m_hir_id
= tcx
.hir().local_def_id_to_hir_id(def_id
);
444 let (trait_m_output
, trait_m_iter
) =
445 match tcx
.hir().expect_trait_item(trait_m_hir_id
).kind
{
446 TraitItemKind
::Fn(ref trait_m_sig
, _
) => {
447 (&trait_m_sig
.decl
.output
, trait_m_sig
.decl
.inputs
.iter())
449 _
=> bug
!("{:?} is not a TraitItemKind::Fn", trait_m
),
452 let impl_iter
= impl_sig
.inputs().iter();
453 let trait_iter
= trait_sig
.inputs().iter();
458 .find_map(|(((&impl_arg_ty
, &trait_arg_ty
), impl_arg
), trait_arg
)| match infcx
459 .at(&cause
, param_env
)
460 .sub(trait_arg_ty
, impl_arg_ty
)
463 Err(_
) => Some((impl_arg
.span
, Some(trait_arg
.span
))),
467 .at(&cause
, param_env
)
468 .sup(trait_sig
.output(), impl_sig
.output())
471 (impl_m_output
.span(), Some(trait_m_output
.span()))
473 (cause
.span(tcx
), tcx
.hir().span_if_local(trait_m
.def_id
))
477 (cause
.span(tcx
), tcx
.hir().span_if_local(trait_m
.def_id
))
480 _
=> (cause
.span(tcx
), tcx
.hir().span_if_local(trait_m
.def_id
)),
484 fn compare_self_type
<'tcx
>(
486 impl_m
: &ty
::AssocItem
,
488 trait_m
: &ty
::AssocItem
,
489 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
490 ) -> Result
<(), ErrorReported
> {
491 // Try to give more informative error messages about self typing
492 // mismatches. Note that any mismatch will also be detected
493 // below, where we construct a canonical function type that
494 // includes the self parameter as a normal parameter. It's just
495 // that the error messages you get out of this code are a bit more
496 // inscrutable, particularly for cases where one method has no
499 let self_string
= |method
: &ty
::AssocItem
| {
500 let untransformed_self_ty
= match method
.container
{
501 ty
::ImplContainer(_
) => impl_trait_ref
.self_ty(),
502 ty
::TraitContainer(_
) => tcx
.types
.self_param
,
504 let self_arg_ty
= tcx
.fn_sig(method
.def_id
).input(0).skip_binder();
505 let param_env
= ty
::ParamEnv
::reveal_all();
507 tcx
.infer_ctxt().enter(|infcx
| {
509 tcx
.liberate_late_bound_regions(method
.def_id
, &ty
::Binder
::bind(self_arg_ty
));
510 let can_eq_self
= |ty
| infcx
.can_eq(param_env
, untransformed_self_ty
, ty
).is_ok();
511 match ExplicitSelf
::determine(self_arg_ty
, can_eq_self
) {
512 ExplicitSelf
::ByValue
=> "self".to_owned(),
513 ExplicitSelf
::ByReference(_
, hir
::Mutability
::Not
) => "&self".to_owned(),
514 ExplicitSelf
::ByReference(_
, hir
::Mutability
::Mut
) => "&mut self".to_owned(),
515 _
=> format
!("self: {}", self_arg_ty
),
520 match (trait_m
.fn_has_self_parameter
, impl_m
.fn_has_self_parameter
) {
521 (false, false) | (true, true) => {}
524 let self_descr
= self_string(impl_m
);
525 let mut err
= struct_span_err
!(
529 "method `{}` has a `{}` declaration in the impl, but \
534 err
.span_label(impl_m_span
, format
!("`{}` used in impl", self_descr
));
535 if let Some(span
) = tcx
.hir().span_if_local(trait_m
.def_id
) {
536 err
.span_label(span
, format
!("trait method declared without `{}`", self_descr
));
538 err
.note_trait_signature(trait_m
.ident
.to_string(), trait_m
.signature(tcx
));
541 return Err(ErrorReported
);
545 let self_descr
= self_string(trait_m
);
546 let mut err
= struct_span_err
!(
550 "method `{}` has a `{}` declaration in the trait, but \
555 err
.span_label(impl_m_span
, format
!("expected `{}` in impl", self_descr
));
556 if let Some(span
) = tcx
.hir().span_if_local(trait_m
.def_id
) {
557 err
.span_label(span
, format
!("`{}` used in trait", self_descr
));
559 err
.note_trait_signature(trait_m
.ident
.to_string(), trait_m
.signature(tcx
));
562 return Err(ErrorReported
);
569 fn compare_number_of_generics
<'tcx
>(
571 impl_
: &ty
::AssocItem
,
573 trait_
: &ty
::AssocItem
,
574 trait_span
: Option
<Span
>,
575 ) -> Result
<(), ErrorReported
> {
576 let trait_own_counts
= tcx
.generics_of(trait_
.def_id
).own_counts();
577 let impl_own_counts
= tcx
.generics_of(impl_
.def_id
).own_counts();
580 ("type", trait_own_counts
.types
, impl_own_counts
.types
),
581 ("const", trait_own_counts
.consts
, impl_own_counts
.consts
),
584 let item_kind
= assoc_item_kind_str(impl_
);
586 let mut err_occurred
= false;
587 for &(kind
, trait_count
, impl_count
) in &matchings
{
588 if impl_count
!= trait_count
{
591 let (trait_spans
, impl_trait_spans
) = if let Some(def_id
) = trait_
.def_id
.as_local() {
592 let trait_hir_id
= tcx
.hir().local_def_id_to_hir_id(def_id
);
593 let trait_item
= tcx
.hir().expect_trait_item(trait_hir_id
);
594 if trait_item
.generics
.params
.is_empty() {
595 (Some(vec
![trait_item
.generics
.span
]), vec
![])
597 let arg_spans
: Vec
<Span
> =
598 trait_item
.generics
.params
.iter().map(|p
| p
.span
).collect();
599 let impl_trait_spans
: Vec
<Span
> = trait_item
603 .filter_map(|p
| match p
.kind
{
604 GenericParamKind
::Type
{
605 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
611 (Some(arg_spans
), impl_trait_spans
)
614 (trait_span
.map(|s
| vec
![s
]), vec
![])
617 let impl_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_
.def_id
.expect_local());
618 let impl_item
= tcx
.hir().expect_impl_item(impl_hir_id
);
619 let impl_item_impl_trait_spans
: Vec
<Span
> = impl_item
623 .filter_map(|p
| match p
.kind
{
624 GenericParamKind
::Type
{
625 synthetic
: Some(hir
::SyntheticTyParamKind
::ImplTrait
),
631 let spans
= impl_item
.generics
.spans();
632 let span
= spans
.primary_span();
634 let mut err
= tcx
.sess
.struct_span_err_with_code(
637 "{} `{}` has {} {kind} parameter{} but its trait \
638 declaration has {} {kind} parameter{}",
642 pluralize
!(impl_count
),
644 pluralize
!(trait_count
),
647 DiagnosticId
::Error("E0049".into()),
650 let mut suffix
= None
;
652 if let Some(spans
) = trait_spans
{
653 let mut spans
= spans
.iter();
654 if let Some(span
) = spans
.next() {
658 "expected {} {} parameter{}",
661 pluralize
!(trait_count
),
666 err
.span_label(*span
, "");
669 suffix
= Some(format
!(", expected {}", trait_count
));
672 if let Some(span
) = span
{
676 "found {} {} parameter{}{}",
679 pluralize
!(impl_count
),
680 suffix
.unwrap_or_else(String
::new
),
685 for span
in impl_trait_spans
.iter().chain(impl_item_impl_trait_spans
.iter()) {
686 err
.span_label(*span
, "`impl Trait` introduces an implicit type parameter");
693 if err_occurred { Err(ErrorReported) }
else { Ok(()) }
696 fn compare_number_of_method_arguments
<'tcx
>(
698 impl_m
: &ty
::AssocItem
,
700 trait_m
: &ty
::AssocItem
,
701 trait_item_span
: Option
<Span
>,
702 ) -> Result
<(), ErrorReported
> {
703 let impl_m_fty
= tcx
.fn_sig(impl_m
.def_id
);
704 let trait_m_fty
= tcx
.fn_sig(trait_m
.def_id
);
705 let trait_number_args
= trait_m_fty
.inputs().skip_binder().len();
706 let impl_number_args
= impl_m_fty
.inputs().skip_binder().len();
707 if trait_number_args
!= impl_number_args
{
708 let trait_span
= if let Some(def_id
) = trait_m
.def_id
.as_local() {
709 let trait_id
= tcx
.hir().local_def_id_to_hir_id(def_id
);
710 match tcx
.hir().expect_trait_item(trait_id
).kind
{
711 TraitItemKind
::Fn(ref trait_m_sig
, _
) => {
712 let pos
= if trait_number_args
> 0 { trait_number_args - 1 }
else { 0 }
;
713 if let Some(arg
) = trait_m_sig
.decl
.inputs
.get(pos
) {
718 trait_m_sig
.decl
.inputs
[0].span
.lo(),
727 _
=> bug
!("{:?} is not a method", impl_m
),
732 let impl_m_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_m
.def_id
.expect_local());
733 let impl_span
= match tcx
.hir().expect_impl_item(impl_m_hir_id
).kind
{
734 ImplItemKind
::Fn(ref impl_m_sig
, _
) => {
735 let pos
= if impl_number_args
> 0 { impl_number_args - 1 }
else { 0 }
;
736 if let Some(arg
) = impl_m_sig
.decl
.inputs
.get(pos
) {
741 impl_m_sig
.decl
.inputs
[0].span
.lo(),
750 _
=> bug
!("{:?} is not a method", impl_m
),
752 let mut err
= struct_span_err
!(
756 "method `{}` has {} but the declaration in \
759 potentially_plural_count(impl_number_args
, "parameter"),
760 tcx
.def_path_str(trait_m
.def_id
),
763 if let Some(trait_span
) = trait_span
{
768 potentially_plural_count(trait_number_args
, "parameter")
772 err
.note_trait_signature(trait_m
.ident
.to_string(), trait_m
.signature(tcx
));
777 "expected {}, found {}",
778 potentially_plural_count(trait_number_args
, "parameter"),
783 return Err(ErrorReported
);
789 fn compare_synthetic_generics
<'tcx
>(
791 impl_m
: &ty
::AssocItem
,
792 trait_m
: &ty
::AssocItem
,
793 ) -> Result
<(), ErrorReported
> {
794 // FIXME(chrisvittal) Clean up this function, list of FIXME items:
795 // 1. Better messages for the span labels
796 // 2. Explanation as to what is going on
797 // If we get here, we already have the same number of generics, so the zip will
799 let mut error_found
= false;
800 let impl_m_generics
= tcx
.generics_of(impl_m
.def_id
);
801 let trait_m_generics
= tcx
.generics_of(trait_m
.def_id
);
802 let impl_m_type_params
= impl_m_generics
.params
.iter().filter_map(|param
| match param
.kind
{
803 GenericParamDefKind
::Type { synthetic, .. }
=> Some((param
.def_id
, synthetic
)),
804 GenericParamDefKind
::Lifetime
| GenericParamDefKind
::Const
=> None
,
806 let trait_m_type_params
= trait_m_generics
.params
.iter().filter_map(|param
| match param
.kind
{
807 GenericParamDefKind
::Type { synthetic, .. }
=> Some((param
.def_id
, synthetic
)),
808 GenericParamDefKind
::Lifetime
| GenericParamDefKind
::Const
=> None
,
810 for ((impl_def_id
, impl_synthetic
), (trait_def_id
, trait_synthetic
)) in
811 impl_m_type_params
.zip(trait_m_type_params
)
813 if impl_synthetic
!= trait_synthetic
{
814 let impl_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_def_id
.expect_local());
815 let impl_span
= tcx
.hir().span(impl_hir_id
);
816 let trait_span
= tcx
.def_span(trait_def_id
);
817 let mut err
= struct_span_err
!(
821 "method `{}` has incompatible signature for trait",
824 err
.span_label(trait_span
, "declaration in trait here");
825 match (impl_synthetic
, trait_synthetic
) {
826 // The case where the impl method uses `impl Trait` but the trait method uses
828 (Some(hir
::SyntheticTyParamKind
::ImplTrait
), None
) => {
829 err
.span_label(impl_span
, "expected generic parameter, found `impl Trait`");
831 // try taking the name from the trait impl
832 // FIXME: this is obviously suboptimal since the name can already be used
833 // as another generic argument
834 let new_name
= tcx
.sess
.source_map().span_to_snippet(trait_span
).ok()?
;
835 let trait_m
= tcx
.hir().local_def_id_to_hir_id(trait_m
.def_id
.as_local()?
);
836 let trait_m
= tcx
.hir().trait_item(hir
::TraitItemId { hir_id: trait_m }
);
838 let impl_m
= tcx
.hir().local_def_id_to_hir_id(impl_m
.def_id
.as_local()?
);
839 let impl_m
= tcx
.hir().impl_item(hir
::ImplItemId { hir_id: impl_m }
);
841 // in case there are no generics, take the spot between the function name
842 // and the opening paren of the argument list
843 let new_generics_span
=
844 tcx
.sess
.source_map().generate_fn_name_span(impl_span
)?
.shrink_to_hi();
845 // in case there are generics, just replace them
847 impl_m
.generics
.span
.substitute_dummy(new_generics_span
);
848 // replace with the generics from the trait
850 tcx
.sess
.source_map().span_to_snippet(trait_m
.generics
.span
).ok()?
;
852 err
.multipart_suggestion(
853 "try changing the `impl Trait` argument to a generic parameter",
855 // replace `impl Trait` with `T`
856 (impl_span
, new_name
),
857 // replace impl method generics with trait method generics
858 // This isn't quite right, as users might have changed the names
859 // of the generics, but it works for the common case
860 (generics_span
, new_generics
),
862 Applicability
::MaybeIncorrect
,
867 // The case where the trait method uses `impl Trait`, but the impl method uses
868 // explicit generics.
869 (None
, Some(hir
::SyntheticTyParamKind
::ImplTrait
)) => {
870 err
.span_label(impl_span
, "expected `impl Trait`, found generic parameter");
872 let impl_m
= tcx
.hir().local_def_id_to_hir_id(impl_m
.def_id
.as_local()?
);
873 let impl_m
= tcx
.hir().impl_item(hir
::ImplItemId { hir_id: impl_m }
);
874 let input_tys
= match impl_m
.kind
{
875 hir
::ImplItemKind
::Fn(ref sig
, _
) => sig
.decl
.inputs
,
878 struct Visitor(Option
<Span
>, hir
::def_id
::DefId
);
879 impl<'v
> intravisit
::Visitor
<'v
> for Visitor
{
880 fn visit_ty(&mut self, ty
: &'v hir
::Ty
<'v
>) {
881 intravisit
::walk_ty(self, ty
);
882 if let hir
::TyKind
::Path(hir
::QPath
::Resolved(None
, ref path
)) =
885 if let Res
::Def(DefKind
::TyParam
, def_id
) = path
.res
{
886 if def_id
== self.1 {
887 self.0 = Some(ty
.span
);
892 type Map
= intravisit
::ErasedMap
<'v
>;
895 ) -> intravisit
::NestedVisitorMap
<Self::Map
>
897 intravisit
::NestedVisitorMap
::None
900 let mut visitor
= Visitor(None
, impl_def_id
);
901 for ty
in input_tys
{
902 intravisit
::Visitor
::visit_ty(&mut visitor
, ty
);
904 let span
= visitor
.0?
;
907 impl_m
.generics
.params
.iter().find_map(|param
| match param
.kind
{
908 GenericParamKind
::Lifetime { .. }
=> None
,
909 GenericParamKind
::Type { .. }
| GenericParamKind
::Const { .. }
=> {
910 if param
.hir_id
== impl_hir_id
{
917 let bounds
= bounds
.first()?
.span().to(bounds
.last()?
.span());
918 let bounds
= tcx
.sess
.source_map().span_to_snippet(bounds
).ok()?
;
920 err
.multipart_suggestion(
921 "try removing the generic parameter and using `impl Trait` instead",
923 // delete generic parameters
924 (impl_m
.generics
.span
, String
::new()),
925 // replace param usage with `impl Trait`
926 (span
, format
!("impl {}", bounds
)),
928 Applicability
::MaybeIncorrect
,
939 if error_found { Err(ErrorReported) }
else { Ok(()) }
942 crate fn compare_const_impl
<'tcx
>(
944 impl_c
: &ty
::AssocItem
,
946 trait_c
: &ty
::AssocItem
,
947 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
949 debug
!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref
);
951 tcx
.infer_ctxt().enter(|infcx
| {
952 let param_env
= tcx
.param_env(impl_c
.def_id
);
953 let inh
= Inherited
::new(infcx
, impl_c
.def_id
.expect_local());
954 let infcx
= &inh
.infcx
;
956 // The below is for the most part highly similar to the procedure
957 // for methods above. It is simpler in many respects, especially
958 // because we shouldn't really have to deal with lifetimes or
959 // predicates. In fact some of this should probably be put into
960 // shared functions because of DRY violations...
961 let trait_to_impl_substs
= impl_trait_ref
.substs
;
963 // Create a parameter environment that represents the implementation's
965 let impl_c_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_c
.def_id
.expect_local());
967 // Compute placeholder form of impl and trait const tys.
968 let impl_ty
= tcx
.type_of(impl_c
.def_id
);
969 let trait_ty
= tcx
.type_of(trait_c
.def_id
).subst(tcx
, trait_to_impl_substs
);
970 let mut cause
= ObligationCause
::new(
973 ObligationCauseCode
::CompareImplConstObligation
,
976 // There is no "body" here, so just pass dummy id.
978 inh
.normalize_associated_types_in(impl_c_span
, impl_c_hir_id
, param_env
, &impl_ty
);
980 debug
!("compare_const_impl: impl_ty={:?}", impl_ty
);
983 inh
.normalize_associated_types_in(impl_c_span
, impl_c_hir_id
, param_env
, &trait_ty
);
985 debug
!("compare_const_impl: trait_ty={:?}", trait_ty
);
988 .at(&cause
, param_env
)
989 .sup(trait_ty
, impl_ty
)
990 .map(|ok
| inh
.register_infer_ok_obligations(ok
));
992 if let Err(terr
) = err
{
994 "checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
998 // Locate the Span containing just the type of the offending impl
999 match tcx
.hir().expect_impl_item(impl_c_hir_id
).kind
{
1000 ImplItemKind
::Const(ref ty
, _
) => cause
.make_mut().span
= ty
.span
,
1001 _
=> bug
!("{:?} is not a impl const", impl_c
),
1004 let mut diag
= struct_span_err
!(
1008 "implemented const `{}` has an incompatible type for \
1013 let trait_c_hir_id
=
1014 trait_c
.def_id
.as_local().map(|def_id
| tcx
.hir().local_def_id_to_hir_id(def_id
));
1015 let trait_c_span
= trait_c_hir_id
.map(|trait_c_hir_id
| {
1016 // Add a label to the Span containing just the type of the const
1017 match tcx
.hir().expect_trait_item(trait_c_hir_id
).kind
{
1018 TraitItemKind
::Const(ref ty
, _
) => ty
.span
,
1019 _
=> bug
!("{:?} is not a trait const", trait_c
),
1023 infcx
.note_type_err(
1026 trait_c_span
.map(|span
| (span
, "type in trait".to_owned())),
1027 Some(infer
::ValuePairs
::Types(ExpectedFound
{
1036 // Check that all obligations are satisfied by the implementation's
1038 if let Err(ref errors
) = inh
.fulfillment_cx
.borrow_mut().select_all_or_error(&infcx
) {
1039 infcx
.report_fulfillment_errors(errors
, None
, false);
1043 let fcx
= FnCtxt
::new(&inh
, param_env
, impl_c_hir_id
);
1044 fcx
.regionck_item(impl_c_hir_id
, impl_c_span
, &[]);
1048 crate fn compare_ty_impl
<'tcx
>(
1050 impl_ty
: &ty
::AssocItem
,
1052 trait_ty
: &ty
::AssocItem
,
1053 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
1054 trait_item_span
: Option
<Span
>,
1056 debug
!("compare_impl_type(impl_trait_ref={:?})", impl_trait_ref
);
1058 let _
: Result
<(), ErrorReported
> = (|| {
1059 compare_number_of_generics(tcx
, impl_ty
, impl_ty_span
, trait_ty
, trait_item_span
)?
;
1061 compare_type_predicate_entailment(tcx
, impl_ty
, impl_ty_span
, trait_ty
, impl_trait_ref
)?
;
1063 compare_projection_bounds(tcx
, trait_ty
, impl_ty
, impl_ty_span
, impl_trait_ref
)
1067 /// The equivalent of [compare_predicate_entailment], but for associated types
1068 /// instead of associated functions.
1069 fn compare_type_predicate_entailment
<'tcx
>(
1071 impl_ty
: &ty
::AssocItem
,
1073 trait_ty
: &ty
::AssocItem
,
1074 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
1075 ) -> Result
<(), ErrorReported
> {
1076 let impl_substs
= InternalSubsts
::identity_for_item(tcx
, impl_ty
.def_id
);
1077 let trait_to_impl_substs
=
1078 impl_substs
.rebase_onto(tcx
, impl_ty
.container
.id(), impl_trait_ref
.substs
);
1080 let impl_ty_generics
= tcx
.generics_of(impl_ty
.def_id
);
1081 let trait_ty_generics
= tcx
.generics_of(trait_ty
.def_id
);
1082 let impl_ty_predicates
= tcx
.predicates_of(impl_ty
.def_id
);
1083 let trait_ty_predicates
= tcx
.predicates_of(trait_ty
.def_id
);
1085 check_region_bounds_on_impl_item(
1094 let impl_ty_own_bounds
= impl_ty_predicates
.instantiate_own(tcx
, impl_substs
);
1096 if impl_ty_own_bounds
.is_empty() {
1097 // Nothing to check.
1101 // This `HirId` should be used for the `body_id` field on each
1102 // `ObligationCause` (and the `FnCtxt`). This is what
1103 // `regionck_item` expects.
1104 let impl_ty_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_ty
.def_id
.expect_local());
1105 let cause
= ObligationCause
::new(
1108 ObligationCauseCode
::CompareImplTypeObligation
{
1109 item_name
: impl_ty
.ident
.name
,
1110 impl_item_def_id
: impl_ty
.def_id
,
1111 trait_item_def_id
: trait_ty
.def_id
,
1115 debug
!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs
);
1117 // The predicates declared by the impl definition, the trait and the
1118 // associated type in the trait are assumed.
1119 let impl_predicates
= tcx
.predicates_of(impl_ty_predicates
.parent
.unwrap());
1120 let mut hybrid_preds
= impl_predicates
.instantiate_identity(tcx
);
1123 .extend(trait_ty_predicates
.instantiate_own(tcx
, trait_to_impl_substs
).predicates
);
1125 debug
!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds
);
1127 let normalize_cause
= traits
::ObligationCause
::misc(impl_ty_span
, impl_ty_hir_id
);
1128 let param_env
= ty
::ParamEnv
::new(
1129 tcx
.intern_predicates(&hybrid_preds
.predicates
),
1133 let param_env
= traits
::normalize_param_env_or_error(
1137 normalize_cause
.clone(),
1139 tcx
.infer_ctxt().enter(|infcx
| {
1140 let inh
= Inherited
::new(infcx
, impl_ty
.def_id
.expect_local());
1141 let infcx
= &inh
.infcx
;
1143 debug
!("compare_type_predicate_entailment: caller_bounds={:?}", param_env
.caller_bounds());
1145 let mut selcx
= traits
::SelectionContext
::new(&infcx
);
1147 for predicate
in impl_ty_own_bounds
.predicates
{
1148 let traits
::Normalized { value: predicate, obligations }
=
1149 traits
::normalize(&mut selcx
, param_env
, normalize_cause
.clone(), &predicate
);
1151 inh
.register_predicates(obligations
);
1152 inh
.register_predicate(traits
::Obligation
::new(cause
.clone(), param_env
, predicate
));
1155 // Check that all obligations are satisfied by the implementation's
1157 if let Err(ref errors
) = inh
.fulfillment_cx
.borrow_mut().select_all_or_error(&infcx
) {
1158 infcx
.report_fulfillment_errors(errors
, None
, false);
1159 return Err(ErrorReported
);
1162 // Finally, resolve all regions. This catches wily misuses of
1163 // lifetime parameters.
1164 let fcx
= FnCtxt
::new(&inh
, param_env
, impl_ty_hir_id
);
1165 fcx
.regionck_item(impl_ty_hir_id
, impl_ty_span
, &[]);
1171 /// Validate that `ProjectionCandidate`s created for this associated type will
1176 /// trait X { type Y: Copy } impl X for T { type Y = S; }
1178 /// We are able to normalize `<T as X>::U` to `S`, and so when we check the
1179 /// impl is well-formed we have to prove `S: Copy`.
1181 /// For default associated types the normalization is not possible (the value
1182 /// from the impl could be overridden). We also can't normalize generic
1183 /// associated types (yet) because they contain bound parameters.
1184 fn compare_projection_bounds
<'tcx
>(
1186 trait_ty
: &ty
::AssocItem
,
1187 impl_ty
: &ty
::AssocItem
,
1189 impl_trait_ref
: ty
::TraitRef
<'tcx
>,
1190 ) -> Result
<(), ErrorReported
> {
1191 let have_gats
= tcx
.features().generic_associated_types
;
1192 if impl_ty
.defaultness
.is_final() && !have_gats
{
1193 // For "final", non-generic associate type implementations, we
1194 // don't need this as described above.
1200 // impl<A, B> Foo<u32> for (A, B) {
1204 // - `impl_substs` would be `[A, B, C]`
1205 // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
1206 // the *trait* with the generic associated type parameters.
1207 let impl_ty_substs
= InternalSubsts
::identity_for_item(tcx
, impl_ty
.def_id
);
1208 let rebased_substs
=
1209 impl_ty_substs
.rebase_onto(tcx
, impl_ty
.container
.id(), impl_trait_ref
.substs
);
1210 let impl_ty_value
= tcx
.type_of(impl_ty
.def_id
);
1212 let param_env
= tcx
.param_env(impl_ty
.def_id
);
1214 // When checking something like
1216 // trait X { type Y: PartialEq<<Self as X>::Y> }
1217 // impl X for T { default type Y = S; }
1219 // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
1220 // we want <T as X>::Y to normalize to S. This is valid because we are
1221 // checking the default value specifically here. Add this equality to the
1222 // ParamEnv for normalization specifically.
1223 let normalize_param_env
= {
1224 let mut predicates
= param_env
.caller_bounds().iter().collect
::<Vec
<_
>>();
1226 ty
::Binder
::dummy(ty
::ProjectionPredicate
{
1227 projection_ty
: ty
::ProjectionTy
{
1228 item_def_id
: trait_ty
.def_id
,
1229 substs
: rebased_substs
,
1235 ty
::ParamEnv
::new(tcx
.intern_predicates(&predicates
), Reveal
::UserFacing
, None
)
1238 tcx
.infer_ctxt().enter(move |infcx
| {
1239 let inh
= Inherited
::new(infcx
, impl_ty
.def_id
.expect_local());
1240 let infcx
= &inh
.infcx
;
1241 let mut selcx
= traits
::SelectionContext
::new(&infcx
);
1243 let impl_ty_hir_id
= tcx
.hir().local_def_id_to_hir_id(impl_ty
.def_id
.expect_local());
1244 let normalize_cause
= traits
::ObligationCause
::misc(impl_ty_span
, impl_ty_hir_id
);
1245 let cause
= ObligationCause
::new(
1248 ObligationCauseCode
::ItemObligation(trait_ty
.def_id
),
1251 let predicates
= tcx
.projection_predicates(trait_ty
.def_id
);
1252 debug
!("compare_projection_bounds: projection_predicates={:?}", predicates
);
1254 for predicate
in predicates
{
1255 let concrete_ty_predicate
= predicate
.subst(tcx
, rebased_substs
);
1256 debug
!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate
);
1258 let traits
::Normalized { value: normalized_predicate, obligations }
= traits
::normalize(
1260 normalize_param_env
,
1261 normalize_cause
.clone(),
1262 &concrete_ty_predicate
,
1264 debug
!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate
);
1266 inh
.register_predicates(obligations
);
1267 inh
.register_predicate(traits
::Obligation
::new(
1270 normalized_predicate
,
1274 // Check that all obligations are satisfied by the implementation's
1276 if let Err(ref errors
) = inh
.fulfillment_cx
.borrow_mut().select_all_or_error(&infcx
) {
1277 infcx
.report_fulfillment_errors(errors
, None
, false);
1278 return Err(ErrorReported
);
1281 // Finally, resolve all regions. This catches wily misuses of
1282 // lifetime parameters.
1283 let fcx
= FnCtxt
::new(&inh
, param_env
, impl_ty_hir_id
);
1284 fcx
.regionck_item(impl_ty_hir_id
, impl_ty_span
, &[]);
1290 fn assoc_item_kind_str(impl_item
: &ty
::AssocItem
) -> &'
static str {
1291 match impl_item
.kind
{
1292 ty
::AssocKind
::Const
=> "const",
1293 ty
::AssocKind
::Fn
=> "method",
1294 ty
::AssocKind
::Type
=> "type",