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:
@@ -0,0 +1,17 @@
|
||||
// Writing to a `#get`-only property (no matching `#set`) is rejected with a
|
||||
// clear "read-only" diagnostic — not the generic "field not found" the bare
|
||||
// struct-store path would emit. (The write counterpart, a `#set`-only
|
||||
// property, accepts plain assignment but rejects compound `+=` because there is
|
||||
// no `#get` to read the current value.)
|
||||
#import "modules/std.sx";
|
||||
|
||||
Reading :: struct {
|
||||
raw: i64 = 0;
|
||||
doubled :: (self: *Reading) -> i64 #get => self.raw * 2;
|
||||
}
|
||||
|
||||
main :: () -> i64 {
|
||||
r : Reading = .{ raw = 5 };
|
||||
r.doubled = 10; // ERROR: property 'doubled' is read-only (no '#set')
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: property 'doubled' is read-only (no '#set')
|
||||
--> examples/diagnostics/1193-diagnostics-readonly-property-write.sx:15:5
|
||||
|
|
||||
15 | r.doubled = 10; // ERROR: property 'doubled' is read-only (no '#set')
|
||||
| ^^^^^^^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user