Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use IO.Std | |
| 3 | ||
| 4 | use System.Text.StringBuilder | |
| 5 | ||
| 6 | use IoC | |
| 7 | use Source | |
| 8 | ||
| 9 | use Types.Type | |
| 10 | ||
| 11 | use Ghul.Pipes | |
| 12 | ||
| 13 | // Shared frame-class machinery for both generator and async | |
| 14 | // state machines: type-parameter capture + substitution, lazily- | |
| 15 | // allocated locals/anonymous fields, and the outer-self-type | |
| 16 | // helper. Subclasses add their protocol-specific fields and | |
| 17 | // ancestors. | |
| 18 | class STATE_MACHINE_FRAME_BASE: Classy is | |
| 19 | _owning_function: Function | |
| 20 | _local_fields: Collections.LIST[Field] | |
| 21 | _hoisted_locals: Collections.LIST[Variable] | |
| 22 | _next_local_id: int | |
| 23 | _function_to_class_type_map: Collections.MAP[Symbol, Type] | |
| 24 | _mirror_by_key: Collections.MAP[TYPE_PARAMETER_KEY, Type] | |
| 25 | ||
| 26 | // The owning function's parameters, one frame field each; the | |
| 27 | // constructor takes one parameter per field and stores into it, | |
| 28 | // so the body's IR for a parameter load routes through | |
| 29 | // `state_machine_field` and becomes ldarg.0; ldfld instead of | |
| 30 | // ldarg. `_ctor_argument_names` records the constructor's | |
| 31 | // parameter names as first declared - the `$outer_self` slot | |
| 32 | // (when present) followed by one per argument field - so | |
| 33 | // refresh re-reads each user name's local to rebuild the types | |
| 34 | // without recomputing the pairing. | |
| 35 | _argument_fields: Collections.LIST[Field] | |
| 36 | _argument_initial_fields: Collections.LIST[Field] | |
| 37 | _ctor_argument_names: Collections.LIST[string]? | |
| 38 | ||
| 39 | _outer_self_field: Field? | |
| 40 | _constructor: Method? | |
| 41 | ||
| 42 | owning_function: Function => _owning_function | |
| 43 | local_fields: Collections.Iterable[Field] => _local_fields | |
| 44 | function_to_class_type_map: Collections.Map[Symbol, Type] => _function_to_class_type_map | |
| 45 | argument_fields: Collections.Iterable[Field] => _argument_fields | |
| 46 | // Pristine copies of the constructor arguments, so a rewind can | |
| 47 | // restore what the body started from after the body has written | |
| 48 | // the working fields. A generator frame declares one per entry in | |
| 49 | // `argument_fields`, at the same index and the same type; an async | |
| 50 | // frame declares none, since an async method runs once. Nothing | |
| 51 | // in between is legal - `has_argument_initial_fields` is the test, | |
| 52 | // and a consumer that has one twin may index all of them. | |
| 53 | argument_initial_fields: Collections.List[Field] => _argument_initial_fields | |
| 54 | ||
| 55 | // Whether this frame carries pristine argument copies at all. | |
| 56 | has_argument_initial_fields: bool => _argument_initial_fields.count > 0 | |
| 57 | outer_self_field: Field? => _outer_self_field | |
| 58 | constructor: Method => _constructor! | |
| 59 | ||
| 60 | init( | |
| 61 | location: LOCATION, | |
| 62 | span: LOCATION, | |
| 63 | owner_owner: Scope, | |
| 64 | name: string, | |
| 65 | owner: Scope, | |
| 66 | owning_function: Function | |
| 67 | ) is | |
| 68 | super.init( | |
| 69 | location, | |
| 70 | span, | |
| 71 | owner_owner, | |
| 72 | name, | |
| 73 | System.Array.empty[string](), | |
| 74 | owner | |
| 75 | ) | |
| 76 | ||
| 77 | _owning_function = owning_function | |
| 78 | _local_fields = Collections.LIST[Field]() | |
| 79 | _hoisted_locals = Collections.LIST[Variable]() | |
| 80 | _function_to_class_type_map = Collections.MAP[Symbol, Type]() | |
| 81 | _mirror_by_key = Collections.MAP[TYPE_PARAMETER_KEY, Type]() | |
| 82 | _argument_fields = Collections.LIST[Field]() | |
| 83 | _argument_initial_fields = Collections.LIST[Field]() | |
| 84 | si | |
| 85 | ||
| 86 | // Declare class-level type parameters mirroring those visible | |
| 87 | // inside the owning function: enclosing class's first, then | |
| 88 | // function's own. Order must match | |
| 89 | // STATE_MACHINE_TYPE_PARAMS.walk_install / | |
| 90 | // construction_type_arguments so `!N` indices line up at IL. | |
| 91 | _declared_type_param_count: int | |
| 92 | ||
| 93 | // Whether this frame declares a parameter of its own standing | |
| 94 | // for `parameter`, and which one. Keyed on the symbol: two | |
| 95 | // parameters in different scopes are routinely spelled alike. | |
| 96 | mirrors(parameter: Symbol) -> bool => | |
| 97 | if let argument: GenericArgument = parameter then | |
| 98 | _mirror_by_key.contains_key(TYPE_PARAMETER_KEY.of(argument)) | |
| 99 | else | |
| 100 | false | |
| 101 | fi | |
| 102 | ||
| 103 | mirror_of(parameter: Symbol) -> Type => | |
| 104 | _mirror_by_key[TYPE_PARAMETER_KEY.of(cast GenericArgument?(parameter)!)] | |
| 105 | ||
| 106 | ||
| 107 | declare_captured_type_params(listener: SymbolDefinitionListener) -> Collections.LIST[string] is | |
| 108 | let parameters = STATE_MACHINE_TYPE_PARAMS.captured_parameters(_owning_function) | |
| 109 | ||
| 110 | let captured_names = Collections.LIST[string]() | |
| 111 | ||
| 112 | for parameter in parameters do | |
| 113 | captured_names.add(parameter.name) | |
| 114 | od | |
| 115 | ||
| 116 | // A closure's captured set grows while its body is walked, | |
| 117 | // and the frame is asked for its parameters before that | |
| 118 | // finishes. Declare the ones that have arrived since rather | |
| 119 | // than the whole list again: an index already handed out | |
| 120 | // names a position the body has rendered against. | |
| 121 | if _declared_type_param_count >= parameters.count then | |
| 122 | return captured_names | |
| 123 | fi | |
| 124 | ||
| 125 | let mirror = CAPTURED_CONSTRAINT_MIRROR(t => _class_relative(t)) | |
| 126 | ||
| 127 | for i in _declared_type_param_count..parameters.count do | |
| 128 | let parameter = parameters[i] | |
| 129 | ||
| 130 | let class_type_arg = declare_type(LOCATION.internal, parameter.name, i, listener) | |
| 131 | ||
| 132 | if let argument: GenericArgument = parameter then | |
| 133 | let mirrored = cast Types.Typed?(class_type_arg)!.type! | |
| 134 | ||
| 135 | _function_to_class_type_map[argument] = mirrored | |
| 136 | _mirror_by_key[TYPE_PARAMETER_KEY.of(argument)] = mirrored | |
| 137 | ||
| 138 | if let source: Symbol = argument.owner then | |
| 139 | mirror.capture(class_type_arg, source, argument.index) | |
| 140 | fi | |
| 141 | fi | |
| 142 | od | |
| 143 | ||
| 144 | _declared_type_param_count = parameters.count | |
| 145 | ||
| 146 | mirror.apply_bounds() | |
| 147 | ||
| 148 | argument_names = captured_names | |
| 149 | ||
| 150 | return captured_names | |
| 151 | si | |
| 152 | ||
| 153 | // Type for the `$outer_self` field + ctor argument, taking each | |
| 154 | // of a generic outer class's arguments from the frame's mirrored | |
| 155 | // class-T's. | |
| 156 | outer_self_type(outer_classy: Classy) -> Type => | |
| 157 | SELF_CAPTURE_TYPE((classy, name) => _mirrored_class_type(classy, name)).of(outer_classy) ?? outer_classy.type! | |
| 158 | ||
| 159 | _mirrored_class_type(owner_classy: Classy, name: string) -> Type? is | |
| 160 | for i in 0..owner_classy.argument_names.count do | |
| 161 | if owner_classy.argument_names[i] =~ name then | |
| 162 | let parameter = cast GenericArgument?(owner_classy.type_parameter_at(i)) | |
| 163 | ||
| 164 | if parameter? /\ _function_to_class_type_map.contains_key(parameter) then | |
| 165 | return _function_to_class_type_map[parameter] | |
| 166 | fi | |
| 167 | fi | |
| 168 | od | |
| 169 | ||
| 170 | return null | |
| 171 | si | |
| 172 | ||
| 173 | // Frame field for a body local. Idempotent — same Variable | |
| 174 | // gets the same field — but refreshes the field's type on | |
| 175 | // every call so iterative-inference narrowing of | |
| 176 | // `local.storage_type` flows into the IL signature. A field | |
| 177 | // of another frame is one a dropped frame declared, and is | |
| 178 | // replaced rather than reused. | |
| 179 | // A local a walk reaches before anything has typed it - a | |
| 180 | // destructure leaf whose source is still an unresolved | |
| 181 | // inference placeholder - has no type to give the field. A | |
| 182 | // later walk declares it once the source settles, which is | |
| 183 | // still before the rows are numbered. | |
| 184 | declare_local_field(local: Variable) -> Field? is | |
| 185 | let storage_type = local.storage_type | |
| 186 | ||
| 187 | if !storage_type? then | |
| 188 | return null | |
| 189 | fi | |
| 190 | ||
| 191 | let existing = local.state_machine_field | |
| 192 | ||
| 193 | if existing? /\ existing.owner == self then | |
| 194 | existing.set_type(_class_relative(storage_type)) | |
| 195 | return existing | |
| 196 | fi | |
| 197 | ||
| 198 | let id = _next_local_id | |
| 199 | _next_local_id = _next_local_id + 1 | |
| 200 | ||
| 201 | let listener = IoC.CONTAINER.instance.symbol_definition_locations | |
| 202 | ||
| 203 | let `field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "$local_{local.name}_{id}") | |
| 204 | `field.set_type(_class_relative(storage_type)) | |
| 205 | declare(LOCATION.internal, `field, listener) | |
| 206 | ||
| 207 | _local_fields.add(`field) | |
| 208 | _hoisted_locals.add(local) | |
| 209 | ||
| 210 | local.state_machine_field = `field | |
| 211 | ||
| 212 | return `field | |
| 213 | si | |
| 214 | ||
| 215 | // Re-derive every hoisted local field's type from the source | |
| 216 | // local. declare_local_field snapshots the type at the walk | |
| 217 | // moment, but flow narrowing mutates a local's type later in | |
| 218 | // compile-expressions — an `if let`-bound local is typed at | |
| 219 | // the scrutinee's optional type when the pattern registers and | |
| 220 | // at the unwrapped type once the body has walked — and nothing | |
| 221 | // re-registers it. IL emission calls this before emitting the | |
| 222 | // frame, mirroring refresh_argument_field_types. | |
| 223 | refresh_local_field_types() is | |
| 224 | for local in _hoisted_locals do | |
| 225 | if let `field = local.state_machine_field then | |
| 226 | if let storage_type = local.storage_type then | |
| 227 | `field.set_type(_class_relative(storage_type)) | |
| 228 | fi | |
| 229 | fi | |
| 230 | od | |
| 231 | si | |
| 232 | ||
| 233 | // Re-derive every argument field's type - and the constructor | |
| 234 | // signature that hands the values in - from the source locals. | |
| 235 | // Types captured at first declare() can predate inference: a | |
| 236 | // closure's first declare() runs mid-inference, so an inferred | |
| 237 | // parameter group holds an INFERRED_VARIABLE_TYPE placeholder | |
| 238 | // until the body-retry walk settles it. Subclasses call this | |
| 239 | // from their declare() when already declared; IL emission | |
| 240 | // declares again before emitting the frame. | |
| 241 | refresh_argument_field_types() is | |
| 242 | if !_constructor? \/ !_ctor_argument_names? then | |
| 243 | return | |
| 244 | fi | |
| 245 | ||
| 246 | let names = _ctor_argument_names | |
| 247 | let offset = names.count - _argument_fields.count | |
| 248 | ||
| 249 | let types = Collections.LIST[Type](names.count) | |
| 250 | ||
| 251 | for i in 0.._argument_fields.count do | |
| 252 | let local = | |
| 253 | cast LOCAL_ARGUMENT?(owning_function.find_direct(names[offset + i])) | |
| 254 | ||
| 255 | if !local? then | |
| 256 | // Cannot currently happen - declare() created a | |
| 257 | // field only for a resolvable local - but keep the | |
| 258 | // constructor's arity stable rather than guess. | |
| 259 | types.add(_argument_fields[i].type!) | |
| 260 | continue | |
| 261 | fi | |
| 262 | ||
| 263 | let arg_field_type = _class_relative( | |
| 264 | SETTLED_PLACEHOLDER_RESOLVER.instance.resolve(local.type ?? Types.ERROR())) | |
| 265 | ||
| 266 | _argument_fields[i].set_type(arg_field_type) | |
| 267 | ||
| 268 | // The pristine copies keep step with the fields they | |
| 269 | // shadow, so a rewind restores values at the type the | |
| 270 | // constructor actually took. | |
| 271 | if has_argument_initial_fields then | |
| 272 | _argument_initial_fields[i].set_type(arg_field_type) | |
| 273 | fi | |
| 274 | ||
| 275 | types.add(arg_field_type) | |
| 276 | od | |
| 277 | ||
| 278 | // The `$outer_self` slot keeps its type; splice it back on. | |
| 279 | if offset > 0 then | |
| 280 | let outer_types = Collections.LIST[Type]() | |
| 281 | outer_types.add(_outer_self_field!.type!) | |
| 282 | for t in types do | |
| 283 | outer_types.add(t) | |
| 284 | od | |
| 285 | _constructor!.set_arguments(names, outer_types) | |
| 286 | else | |
| 287 | _constructor!.set_arguments(names, types) | |
| 288 | fi | |
| 289 | si | |
| 290 | ||
| 291 | // Anonymous frame field for a synthesised value with no | |
| 292 | // user-named source symbol (the FOR iterator, async spill | |
| 293 | // slots). Each call produces a fresh field. | |
| 294 | declare_anonymous_field(prefix: string, type: Type) -> Field is | |
| 295 | let id = _next_local_id | |
| 296 | _next_local_id = _next_local_id + 1 | |
| 297 | ||
| 298 | let listener = IoC.CONTAINER.instance.symbol_definition_locations | |
| 299 | ||
| 300 | let `field = Symbols.INSTANCE_FIELD(LOCATION.internal, self, "${prefix}_{id}") | |
| 301 | `field.set_type(_class_relative(type)) | |
| 302 | declare(LOCATION.internal, `field, listener) | |
| 303 | ||
| 304 | _local_fields.add(`field) | |
| 305 | ||
| 306 | return `field | |
| 307 | si | |
| 308 | ||
| 309 | // The field for a syntactic site a body re-walk reaches again. | |
| 310 | // Reusing the one the earlier walk allocated keeps the frame | |
| 311 | // from growing a dead member per walk, and re-reading the type | |
| 312 | // is what carries an inference result the earlier walk did not | |
| 313 | // have: a field left holding that walk's placeholder reaches | |
| 314 | // the emitter as a type it cannot encode. A field of another | |
| 315 | // frame is one a dropped frame declared, and is replaced. | |
| 316 | declare_or_retype_anonymous_field(existing: Field?, prefix: string, type: Type) -> Field is | |
| 317 | if let `field = existing /\ `field.owner == self then | |
| 318 | `field.set_type(_class_relative(type)) | |
| 319 | ||
| 320 | return `field | |
| 321 | fi | |
| 322 | ||
| 323 | return declare_anonymous_field(prefix, type) | |
| 324 | si | |
| 325 | ||
| 326 | // A fresh field for a spilled intermediate value or for an | |
| 327 | // await's result. The frame holds them so they survive across | |
| 328 | // MoveNext re-entries. | |
| 329 | declare_spill_field(type: Type) -> Field => | |
| 330 | declare_anonymous_field("spill", type) | |
| 331 | ||
| 332 | // Bump the shared counter without creating a field — for | |
| 333 | // subclasses that name fields outside the standard prefixes | |
| 334 | // (e.g. async's `$awaiter_N`). | |
| 335 | next_local_id() -> int is | |
| 336 | let id = _next_local_id | |
| 337 | _next_local_id = _next_local_id + 1 | |
| 338 | return id | |
| 339 | si | |
| 340 | ||
| 341 | // Mirrors Classy.FRAME.set_type_arguments — base-level Classy | |
| 342 | // doesn't define one. | |
| 343 | populate_argument_names(arguments: Collections.Iterable[Symbol]) is | |
| 344 | argument_names = arguments |> map(a => a.name) |> collect() | |
| 345 | si | |
| 346 | ||
| 347 | // Override Classy's default declare_type (which errors out) | |
| 348 | // so generic state machines can install their type | |
| 349 | // parameters, matching the CLASS shape. | |
| 350 | declare_type(location: LOCATION, name: string, index: int, symbol_definition_listener: SymbolDefinitionListener?) -> Symbol is | |
| 351 | let result = Symbols.CLASSY_GENERIC_ARGUMENT(location, self, name, index) | |
| 352 | declare(location, result, symbol_definition_listener) | |
| 353 | return result | |
| 354 | si | |
| 355 | ||
| 356 | // Rewrite function-T references in `t` to the parallel | |
| 357 | // CLASSY_GENERIC_ARGUMENT declared on this frame, so types | |
| 358 | // emit `!N` (class-level) rather than `!!N` (method-level). | |
| 359 | // No-op when the owning function is non-generic. | |
| 360 | _class_relative(t: Type) -> Type is | |
| 361 | if _function_to_class_type_map.count == 0 then | |
| 362 | return t | |
| 363 | fi | |
| 364 | ||
| 365 | return t.specialize(_function_to_class_type_map) | |
| 366 | si | |
| 367 | ||
| 368 | si | |
| 369 | si |