docs(lang): precise reserved-name rule — member-name positions are EXEMPT [F0.6]
AGRA RULING (issue 0089, attempt 7): bare reserved-name MEMBER positions are intentionally exempt from the reserved-type-name rule, and the implementation already does the right thing — this is a docs + one-example change, no code. The exempt member positions are struct FIELD names, union TAG names, and protocol method-SIGNATURE names: they sit in a member slot, are reached via obj.name (or dispatched by string), and are never type-classified, so they never mis-lower. The backtick is optional there. The exemption stops at member DEFINITIONS: an impl method is a real function (reached through the impl_block -> fn_decl arm), so a reserved-spelled impl method still needs the backtick, exactly like a free function (cf. examples/1122) — and every bare reserved-name value binding / declaration name still errors (0076 preserved). - specs.md / readme.md: replace the "every binding site" / "any binding site" overclaim with the precise rule — required positions (value bindings + declaration names + impl method definitions) vs the exempt member-name positions (field / tag / protocol signature; backtick optional). - examples/0158-types-reserved-name-member-exempt.sx: pins the exempt behavior — bare reserved-name struct fields + union tag read & written bare AND via backtick, and a protocol with a bare reserved-name method dispatched through the protocol (impl definition takes the backtick). - issues/0089: document the member-name exemption in the RESOLVED banner + add 0158 to the regression list. Gate: zig build, zig build test, bash tests/run_examples.sh — all green (430 passed, 0 failed, 0 timed out).
This commit is contained in:
55
examples/0158-types-reserved-name-member-exempt.sx
Normal file
55
examples/0158-types-reserved-name-member-exempt.sx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// Reserved-name MEMBER positions are EXEMPT from the reserved-type-name rule:
|
||||||
|
// a bare reserved spelling (`s2`, `u8`, `s1`, …) is legal as a struct FIELD
|
||||||
|
// name, a union TAG name, and a protocol METHOD-SIGNATURE name. These are
|
||||||
|
// unambiguous — the name sits in a member slot and is reached via `obj.name`
|
||||||
|
// (or dispatched by string), so it is never type-classified and never
|
||||||
|
// mislowers. The backtick form is optional there and resolves to the same
|
||||||
|
// member. Backtick access (`obj.`s2`) and bare access (`obj.s2`) both work.
|
||||||
|
//
|
||||||
|
// The exemption stops at member SIGNATURES: an `impl` method DEFINITION is a
|
||||||
|
// real function, so its name is a declaration site (like a free function) and a
|
||||||
|
// reserved spelling still needs the backtick (`` `s2 :: (self) ``) — bare would
|
||||||
|
// be type-classified and mislower (the issue-0076 protection). A bare reserved
|
||||||
|
// VALUE binding / declaration name still errors (see examples/1119, 1141, 1142).
|
||||||
|
// Regression (issue 0089 — attempt-7: pins the Agra-ruled member-name exemption).
|
||||||
|
#import "modules/std.sx";
|
||||||
|
|
||||||
|
// Struct fields spelled with reserved type names — bare is legal.
|
||||||
|
Holder :: struct {
|
||||||
|
s2: s64;
|
||||||
|
u8: s64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union tags spelled with reserved type names — bare is legal.
|
||||||
|
Tag :: union {
|
||||||
|
s1: s32;
|
||||||
|
u16: f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protocol method SIGNATURE spelled with a reserved type name — bare is legal.
|
||||||
|
Speaker :: protocol {
|
||||||
|
s2 :: () -> s64;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dog :: struct { n: s64; }
|
||||||
|
impl Speaker for Dog {
|
||||||
|
`s2 :: (self: *Dog) -> s64 { self.n } // impl DEFINITION → backtick required
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: () -> s32 {
|
||||||
|
h := Holder.{ s2 = 10, u8 = 20 };
|
||||||
|
print("fields bare = {} {}\n", h.s2, h.u8); // bare member access
|
||||||
|
print("fields tick = {} {}\n", h.`s2, h.`u8); // backtick member access
|
||||||
|
h.s2 = 11;
|
||||||
|
h.`u8 = 21; // backtick write
|
||||||
|
print("fields set = {} {}\n", h.s2, h.u8);
|
||||||
|
|
||||||
|
t : Tag = ---;
|
||||||
|
t.s1 = 5;
|
||||||
|
print("union = {} {}\n", t.s1, t.`s1); // bare + backtick — same tag
|
||||||
|
|
||||||
|
items : List(Speaker) = .{};
|
||||||
|
items.append(Dog.{ n = 7 });
|
||||||
|
print("dispatch = {}\n", items.items[0].s2()); // bare reserved-name method call
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fields bare = 10 20
|
||||||
|
fields tick = 10 20
|
||||||
|
fields set = 11 21
|
||||||
|
union = 5 5
|
||||||
|
dispatch = 7
|
||||||
@@ -58,6 +58,20 @@
|
|||||||
> that omits them. `FnDecl` is built at every parser site through `parseFnDecl`,
|
> that omits them. `FnDecl` is built at every parser site through `parseFnDecl`,
|
||||||
> whose `name_is_raw` is a REQUIRED parameter (the equivalent guarantee); the
|
> whose `name_is_raw` is a REQUIRED parameter (the equivalent guarantee); the
|
||||||
> type decls likewise route through parse-functions taking `name_is_raw`.
|
> type decls likewise route through parse-functions taking `name_is_raw`.
|
||||||
|
> - **Member-name positions are exempt** (Agra ruling, attempt 7). A struct
|
||||||
|
> **field** name, a union **tag** name, and a protocol **method-signature**
|
||||||
|
> name accept a bare reserved spelling: these sit in a member slot and are
|
||||||
|
> reached via `obj.name` / dispatched by string, so they are never
|
||||||
|
> type-classified and never mis-lower — the binding-name walk's `struct_decl`
|
||||||
|
> / `union_decl` / `enum_decl` / `protocol_decl` arms
|
||||||
|
> ([src/ir/semantic_diagnostics.zig]) check only the *type* name (and method
|
||||||
|
> *params*), not field / tag / variant / method-signature names. The backtick
|
||||||
|
> is optional there (`obj.s2` and `` obj.`s2 `` resolve to the same member).
|
||||||
|
> The exemption stops at member *definitions*: an `impl` method is a real
|
||||||
|
> function reached through the `impl_block` → `fn_decl` arm, so a
|
||||||
|
> reserved-spelled impl method needs the backtick (`` `s2 :: (self) ``), no
|
||||||
|
> more exempt than a free function (cf. `examples/1122`). Pinned by
|
||||||
|
> `examples/0158-types-reserved-name-member-exempt.sx`.
|
||||||
> 2. **`#import c` foreign-name exemption.** `c_import.zig` synthesizes foreign
|
> 2. **`#import c` foreign-name exemption.** `c_import.zig` synthesizes foreign
|
||||||
> `#foreign` decls with `Param.is_raw = true` (and the synthesized `FnDecl`
|
> `#foreign` decls with `Param.is_raw = true` (and the synthesized `FnDecl`
|
||||||
> `is_raw = true`), so generated C names that collide with reserved type names
|
> `is_raw = true`), so generated C names that collide with reserved type names
|
||||||
@@ -80,6 +94,9 @@
|
|||||||
> `examples/0156-types-backtick-struct-const.sx` (struct-body const, untyped + typed),
|
> `examples/0156-types-backtick-struct-const.sx` (struct-body const, untyped + typed),
|
||||||
> `examples/0157-types-backtick-parameterized-raw-type.sx` (raw parameterized type +
|
> `examples/0157-types-backtick-parameterized-raw-type.sx` (raw parameterized type +
|
||||||
> pointer/field wrappers),
|
> pointer/field wrappers),
|
||||||
|
> `examples/0158-types-reserved-name-member-exempt.sx` (bare reserved-name struct
|
||||||
|
> fields / union tag / protocol method signature — read & written bare and via
|
||||||
|
> backtick; impl method definition takes the backtick),
|
||||||
> `examples/1054-errors-backtick-reserved-binding.sx` (`catch`/`onfail` tag
|
> `examples/1054-errors-backtick-reserved-binding.sx` (`catch`/`onfail` tag
|
||||||
> bindings), `examples/1220-ffi-c-import-reserved-name-params.{sx,h,c}` (foreign
|
> bindings), `examples/1220-ffi-c-import-reserved-name-params.{sx,h,c}` (foreign
|
||||||
> param + fn-name exemption, bare-callable foreign fn); negatives
|
> param + fn-name exemption, bare-callable foreign fn); negatives
|
||||||
|
|||||||
21
readme.md
21
readme.md
@@ -106,14 +106,19 @@ z : s32 = ---; // uninitialized
|
|||||||
```
|
```
|
||||||
|
|
||||||
Builtin type names (`s2`, `u8`, `bool`, `string`, …) are reserved and a *bare*
|
Builtin type names (`s2`, `u8`, `bool`, `string`, …) are reserved and a *bare*
|
||||||
spelling can't be used as an identifier at **any** binding site — a value binding
|
spelling can't be used as an identifier at a **value-binding or declaration-name**
|
||||||
(`:=` / typed local / parameter), a `::` constant or function declaration, or a
|
site — a value binding (`:=` / typed local / parameter), a `::` constant or
|
||||||
`::` type declaration (`struct` / `enum` / `union` / alias / `protocol` / …) — each
|
function declaration, an `impl` method definition, or a `::` type declaration
|
||||||
is an error (`s2 :: 5` and `s2 :: (n) { … }` are rejected just like `s2 := 5`). A
|
(`struct` / `enum` / `union` / alias / `protocol` / …) — each is an error
|
||||||
leading backtick escapes one into a **raw identifier**: `` `name `` is the literal
|
(`s2 :: 5` and `s2 :: (n) { … }` are rejected just like `s2 := 5`). **Member-name
|
||||||
identifier `name` (the backtick drops out of the text), usable in **every**
|
positions are exempt**: a struct *field*, a union *tag*, and a protocol
|
||||||
position — value, declaration, and type. It is the only way handwritten sx can
|
*method-signature* may be a bare reserved spelling (`struct { s2: s64 }`,
|
||||||
spell a reserved name.
|
`union { u8: … }`, `protocol { s2 :: (self) }`) — they are reached via `obj.name`,
|
||||||
|
so they never mis-lower. A leading backtick escapes one into a **raw identifier**:
|
||||||
|
`` `name `` is the literal identifier `name` (the backtick drops out of the text),
|
||||||
|
usable in **every** position — value, declaration, and type, and optional in the
|
||||||
|
exempt member positions. It is the only way handwritten sx can spell a reserved
|
||||||
|
name in a binding or declaration site.
|
||||||
|
|
||||||
```sx
|
```sx
|
||||||
`s2 := 2.5; // identifier "s2", distinct from the s2 type
|
`s2 := 2.5; // identifier "s2", distinct from the s2 type
|
||||||
|
|||||||
34
specs.md
34
specs.md
@@ -17,14 +17,26 @@ Line comments start with `//` and extend to end of line.
|
|||||||
|
|
||||||
A spelling that names a builtin type — the arbitrary-width integers `s1`..`s64` /
|
A spelling that names a builtin type — the arbitrary-width integers `s1`..`s64` /
|
||||||
`u1`..`u64`, plus `bool`, `string`, `void`, `f32`, `f64`, `usize`, `isize`, `Any` —
|
`u1`..`u64`, plus `bool`, `string`, `void`, `f32`, `f64`, `usize`, `isize`, `Any` —
|
||||||
is reserved. A bare reserved spelling is rejected at **every binding site** —
|
is reserved. A bare reserved spelling is rejected at **value-binding and
|
||||||
anywhere handwritten sx introduces a name: a value binding (`:=` / typed local /
|
declaration-name sites**: a value binding (`:=` / typed local / parameter), a
|
||||||
parameter), a `::` **constant** or **function** declaration, and a `::` **type**
|
`::` **constant** or **function** declaration, an `impl` method **definition**,
|
||||||
declaration (`struct` / `enum` / `union` / `error` / type alias / `protocol` /
|
and a `::` **type** declaration (`struct` / `enum` / `union` / `error` / type
|
||||||
foreign class / ufcs alias / namespaced import). A value-spelled-as-type parses as
|
alias / `protocol` / foreign class / ufcs alias / namespaced import). A
|
||||||
a *type*, not a value, so its address-of / autoref paths would mis-lower; a
|
value-spelled-as-type parses as a *type*, not a value, so its address-of /
|
||||||
type/const/function name spelled as a builtin would shadow the builtin. The only
|
autoref paths would mis-lower; a type / const / function / method name spelled as
|
||||||
exemptions are the backtick escape (below) and `#import c` foreign decls.
|
a builtin would shadow the builtin. The exemptions are the backtick escape
|
||||||
|
(below), `#import c` foreign decls, and **member-name positions** (next) — it is
|
||||||
|
**not** rejected at every place a name appears.
|
||||||
|
|
||||||
|
**Member-name positions are exempt.** A struct **field** name, a union **tag**
|
||||||
|
name, and a protocol **method-signature** name may be a bare reserved spelling.
|
||||||
|
These sit in a member slot (`name: T` / `name :: (…)`) and are reached only via
|
||||||
|
`obj.name` (or dispatched by string), so they are never type-classified and never
|
||||||
|
mis-lower. The backtick form is optional there and names the same member — `obj.s2`
|
||||||
|
and `` obj.`s2 `` both resolve. The exemption covers member *signatures* only: an
|
||||||
|
`impl` method **definition** is a real function (a declaration site, not a member
|
||||||
|
slot), so a reserved-spelled impl method still needs the backtick
|
||||||
|
(`` `s2 :: (self) ``), exactly like a free function. See `examples/0158`.
|
||||||
|
|
||||||
```sx
|
```sx
|
||||||
s2 := 2.5; // ERROR: 's2' is a reserved type name and cannot be used as an identifier
|
s2 := 2.5; // ERROR: 's2' is a reserved type name and cannot be used as an identifier
|
||||||
@@ -91,6 +103,12 @@ for xs: (`bool, `u16) { } // for capture + index
|
|||||||
x catch `s2 { } // catch tag binding
|
x catch `s2 { } // catch tag binding
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In the **member-name positions** among these — struct field, union tag, and
|
||||||
|
protocol method signature — the backtick is *optional*: the bare reserved
|
||||||
|
spelling is already legal there (see "Member-name positions are exempt" above).
|
||||||
|
Everywhere else (value bindings and declaration names, including an `impl` method
|
||||||
|
definition) the backtick is *required* to spell a reserved name.
|
||||||
|
|
||||||
A reserved-spelled **function** is bare-callable: `` `s2 :: (n: s64) -> s64 { … } ``
|
A reserved-spelled **function** is bare-callable: `` `s2 :: (n: s64) -> s64 { … } ``
|
||||||
can be invoked as `s2(10)` (the bare callee spelling parses as a type but resolves
|
can be invoked as `s2(10)` (the bare callee spelling parses as a type but resolves
|
||||||
to the function when one of that name is in scope; `TypeName(val)` is not a cast).
|
to the function when one of that name is in scope; `TypeName(val)` is not a cast).
|
||||||
|
|||||||
Reference in New Issue
Block a user