Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 3 additions & 141 deletions docs/specs/SPEC.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -652,147 +652,9 @@ Compiles to (ownership removed):

== 8. Top-Level Binding Environment

This section specifies how top-level declarations populate the binding
environment that subsequent declarations and their bodies resolve against.
It complements §3 (which gives the typing judgements) by fixing the
*operational* rules every conforming code generator must obey, independent
of any concrete target.

The WebAssembly realisation of these rules is documented at
link:codegen-environment.adoc[`docs/specs/codegen-environment.adoc`].

=== 8.1 Top-Level Kinds

A program is an ordered sequence of top-level declarations. Each kind
contributes to the binding environment as follows:

[cols="1,2,2", options="header"]
|===
| Declaration | Binds | Runtime artefact

| `fn f(…) { … }` (§2.4)
| `f` as a function value
| Yes — function in the target module

| `extern fn f(…) -> T;` (§2.10)
| `f` as a function value
| Yes — host-supplied import

| `const c: T = e;` (§2.9)
| `c` as an immutable value of type `T`
| Yes — same-type immutable cell

| `type T = …;` (§2.2)
| `T` as a type
| No — compile-time only

| `extern type T;` (§2.10)
| `T` as an opaque type
| No — compile-time only

| `effect E { … }` (§2.7)
| `E` and its operations
| No — handled by effect lowering (§7)

| `trait Tr { … }` (§2.8)
| `Tr` as a trait
| No — compile-time only

| `impl Tr for T { … }` (§2.8)
| Trait dictionary for `(Tr, T)`
| No — compile-time only
|===

=== 8.2 Declaration Order and Visibility

Top-level declarations are processed in source order. The binding
environment in scope when a declaration is processed contains exactly
the names of declarations that *precede* it in source order, together
with the names introduced by the module's `use` clauses (§8.4).

A reference to a name not yet bound at its use site is a static error:

[source,affinescript]
----
fn use_pi() -> Float { pi } // ERROR: `pi` not yet declared
const pi: Float = 3.141592;
----

Reordering resolves it:

[source,affinescript]
----
const pi: Float = 3.141592;
fn use_pi() -> Float { pi } // OK: `pi` is in scope here
----

The recommended source ordering — types, effects, constants, traits,
impls, functions — is sufficient (though not necessary) to avoid every
forward-reference error.

=== 8.3 Identifier Resolution

A bare identifier `x` in expression position resolves by the following
lookup order, in the context where the expression appears:

. Local bindings introduced by enclosing `let`, lambda parameters, or
function parameters.
. Variant constructors of any in-scope `enum` type, resolved to their
tag (§2.2).
. Top-level bindings: `fn`, `extern fn`, and `const` names registered
under §8.1.

A call expression `f(args)` resolves `f` against the same environment.
A name bound to a `const` may appear in expression position only; a
name bound to a `fn` or `extern fn` may appear in either expression or
call position. The well-formedness of these positions is established by
the type system (§3); a backend may rely on the typechecker having
rejected ill-positioned references.

=== 8.4 Cross-Module Bindings

Imports (`use M::{…}`, `use M::*`) extend the binding environment of
the importer with the public top-level names of the imported module,
under the alias chosen by the import form (§2.1). The order in which
import-introduced names enter the environment is *before* every
local top-level declaration of the importer.

Items that flow across module boundaries:

* `fn` and `extern fn` — imported as references to the original definition.
* `const` — its initialiser is compiled inline into the importer's
module, so each importer materialises its own copy of the value.
The denotation seen at use sites is the same as the source `const`
in the defining module.

=== 8.5 Conformance Criteria

A conforming code generator MUST:

C1:: Process top-level declarations in source order.

C2:: Register a top-level name in its environment *before* generating
the body of any later declaration that may reference it.

C3:: For each runtime-bearing declaration (`fn`, `extern fn`, `const`)
emit an artefact whose denotation matches §2 and §3 — functions are
first-class values, constants are immutable cells of their declared
type.

C4:: For each compile-time declaration (`type`, `extern type`, `effect`,
`trait`, `impl`) record sufficient information in the environment for
subsequent declarations to typecheck and lower correctly, without
necessarily emitting any target artefact.

C5:: Report a static error (rather than emit a malformed module) when
an identifier escapes its lexical scope or names a binding not yet in
the environment under C1–C2.

C6:: If a binding kind is unsupported by the target, raise
`UnsupportedFeature` at the declaration site, never silently drop it.

Implementations MAY use any internal representation for the binding
environment; C1–C6 fix what is observable, not how it is stored.
See link:codegen-environment.adoc[`docs/specs/codegen-environment.adoc`] for the
full codegen module environment reference, including the `func_indices`
dual-use encoding, population order, and extern binding rules.

== Appendix: Grammar Reference

Expand Down
Loading