iOS lock step keyboard + metal
This commit is contained in:
66
specs.md
66
specs.md
@@ -475,6 +475,72 @@ The impl is instantiated per concrete type argument, like generic struct methods
|
||||
|
||||
Static dispatch is automatic when the concrete type is known. Dynamic dispatch only when explicitly type-erased via `xx` into a protocol value.
|
||||
|
||||
#### Parameterised Protocols (compile-time only)
|
||||
|
||||
A protocol with type parameters is compile-time only — it has no vtable
|
||||
and no boxed instance shape. Each `impl` is monomorphised per
|
||||
`(ProtocolArgs, Source)` pair. The canonical example is `Into`, declared
|
||||
in `modules/std.sx`:
|
||||
|
||||
```sx
|
||||
Into :: protocol(Target: Type) {
|
||||
convert :: () -> Target;
|
||||
}
|
||||
```
|
||||
|
||||
A user can then add conversions for any `(Source, Target)` pair:
|
||||
|
||||
```sx
|
||||
MyString :: struct { tag: s64 = 0; }
|
||||
|
||||
impl Into(MyString) for s64 {
|
||||
convert :: (self: s64) -> MyString { .{ tag = self }; }
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
x : MyString = xx 42; // direct call to monomorphised convert
|
||||
0;
|
||||
}
|
||||
```
|
||||
|
||||
The `xx` operator hooks into this mechanism: when an explicit target type
|
||||
is provided and the built-in coercion ladder doesn't apply,
|
||||
`xx val : T` lowers to `val.convert()` where `convert` comes from the
|
||||
visible `impl Into(T) for typeof(val)`. The call is a direct call — no
|
||||
vtable, no runtime dispatch.
|
||||
|
||||
**Source side is a TypeExpr.** Unlike nullary `impl P for SomeStruct`,
|
||||
the `for`-side of a parameterised impl accepts any type expression,
|
||||
including closure and function types:
|
||||
|
||||
```sx
|
||||
impl Into(Block) for Closure() -> void { ... }
|
||||
impl Into(MyBuf) for []u8 { ... }
|
||||
```
|
||||
|
||||
**Lookup rules:**
|
||||
- **Built-ins win.** The user-space fallback only fires when
|
||||
`coerceToType` made no progress (numeric narrow/widen, ptr↔int, etc.
|
||||
take priority).
|
||||
- **Only at explicit `xx`.** Implicit conversions (assignment,
|
||||
parameter passing) never trigger user-space coercions.
|
||||
- **Explicit target required.** `xx val` with no surrounding type
|
||||
context still defaults to `s64` for legacy reasons; the user-space
|
||||
fallback only fires when the target was named explicitly.
|
||||
- **Import-scoped visibility.** An `impl` is visible from a file only
|
||||
if the file transitively imports the impl's defining module. An impl
|
||||
in an imported-but-not-directly-related module produces a clean
|
||||
diagnostic (`no visible xx conversion …`).
|
||||
- **Duplicate impls error.** If two impls for the same
|
||||
`(Source, Target)` pair are both visible, the compiler emits a
|
||||
diagnostic naming both source modules. Same-file duplicates are
|
||||
caught at registration time. Cross-module duplicates are caught at
|
||||
the `xx` site.
|
||||
- **No recursion.** A `convert` body that re-enters `xx self : Target`
|
||||
for the same `(Source, Target)` pair produces a "recursive xx
|
||||
conversion" diagnostic; the compiler does not try to monomorphise
|
||||
the convert into itself.
|
||||
|
||||
### Tuple Types
|
||||
Anonymous product types with optional field names. Tuples are first-class values — they can be stored in variables, passed to functions, and returned.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user