mirror of
https://github.com/github/codeql.git
synced 2026-07-30 23:13:01 +02:00
Wrapping an optional capture in a node meant building the wrapper inside
an `Option::map`, which buried the shape of the output in a closure:
(break_expr label: {lbl.map(|l| tree!((identifier #{l})))})
A field's value can now be marked with `?` instead. If a `#{expr}`
anywhere beneath it interpolates an absent value, the subtree is
abandoned and the field is left unset:
(break_expr label: (identifier #{lbl})?)
The marker follows the value, as quantifiers do in the query language
(`label: _? @@lbl`). Absence propagates through as many levels as
necessary, and a nested `?` catches first, so an inner absent value need
not discard the outer node.
Only `#{expr}` propagates absence, since it supplies a node's content:
with no value there is no leaf to build. A `{expr}` splice supplies
children, where yielding nothing already leaves the field unset, so `?`
is rejected on one. Outside a `?`, interpolating an `Option` with
`#{expr}` remains a compile error, keeping the choice between leaving a
field unset and unwrapping explicit; `YeastDisplay` now carries an
`on_unimplemented` note pointing at the new syntax.
Inside a fallible field, interpolations route through a new
`MaybeYeastValue` trait, whose impls are enumerated rather than blanket
for the same coherence reason `YeastDisplay`'s are.
Codegen outside a `?` is unchanged, so `tree!` and `trees!` keep their
return types. Converting the ten `Option::map` sites in the Swift rules
leaves the corpus byte-identical; four captures become `@@` now that
their values are only ever interpolated.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>