Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use Logging | |
| 3 | ||
| 4 | // .NET lets an interface declare a static member that an | |
| 5 | // implementing type must supply, which is how the generic-math | |
| 6 | // interfaces work. Calling one through a bounded type parameter is | |
| 7 | // supported; supplying one is not, because nothing binds the | |
| 8 | // implementing type's static to the interface's slot, and the CLR | |
| 9 | // refuses to load a type that leaves one unfilled. | |
| 10 | // | |
| 11 | // The assembly compiles either way, so without this the failure is a | |
| 12 | // TypeLoadException at run time naming a member the source declared. | |
| 13 | class STATIC_INTERFACE_IMPLEMENTATION_CHECKER is | |
| 14 | _logger: Logger | |
| 15 | ||
| 16 | init(logger: Logger) is | |
| 17 | _logger = logger | |
| 18 | si | |
| 19 | ||
| 20 | check(type: Classy) is | |
| 21 | // A trait passes the obligation to whatever implements it, | |
| 22 | // and an abstract class to whatever completes it. A | |
| 23 | // reflected type was answered for by the compiler that | |
| 24 | // built its assembly. | |
| 25 | if type.is_trait \/ type.is_reflected \/ type.is_abstract then | |
| 26 | return | |
| 27 | fi | |
| 28 | ||
| 29 | let _ = _check_ancestors(type, type) | |
| 30 | si | |
| 31 | ||
| 32 | // `Classy.ancestors` holds what a type declares, not what it | |
| 33 | // inherits, so reaching an interface a base class or a trait | |
| 34 | // brought in means walking it. A type hierarchy is acyclic, and | |
| 35 | // a diamond only costs a repeated visit that answers the same. | |
| 36 | _check_ancestors(type: Classy, current: Classy) -> bool is | |
| 37 | for ancestor in current.ancestors do | |
| 38 | // Asked of the type rather than of its symbol: where the | |
| 39 | // interface is constructed the symbol is a GENERIC, and | |
| 40 | // a GENERIC is not a Classy. | |
| 41 | if ancestor.is_trait then | |
| 42 | for member in _members(ancestor.symbol) do | |
| 43 | if is_static_slot(member) then | |
| 44 | _logger.error( | |
| 45 | type.location, | |
| 46 | "cannot implement static member {member.name} of {ancestor}", | |
| 47 | member.location, | |
| 48 | "member declared here") | |
| 49 | ||
| 50 | return true | |
| 51 | fi | |
| 52 | od | |
| 53 | fi | |
| 54 | ||
| 55 | // Not through a reflected base class: it already supplies | |
| 56 | // whatever it implements and .NET lets a derived type | |
| 57 | // inherit that, so descending would reject source that | |
| 58 | // loads. A reflected trait supplies nothing, so its own | |
| 59 | // ancestors are still walked. | |
| 60 | if | |
| 61 | let above = _as_classy(ancestor.symbol) /\ | |
| 62 | (above.is_trait \/ !above.is_reflected) /\ | |
| 63 | _check_ancestors(type, above) | |
| 64 | then | |
| 65 | return true | |
| 66 | fi | |
| 67 | od | |
| 68 | ||
| 69 | return false | |
| 70 | si | |
| 71 | ||
| 72 | _as_classy(symbol: Symbol) -> Classy? is | |
| 73 | if let generic: GENERIC = symbol then | |
| 74 | return generic.symbol | |
| 75 | elif let classy: Classy = symbol then | |
| 76 | return classy | |
| 77 | fi | |
| 78 | ||
| 79 | return null | |
| 80 | si | |
| 81 | ||
| 82 | _members(symbol: Symbol) -> Collections.Iterable[Symbol] is | |
| 83 | if let generic: GENERIC = symbol then | |
| 84 | return generic.symbols | |
| 85 | elif let classy: Classy = symbol then | |
| 86 | return classy.symbols | |
| 87 | fi | |
| 88 | ||
| 89 | return Collections.LIST[Symbol]() | |
| 90 | si | |
| 91 | ||
| 92 | // True where the member is, or carries, a slot an implementing | |
| 93 | // type would have to fill with a static. | |
| 94 | is_static_slot(member: Symbol) -> bool static is | |
| 95 | for function in _functions(member) do | |
| 96 | if let method: STATIC_METHOD = function /\ method.is_static_interface_virtual then | |
| 97 | return true | |
| 98 | fi | |
| 99 | od | |
| 100 | ||
| 101 | return false | |
| 102 | si | |
| 103 | ||
| 104 | // A property's slot is its accessor, so the accessors are what | |
| 105 | // carry the static-virtual marker. | |
| 106 | _functions(member: Symbol) -> Collections.Iterable[Function] static is | |
| 107 | let result = Collections.LIST[Function]() | |
| 108 | ||
| 109 | if let group: FUNCTION_GROUP = member then | |
| 110 | for overload in group.functions do | |
| 111 | result.add(overload) | |
| 112 | od | |
| 113 | elif let property: Property = member then | |
| 114 | if let read = property.read_function then | |
| 115 | result.add(read) | |
| 116 | fi | |
| 117 | ||
| 118 | if let assign = property.assign_function then | |
| 119 | result.add(assign) | |
| 120 | fi | |
| 121 | elif let function: Function = member then | |
| 122 | result.add(function) | |
| 123 | fi | |
| 124 | ||
| 125 | return result | |
| 126 | si | |
| 127 | si | |
| 128 | si |