@@ -124,6 +124,65 @@ For example, two different imported names that refer to the same definition are
124124still different unless their parsed source spelling matches or a metavariable
125125captures them.
126126
127+ ### Let Shapes With Omitted Bodies
128+
129+ An ordinary ` let ` shape without an explicit body is a let-header pattern. For
130+ example, this shape matches the binding pattern and right-hand side, but does
131+ not constrain the candidate body:
132+
133+ ``` yaml
134+ patterns :
135+ - shape : let $(name:id) = $(value:exp)
136+ ` ` `
137+
138+ It can match candidates such as:
139+
140+ ` ` ` moonbit
141+ let item = load()
142+ ```
143+
144+ ``` moonbit
145+ let item = load(); use(item)
146+ ```
147+
148+ ``` moonbit
149+ let item = load(); { trace(item); item }
150+ ```
151+
152+ This exception exists because the MoonBit parser represents ` let item = load() `
153+ as an ` Expr::Let ` whose body is a synthesized unit expression. When that
154+ synthesized unit appears in the pattern shape, the matcher treats it as "body
155+ omitted in the pattern" instead of requiring the candidate body to be the same
156+ unit node.
157+
158+ Write an explicit body when the body matters:
159+
160+ ``` yaml
161+ patterns :
162+ - shape : let $(name:id) = $(value:exp); use($(name:id))
163+ ` ` `
164+
165+ To capture whichever body the candidate has, write a body metavar explicitly:
166+
167+ ` ` ` yaml
168+ patterns :
169+ - shape : let $(name:id) = $(value:exp); $(body:exp)
170+ ` ` `
171+
172+ To require a unit body, write an explicit ` ()` body:
173+
174+ ` ` ` yaml
175+ patterns:
176+ - shape: let $(name:id) = $(value:exp); ()
177+ ` ` `
178+
179+ This matches an explicit unit body. It is not the same as the omitted-body
180+ shape above, which intentionally ignores the candidate body. Omitted-body-only
181+ matching is not currently expressible as a structural shape.
182+
183+ This shortcut applies only to ordinary `let` expressions. `let mut`, local
184+ function definitions, and `letrec` shapes use normal structural matching.
185+
127186# # Metavariables
128187
129188Identifiers and labels in a shape are literal by default. A name becomes a
0 commit comments