406 lines
15 KiB
Markdown
406 lines
15 KiB
Markdown
# PBS Name Resolution and Module Linking Specification
|
|
|
|
Status: Draft v1 (Normative)
|
|
Applies to: scope formation, name lookup, imports, exports, barrel visibility, cross-module resolution, and semantic linking of PBS programs
|
|
|
|
## 1. Purpose
|
|
|
|
This document defines the normative name-resolution and semantic-linking model for PBS v1.
|
|
|
|
Its purpose is to make the visible declaration space of a PBS program deterministic enough that:
|
|
|
|
- frontend implementations do not invent lookup or collision rules,
|
|
- diagnostics can classify failures consistently,
|
|
- conformance can test source-facing rejection classes,
|
|
- and lowering begins from an already-linked visible program.
|
|
|
|
## 2. Scope
|
|
|
|
This document defines:
|
|
|
|
- module scope construction,
|
|
- lookup order by namespace,
|
|
- import and alias resolution,
|
|
- barrel-mediated visibility,
|
|
- reserved stdlib shell resolution for builtin and host-backed surfaces,
|
|
- callable visibility across modules,
|
|
- and linking-time rejection conditions before lowering.
|
|
|
|
This document does not define:
|
|
|
|
- runtime execution behavior,
|
|
- optimizer or backend internals,
|
|
- full PBX binary linking,
|
|
- or loader/runtime artifact behavior after lowering.
|
|
|
|
## 3. Authority and Precedence
|
|
|
|
Normative precedence:
|
|
|
|
1. `3. Core Syntax Specification.md`
|
|
2. `4. Static Semantics Specification.md`
|
|
3. `5. Manifest, Stdlib, and SDK Resolution Specification.md`
|
|
4. `6. VM-owned vs Host-backed.md`
|
|
5. `6.1. Intrinsics and Builtin Types Specification.md`
|
|
6. `6.2. Host ABI Binding and Loader Resolution Specification.md`
|
|
7. `8. Stdlib Environment Packaging and Loading Specification.md`
|
|
8. `18. Standard Library Surface Specification.md`
|
|
9. This document
|
|
|
|
If a rule here conflicts with higher-precedence specs, it is invalid.
|
|
|
|
## 4. Normative Inputs
|
|
|
|
This document depends on, at minimum:
|
|
|
|
- `3. Core Syntax Specification.md`
|
|
- `4. Static Semantics Specification.md`
|
|
- `5. Manifest, Stdlib, and SDK Resolution Specification.md`
|
|
- `6. VM-owned vs Host-backed.md`
|
|
- `6.1. Intrinsics and Builtin Types Specification.md`
|
|
- `6.2. Host ABI Binding and Loader Resolution Specification.md`
|
|
- `8. Stdlib Environment Packaging and Loading Specification.md`
|
|
- `18. Standard Library Surface Specification.md`
|
|
|
|
## 5. Already-Settled Inputs
|
|
|
|
The following inputs are already fixed elsewhere and must not be contradicted here:
|
|
|
|
- PBS has distinct type, value, callable, and host-owner namespaces.
|
|
- `mod.barrel` is the single source of module visibility.
|
|
- Imports target modules, not files.
|
|
- Reserved stdlib project spaces are resolved only from the selected stdlib environment.
|
|
- Only `pub` symbols may be imported from another module.
|
|
- Reserved stdlib/interface modules may expose compile-time-only shells for both host-backed and VM-owned surfaces, and may expose service facades over non-public host owners.
|
|
- Source-visible builtin names are resolved through imported builtin shell declarations rather than by hardcoded source spelling alone.
|
|
- Canonical builtin identity and canonical intrinsic identity are governed by builtin metadata rather than by the imported PBS-visible declaration name alone.
|
|
- Canonical host identity is governed by host metadata rather than by imported owner spelling alone.
|
|
|
|
## 6. Module Scope Construction
|
|
|
|
### 6.1 Module collection
|
|
|
|
For one module:
|
|
|
|
- the compiler collects top-level declarations from all `.pbs` files in that module,
|
|
- forms one module-level declaration space,
|
|
- and only then applies `mod.barrel` to determine `mod` and `pub` visibility.
|
|
|
|
Rules:
|
|
|
|
- declaration existence is not derived from barrel entries,
|
|
- module-internal top-level declaration availability does not depend on source-file order,
|
|
- and `mod.barrel` is a visibility filter over existing declarations rather than a declaration source.
|
|
|
|
### 6.2 Lexical scope
|
|
|
|
Inside executable bodies:
|
|
|
|
- lexical block scope nests normally over module scope,
|
|
- nearest local bindings win within value lookup,
|
|
- and lexical nesting remains independent from cross-module visibility.
|
|
|
|
## 7. Lookup Order By Namespace
|
|
|
|
Lookup in PBS remains namespace-based.
|
|
|
|
### 7.1 Value position
|
|
|
|
Value-position lookup follows this order:
|
|
|
|
1. nearest local lexical bindings,
|
|
2. parameters in the current lexical function scope,
|
|
3. visible module-local values,
|
|
4. visible imported values.
|
|
|
|
For lookup purposes, parameters and local `let` bindings participate in one nearest lexical value layer.
|
|
|
|
### 7.2 Type position
|
|
|
|
Type-position lookup follows this order:
|
|
|
|
1. visible module-local type declarations,
|
|
2. visible imported type declarations,
|
|
3. builtin simple types `int`, `float`, `bool`, and `str` as always-available reserved type names.
|
|
|
|
Builtin simple types:
|
|
|
|
- are not treated as ordinary imported declarations,
|
|
- do not participate in ordinary import competition,
|
|
- and remain always available without import.
|
|
|
|
### 7.3 Callable position
|
|
|
|
Callable-position lookup follows this order:
|
|
|
|
1. visible module-local callables,
|
|
2. visible imported callables.
|
|
|
|
Callable lookup operates only on already-formed visible callable sets as defined later in this document.
|
|
|
|
### 7.4 Host-owner position
|
|
|
|
Host-owner lookup follows this order:
|
|
|
|
1. visible module-local host owners,
|
|
2. visible imported host owners.
|
|
|
|
Host-owner lookup remains separate from type, value, and callable lookup.
|
|
|
|
## 8. Import Surface And Naming
|
|
|
|
### 8.1 Effective local imported name
|
|
|
|
The local visible name introduced by an import is always the post-alias name when an alias is present.
|
|
|
|
Rules:
|
|
|
|
- `import { X } from @project:path;` introduces the visible local name `X`,
|
|
- `import { X as Y } from @project:path;` introduces only the visible local name `Y`,
|
|
- and alias spelling changes only the local visible name, never canonical builtin identity or canonical host identity.
|
|
|
|
### 8.2 Named import
|
|
|
|
`import { X } from @project:path;`:
|
|
|
|
- resolves the target module,
|
|
- checks that `X` is exported and importable from that module,
|
|
- and introduces `X` into the corresponding namespace locally.
|
|
|
|
### 8.3 Whole-module import
|
|
|
|
`import { * } from @project:path;`:
|
|
|
|
- resolves the target module,
|
|
- introduces the target module's exported visible names under their exported spellings,
|
|
- but does not create a module-valued binding,
|
|
- does not create a namespace object,
|
|
- and does not authorize qualified member access by itself.
|
|
|
|
If PBS later wants module-object or namespace-qualified source semantics, that must be added explicitly rather than inferred from this import form.
|
|
|
|
## 9. Collision And Ambiguity Rules
|
|
|
|
### 9.1 Local versus imported
|
|
|
|
If a module-local declaration and an imported declaration produce the same visible name in the same namespace:
|
|
|
|
- the program is rejected,
|
|
- and the implementation must not silently shadow either declaration.
|
|
|
|
This includes function names.
|
|
A module-local function and an imported function with the same visible name are rejected rather than merged.
|
|
|
|
### 9.2 Imported versus imported
|
|
|
|
If two imports produce the same visible name in the same namespace:
|
|
|
|
- the program is not rejected only when both imports resolve to the same canonical underlying declaration after module resolution,
|
|
- such same-origin duplication is redundant but tolerated,
|
|
- and the program is rejected if the imports resolve to different canonical underlying declarations.
|
|
|
|
### 9.3 Namespace separation
|
|
|
|
Names in different namespaces do not collide merely by spelling.
|
|
|
|
For example:
|
|
|
|
- a host owner and a type declaration do not collide by spelling alone,
|
|
- because host-owner namespace remains distinct from type namespace.
|
|
|
|
### 9.4 Non-callable names do not merge
|
|
|
|
Non-callable namespaces do not merge by name.
|
|
|
|
## 10. Callable Sets And Cross-Module Linking
|
|
|
|
### 10.1 Imported callable set
|
|
|
|
`import { f } from @project:path;` imports the exported callable set named `f` from the target module.
|
|
|
|
Rules:
|
|
|
|
- the imported callable set for `f` consists only of those overload signatures of `f` that are exported through that module's `mod.barrel`,
|
|
- non-exported overloads in the target module do not participate in the imported callable set,
|
|
- and import operates on the exported callable name rather than on one overload at a time.
|
|
|
|
### 10.2 Same-origin versus different-origin callable imports
|
|
|
|
If the same visible callable name is imported more than once:
|
|
|
|
- same-origin duplicate imports are tolerated as redundancy when they resolve to the same canonical callable-set origin,
|
|
- different-origin imports are rejected immediately,
|
|
- and the implementation must not wait until a callsite to reject different-origin callable-name collisions.
|
|
|
|
### 10.3 Local versus imported callable names
|
|
|
|
If a module-local function name and an imported function name are the same visible callable name:
|
|
|
|
- the program is rejected immediately,
|
|
- and the implementation must not merge the local and imported callable sets.
|
|
|
|
### 10.4 Overload-resolution boundary
|
|
|
|
PBS separates:
|
|
|
|
- callable-set formation,
|
|
- and overload resolution at a callsite.
|
|
|
|
Rules:
|
|
|
|
- the implementation must first form one unambiguous visible callable set,
|
|
- only then may ordinary overload resolution operate on the candidate signatures of that set,
|
|
- and callsite context must not be used to resolve ambiguity between different imported callable origins.
|
|
|
|
## 11. Reserved Stdlib Shell Resolution
|
|
|
|
### 11.1 Reserved shells as imported declarations
|
|
|
|
Source-visible declarations exposed by reserved builtin shells are imported into their ordinary corresponding namespaces.
|
|
|
|
This means:
|
|
|
|
- builtin-exposed types enter type lookup as imported type declarations,
|
|
- builtin-exposed constants enter value lookup as imported values,
|
|
- and host owners enter host-owner lookup as imported host-owner declarations.
|
|
|
|
`declare builtin type` itself remains a reserved stdlib/toolchain declaration form rather than ordinary user-authored source syntax.
|
|
|
|
### 11.2 Builtin simple types versus imported builtin shells
|
|
|
|
PBS distinguishes:
|
|
|
|
- the predeclared builtin simple-type set `int`, `float`, `bool`, `str`,
|
|
- and imported builtin shells such as `Vec2` or `Color`.
|
|
|
|
Imported builtin shells are not promoted to the same always-available status as builtin simple types.
|
|
|
|
### 11.3 Intrinsic member lookup
|
|
|
|
Builtin intrinsic methods:
|
|
|
|
- never participate in free lookup,
|
|
- are not introduced by import as free functions,
|
|
- and are resolved only through member lookup on a receiver already known to have the corresponding builtin type.
|
|
|
|
Alias changes to the imported builtin type affect only the local visible owner spelling, not the canonical builtin or intrinsic identity.
|
|
|
|
### 11.4 Collision policy for reserved shells
|
|
|
|
Reserved builtin shells and host owners follow the same collision policy as ordinary imported declarations.
|
|
|
|
Rules:
|
|
|
|
- same visible name in the same namespace is an error unless another already-closed rule explicitly permits otherwise,
|
|
- reserved-shell status does not authorize silent shadowing,
|
|
- and host owners do not collide with types or values merely by spelling because host-owner namespace remains separate.
|
|
|
|
### 11.5 Reserved project-space policy
|
|
|
|
For source-level policy:
|
|
|
|
- builtin shells are preferred under `@core:*`,
|
|
- and host-facing capability surfaces remain the natural fit for `@sdk:*`.
|
|
|
|
### 11.6 Canonical identity
|
|
|
|
Canonical builtin identity and canonical host identity are not derived from local alias spelling.
|
|
|
|
Duplicate canonical builtin identities or duplicate canonical host identities in one resolved environment are rejected as linking failures.
|
|
|
|
## 12. Linking Phase Boundary And Deterministic Failures
|
|
|
|
### 12.1 Normative phase baseline
|
|
|
|
PBS v1 adopts the following normative phase baseline for name resolution and related frontend failures:
|
|
|
|
1. `syntax`
|
|
2. `manifest/import resolution`
|
|
3. `linking`
|
|
4. `static semantics`
|
|
|
|
### 12.2 Syntax
|
|
|
|
`syntax` owns malformed import grammar and other token-shape or grammar-shape failures.
|
|
|
|
### 12.3 Manifest and import resolution
|
|
|
|
`manifest/import resolution` owns failures to resolve:
|
|
|
|
- project space,
|
|
- reserved stdlib space,
|
|
- dependency graph target,
|
|
- module path,
|
|
- or environment source.
|
|
|
|
### 12.4 Linking
|
|
|
|
`linking` owns assembly of visible declarations across files and modules.
|
|
|
|
At minimum, `linking` owns:
|
|
|
|
1. import of non-exported names,
|
|
2. unresolved barrel entries against module declarations,
|
|
3. collisions between visible imported names from different canonical origins,
|
|
4. local-versus-import visibility collisions,
|
|
5. callable-origin conflicts across module boundaries,
|
|
6. duplicate canonical builtin identities in one resolved environment,
|
|
7. duplicate canonical host identities in one resolved environment.
|
|
|
|
### 12.5 Static semantics
|
|
|
|
`static semantics` owns:
|
|
|
|
1. duplicate local declarations,
|
|
2. declaration validity,
|
|
3. type checking,
|
|
4. member lookup once the receiver type is known,
|
|
5. overload resolution within an already-formed visible callable set.
|
|
|
|
Member lookup failure on an already-typed builtin receiver therefore belongs to `static semantics`.
|
|
|
|
### 12.6 Imported-origin conflicts are rejected before callsite analysis
|
|
|
|
Conflicts between different imported origins are rejected in `linking` immediately.
|
|
|
|
The implementation must not:
|
|
|
|
- wait for a specific callsite,
|
|
- use overload resolution to rescue imported-origin ambiguity,
|
|
- or defer visible declaration conflicts to later typing work.
|
|
|
|
## 13. Deterministic Resolution Failures
|
|
|
|
At minimum, a conforming implementation must reject:
|
|
|
|
1. import of a non-exported builtin type shell,
|
|
2. import of a non-exported builtin constant shell,
|
|
3. import of a non-exported host owner shell,
|
|
4. import of any non-exported name from a resolved module,
|
|
5. unresolved barrel entries against module declarations,
|
|
6. local-versus-import same-namespace collisions,
|
|
7. imported same-name collisions from different canonical origins,
|
|
8. local-versus-import function-name collisions,
|
|
9. duplicate visible builtin type declarations that claim the same canonical builtin identity in one resolved environment,
|
|
10. duplicate visible builtin constants that claim the same canonical builtin constant identity in one resolved environment,
|
|
11. duplicate visible host owners that claim the same canonical host identity in one resolved environment,
|
|
12. member lookup on a builtin receiver where the imported builtin shell does not declare the requested field or intrinsic member,
|
|
13. any resolution path that attempts to derive host or builtin canonical identity from alias spelling alone.
|
|
|
|
## 14. Non-Goals
|
|
|
|
- Reopening the already-settled import surface syntax.
|
|
- Defining runtime loader behavior.
|
|
- Freezing one compiler symbol-table implementation.
|
|
- Freezing one internal compiler pass graph.
|
|
|
|
## 15. Exit Criteria
|
|
|
|
This document is ready to move beyond its current draft status only when:
|
|
|
|
1. name lookup is deterministic across all relevant scopes,
|
|
2. barrel and module linking behavior is explicit,
|
|
3. reserved stdlib shell resolution is explicit for host-backed and VM-owned surfaces,
|
|
4. cross-module callable visibility and ambiguity behavior are normatively defined,
|
|
5. and the phase ownership of source-facing name-resolution failures is explicit enough for diagnostics and conformance.
|