feat: #get property accessors (no-paren method-as-field)

A method declared `name :: (self: *T) -> R #get => expr;` is invoked via
no-paren field syntax (`obj.name`) instead of `obj.name()`. It is an ordinary
method (registered `Type.method`, flagged is_get); field-access lowering and
inference dispatch to it when no real field of that name exists, by synthesizing
a no-arg `obj.name()` call routed through the normal call path (so receiver
address-of and generic binding are reused).

- Lexer/token: `#get`. Parser: parsed after the return type in parseFnDecl;
  hasFnBodyAfterArrow treats it as a body marker so struct-body methods parse.
- Resolution: getAccessorFor handles a generic-struct instance and a plain
  struct. A REAL field of the same name wins (a getter never shadows stored
  data). An explicit postfix-deref receiver (`p.*.getter`) dispatches on the
  inner pointer so it takes the working auto-deref path.
- Works on plain + generic structs (incl. getters returning the type param),
  in expressions/conditions/args/loop-bounds, chained, and via a pointer
  receiver. Examples: types/0196 (basic) + types/0197 (stress).

Known narrow limitations (clean errors / workarounds, not silent): a getter
RESULT used directly as a method/getter receiver (`o.gi.dbl`) errors — bind it
to a local first; a getter named `len`/`ptr` returning non-i64 mis-infers
(the .len/.ptr builtin-field shortcut).
This commit is contained in:
agra
2026-06-22 11:55:01 +03:00
parent b9311e7de4
commit 9d3a019670
20 changed files with 195 additions and 0 deletions

View File

@@ -1958,6 +1958,14 @@ pub const Parser = struct {
return_type = try self.parseTypeExpr();
}
// Optional `#get` property-accessor marker: `name :: (self) -> R #get => expr;`.
// The method is invoked via field syntax (`obj.name`) rather than `obj.name()`.
var is_get = false;
if (self.current.tag == .hash_get) {
is_get = true;
self.advance();
}
// Optional ABI / calling-convention annotation: `abi(.c)` / `abi(.zig)` /
// `abi(.naked)`. Sits in the postfix slot BEFORE the `extern`/`export`
// linkage keyword (it is part of the function declaration). `abi(.zig)`
@@ -2048,6 +2056,7 @@ pub const Parser = struct {
.extern_name = extern_name,
.name_span = name_span,
.is_raw = name_is_raw,
.is_get = is_get,
} });
}
@@ -3793,6 +3802,7 @@ pub const Parser = struct {
if (self.current.tag == .fat_arrow) return true;
if (self.current.tag == .l_brace) return true;
if (self.current.tag == .hash_builtin) return true;
if (self.current.tag == .hash_get) return true; // `-> R #get => …` is a fn def
if (self.current.tag == .kw_abi) return true;
// Postfix linkage modifier after the return type: `-> R extern;` /
// `-> R export { … }` (and `-> R abi(.c) extern`). Marks a fn def.