Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use System.Exception | |
| 3 | use System.Text.StringBuilder | |
| 4 | ||
| 5 | use Logging | |
| 6 | use Source | |
| 7 | ||
| 8 | use IR.Values.Value | |
| 9 | ||
| 10 | use Types.Type | |
| 11 | ||
| 12 | class Property: Symbol, Types.SettableTyped abstract is | |
| 13 | _overriders: Collections.MutableList[Symbol]? | |
| 14 | _overridees: Collections.MutableList[Symbol]? | |
| 15 | ||
| 16 | span: LOCATION | |
| 17 | type: Type? | |
| 18 | ||
| 19 | // Incremental body re-walk override: also shift the declaration | |
| 20 | // span when the retained interface symbol is relocated. | |
| 21 | set_span(span_location: LOCATION) is | |
| 22 | span = span_location | |
| 23 | si | |
| 24 | ||
| 25 | set_type(value: Type) is type = value; si | |
| 26 | ||
| 27 | short_description: string => "{name}: {if type? then type.short_description else "?" fi}" | |
| 28 | symbol_kind: SymbolKind => SymbolKind.PROPERTY | |
| 29 | completion_kind: CompletionKind => CompletionKind.PROPERTY | |
| 30 | is_private: bool | |
| 31 | is_assignable: bool public | |
| 32 | is_workspace_visible: bool => !name.starts_with('_') | |
| 33 | ||
| 34 | read_function: Function? public | |
| 35 | read_function_il_name_override: string? public | |
| 36 | ||
| 37 | assign_function: Function? public | |
| 38 | assign_function_il_name_override: string? public | |
| 39 | ||
| 40 | overriders: Collections.Iterable[Symbol]? => _overriders | |
| 41 | overridees: Collections.Iterable[Symbol]? => _overridees | |
| 42 | ||
| 43 | has_overriders: bool => _overriders? /\ _overriders.count > 0 | |
| 44 | ||
| 45 | // Set for a property whose accessors were synthesized over a | |
| 46 | // backing field. The getter of one reads only that field, by | |
| 47 | // construction, which is what lets it narrow without any | |
| 48 | // whole-program analysis. | |
| 49 | is_auto: bool public | |
| 50 | ||
| 51 | // Declared `stable` on a property with no getter to carry the | |
| 52 | // mark — a body-less trait requirement. A property with a | |
| 53 | // read accessor reports the accessor's mark instead; the two | |
| 54 | // are set together where both exist. | |
| 55 | _is_declared_stable: bool | |
| 56 | ||
| 57 | mark_declared_stable() is | |
| 58 | let rsf = root_specialized_from | |
| 59 | ||
| 60 | if rsf != self then | |
| 61 | (cast Property?(rsf)!).mark_declared_stable() | |
| 62 | return | |
| 63 | fi | |
| 64 | ||
| 65 | _is_declared_stable = true | |
| 66 | si | |
| 67 | ||
| 68 | // Whether the property is declared stable — trusted, not | |
| 69 | // verified — so facts narrowed through it count as backed | |
| 70 | // and every override must honour the contract. | |
| 71 | is_declared_stable: bool is | |
| 72 | let rsf = root_specialized_from | |
| 73 | ||
| 74 | if rsf != self then | |
| 75 | return (cast Property?(rsf)!).is_declared_stable | |
| 76 | fi | |
| 77 | ||
| 78 | if read_function? then | |
| 79 | return read_function.is_declared_stable \/ _is_declared_stable | |
| 80 | fi | |
| 81 | ||
| 82 | return _is_declared_stable | |
| 83 | si | |
| 84 | ||
| 85 | // Whether a fact can narrow through this property: its getter | |
| 86 | // must re-read to the same answer under an unchanged heap, | |
| 87 | // provable from the symbol alone - the getter is declared | |
| 88 | // pure or stable (checked contracts that bind overriders), is | |
| 89 | // on the curated store-free import whitelist, or is a | |
| 90 | // synthesized backing-field read; and every property | |
| 91 | // overriding it must qualify the same way, since a call | |
| 92 | // through this one can dispatch to any of them, with nothing | |
| 93 | // outside the assembly able to add one. | |
| 94 | narrowable_getter: bool is | |
| 95 | let getter = read_function | |
| 96 | ||
| 97 | if !getter? then | |
| 98 | return false | |
| 99 | fi | |
| 100 | ||
| 101 | // a pure or stable declaration is a contract every | |
| 102 | // override must honour, checked wherever the override | |
| 103 | // appears, so there is nothing further to ask of the | |
| 104 | // dispatch | |
| 105 | if getter.is_declared_pure \/ getter.is_declared_stable \/ STORE_FREE_IMPORTS.is_store_free(getter) then | |
| 106 | return true | |
| 107 | fi | |
| 108 | ||
| 109 | if !is_auto \/ _openly_dispatchable(getter) then | |
| 110 | return false | |
| 111 | fi | |
| 112 | ||
| 113 | let overriders = self.overriders | |
| 114 | ||
| 115 | if !overriders? then | |
| 116 | return true | |
| 117 | fi | |
| 118 | ||
| 119 | for overrider in overriders do | |
| 120 | if !isa Property(overrider) then | |
| 121 | return false | |
| 122 | fi | |
| 123 | ||
| 124 | if !(cast Property(overrider)).narrowable_getter then | |
| 125 | return false | |
| 126 | fi | |
| 127 | od | |
| 128 | ||
| 129 | return true | |
| 130 | si | |
| 131 | ||
| 132 | // Whether an override outside this compilation could stand | |
| 133 | // behind a call to `getter`: an instance method of anything | |
| 134 | // but a closed class. Mirrors the dispatch-shadow rule the | |
| 135 | // store-free solvers apply, restated here from symbol shape | |
| 136 | // alone. | |
| 137 | _openly_dispatchable(getter: Function) -> bool static is | |
| 138 | if isa STRUCT_METHOD(getter) then | |
| 139 | return false | |
| 140 | fi | |
| 141 | ||
| 142 | if !isa INSTANCE_METHOD(getter) then | |
| 143 | return false | |
| 144 | fi | |
| 145 | ||
| 146 | let owner = getter.owner | |
| 147 | ||
| 148 | if !owner? \/ !isa Classy(owner) then | |
| 149 | return true | |
| 150 | fi | |
| 151 | ||
| 152 | let owner_classy = cast Classy(owner) | |
| 153 | ||
| 154 | return owner_classy.is_open | |
| 155 | si | |
| 156 | ||
| 157 | // Prefixes the description's trailing kind comment when the | |
| 158 | // getter is proven store-free — diagnostic surfacing only, | |
| 159 | // deliberately inside the comment so it does not read as | |
| 160 | // source syntax. | |
| 161 | pure_prefix: string => | |
| 162 | if read_function? /\ read_function.is_proven_store_free then | |
| 163 | "pure " | |
| 164 | else | |
| 165 | "" | |
| 166 | fi | |
| 167 | ||
| 168 | // Shared body for the three concrete Property kinds. Delegates | |
| 169 | // to Symbol._describe_typed so a narrowed property (path | |
| 170 | // narrowing over a `T?` getter) surfaces the same | |
| 171 | // `declared → narrowed` display a variable use gets. | |
| 172 | _describe_property(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 173 | _describe_typed(context, PARTS.name(self), type) | |
| 174 | ||
| 175 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is | |
| 176 | super.init(location, owner, name) | |
| 177 | ||
| 178 | self.span = span | |
| 179 | self.is_assignable = is_assignable | |
| 180 | self.is_private = is_private | |
| 181 | si | |
| 182 | ||
| 183 | add_overrider(overrider: Symbol mut) is | |
| 184 | let rsf = root_specialized_from | |
| 185 | if rsf != self then | |
| 186 | rsf.add_overrider(overrider) | |
| 187 | return | |
| 188 | fi | |
| 189 | ||
| 190 | let overriders mut = _overriders | |
| 191 | ||
| 192 | if !overriders? then | |
| 193 | overriders = Collections.LIST[Symbol]() | |
| 194 | _overriders = overriders | |
| 195 | fi | |
| 196 | ||
| 197 | overrider = overrider.root_specialized_from | |
| 198 | ||
| 199 | if overriders.contains(overrider) then | |
| 200 | return | |
| 201 | fi | |
| 202 | ||
| 203 | overriders.add(overrider) | |
| 204 | ||
| 205 | if let journal = INHERITANCE_JOURNAL.current then | |
| 206 | journal.record(InheritanceOp.PROPERTY_OVERRIDER_ADDED(self, overrider)) | |
| 207 | fi | |
| 208 | si | |
| 209 | ||
| 210 | remove_overrider(overrider: Symbol) is | |
| 211 | let rsf = root_specialized_from | |
| 212 | if rsf != self then | |
| 213 | rsf.remove_overrider(overrider) | |
| 214 | return | |
| 215 | fi | |
| 216 | ||
| 217 | let overriders = _overriders | |
| 218 | ||
| 219 | if overriders? then | |
| 220 | overriders.remove(overrider.root_specialized_from) | |
| 221 | fi | |
| 222 | si | |
| 223 | ||
| 224 | add_overridee(overridee: Symbol mut) is | |
| 225 | let rsf = root_specialized_from | |
| 226 | if rsf != self then | |
| 227 | rsf.add_overridee(overridee) | |
| 228 | return | |
| 229 | fi | |
| 230 | ||
| 231 | let overridees mut = _overridees | |
| 232 | ||
| 233 | if !overridees? then | |
| 234 | overridees = Collections.LIST[Symbol]() | |
| 235 | _overridees = overridees | |
| 236 | fi | |
| 237 | ||
| 238 | overridee = overridee.root_specialized_from | |
| 239 | ||
| 240 | if overridees.contains(overridee) then | |
| 241 | return | |
| 242 | fi | |
| 243 | ||
| 244 | overridees.add(overridee) | |
| 245 | ||
| 246 | if let journal = INHERITANCE_JOURNAL.current then | |
| 247 | journal.record(InheritanceOp.PROPERTY_OVERRIDEE_ADDED(self, overridee)) | |
| 248 | fi | |
| 249 | si | |
| 250 | ||
| 251 | remove_overridee(overridee: Symbol) is | |
| 252 | let rsf = root_specialized_from | |
| 253 | if rsf != self then | |
| 254 | rsf.remove_overridee(overridee) | |
| 255 | return | |
| 256 | fi | |
| 257 | ||
| 258 | let overridees = _overridees | |
| 259 | ||
| 260 | if overridees? then | |
| 261 | overridees.remove(overridee.root_specialized_from) | |
| 262 | fi | |
| 263 | si | |
| 264 | ||
| 265 | specialize(type_map: Collections.Map[Symbol,Type], owner: GENERIC) -> Symbol is | |
| 266 | let result = cast Property?(self.memberwise_clone())! | |
| 267 | ||
| 268 | result.specialized_from = self | |
| 269 | ||
| 270 | if type? then | |
| 271 | result.type = type.specialize(type_map) | |
| 272 | fi | |
| 273 | ||
| 274 | if read_function? then | |
| 275 | result.read_function = read_function.specialize_function(type_map, owner) | |
| 276 | fi | |
| 277 | ||
| 278 | if assign_function? then | |
| 279 | result.assign_function = assign_function.specialize_function(type_map, owner) | |
| 280 | fi | |
| 281 | ||
| 282 | // Attribute the specialized property to the constructed generic so | |
| 283 | // its owner renders with the actual type arguments | |
| 284 | // (`Iterator[char].current`, not `Iterator[T].current`), matching | |
| 285 | // how fields and methods specialize. | |
| 286 | result.owner = owner | |
| 287 | ||
| 288 | return result | |
| 289 | si | |
| 290 | ||
| 291 | to_string() -> string is | |
| 292 | let result = System.Text.StringBuilder() | |
| 293 | ||
| 294 | try | |
| 295 | result.append(IoC.CONTAINER.instance.name_display.name_for(self)) | |
| 296 | result.append(": ") | |
| 297 | result.append(type) | |
| 298 | ||
| 299 | return result.to_string() | |
| 300 | catch ex: Exception | |
| 301 | return "[garbled property: {result}]" | |
| 302 | yrt | |
| 303 | si | |
| 304 | si | |
| 305 | ||
| 306 | class INSTANCE_PROPERTY: Property is | |
| 307 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 308 | _describe_property(context) | |
| 309 | ||
| 310 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 311 | "{pure_prefix}instance property" | |
| 312 | ||
| 313 | is_instance: bool => true | |
| 314 | ||
| 315 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is | |
| 316 | super.init(location, span, owner, name, is_assignable, is_private) | |
| 317 | si | |
| 318 | ||
| 319 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_instance_property(location, from, self) | |
| 320 | ||
| 321 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_instance_property(location, from, self, value) | |
| 322 | ||
| 323 | si | |
| 324 | ||
| 325 | class STATIC_PROPERTY: Property is | |
| 326 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 327 | _describe_property(context) | |
| 328 | ||
| 329 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 330 | "{pure_prefix}class property" | |
| 331 | ||
| 332 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool, is_private: bool) is | |
| 333 | super.init(location, span, owner, name, is_assignable, is_private) | |
| 334 | si | |
| 335 | ||
| 336 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_static_property(location, self) | |
| 337 | ||
| 338 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_static_property(location, self, value) | |
| 339 | ||
| 340 | si | |
| 341 | ||
| 342 | class GLOBAL_PROPERTY: Property is | |
| 343 | describe(context: DESCRIBE_CONTEXT) -> SignaturePart => | |
| 344 | _describe_property(context) | |
| 345 | ||
| 346 | describe_kind(context: DESCRIBE_CONTEXT) -> string? => | |
| 347 | "{pure_prefix}global property" | |
| 348 | ||
| 349 | init(location: LOCATION, span: LOCATION, owner: Scope, name: string, is_assignable: bool) is | |
| 350 | super.init(location, span, owner, name, is_assignable, false) | |
| 351 | si | |
| 352 | ||
| 353 | load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value => loader.load_global_property(location, self) | |
| 354 | ||
| 355 | store(location: LOCATION, from: Value?, value: Value, loader: SYMBOL_LOADER, is_initialize: bool) -> Value => loader.store_global_property(location, self, value) | |
| 356 | ||
| 357 | si | |
| 358 | si |