8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ //! This pass enforces various "well-formedness constraints" on impls.
12
+ //! Logically, it is part of wfcheck -- but we do it early so that we
13
+ //! can stop compilation afterwards, since part of the trait matching
14
+ //! infrastructure gets very grumpy if these conditions don't hold. In
15
+ //! particular, if there are type parameters that are not part of the
16
+ //! impl, then coherence will report strange inference ambiguity
17
+ //! errors; if impls have duplicate items, we get misleading
18
+ //! specialization errors. These things can (and probably should) be
19
+ //! fixed, but for the moment it's easier to do these checks early.
20
+
11
21
use constrained_type_params as ctp;
22
+ use rustc:: dep_graph:: DepNode ;
12
23
use rustc:: hir;
24
+ use rustc:: hir:: itemlikevisit:: ItemLikeVisitor ;
13
25
use rustc:: hir:: def_id:: DefId ;
14
26
use rustc:: ty;
15
- use rustc:: util:: nodemap:: FxHashSet ;
27
+ use rustc:: util:: nodemap:: { FxHashMap , FxHashSet } ;
28
+ use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
16
29
17
30
use syntax_pos:: Span ;
18
31
@@ -48,22 +61,52 @@ use CrateCtxt;
48
61
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
49
62
/// ^ 'a is unused and appears in assoc type, error
50
63
/// ```
51
- pub fn enforce_impl_params_are_constrained < ' a , ' tcx > ( ccx : & CrateCtxt < ' a , ' tcx > ,
52
- impl_hir_generics : & hir:: Generics ,
53
- impl_def_id : DefId ,
54
- impl_item_refs : & [ hir:: ImplItemRef ] )
64
+ pub fn impl_wf_check < ' a , ' tcx > ( ccx : & CrateCtxt < ' a , ' tcx > ) {
65
+ // We will tag this as part of the WF check -- logically, it is,
66
+ // but it's one that we must perform earlier than the rest of
67
+ // WfCheck.
68
+ ccx. tcx . visit_all_item_likes_in_krate ( DepNode :: WfCheck , & mut ImplWfCheck { ccx : ccx } ) ;
69
+ }
70
+
71
+ struct ImplWfCheck < ' a , ' tcx : ' a > {
72
+ ccx : & ' a CrateCtxt < ' a , ' tcx > ,
73
+ }
74
+
75
+ impl < ' a , ' tcx > ItemLikeVisitor < ' tcx > for ImplWfCheck < ' a , ' tcx > {
76
+ fn visit_item ( & mut self , item : & ' tcx hir:: Item ) {
77
+ match item. node {
78
+ hir:: ItemImpl ( .., ref generics, _, _, ref impl_item_refs) => {
79
+ let impl_def_id = self . ccx . tcx . map . local_def_id ( item. id ) ;
80
+ enforce_impl_params_are_constrained ( self . ccx ,
81
+ generics,
82
+ impl_def_id,
83
+ impl_item_refs) ;
84
+ enforce_impl_items_are_distinct ( self . ccx , impl_item_refs) ;
85
+ }
86
+ _ => { }
87
+ }
88
+ }
89
+
90
+ fn visit_impl_item ( & mut self , _impl_item : & ' tcx hir:: ImplItem ) { }
91
+ }
92
+
93
+ fn enforce_impl_params_are_constrained < ' a , ' tcx > ( ccx : & CrateCtxt < ' a , ' tcx > ,
94
+ impl_hir_generics : & hir:: Generics ,
95
+ impl_def_id : DefId ,
96
+ impl_item_refs : & [ hir:: ImplItemRef ] )
55
97
{
56
98
// Every lifetime used in an associated type must be constrained.
57
- let impl_scheme = ccx. tcx . lookup_item_type ( impl_def_id) ;
58
- let impl_predicates = ccx. tcx . lookup_predicates ( impl_def_id) ;
99
+ let impl_self_ty = ccx. tcx . item_type ( impl_def_id) ;
100
+ let impl_generics = ccx. tcx . item_generics ( impl_def_id) ;
101
+ let impl_predicates = ccx. tcx . item_predicates ( impl_def_id) ;
59
102
let impl_trait_ref = ccx. tcx . impl_trait_ref ( impl_def_id) ;
60
103
61
- let mut input_parameters = ctp:: parameters_for_impl ( impl_scheme . ty , impl_trait_ref) ;
104
+ let mut input_parameters = ctp:: parameters_for_impl ( impl_self_ty , impl_trait_ref) ;
62
105
ctp:: identify_constrained_type_params (
63
106
& impl_predicates. predicates . as_slice ( ) , impl_trait_ref, & mut input_parameters) ;
64
107
65
108
// Disallow ANY unconstrained type parameters.
66
- for ( ty_param, param) in impl_scheme . generics . types . iter ( ) . zip ( & impl_hir_generics. ty_params ) {
109
+ for ( ty_param, param) in impl_generics . types . iter ( ) . zip ( & impl_hir_generics. ty_params ) {
67
110
let param_ty = ty:: ParamTy :: for_def ( ty_param) ;
68
111
if !input_parameters. contains ( & ctp:: Parameter :: from ( param_ty) ) {
69
112
report_unused_parameter ( ccx, param. span , "type" , & param_ty. to_string ( ) ) ;
@@ -78,9 +121,9 @@ pub fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
78
121
item. kind == ty:: AssociatedKind :: Type && item. has_value
79
122
} )
80
123
. flat_map ( |def_id| {
81
- ctp:: parameters_for ( & ccx. tcx . lookup_item_type ( def_id) . ty , true )
124
+ ctp:: parameters_for ( & ccx. tcx . item_type ( def_id) , true )
82
125
} ) . collect ( ) ;
83
- for ( ty_lifetime, lifetime) in impl_scheme . generics . regions . iter ( )
126
+ for ( ty_lifetime, lifetime) in impl_generics . regions . iter ( )
84
127
. zip ( & impl_hir_generics. lifetimes )
85
128
{
86
129
let param = ctp:: Parameter :: from ( ty_lifetime. to_early_bound_region_data ( ) ) ;
@@ -127,3 +170,34 @@ fn report_unused_parameter(ccx: &CrateCtxt,
127
170
. span_label ( span, & format ! ( "unconstrained {} parameter" , kind) )
128
171
. emit ( ) ;
129
172
}
173
+
174
+ /// Enforce that we do not have two items in an impl with the same name.
175
+ fn enforce_impl_items_are_distinct < ' a , ' tcx > ( ccx : & CrateCtxt < ' a , ' tcx > ,
176
+ impl_item_refs : & [ hir:: ImplItemRef ] )
177
+ {
178
+ let tcx = ccx. tcx ;
179
+ let mut seen_type_items = FxHashMap ( ) ;
180
+ let mut seen_value_items = FxHashMap ( ) ;
181
+ for impl_item_ref in impl_item_refs {
182
+ let impl_item = tcx. map . impl_item ( impl_item_ref. id ) ;
183
+ let seen_items = match impl_item. node {
184
+ hir:: ImplItemKind :: Type ( _) => & mut seen_type_items,
185
+ _ => & mut seen_value_items,
186
+ } ;
187
+ match seen_items. entry ( impl_item. name ) {
188
+ Occupied ( entry) => {
189
+ let mut err = struct_span_err ! ( tcx. sess, impl_item. span, E0201 ,
190
+ "duplicate definitions with name `{}`:" ,
191
+ impl_item. name) ;
192
+ err. span_label ( * entry. get ( ) ,
193
+ & format ! ( "previous definition of `{}` here" ,
194
+ impl_item. name) ) ;
195
+ err. span_label ( impl_item. span , & format ! ( "duplicate definition" ) ) ;
196
+ err. emit ( ) ;
197
+ }
198
+ Vacant ( entry) => {
199
+ entry. insert ( impl_item. span ) ;
200
+ }
201
+ }
202
+ }
203
+ }
0 commit comments