Expand description
Hygiene scope facts: the side-table vocabulary for binding-introducing ops (P2-8).
§The imported practice
docs/davinci/prior-art-toolchains.md (Lean 4, metaprogramming
anti-lesson): dialect lowerings that synthesize identifiers (slot
props, v-for scopes) need hygiene-style scope tagging so
synthesized names can’t capture author bindings. The mechanism here
is the classic one reduced to what L2 needs:
- Every binding-introducing op (a
ui.for, a slot-props position) gets a freshScopeTag, minted densely by the lowering artifact. Names are compared as(name, tag)pairs, never as bare text, so two scopes spelling the same name never collide. - Every introduced binding carries a
ScopeOrigin:Authoredwith the author’s span, orSynthesizedwith the rule that minted it. A later pass can therefore never confuse a synthesized name with an author’s - the origin is a recorded fact, not a naming convention. - A pass that synthesizes a new name must mint a fresh tag for it
and record it as
ScopeOrigin::Synthesized; re-using an authored scope’s tag for a synthesized name is the capture bug the tag exists to prevent.
§Residency
Facts live beside the tree in a
SideTable<ScopeFacts> keyed by
the introducing op’s NodeId (dense
page-order ids, folio-format.md “Node numbering”). The table is the
sparse non-arena form, so names are owned Strings and the facts are
'static - they survive Allocator::reset the way diagnostics do
(P1-11), which is what keeps the LSP live on a broken SFC.
§Binding enumeration
Ordinary ASCII Vue positions keep the original simple-identifier path:
destructuring patterns contribute no names. Exceptional v-for aliases
containing escapes or non-ASCII text instead use their original, complete
parameter goal. Its actual binding patterns enumerate cooked declaration
names, with each authored origin covering the full original identifier
token, including its escape or entity spelling. Refused goals contribute
no partial or inferred names.
This table only stores the lowering’s facts; it never scans or decodes
names. Other dialects keep the ExprDialect::enumerate_bindings seam
(#4365). A position without an entry still has its scope tag - the
scope is a fact even where the names wait.
Structs§
- Scope
Binding - One binding a scope introduces into its op’s region(s).
- Scope
Facts - The scope facts of one binding-introducing op.
- Scope
Tag - One binding-introduction site, minted densely per artifact.
Enums§
- Scope
Origin - Where a binding’s name came from.