7
7
import metadata:: csearch:: { each_path, get_impl_traits, get_impls_for_mod} ;
8
8
import metadata:: cstore:: { cstore, iter_crate_data} ;
9
9
import metadata:: decoder:: { dl_def, dl_field, dl_impl} ;
10
- import middle:: resolve3:: Impl ;
10
+ import middle:: resolve3:: { Impl , MethodInfo } ;
11
11
import middle:: ty:: { get, lookup_item_type, subst, t, ty_box} ;
12
12
import middle:: ty:: { ty_uniq, ty_ptr, ty_rptr, ty_enum} ;
13
13
import 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,
108
108
}
109
109
}
110
110
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
+
111
121
class CoherenceInfo {
112
122
// Contains implementations of methods that are inherent to a type.
113
123
// Methods in these implementations don't need to be exported.
@@ -151,10 +161,70 @@ class CoherenceChecker {
151
161
self . privileged_types = new_def_hash ( ) ;
152
162
}
153
163
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
+
154
224
fn check_coherence ( crate : @crate ) {
225
+
155
226
// Check implementations. This populates the tables containing the
156
227
// inherent methods and extension methods.
157
-
158
228
visit_crate ( * crate , ( ) , mk_simple_visitor ( @{
159
229
visit_item: |item| {
160
230
debug ! { "(checking coherence) item '%s'" , * item. ident} ;
@@ -430,15 +500,13 @@ class CoherenceChecker {
430
500
// trait was defined in this
431
501
// crate.
432
502
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 ;
442
510
session. span_err ( item. span ,
443
511
~"cannot \
444
512
provide an \
@@ -466,6 +534,13 @@ class CoherenceChecker {
466
534
}));
467
535
}
468
536
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
+
469
544
fn gather_privileged_types(items: ~[@item]) -> @dvec<def_id> {
470
545
let results = @dvec();
471
546
for items.each |item| {
@@ -487,16 +562,70 @@ class CoherenceChecker {
487
562
488
563
// Converts an implementation in the AST to an Impl structure.
489
564
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
+
490
592
match item. node {
491
- item_impl(ty_params, _ , _, ast_methods) => {
593
+ item_impl ( ty_params, trait_refs , _, ast_methods) => {
492
594
let mut methods = ~[ ] ;
595
+
493
596
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
+ }
500
629
}
501
630
502
631
return @{
@@ -669,6 +798,8 @@ class CoherenceChecker {
669
798
}
670
799
671
800
fn 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 ) ;
673
804
}
674
805
0 commit comments