77import metadata:: csearch:: { each_path, get_impl_traits, get_impls_for_mod} ;
88import metadata:: cstore:: { cstore, iter_crate_data} ;
99import metadata:: decoder:: { dl_def, dl_field, dl_impl} ;
10- import middle:: resolve3:: Impl ;
10+ import middle:: resolve3:: { Impl , MethodInfo } ;
1111import middle:: ty:: { get, lookup_item_type, subst, t, ty_box} ;
1212import middle:: ty:: { ty_uniq, ty_ptr, ty_rptr, ty_enum} ;
1313import middle:: ty:: { ty_class, ty_nil, ty_bot, ty_bool, ty_int, ty_uint} ;
@@ -108,6 +108,16 @@ fn get_base_type_def_id(inference_context: infer_ctxt,
108108 }
109109}
110110
111+
112+ fn method_to_MethodInfo ( ast_method : @method ) -> @MethodInfo {
113+ @{
114+ did: local_def ( ast_method. id ) ,
115+ n_tps: ast_method. tps . len ( ) ,
116+ ident: ast_method. ident ,
117+ self_type: ast_method. self_ty . node
118+ }
119+ }
120+
111121class CoherenceInfo {
112122 // Contains implementations of methods that are inherent to a type.
113123 // Methods in these implementations don't need to be exported.
@@ -151,10 +161,70 @@ class CoherenceChecker {
151161 self . privileged_types = new_def_hash ( ) ;
152162 }
153163
164+ // Create a mapping containing a MethodInfo for every provided
165+ // method in every trait.
166+ fn build_provided_methods_map ( crate : @crate ) {
167+
168+ let pmm = self . crate_context . provided_methods_map ;
169+
170+ visit_crate ( * crate , ( ) , mk_simple_visitor ( @{
171+ visit_item: |item| {
172+ match item. node {
173+ item_trait( _, _, trait_methods) => {
174+ for trait_methods. each |trait_method| {
175+ debug ! { "(building provided methods map) checking \
176+ trait `%s` with id %d", * item. ident, item. id} ;
177+
178+ match trait_method {
179+ required( _) => { /* fall through */ }
180+ provided( m) => {
181+ // For every provided method in the
182+ // trait, store a MethodInfo.
183+ let mi = method_to_MethodInfo ( m) ;
184+
185+ match pmm. find ( item. id ) {
186+ some( mis) => {
187+ // If the trait already has an
188+ // entry in the
189+ // provided_methods_map, we just
190+ // need to add this method to
191+ // that entry.
192+ debug ! { "(building provided \
193+ methods map) adding \
194+ method `%s` to entry for \
195+ existing trait",
196+ * mi. ident} ;
197+ let mut method_infos = mis;
198+ push ( method_infos, mi) ;
199+ pmm. insert ( item. id , method_infos) ;
200+ }
201+ none => {
202+ // If the trait doesn't have an
203+ // entry yet, create one.
204+ debug ! { "(building provided \
205+ methods map) creating new \
206+ entry for method `%s`",
207+ * mi. ident} ;
208+ pmm. insert ( item. id , ~[ mi] ) ;
209+ }
210+ }
211+ }
212+ }
213+ }
214+ }
215+ _ => {
216+ // Nothing to do.
217+ }
218+ } ;
219+ }
220+ with * default_simple_visitor ( )
221+ } ) ) ;
222+ }
223+
154224 fn check_coherence ( crate : @crate ) {
225+
155226 // Check implementations. This populates the tables containing the
156227 // inherent methods and extension methods.
157-
158228 visit_crate ( * crate , ( ) , mk_simple_visitor ( @{
159229 visit_item: |item| {
160230 debug ! { "(checking coherence) item '%s'" , * item. ident} ;
@@ -430,15 +500,13 @@ class CoherenceChecker {
430500 // trait was defined in this
431501 // crate.
432502
433- let def_map = self . crate_context . tcx
434- . def_map ;
435- let trait_def = def_map. get
436- ( trait_ref. ref_id ) ;
437- let trait_id =
438- def_id_of_def ( trait_def) ;
439- if trait_id. crate != local_crate {
440- let session = self . crate_context
441- . tcx . sess ;
503+ let trait_def_id =
504+ self . trait_ref_to_trait_def_id (
505+ trait_ref) ;
506+
507+ if trait_def_id. crate != local_crate {
508+ let session =
509+ self . crate_context . tcx . sess ;
442510 session. span_err ( item. span ,
443511 ~"cannot \
444512 provide an \
@@ -466,6 +534,13 @@ class CoherenceChecker {
466534 }));
467535 }
468536
537+ fn trait_ref_to_trait_def_id(trait_ref: @trait_ref) -> def_id {
538+ let def_map = self.crate_context.tcx.def_map;
539+ let trait_def = def_map.get(trait_ref.ref_id);
540+ let trait_id = def_id_of_def(trait_def);
541+ return trait_id;
542+ }
543+
469544 fn gather_privileged_types(items: ~[@item]) -> @dvec<def_id> {
470545 let results = @dvec();
471546 for items.each |item| {
@@ -487,16 +562,70 @@ class CoherenceChecker {
487562
488563 // Converts an implementation in the AST to an Impl structure.
489564 fn create_impl_from_item(item: @item) -> @Impl {
565+
566+ fn add_provided_methods(inherent_methods: ~[@MethodInfo],
567+ all_provided_methods: ~[@MethodInfo])
568+ -> ~[@MethodInfo] {
569+
570+ let mut methods = inherent_methods;
571+
572+ // If there's no inherent method with the same name as a
573+ // provided method, add that provided method to `methods`.
574+ for all_provided_methods.each |provided_method| {
575+ let mut method_inherent_to_impl = false;
576+ for inherent_methods.each |inherent_method| {
577+ if provided_method.ident == inherent_method.ident {
578+ method_inherent_to_impl = true;
579+ }
580+ }
581+
582+ if !method_inherent_to_impl {
583+ debug!{" ( creating impl) adding provided method `%s` to \
584+ impl ", * provided_method. ident } ;
585+ push( methods, provided_method) ;
586+ }
587+ }
588+
589+ return methods;
590+ }
591+
490592 match item. node {
491- item_impl(ty_params, _ , _, ast_methods) => {
593+ item_impl ( ty_params, trait_refs , _, ast_methods) => {
492594 let mut methods = ~[ ] ;
595+
493596 for ast_methods. each |ast_method| {
494- push(methods, @{
495- did: local_def(ast_method.id),
496- n_tps: ast_method.tps.len(),
497- ident: ast_method.ident,
498- self_type: ast_method.self_ty.node
499- });
597+ push ( methods,
598+ method_to_MethodInfo ( ast_method) ) ;
599+ }
600+
601+ // For each trait that the impl implements, see what
602+ // methods are provided. For each of those methods,
603+ // if a method of that name is not inherent to the
604+ // impl, use the provided definition in the trait.
605+ for trait_refs. each |trait_ref| {
606+
607+ let trait_did = self . trait_ref_to_trait_def_id ( trait_ref) ;
608+
609+ match self . crate_context . provided_methods_map
610+ . find ( trait_did. node ) {
611+ none => {
612+ debug ! { "(creating impl) trait with node_id `%d` \
613+ has no provided methods", trait_did. node} ;
614+ /* fall through */
615+ }
616+ some( all_provided)
617+ => {
618+ debug ! { "(creating impl) trait with node_id `%d` \
619+ has provided methods", trait_did. node} ;
620+ // Selectively add only those provided
621+ // methods that aren't inherent to the
622+ // trait.
623+
624+ // XXX: could probably be doing this with filter.
625+ methods = add_provided_methods ( methods,
626+ all_provided) ;
627+ }
628+ }
500629 }
501630
502631 return @{
@@ -669,6 +798,8 @@ class CoherenceChecker {
669798}
670799
671800fn check_coherence( crate_context: @crate_ctxt, crate : @crate ) {
672- CoherenceChecker ( crate_context) . check_coherence( crate ) ;
801+ let coherence_checker = @CoherenceChecker ( crate_context) ;
802+ ( * coherence_checker) . build_provided_methods_map( crate ) ;
803+ ( * coherence_checker) . check_coherence( crate ) ;
673804}
674805
0 commit comments