@@ -16,9 +16,9 @@ is equivalent to:
1616items |> filter(|n| n % 2 == 0)
1717```
1818
19- ---
19+ ## Design
2020
21- ## Syntax
21+ ### Syntax
2222
2323Any expression passed in a closure position that references ` it `
2424and has no explicit parameter list is treated as an implicit
@@ -36,22 +36,16 @@ single-parameter closure.
3636// 3. No explicit parameter list is present
3737```
3838
39- ---
40-
41- ## Semantics
42-
4339### Type Inference
4440
4541` it ` receives its type from the expected parameter type at the call
4642site, exactly as explicit closure parameters do today.
4743
4844```
49- // filter expects fn(i32) -> bool
50- // therefore it: i32
45+ // filter expects fn(i32) -> bool → it: i32
5146items |> filter(it % 2 == 0)
5247
53- // map expects fn(User) -> str
54- // therefore it: User
48+ // map expects fn(User) -> str → it: User
5549users |> map(it.name)
5650```
5751
@@ -74,54 +68,6 @@ items |> map(it.children |> filter(it.active))
7468// use explicit parameter: |c| c.active
7569```
7670
77- ### Where ` it ` Is Available
78-
79- ` it ` is available anywhere a single-parameter closure is expected:
80-
81- ```
82- // Pipeline functions
83- items |> filter(it > 0)
84- items |> map(it.name)
85- items |> any(it.active)
86- items |> all(it > threshold)
87- items |> find(it.id == target_id)
88- items |> count(it.is_valid())
89- items |> reduce(0, |acc, x| acc + x) // multi-param: explicit
90-
91- // Method calls
92- items.filter(it > 0)
93- items.map(it.name)
94- items.sort_by(it.age)
95-
96- // Standalone closures assigned to variables
97- let is_even = (it % 2 == 0) // type inferred from usage
98- let double = (it * 2)
99-
100- // Function arguments
101- let result = retry(3, it + 1) // ERROR if fn expects 2+ params
102- ```
103-
104- ### Where ` it ` Is NOT Available
105-
106- - ** Multi-parameter closures.** If the expected function type has more
107- than one parameter, ` it ` is not available. Use explicit parameters.
108-
109- ```
110- // reduce expects fn(Acc, T) -> Acc — two params, must be explicit
111- items |> reduce(0, |acc, x| acc + x)
112-
113- // zip_with expects fn(A, B) -> C — two params, must be explicit
114- zip_with(xs, ys, |a, b| a + b)
115- ```
116-
117- - ** Ambiguous closure position.** If the compiler cannot determine
118- that the expression is in a closure position (e.g., it's a bare
119- expression not passed to a function), ` it ` is a normal identifier
120- lookup and follows standard resolution.
121-
122- - ** Nested implicit closures.** As described above, the inner closure
123- must use explicit parameters.
124-
12571### ` it ` Is A Reserved Keyword
12672
12773` it ` is a keyword, the same as ` if ` , ` for ` , ` match ` , ` fn ` . It cannot
@@ -137,33 +83,32 @@ fn it(): // ERROR: `it` is a reserved keyword
13783items |> filter(it > 0) // implicit closure parameter
13884```
13985
140- This eliminates all shadowing ambiguity. ` it ` always means exactly
141- one thing: the implicit single-parameter closure reference.
142-
143- ### Interaction With ` _ `
86+ ### ` _ ` Is Not A Closure Placeholder
14487
145- ` _ ` remains the discard/wildcard symbol. ` it ` is the implicit parameter.
146- They do not overlap.
88+ The ` _ ` placeholder syntax (e.g., ` items |> filter(_.age > 21) ` ) was
89+ previously specified as a closure shorthand. This has been removed from
90+ the language. ` it ` is the sole implicit closure parameter. ` _ ` is
91+ exclusively a discard/wildcard:
14792
148- ```
149- // _ discards a value
150- let _ = expensive_call()
151-
152- // it is the implicit parameter
153- items |> filter(it > 0)
93+ - ` _ ` in patterns: wildcard/discard (unchanged)
94+ - ` _ ` in partial application: placeholder for curried argument (unchanged)
95+ - ` _.field ` as closure shorthand: ** REMOVED** — use ` it.field ` instead
96+ - ` it ` in expressions: implicit single closure parameter (the one way)
15497
155- // In match arms, _ is wildcard, it is not special
156- match value
157- Some(x) -> x
158- _ -> 0
159- ```
98+ ### Where ` it ` Is NOT Available
16099
161- ---
100+ - ** Multi-parameter closures.** If the expected function type has more
101+ than one parameter, ` it ` is not available. Use explicit parameters.
102+ - ** Ambiguous closure position.** If the compiler cannot determine
103+ that the expression is in a closure position, ` it ` is a normal
104+ identifier lookup and follows standard resolution.
105+ - ** Nested implicit closures.** The inner closure must use explicit
106+ parameters.
162107
163- ## Desugaring
108+ ### Desugaring
164109
165110The compiler desugars implicit closures early, during parsing or
166- immediately after. The transformation is :
111+ immediately after:
167112
168113```
169114// Source
@@ -175,10 +120,7 @@ items |> filter(|__it| __it % 2 == 0)
175120
176121The desugared parameter name is internal. The user always writes ` it ` .
177122
178- ### Detection Algorithm
179-
180- When the compiler encounters an expression in a closure-expected
181- position:
123+ ** Detection algorithm:**
182124
1831251 . Walk the expression tree.
1841262 . If ` it ` appears anywhere in the expression:
@@ -193,110 +135,9 @@ Since `it` is a reserved keyword, it can never appear as a local
193135variable or other binding. Any occurrence of ` it ` in an expression
194136unambiguously signals an implicit closure.
195137
196- ---
197-
198- ## Method Access Shorthand
199-
200- A common pattern is accessing a field or calling a method:
201-
202- ```
203- users |> map(it.name)
204- users |> filter(it.is_active())
205- users |> sort_by(it.age)
206- ```
138+ ### Error Messages
207139
208- These desugar to:
209-
210- ```
211- users |> map(|__it| __it.name)
212- users |> filter(|__it| __it.is_active())
213- users |> sort_by(|__it| __it.age)
214- ```
215-
216- ---
217-
218- ## Chaining
219-
220- ` it ` works naturally in chained expressions:
221-
222- ```
223- users
224- |> filter(it.age >= 18)
225- |> map(it.name |> uppercase)
226- |> filter(it |> starts_with("A"))
227- ```
228-
229- Each ` it ` in each pipeline step refers to that step's closure
230- parameter. There is no ambiguity because each step is a separate
231- closure position.
232-
233- ---
234-
235- ## Comparison With Explicit Closures
236-
237- | Pattern | Explicit | Implicit |
238- | ---| ---| ---|
239- | Simple predicate | ` \|n\| n > 0 ` | ` it > 0 ` |
240- | Field access | ` \|u\| u.name ` | ` it.name ` |
241- | Method call | ` \|u\| u.is_active() ` | ` it.is_active() ` |
242- | Arithmetic | ` \|n\| n * 2 + 1 ` | ` it * 2 + 1 ` |
243- | Two params | ` \|a, b\| a + b ` | not available |
244- | Nested closure | ` \|u\| u.items.filter(\|i\| i.ok) ` | ` it.items.filter(\|i\| i.ok) ` |
245-
246- ---
247-
248- ## Examples
249-
250- ### Idiomatic With with ` it `
251-
252- ```
253- // Filter and sum
254- let total = items |> filter(it > 0) |> sum
255-
256- // Extract field
257- let names = users |> map(it.name) |> collect[Vec]
258-
259- // Chain predicates
260- let results = entries
261- |> filter(it.active)
262- |> filter(it.score > threshold)
263- |> map(it.name)
264-
265- // Sort
266- let sorted = users |> sort_by(it.age)
267-
268- // Find
269- let admin = users |> find(it.role == .Admin)
270-
271- // Any / All
272- let has_errors = results |> any(it.is_err())
273- let all_valid = inputs |> all(it.len() > 0)
274-
275- // String processing
276- let cleaned = lines
277- |> map(it |> trim)
278- |> filter(it.len() > 0)
279- |> filter(it |> starts_with("#") |> not)
280-
281- // Nested — inner must be explicit
282- let active_children = groups
283- |> map(it.members |> filter(|m| m.active) |> count)
284- ```
285-
286- ### The Landing Page Example
287-
288- ```
289- fn main:
290- let sum = read_file("nums.txt")?
291- |> lines |> map(parse[i32]) |> filter(it % 2 == 0) |> sum
292- println("Sum of evens: {sum}")
293- ```
294-
295- ---
296-
297- ## Error Messages
298-
299- ### Nested implicit closure
140+ Three dedicated error codes:
300141
301142```
302143error[E0901]: nested implicit closure is ambiguous
@@ -309,8 +150,6 @@ error[E0901]: nested implicit closure is ambiguous
309150 = suggestion: groups |> map(it.items |> filter(|x| x.active))
310151```
311152
312- ### Wrong arity
313-
314153```
315154error[E0902]: `it` used in context expecting 2 parameters
316155 --> src/main.w:8:30
@@ -321,8 +160,6 @@ error[E0902]: `it` used in context expecting 2 parameters
321160 = help: use explicit parameters: |acc, x| acc + x
322161```
323162
324- ### ` it ` used as identifier
325-
326163```
327164error[E0903]: `it` is a reserved keyword
328165 --> src/main.w:3:9
@@ -332,4 +169,66 @@ error[E0903]: `it` is a reserved keyword
332169 |
333170 = note: `it` is the implicit closure parameter keyword
334171 = help: choose a different name
335- ```
172+ ```
173+
174+ ---
175+
176+ ## Implementation Checklist
177+
178+ ### 1. Spec (` docs/with-specification.md ` )
179+ - [x] Remove ` _.field ` closure shorthand from spec. ` it.field ` is the one way.
180+ Done: ` _.active ` → ` it.active ` in §feature summary and intro.md;
181+ "Placeholder syntax" → "Implicit ` it ` parameter (see §9.3.1)";
182+ added full §9.3.1 subsection defining ` it ` keyword, scoping,
183+ nested prohibition, and clarifying ` _ ` is not a closure placeholder.
184+ - [ ] Add ` it ` to the keyword list in the lexical grammar section.
185+ - [ ] Add the implicit closure grammar production to §9.3 (closure expressions).
186+ - [ ] Document the desugaring algorithm in the spec.
187+ - [ ] Add error code definitions for E0901, E0902, E0903.
188+
189+ ### 2. Tokenizer / Parser (` src/Token.w ` , ` src/Parser.w ` )
190+ - [ ] Add ` it ` as a reserved keyword token (e.g., ` TK_IT ` ).
191+ - [ ] Reject ` it ` as an identifier in let bindings, fn declarations, parameter lists, and field names.
192+ - [ ] Detect implicit closure form: when parsing a call argument in a closure-expected position, check if the expression contains ` it ` with no explicit ` |...| ` parameter list.
193+ - [ ] Desugar to an explicit closure AST node with a synthetic parameter bound to ` it ` .
194+ - [ ] Handle nested detection: if an implicit closure body contains another ` it ` reference at a nested closure-expected position, emit E0901.
195+
196+ ### 3. Sema (` src/Sema.w ` )
197+ - [ ] Type-check desugared implicit closures the same as explicit closures (no special path needed if desugaring is complete before sema).
198+ - [ ] Validate arity: if ` it ` appears in a context expecting ` fn(A, B, ...) -> R ` with arity != 1, emit E0902.
199+ - [ ] Validate keyword: if ` it ` appears as a binding name (let, fn, param, field), emit E0903.
200+
201+ ### 4. Codegen
202+ - [ ] No changes expected — implicit closures are desugared to standard closure AST nodes before codegen. Verify this holds.
203+
204+ ### 5. Docs
205+ - [ ] Update ` docs/with-idiomatic-guide.md ` with ` it ` usage examples and guidance (when to use ` it ` vs explicit params).
206+ - [ ] Update ` docs/with-migration-guide.md ` with mappings from Rust closure patterns to ` it ` .
207+ - [ ] Update ` docs/intro.md ` examples to use ` it ` where appropriate (partially done: ` filter(it.active) ` already there).
208+
209+ ### 6. Tests
210+ - [ ] Parser test: ` it > 0 ` in closure position desugars to ` |__it| __it > 0 ` .
211+ - [ ] Parser test: ` it.name ` field access desugars correctly.
212+ - [ ] Parser test: ` it.is_active() ` method call desugars correctly.
213+ - [ ] Parser test: nested ` it ` in nested closure position → E0901 error.
214+ - [ ] Parser test: ` it ` in multi-param context → E0902 error.
215+ - [ ] Parser test: ` let it = 42 ` → E0903 error.
216+ - [ ] Parser test: ` fn it(): ` → E0903 error.
217+ - [ ] Parser test: ` |it| it + 1 ` → E0903 error (cannot use keyword as param name).
218+ - [ ] Sema test: ` it ` receives correct type from expected parameter type.
219+ - [ ] Sema test: chained pipelines — each ` it ` gets its step's type.
220+ - [ ] Integration test: ` items |> filter(it > 0) |> map(it * 2) ` produces correct output.
221+ - [ ] Integration test: explicit inner closure with implicit outer works (` it.children |> filter(|c| c.active) ` ).
222+ - [ ] Integration test: ` it ` works with method call syntax (` items.filter(it > 0) ` ).
223+
224+ ### 7. Bootstrap Compatibility
225+ - [ ] ` it ` implementation goes into the self-host compiler only. Bootstrap (Zig) is unchanged.
226+ - [ ] Self-host source (` src/ ` ) must NOT use ` it ` syntax — bootstrap cannot compile it.
227+ - [ ] Self-host compiler must be able to compile user code that uses ` it ` .
228+
229+ ### 8. Validation Gates
230+ - [ ] All parser tests pass.
231+ - [ ] All sema tests pass.
232+ - [ ] All integration tests pass.
233+ - [ ] Stage3 chain passes with ` it ` support compiled in.
234+ - [ ] No regressions in existing closure tests.
0 commit comments