Skip to main content

Module scope

Module scope 

Source
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 fresh ScopeTag, 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: Authored with the author’s span, or Synthesized with 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§

ScopeBinding
One binding a scope introduces into its op’s region(s).
ScopeFacts
The scope facts of one binding-introducing op.
ScopeTag
One binding-introduction site, minted densely per artifact.

Enums§

ScopeOrigin
Where a binding’s name came from.