feat: #set property accessors (write counterpart of #get)
A method `name :: (self: *T, value: V) #set { ... }` (or `=> expr;`) is the
write counterpart of a `#get` accessor: `obj.name = rhs` dispatches to it as
`obj.name(rhs)` when no real field matches. Plumbed parallel to `#get`:
- lexer/token `#set`; `FnDecl.is_set` + `Function.is_set`; parsed in the same
marker slot as `#get` (no return type, exactly self + one value param).
- get+set coexistence: a setter registers/mangles/dispatches under an effective
`name$set` name (`$` is illegal in sx identifiers, so unmistakable), keeping a
same-name `#get` under the plain `name`. Resolution is declaration-order-
independent: a plain read query picks the non-setter, a `name$set` write query
picks the setter (accessorEffName / accessorNameMatches / structMethodFn).
- write dispatch in lowerAssignment via tryLowerPropertyAssignment: plain assign
synthesizes `obj.name$set(rhs)`; compound `OP=` is get-modify-set and
evaluates the receiver EXACTLY ONCE (bound to a synthetic local); read-only
(#get-only) and write-only (#set-only + compound) emit clear diagnostics; a
real field of the same name still wins. Multi-assign property targets dispatch
the setter too (tryLowerPropertyStore, via a pre-lowered-Ref binding).
Payoff: List gains a `len` #set, so `xs.len = n` works; the `.items.len = N`
write workarounds in sched.sx + ui/* + platform/* revert to `xs.len = N`.
issues/0160 records an optional-chain interaction surfaced by the review (a
pre-existing `?T` value-optional read miscompile that blocks getter-through-`?.`).
This commit is contained in:
@@ -400,7 +400,7 @@ impl Platform for AndroidPlatform {
|
||||
}
|
||||
|
||||
poll_events :: (self: *AndroidPlatform) -> []Event {
|
||||
self.events.items.len = 0;
|
||||
self.events.len = 0;
|
||||
sx_android_drain_touches(self, @self.events);
|
||||
result : []Event = ---;
|
||||
result.ptr = self.events.items;
|
||||
|
||||
@@ -144,7 +144,7 @@ impl Platform for SdlPlatform {
|
||||
}
|
||||
|
||||
poll_events :: (self: *SdlPlatform) -> []Event {
|
||||
self.events.items.len = 0;
|
||||
self.events.len = 0;
|
||||
sdl_event : SDL_Event = .none;
|
||||
while SDL_PollEvent(@sdl_event) {
|
||||
if sdl_event == {
|
||||
|
||||
@@ -379,7 +379,7 @@ impl Platform for UIKitPlatform {
|
||||
result : []Event = ---;
|
||||
result.ptr = self.events.items;
|
||||
result.len = self.events.len;
|
||||
self.events.items.len = 0;
|
||||
self.events.len = 0;
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ List :: struct ($T: Type) {
|
||||
|
||||
// No-paren read accessor: `xs.len` → the live element count.
|
||||
len :: (self: *List(T)) -> i64 #get => self.items.len;
|
||||
// Write accessor: `xs.len = n` sets the live count (e.g. `xs.len = 0` to
|
||||
// clear without freeing). Mirrors the `#get` above; the buffer / `cap` are
|
||||
// untouched, so `n` must be `<= cap`.
|
||||
len :: (self: *List(T), v: i64) #set { self.items.len = v; }
|
||||
|
||||
append :: (list: *List(T), item: T, alloc: Allocator = context.allocator) {
|
||||
if list.items.len >= list.cap {
|
||||
|
||||
@@ -647,7 +647,7 @@ remove_timer :: (self: *Scheduler, idx: i64) {
|
||||
self.timers.items[i] = self.timers.items[i + 1];
|
||||
i = i + 1;
|
||||
}
|
||||
self.timers.items.len = self.timers.items.len - 1;
|
||||
self.timers.len = self.timers.len - 1;
|
||||
}
|
||||
|
||||
// Remove a pending sleep timer referencing fiber `f`, if any. A fiber has at
|
||||
@@ -676,7 +676,7 @@ remove_io_waiter :: (self: *Scheduler, idx: i64) {
|
||||
self.io_waiters.items[i] = self.io_waiters.items[i + 1];
|
||||
i = i + 1;
|
||||
}
|
||||
self.io_waiters.items.len = self.io_waiters.items.len - 1;
|
||||
self.io_waiters.len = self.io_waiters.len - 1;
|
||||
}
|
||||
|
||||
// Remove a pending fd-waiter referencing fiber `f`, if any. A fiber has at most
|
||||
|
||||
@@ -575,7 +575,7 @@ GlyphCache :: struct {
|
||||
return; // shaped_buf already has the result
|
||||
}
|
||||
|
||||
self.shaped_buf.items.len = 0;
|
||||
self.shaped_buf.len = 0;
|
||||
if text.len == 0 { return; }
|
||||
|
||||
if is_ascii(text) {
|
||||
|
||||
@@ -141,7 +141,7 @@ UIPipeline :: struct {
|
||||
|
||||
// Reset render_tree nodes (backing is stale after arena reset)
|
||||
self.render_tree.nodes.items = null;
|
||||
self.render_tree.nodes.items.len = 0;
|
||||
self.render_tree.nodes.len = 0;
|
||||
self.render_tree.nodes.cap = 0;
|
||||
|
||||
push Context.{ allocator = xx build_arena, data = context.data } {
|
||||
|
||||
@@ -47,7 +47,7 @@ RenderTree :: struct {
|
||||
}
|
||||
|
||||
clear :: (self: *RenderTree) {
|
||||
self.nodes.items.len = 0;
|
||||
self.nodes.len = 0;
|
||||
self.generation += 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user