88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
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+
1121use constrained_type_params as ctp;
22+ use rustc:: dep_graph:: DepNode ;
1223use rustc:: hir;
24+ use rustc:: hir:: itemlikevisit:: ItemLikeVisitor ;
1325use rustc:: hir:: def_id:: DefId ;
1426use rustc:: ty;
15- use rustc:: util:: nodemap:: FxHashSet ;
27+ use rustc:: util:: nodemap:: { FxHashMap , FxHashSet } ;
28+ use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
1629
1730use syntax_pos:: Span ;
1831
@@ -48,22 +61,52 @@ use CrateCtxt;
4861/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
4962/// ^ 'a is unused and appears in assoc type, error
5063/// ```
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 ] )
5597{
5698 // 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) ;
59102 let impl_trait_ref = ccx. tcx . impl_trait_ref ( impl_def_id) ;
60103
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) ;
62105 ctp:: identify_constrained_type_params (
63106 & impl_predicates. predicates . as_slice ( ) , impl_trait_ref, & mut input_parameters) ;
64107
65108 // 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 ) {
67110 let param_ty = ty:: ParamTy :: for_def ( ty_param) ;
68111 if !input_parameters. contains ( & ctp:: Parameter :: from ( param_ty) ) {
69112 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>,
78121 item. kind == ty:: AssociatedKind :: Type && item. has_value
79122 } )
80123 . 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 )
82125 } ) . collect ( ) ;
83- for ( ty_lifetime, lifetime) in impl_scheme . generics . regions . iter ( )
126+ for ( ty_lifetime, lifetime) in impl_generics . regions . iter ( )
84127 . zip ( & impl_hir_generics. lifetimes )
85128 {
86129 let param = ctp:: Parameter :: from ( ty_lifetime. to_early_bound_region_data ( ) ) ;
@@ -127,3 +170,34 @@ fn report_unused_parameter(ccx: &CrateCtxt,
127170 . span_label ( span, & format ! ( "unconstrained {} parameter" , kind) )
128171 . emit ( ) ;
129172}
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