Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use Source.LOCATION | |
| 3 | ||
| 4 | use Types.Type | |
| 5 | ||
| 6 | // `Collections.Iterator[T]` maps to `IEnumerator[T]`, which carries | |
| 7 | // `Reset` from the interface .NET's own iterators answer by | |
| 8 | // throwing: it is there for COM and almost nothing calls it. An | |
| 9 | // implementor that writes one is writing a method that will not be | |
| 10 | // called, so one is synthesized where none is declared, throwing | |
| 11 | // rather than doing nothing - a caller that did ask for a restart | |
| 12 | // is owed the news that it did not happen. | |
| 13 | // | |
| 14 | // `dispose` is left an obligation: what a type holds and must | |
| 15 | // release is the author's to answer. | |
| 16 | class ITERATOR_RESET_SYNTHESIS is | |
| 17 | _innate_symbol_lookup: Lookups.InnateSymbolLookup | |
| 18 | ||
| 19 | init(innate_symbol_lookup: Lookups.InnateSymbolLookup) is | |
| 20 | _innate_symbol_lookup = innate_symbol_lookup | |
| 21 | si | |
| 22 | ||
| 23 | // Answers the synthesized method, or null where the type wants | |
| 24 | // none: one it declares itself always wins. | |
| 25 | try_synthesize(type: Classy) -> Function? is | |
| 26 | if type.is_trait \/ type.is_reflected \/ type.is_abstract then | |
| 27 | return null | |
| 28 | fi | |
| 29 | ||
| 30 | if !_implements_iterator(type) then | |
| 31 | return null | |
| 32 | fi | |
| 33 | ||
| 34 | if _has_reset_body(type) then | |
| 35 | return null | |
| 36 | fi | |
| 37 | ||
| 38 | let reset = | |
| 39 | if type.is_value_type then | |
| 40 | STRUCT_METHOD(type.location, type.location, type, "reset", type) | |
| 41 | else | |
| 42 | INSTANCE_METHOD(type.location, type.location, type, "reset", type) | |
| 43 | fi | |
| 44 | ||
| 45 | reset.set_arguments( | |
| 46 | Collections.LIST[string](), Collections.LIST[Type]()) | |
| 47 | ||
| 48 | reset.set_void_return_type() | |
| 49 | reset.mark_throws_not_supported() | |
| 50 | ||
| 51 | type.add_member(reset) | |
| 52 | ||
| 53 | return reset | |
| 54 | si | |
| 55 | ||
| 56 | // Whether anything already answers `reset` with a body: the | |
| 57 | // type's own, a base class's, or the default a trait supplies. | |
| 58 | // Overrides have not been resolved yet, so the ancestors are | |
| 59 | // walked rather than asked - and the interface's own | |
| 60 | // declaration is passed over, since that is the obligation | |
| 61 | // being answered rather than an answer to it. | |
| 62 | _has_reset_body(type: Classy) -> bool is | |
| 63 | if _declares_reset_body(type) then | |
| 64 | return true | |
| 65 | fi | |
| 66 | ||
| 67 | for ancestor in type.ancestors do | |
| 68 | if let classy: Classy = ancestor.symbol /\ _has_reset_body(classy) then | |
| 69 | return true | |
| 70 | fi | |
| 71 | od | |
| 72 | ||
| 73 | return false | |
| 74 | si | |
| 75 | ||
| 76 | _declares_reset_body(type: Classy) -> bool is | |
| 77 | let found = type.find_direct("reset") | |
| 78 | ||
| 79 | if let group: FUNCTION_GROUP = found then | |
| 80 | for f in group.functions do | |
| 81 | if _is_implementation(f) then | |
| 82 | return true | |
| 83 | fi | |
| 84 | od | |
| 85 | ||
| 86 | return false | |
| 87 | fi | |
| 88 | ||
| 89 | if let single: Function = found then | |
| 90 | return _is_implementation(single) | |
| 91 | fi | |
| 92 | ||
| 93 | return false | |
| 94 | si | |
| 95 | ||
| 96 | _is_implementation(f: Function) -> bool static => | |
| 97 | f.arguments.count == 0 /\ !f.is_abstract | |
| 98 | ||
| 99 | _implements_iterator(type: Classy) -> bool is | |
| 100 | let iterator = _innate_symbol_lookup.get_unspecialized_iterator_type() | |
| 101 | ||
| 102 | for ancestor in type.ancestors do | |
| 103 | if !ancestor.is_trait then | |
| 104 | continue | |
| 105 | fi | |
| 106 | ||
| 107 | if ancestor.find_ancestor(iterator)? then | |
| 108 | return true | |
| 109 | fi | |
| 110 | od | |
| 111 | ||
| 112 | return false | |
| 113 | si | |
| 114 | si | |
| 115 | si |