You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Stdlib lives in `stdlib/` (`io.ion`, `fmt.ion`, `fs.ion`, `result.ion`); imported module functions are emitted as `{alias}_{name}` in single-file merge mode (e.g. `io::print_int` -> `io_print_int`).
107
107
- Integration tests: add `tests/test_*.ion` plus one row in `tests/test_expectations.tsv` (see `ion-integration-tests` skill). Run `cd tests && ./test_runner.sh` to verify.
108
+
- Fn literals are capture-free only; references to outer bindings are rejected with `ClosureCapture`.
108
109
- LSP parses the **open buffer** in memory (lexer → parser), then `load_imports` which **fully `parse_module`s imported files from disk** (per-import errors are published). Parser/tc/import changes may need LSP updates (`ion-lsp-vscode` skill).
Copy file name to clipboardExpand all lines: .cursor/skills/writing-ion-code/SKILL.md
+10-1Lines changed: 10 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -112,6 +112,15 @@ let result: int = recv(&mut rx_back_mut);
112
112
113
113
`spawn` captures owned values by move. `T` in `channel<T>()` must be `Send`.
114
114
115
+
**Fn literals (capture-free)**
116
+
117
+
```ion
118
+
let f: fn(int) -> int = fn(x: int) -> int { return x + 5; };
119
+
return f(7);
120
+
```
121
+
122
+
Fn literals lower to static C functions and must not reference outer bindings (owned or by reference). Use named functions with extra parameters for customized behavior. See [tests/test_fn_literal_basic.ion](../../../tests/test_fn_literal_basic.ion) and [tests/test_fn_literal_callback.ion](../../../tests/test_fn_literal_callback.ion).
123
+
115
124
**Unsafe and FFI**
116
125
117
126
All `extern "C"` calls belong inside `unsafe { ... }`. See [tests/test_ffi_basic.ion](../../../tests/test_ffi_basic.ion).
@@ -147,7 +156,7 @@ For programs under `tests/`, follow the `ion-integration-tests` skill (`test_exp
147
156
148
157
These are **not** in Ion today. Check ION_SPEC.md section 10.2 before using anything similar:
149
158
150
-
-Closures, fn literals, or `impl` blocks in user code
159
+
-Capturing closures (fn literals that reference outer variables), or `impl` blocks in user code
151
160
- Traits, trait bounds, or `where` clauses on generics
152
161
- Returning `&T` / `&mut T` or `Option<&T>` from functions
153
162
- References in struct fields, enum payloads, or channels
@@ -612,7 +615,11 @@ The corresponding function type is:
612
615
fn(T1, T2) -> R
613
616
```
614
617
615
-
Function types are **first-class**: they may be stored in variables, passed as arguments, and returned. However, **function values may not capture references that would violate the no-escape rule** (see Section 5.4).
618
+
Function types are **first-class**: they may be stored in variables, passed as arguments, and returned.
619
+
620
+
**Fn literals** (capture-free only): an expression `fn(params) [-> R] { ... }` has type `fn(T1, T2, ...) -> R` matching its signature. The body may reference only parameters and locals declared inside the literal; any use of a binding from an outer scope is a compile-time error (`ClosureCapture`). Fn literals lower to plain C function pointers (each site gets a unique `static` function); there is no environment payload and no heap allocation.
621
+
622
+
Named functions and capture-free fn literals may not capture references that would violate the no-escape rule (see Section 5.4). **Capturing closures** (literals that move owned state from outer scopes) are not implemented; use named functions with extra parameters, explicit context structs, or `spawn` for move-only thread capture.
616
623
617
624
#### 4.4 Type Inference
618
625
@@ -778,11 +785,13 @@ fn main() {
778
785
```ion
779
786
fn make_printer(x: &int) -> fn() {
780
787
return fn() {
781
-
println("x = {}", x); // would capture x by reference
Capturing closures are not implemented; the compiler rejects any outer binding referenced from a fn literal body.
794
+
786
795
**Example (valid – borrow within function):**
787
796
788
797
```ion
@@ -836,7 +845,7 @@ Uninitialized `Box`/`Vec`/`String` bindings are zero-initialized to `NULL` so dr
836
845
837
846
Ion does **not** perform implicit heap allocation for:
838
847
839
-
- Captured closures
848
+
- Captured closures (not implemented; fn literals are capture-free and use static functions only)
840
849
- Slices or views
841
850
- Temporaries (beyond what is required for expression evaluation)
842
851
@@ -1193,7 +1202,7 @@ Build with `cargo build --release --bin ion-lsp`. Rebuild after compiler or LSP
1193
1202
- Match guards on the same variant are lowered to a single `switch` case with sequential `if` checks
1194
1203
- LSP go-to-definition for built-in methods (`Vec::push`, `String::len`, etc.) has no target (signature hover only)
1195
1204
- LSP go-to-definition for type names in type annotations (no source spans on `Type` AST nodes)
1196
-
- Function types: named functions only; no fn literals/closures, no generic `fn(T) -> R` type parameters, no method values as fn pointers
1205
+
- Function types: capture-free fn literals implemented; no capturing closures, no generic `fn(T) -> R` type parameters, no method values as fn pointers
1197
1206
- Tuple values: no nested tuples, `==` on tuples, struct fields holding tuples, or generic `(T1, T2)` parameters
1198
1207
1199
1208
### 11. Future Work (Non-Normative)
@@ -1204,6 +1213,7 @@ The following features are **not planned** for the current compiler:
1204
1213
- Complex trait or typeclass systems.
1205
1214
- Macros and compile-time metaprogramming.
1206
1215
- Advanced iterator pipelines and zero-cost abstractions beyond the basics.
1216
+
- Capturing closures (fn literals that move owned environment from outer scopes).
0 commit comments