1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use check
::{FnCtxt, Inherited, blank_fn_ctxt, regionck}
;
13 use constrained_type_params
::{identify_constrained_type_params, Parameter}
;
15 use hir
::def_id
::DefId
;
16 use middle
::region
::{CodeExtent}
;
17 use rustc
::ty
::subst
::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}
;
19 use rustc
::ty
::{self, Ty, TyCtxt}
;
20 use rustc
::ty
::fold
::{TypeFolder}
;
22 use std
::cell
::RefCell
;
23 use std
::collections
::HashSet
;
25 use syntax
::codemap
::{Span}
;
26 use syntax
::errors
::DiagnosticBuilder
;
27 use syntax
::parse
::token
::{special_idents}
;
28 use rustc
::hir
::intravisit
::{self, Visitor}
;
31 pub struct CheckTypeWellFormedVisitor
<'ccx
, 'tcx
:'ccx
> {
32 ccx
: &'ccx CrateCtxt
<'ccx
, 'tcx
>,
33 code
: traits
::ObligationCauseCode
<'tcx
>,
36 impl<'ccx
, 'tcx
> CheckTypeWellFormedVisitor
<'ccx
, 'tcx
> {
37 pub fn new(ccx
: &'ccx CrateCtxt
<'ccx
, 'tcx
>)
38 -> CheckTypeWellFormedVisitor
<'ccx
, 'tcx
> {
39 CheckTypeWellFormedVisitor
{
41 code
: traits
::ObligationCauseCode
::MiscObligation
45 fn tcx(&self) -> &TyCtxt
<'tcx
> {
49 /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
50 /// well-formed, meaning that they do not require any constraints not declared in the struct
51 /// definition itself. For example, this definition would be illegal:
53 /// struct Ref<'a, T> { x: &'a T }
55 /// because the type did not declare that `T:'a`.
57 /// We do this check as a pre-pass before checking fn bodies because if these constraints are
58 /// not included it frequently leads to confusing errors in fn bodies. So it's better to check
60 fn check_item_well_formed(&mut self, item
: &hir
::Item
) {
62 debug
!("check_item_well_formed(it.id={}, it.name={})",
64 ccx
.tcx
.item_path_str(ccx
.tcx
.map
.local_def_id(item
.id
)));
67 /// Right now we check that every default trait implementation
68 /// has an implementation of itself. Basically, a case like:
70 /// `impl Trait for T {}`
72 /// has a requirement of `T: Trait` which was required for default
73 /// method implementations. Although this could be improved now that
74 /// there's a better infrastructure in place for this, it's being left
75 /// for a follow-up work.
77 /// Since there's such a requirement, we need to check *just* positive
78 /// implementations, otherwise things like:
80 /// impl !Send for T {}
82 /// won't be allowed unless there's an *explicit* implementation of `Send`
84 hir
::ItemImpl(_
, hir
::ImplPolarity
::Positive
, _
,
85 ref trait_ref
, ref self_ty
, _
) => {
86 self.check_impl(item
, self_ty
, trait_ref
);
88 hir
::ItemImpl(_
, hir
::ImplPolarity
::Negative
, _
, Some(_
), _
, _
) => {
89 // FIXME(#27579) what amount of WF checking do we need for neg impls?
91 let trait_ref
= ccx
.tcx
.impl_trait_ref(ccx
.tcx
.map
.local_def_id(item
.id
)).unwrap();
92 ccx
.tcx
.populate_implementations_for_trait_if_necessary(trait_ref
.def_id
);
93 match ccx
.tcx
.lang_items
.to_builtin_kind(trait_ref
.def_id
) {
94 Some(ty
::BoundSend
) | Some(ty
::BoundSync
) => {}
96 if !ccx
.tcx
.trait_has_default_impl(trait_ref
.def_id
) {
97 error_192(ccx
, item
.span
);
102 hir
::ItemFn(_
, _
, _
, _
, _
, ref body
) => {
103 self.check_item_fn(item
, body
);
105 hir
::ItemStatic(..) => {
106 self.check_item_type(item
);
108 hir
::ItemConst(..) => {
109 self.check_item_type(item
);
111 hir
::ItemStruct(ref struct_def
, ref ast_generics
) => {
112 self.check_type_defn(item
, |fcx
| {
113 vec
![struct_variant(fcx
, struct_def
)]
116 self.check_variances_for_type_defn(item
, ast_generics
);
118 hir
::ItemEnum(ref enum_def
, ref ast_generics
) => {
119 self.check_type_defn(item
, |fcx
| {
120 enum_variants(fcx
, enum_def
)
123 self.check_variances_for_type_defn(item
, ast_generics
);
125 hir
::ItemTrait(_
, _
, _
, ref items
) => {
126 self.check_trait(item
, items
);
132 fn check_trait_or_impl_item(&mut self, item_id
: ast
::NodeId
, span
: Span
) {
133 let code
= self.code
.clone();
134 self.with_fcx(item_id
, span
, |fcx
, this
| {
135 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
136 let free_id_outlive
= fcx
.inh
.infcx
.parameter_environment
.free_id_outlive
;
138 let item
= fcx
.tcx().impl_or_trait_item(fcx
.tcx().map
.local_def_id(item_id
));
140 let (mut implied_bounds
, self_ty
) = match item
.container() {
141 ty
::TraitContainer(_
) => (vec
![], fcx
.tcx().mk_self_type()),
142 ty
::ImplContainer(def_id
) => (impl_implied_bounds(fcx
, def_id
, span
),
143 fcx
.tcx().lookup_item_type(def_id
).ty
)
147 ty
::ConstTraitItem(assoc_const
) => {
148 let ty
= fcx
.instantiate_type_scheme(span
, free_substs
, &assoc_const
.ty
);
149 fcx
.register_wf_obligation(ty
, span
, code
.clone());
151 ty
::MethodTraitItem(method
) => {
152 reject_shadowing_type_parameters(fcx
.tcx(), span
, &method
.generics
);
153 let method_ty
= fcx
.instantiate_type_scheme(span
, free_substs
, &method
.fty
);
154 let predicates
= fcx
.instantiate_bounds(span
, free_substs
, &method
.predicates
);
155 this
.check_fn_or_method(fcx
, span
, &method_ty
, &predicates
,
156 free_id_outlive
, &mut implied_bounds
);
157 this
.check_method_receiver(fcx
, span
, &method
,
158 free_id_outlive
, self_ty
);
160 ty
::TypeTraitItem(assoc_type
) => {
161 if let Some(ref ty
) = assoc_type
.ty
{
162 let ty
= fcx
.instantiate_type_scheme(span
, free_substs
, ty
);
163 fcx
.register_wf_obligation(ty
, span
, code
.clone());
172 fn with_item_fcx
<F
>(&mut self, item
: &hir
::Item
, f
: F
) where
173 F
: for<'fcx
> FnMut(&FnCtxt
<'fcx
, 'tcx
>,
174 &mut CheckTypeWellFormedVisitor
<'ccx
,'tcx
>) -> Vec
<Ty
<'tcx
>>,
176 self.with_fcx(item
.id
, item
.span
, f
)
179 fn with_fcx
<F
>(&mut self, id
: ast
::NodeId
, span
: Span
, mut f
: F
) where
180 F
: for<'fcx
> FnMut(&FnCtxt
<'fcx
, 'tcx
>,
181 &mut CheckTypeWellFormedVisitor
<'ccx
,'tcx
>) -> Vec
<Ty
<'tcx
>>,
184 let param_env
= ty
::ParameterEnvironment
::for_item(ccx
.tcx
, id
);
185 let tables
= RefCell
::new(ty
::Tables
::empty());
186 let inh
= Inherited
::new(ccx
.tcx
, &tables
, param_env
);
187 let fcx
= blank_fn_ctxt(ccx
, &inh
, ty
::FnDiverging
, id
);
188 let wf_tys
= f(&fcx
, self);
189 fcx
.select_all_obligations_or_error();
190 regionck
::regionck_item(&fcx
, id
, span
, &wf_tys
);
193 /// In a type definition, we check that to ensure that the types of the fields are well-formed.
194 fn check_type_defn
<F
>(&mut self, item
: &hir
::Item
, mut lookup_fields
: F
) where
195 F
: for<'fcx
> FnMut(&FnCtxt
<'fcx
, 'tcx
>) -> Vec
<AdtVariant
<'tcx
>>,
197 self.with_item_fcx(item
, |fcx
, this
| {
198 let variants
= lookup_fields(fcx
);
200 for variant
in &variants
{
201 // For DST, all intermediate types must be sized.
202 if let Some((_
, fields
)) = variant
.fields
.split_last() {
203 for field
in fields
{
204 fcx
.register_builtin_bound(
207 traits
::ObligationCause
::new(field
.span
,
209 traits
::FieldSized
));
213 // All field types must be well-formed.
214 for field
in &variant
.fields
{
215 fcx
.register_wf_obligation(field
.ty
, field
.span
, this
.code
.clone())
219 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
220 let predicates
= fcx
.tcx().lookup_predicates(fcx
.tcx().map
.local_def_id(item
.id
));
221 let predicates
= fcx
.instantiate_bounds(item
.span
, free_substs
, &predicates
);
222 this
.check_where_clauses(fcx
, item
.span
, &predicates
);
224 vec
![] // no implied bounds in a struct def'n
228 fn check_trait(&mut self,
230 items
: &[hir
::TraitItem
])
232 let trait_def_id
= self.tcx().map
.local_def_id(item
.id
);
234 if self.ccx
.tcx
.trait_has_default_impl(trait_def_id
) {
235 if !items
.is_empty() {
236 error_380(self.ccx
, item
.span
);
240 self.with_item_fcx(item
, |fcx
, this
| {
241 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
242 let predicates
= fcx
.tcx().lookup_predicates(trait_def_id
);
243 let predicates
= fcx
.instantiate_bounds(item
.span
, free_substs
, &predicates
);
244 this
.check_where_clauses(fcx
, item
.span
, &predicates
);
249 fn check_item_fn(&mut self,
253 self.with_item_fcx(item
, |fcx
, this
| {
254 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
255 let type_scheme
= fcx
.tcx().lookup_item_type(fcx
.tcx().map
.local_def_id(item
.id
));
256 let item_ty
= fcx
.instantiate_type_scheme(item
.span
, free_substs
, &type_scheme
.ty
);
257 let bare_fn_ty
= match item_ty
.sty
{
258 ty
::TyFnDef(_
, _
, ref bare_fn_ty
) => bare_fn_ty
,
260 span_bug
!(item
.span
, "Fn item without fn type");
264 let predicates
= fcx
.tcx().lookup_predicates(fcx
.tcx().map
.local_def_id(item
.id
));
265 let predicates
= fcx
.instantiate_bounds(item
.span
, free_substs
, &predicates
);
267 let mut implied_bounds
= vec
![];
268 let free_id_outlive
= fcx
.tcx().region_maps
.call_site_extent(item
.id
, body
.id
);
269 this
.check_fn_or_method(fcx
, item
.span
, bare_fn_ty
, &predicates
,
270 free_id_outlive
, &mut implied_bounds
);
275 fn check_item_type(&mut self,
278 debug
!("check_item_type: {:?}", item
);
280 self.with_item_fcx(item
, |fcx
, this
| {
281 let type_scheme
= fcx
.tcx().lookup_item_type(fcx
.tcx().map
.local_def_id(item
.id
));
282 let item_ty
= fcx
.instantiate_type_scheme(item
.span
,
285 .parameter_environment
289 fcx
.register_wf_obligation(item_ty
, item
.span
, this
.code
.clone());
291 vec
![] // no implied bounds in a const etc
295 fn check_impl(&mut self,
297 ast_self_ty
: &hir
::Ty
,
298 ast_trait_ref
: &Option
<hir
::TraitRef
>)
300 debug
!("check_impl: {:?}", item
);
302 self.with_item_fcx(item
, |fcx
, this
| {
303 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
304 let item_def_id
= fcx
.tcx().map
.local_def_id(item
.id
);
306 match *ast_trait_ref
{
307 Some(ref ast_trait_ref
) => {
308 let trait_ref
= fcx
.tcx().impl_trait_ref(item_def_id
).unwrap();
310 fcx
.instantiate_type_scheme(
311 ast_trait_ref
.path
.span
, free_substs
, &trait_ref
);
313 ty
::wf
::trait_obligations(fcx
.infcx(),
316 ast_trait_ref
.path
.span
);
317 for obligation
in obligations
{
318 fcx
.register_predicate(obligation
);
322 let self_ty
= fcx
.tcx().node_id_to_type(item
.id
);
323 let self_ty
= fcx
.instantiate_type_scheme(item
.span
, free_substs
, &self_ty
);
324 fcx
.register_wf_obligation(self_ty
, ast_self_ty
.span
, this
.code
.clone());
328 let predicates
= fcx
.tcx().lookup_predicates(item_def_id
);
329 let predicates
= fcx
.instantiate_bounds(item
.span
, free_substs
, &predicates
);
330 this
.check_where_clauses(fcx
, item
.span
, &predicates
);
332 impl_implied_bounds(fcx
, fcx
.tcx().map
.local_def_id(item
.id
), item
.span
)
336 fn check_where_clauses
<'fcx
>(&mut self,
337 fcx
: &FnCtxt
<'fcx
,'tcx
>,
339 predicates
: &ty
::InstantiatedPredicates
<'tcx
>)
342 predicates
.predicates
344 .flat_map(|p
| ty
::wf
::predicate_obligations(fcx
.infcx(),
349 for obligation
in obligations
{
350 fcx
.register_predicate(obligation
);
354 fn check_fn_or_method
<'fcx
>(&mut self,
355 fcx
: &FnCtxt
<'fcx
,'tcx
>,
357 fty
: &ty
::BareFnTy
<'tcx
>,
358 predicates
: &ty
::InstantiatedPredicates
<'tcx
>,
359 free_id_outlive
: CodeExtent
,
360 implied_bounds
: &mut Vec
<Ty
<'tcx
>>)
362 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
363 let fty
= fcx
.instantiate_type_scheme(span
, free_substs
, fty
);
364 let sig
= fcx
.tcx().liberate_late_bound_regions(free_id_outlive
, &fty
.sig
);
366 for &input_ty
in &sig
.inputs
{
367 fcx
.register_wf_obligation(input_ty
, span
, self.code
.clone());
369 implied_bounds
.extend(sig
.inputs
);
372 ty
::FnConverging(output
) => {
373 fcx
.register_wf_obligation(output
, span
, self.code
.clone());
375 // FIXME(#25759) return types should not be implied bounds
376 implied_bounds
.push(output
);
378 ty
::FnDiverging
=> { }
381 self.check_where_clauses(fcx
, span
, predicates
);
384 fn check_method_receiver
<'fcx
>(&mut self,
385 fcx
: &FnCtxt
<'fcx
,'tcx
>,
387 method
: &ty
::Method
<'tcx
>,
388 free_id_outlive
: CodeExtent
,
389 self_ty
: ty
::Ty
<'tcx
>)
391 // check that the type of the method's receiver matches the
392 // method's first parameter.
394 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
395 let fty
= fcx
.instantiate_type_scheme(span
, free_substs
, &method
.fty
);
396 let sig
= fcx
.tcx().liberate_late_bound_regions(free_id_outlive
, &fty
.sig
);
398 debug
!("check_method_receiver({:?},cat={:?},self_ty={:?},sig={:?})",
399 method
.name
, method
.explicit_self
, self_ty
, sig
);
401 let rcvr_ty
= match method
.explicit_self
{
402 ty
::ExplicitSelfCategory
::Static
=> return,
403 ty
::ExplicitSelfCategory
::ByValue
=> self_ty
,
404 ty
::ExplicitSelfCategory
::ByReference(region
, mutability
) => {
405 fcx
.tcx().mk_ref(fcx
.tcx().mk_region(region
), ty
::TypeAndMut
{
410 ty
::ExplicitSelfCategory
::ByBox
=> fcx
.tcx().mk_box(self_ty
)
412 let rcvr_ty
= fcx
.instantiate_type_scheme(span
, free_substs
, &rcvr_ty
);
413 let rcvr_ty
= fcx
.tcx().liberate_late_bound_regions(free_id_outlive
,
414 &ty
::Binder(rcvr_ty
));
416 debug
!("check_method_receiver: receiver ty = {:?}", rcvr_ty
);
418 let _
= ::require_same_types(
419 fcx
.tcx(), Some(fcx
.infcx()), false, span
,
420 sig
.inputs
[0], rcvr_ty
,
421 || "mismatched method receiver".to_owned()
425 fn check_variances_for_type_defn(&self,
427 ast_generics
: &hir
::Generics
)
429 let item_def_id
= self.tcx().map
.local_def_id(item
.id
);
430 let ty_predicates
= self.tcx().lookup_predicates(item_def_id
);
431 let variances
= self.tcx().item_variances(item_def_id
);
433 let mut constrained_parameters
: HashSet
<_
> =
436 .filter(|&(_
, _
, &variance
)| variance
!= ty
::Bivariant
)
437 .map(|(space
, index
, _
)| self.param_ty(ast_generics
, space
, index
))
438 .map(|p
| Parameter
::Type(p
))
441 identify_constrained_type_params(self.tcx(),
442 ty_predicates
.predicates
.as_slice(),
444 &mut constrained_parameters
);
446 for (space
, index
, _
) in variances
.types
.iter_enumerated() {
447 let param_ty
= self.param_ty(ast_generics
, space
, index
);
448 if constrained_parameters
.contains(&Parameter
::Type(param_ty
)) {
451 let span
= self.ty_param_span(ast_generics
, item
, space
, index
);
452 self.report_bivariance(span
, param_ty
.name
);
455 for (space
, index
, &variance
) in variances
.regions
.iter_enumerated() {
456 if variance
!= ty
::Bivariant
{
460 assert_eq
!(space
, TypeSpace
);
461 let span
= ast_generics
.lifetimes
[index
].lifetime
.span
;
462 let name
= ast_generics
.lifetimes
[index
].lifetime
.name
;
463 self.report_bivariance(span
, name
);
468 ast_generics
: &hir
::Generics
,
473 let name
= match space
{
474 TypeSpace
=> ast_generics
.ty_params
[index
].name
,
475 SelfSpace
=> special_idents
::type_self
.name
,
476 FnSpace
=> bug
!("Fn space occupied?"),
479 ty
::ParamTy { space: space, idx: index as u32, name: name }
482 fn ty_param_span(&self,
483 ast_generics
: &hir
::Generics
,
490 TypeSpace
=> ast_generics
.ty_params
[index
].span
,
491 SelfSpace
=> item
.span
,
492 FnSpace
=> span_bug
!(item
.span
, "Fn space occupied?"),
496 fn report_bivariance(&self,
498 param_name
: ast
::Name
)
500 let mut err
= error_392(self.tcx(), span
, param_name
);
502 let suggested_marker_id
= self.tcx().lang_items
.phantom_data();
503 match suggested_marker_id
{
507 &format
!("consider removing `{}` or using a marker such as `{}`",
509 self.tcx().item_path_str(def_id
)));
512 // no lang items, no help!
519 fn reject_shadowing_type_parameters
<'tcx
>(tcx
: &TyCtxt
<'tcx
>,
521 generics
: &ty
::Generics
<'tcx
>) {
522 let impl_params
= generics
.types
.get_slice(subst
::TypeSpace
).iter()
523 .map(|tp
| tp
.name
).collect
::<HashSet
<_
>>();
525 for method_param
in generics
.types
.get_slice(subst
::FnSpace
) {
526 if impl_params
.contains(&method_param
.name
) {
527 error_194(tcx
, span
, method_param
.name
);
532 impl<'ccx
, 'tcx
, 'v
> Visitor
<'v
> for CheckTypeWellFormedVisitor
<'ccx
, 'tcx
> {
533 fn visit_item(&mut self, i
: &hir
::Item
) {
534 debug
!("visit_item: {:?}", i
);
535 self.check_item_well_formed(i
);
536 intravisit
::walk_item(self, i
);
539 fn visit_trait_item(&mut self, trait_item
: &'v hir
::TraitItem
) {
540 debug
!("visit_trait_item: {:?}", trait_item
);
541 self.check_trait_or_impl_item(trait_item
.id
, trait_item
.span
);
542 intravisit
::walk_trait_item(self, trait_item
)
545 fn visit_impl_item(&mut self, impl_item
: &'v hir
::ImplItem
) {
546 debug
!("visit_impl_item: {:?}", impl_item
);
547 self.check_trait_or_impl_item(impl_item
.id
, impl_item
.span
);
548 intravisit
::walk_impl_item(self, impl_item
)
552 ///////////////////////////////////////////////////////////////////////////
555 struct AdtVariant
<'tcx
> {
556 fields
: Vec
<AdtField
<'tcx
>>,
559 struct AdtField
<'tcx
> {
564 fn struct_variant
<'a
, 'tcx
>(fcx
: &FnCtxt
<'a
, 'tcx
>,
565 struct_def
: &hir
::VariantData
)
566 -> AdtVariant
<'tcx
> {
568 struct_def
.fields().iter()
570 let field_ty
= fcx
.tcx().node_id_to_type(field
.id
);
571 let field_ty
= fcx
.instantiate_type_scheme(field
.span
,
574 .parameter_environment
577 AdtField { ty: field_ty, span: field.span }
580 AdtVariant { fields: fields }
583 fn enum_variants
<'a
, 'tcx
>(fcx
: &FnCtxt
<'a
, 'tcx
>,
584 enum_def
: &hir
::EnumDef
)
585 -> Vec
<AdtVariant
<'tcx
>> {
586 enum_def
.variants
.iter()
587 .map(|variant
| struct_variant(fcx
, &variant
.node
.data
))
591 fn impl_implied_bounds
<'fcx
,'tcx
>(fcx
: &FnCtxt
<'fcx
, 'tcx
>,
596 let free_substs
= &fcx
.inh
.infcx
.parameter_environment
.free_substs
;
597 match fcx
.tcx().impl_trait_ref(impl_def_id
) {
598 Some(ref trait_ref
) => {
599 // Trait impl: take implied bounds from all types that
600 // appear in the trait reference.
601 let trait_ref
= fcx
.instantiate_type_scheme(span
, free_substs
, trait_ref
);
602 trait_ref
.substs
.types
.as_slice().to_vec()
606 // Inherent impl: take implied bounds from the self type.
607 let self_ty
= fcx
.tcx().lookup_item_type(impl_def_id
).ty
;
608 let self_ty
= fcx
.instantiate_type_scheme(span
, free_substs
, &self_ty
);
614 pub fn error_192
<'ccx
,'tcx
>(ccx
: &'ccx CrateCtxt
<'ccx
, 'tcx
>, span
: Span
) {
615 span_err
!(ccx
.tcx
.sess
, span
, E0192
,
616 "negative impls are only allowed for traits with \
617 default impls (e.g., `Send` and `Sync`)")
620 pub fn error_380
<'ccx
,'tcx
>(ccx
: &'ccx CrateCtxt
<'ccx
, 'tcx
>, span
: Span
) {
621 span_err
!(ccx
.tcx
.sess
, span
, E0380
,
622 "traits with default impls (`e.g. unsafe impl \
623 Trait for ..`) must have no methods or associated items")
626 pub fn error_392
<'tcx
>(tcx
: &TyCtxt
<'tcx
>, span
: Span
, param_name
: ast
::Name
)
627 -> DiagnosticBuilder
<'tcx
> {
628 struct_span_err
!(tcx
.sess
, span
, E0392
,
629 "parameter `{}` is never used", param_name
)
632 pub fn error_194
<'tcx
>(tcx
: &TyCtxt
<'tcx
>, span
: Span
, name
: ast
::Name
) {
633 span_err
!(tcx
.sess
, span
, E0194
,
634 "type parameter `{}` shadows another type parameter of the same name",