201 lines
7.6 KiB
Markdown
201 lines
7.6 KiB
Markdown
# Name Resolution - Linking Phase Boundary Decision
|
|
|
|
Status: Accepted (Implemented)
|
|
Cycle: Initial name-resolution closure pass
|
|
|
|
## 1. Context
|
|
|
|
PBS v1 needs an explicit phase boundary around source-level name resolution so that:
|
|
|
|
- frontend implementation does not invent phase ownership,
|
|
- diagnostics can attribute failures consistently,
|
|
- conformance can test rejection classes coherently,
|
|
- and later lowering work does not have to guess whether a failure belongs to syntax, linking, or typing.
|
|
|
|
Earlier closure already established rules for:
|
|
|
|
- module scope construction,
|
|
- import naming and aliasing,
|
|
- builtin shell visibility,
|
|
- callable-set visibility across modules.
|
|
|
|
The remaining open question was how to classify the failure classes that arise while assembling visible declarations across files and modules.
|
|
|
|
## 2. Decision
|
|
|
|
PBS v1 adopts the following normative phase baseline for name resolution and related frontend failures:
|
|
|
|
1. `syntax` is a distinct normative phase.
|
|
2. `manifest/import resolution` is a distinct normative phase.
|
|
3. `linking` is a distinct normative phase.
|
|
4. `static semantics` is a distinct normative phase.
|
|
5. `syntax` owns malformed import grammar and other token-shape or grammar-shape failures.
|
|
6. `manifest/import resolution` owns failures to resolve project space, reserved stdlib space, dependency graph, module path, or environment source.
|
|
7. `linking` owns assembly of visible declarations across files and modules.
|
|
8. `linking` therefore owns:
|
|
- import of non-exported names,
|
|
- unresolved barrel entries against module declarations,
|
|
- collisions between visible imported names from different canonical origins,
|
|
- local-versus-import visibility collisions,
|
|
- callable-origin conflicts across module boundaries,
|
|
- and duplicate canonical builtin or host identities in one resolved environment.
|
|
9. `static semantics` owns declaration validity, type checking, member lookup once the receiver type is known, and overload resolution within an already-formed visible callable set.
|
|
10. Member lookup failure on an already-typed builtin receiver belongs to `static semantics`.
|
|
11. Ambiguity between different imported origins must be rejected in `linking` before any callsite analysis.
|
|
|
|
## 3. Phase Roles
|
|
|
|
### 3.1 Syntax
|
|
|
|
`syntax` owns failures that arise before module or declaration assembly.
|
|
|
|
Examples:
|
|
|
|
- malformed import declaration shape,
|
|
- malformed alias syntax,
|
|
- malformed declaration grammar,
|
|
- unexpected tokens.
|
|
|
|
### 3.2 Manifest and Import Resolution
|
|
|
|
`manifest/import resolution` owns failures of locating and loading the source of a module or reserved environment.
|
|
|
|
Examples:
|
|
|
|
- unresolved `@project:*` dependency target,
|
|
- unresolved reserved stdlib module,
|
|
- invalid project-space selection,
|
|
- failure to load the module source from the selected environment.
|
|
|
|
### 3.3 Linking
|
|
|
|
`linking` owns the assembly of the visible declaration space after modules have been found and loaded.
|
|
|
|
Examples:
|
|
|
|
- imported name is not exported by the target module,
|
|
- `mod.barrel` entry does not resolve against declarations of the module,
|
|
- two imports expose the same visible name from different canonical origins,
|
|
- a local visible declaration collides with an imported visible declaration,
|
|
- callable-origin conflicts across module boundaries,
|
|
- duplicate canonical builtin identities in one resolved environment,
|
|
- duplicate canonical host identities in one resolved environment.
|
|
|
|
### 3.4 Static Semantics
|
|
|
|
`static semantics` owns validation and typing of the already-linked visible program.
|
|
|
|
Examples:
|
|
|
|
- duplicate local declarations,
|
|
- invalid declaration validity conditions,
|
|
- type mismatch,
|
|
- member lookup on a known receiver type,
|
|
- overload resolution inside one already-visible callable set.
|
|
|
|
## 4. Linking As A Real Normative Phase
|
|
|
|
PBS keeps `linking` as a distinct normative phase rather than collapsing it fully into `static semantics`.
|
|
|
|
Reasoning:
|
|
|
|
- some failures arise only when assembling visible declarations across files and modules,
|
|
- those failures are neither pure grammar failures nor ordinary local typing failures,
|
|
- and naming `linking` gives diagnostics and conformance a stable vocabulary for them.
|
|
|
|
This does not require every implementation to expose one identical internal compiler pass graph.
|
|
It only requires the externally visible failure ownership to map back to this normative phase model.
|
|
|
|
## 5. Barrel Matching And Visible Assembly
|
|
|
|
`mod.barrel` matching belongs to `linking`.
|
|
|
|
This means:
|
|
|
|
- failure of a barrel item to resolve to a declaration of the module is not merely a syntax issue,
|
|
- and it is not deferred until later typing or lowering.
|
|
|
|
Barrel matching is part of assembling the module's visible declaration contract.
|
|
|
|
## 6. Imported-Origin Conflicts
|
|
|
|
Conflicts between different imported origins are rejected in `linking` immediately.
|
|
|
|
This means:
|
|
|
|
- the implementation must not wait for a specific callsite or use-site,
|
|
- overload resolution is not allowed to rescue ambiguity between different imported origins,
|
|
- and visible declaration conflicts are resolved structurally before later typing work proceeds.
|
|
|
|
## 7. Builtin Receiver Lookup
|
|
|
|
Member lookup on a builtin receiver whose type is already known remains `static semantics`.
|
|
|
|
The reason is:
|
|
|
|
- by that point the relevant shell visibility work has already completed,
|
|
- and the remaining question is ordinary typed member validity rather than module assembly.
|
|
|
|
## 8. Invariants
|
|
|
|
- The phase model exposed to users and conformance must remain deterministic.
|
|
- `linking` remains the phase for visible declaration assembly across module boundaries.
|
|
- Callsite analysis must not be used to resolve imported-origin conflicts.
|
|
- `static semantics` operates on an already-linked visible declaration space.
|
|
- Syntax and manifest/import resolution remain narrower than linking and do not absorb visible-name conflicts that arise only after module loading.
|
|
|
|
## 9. Explicit Non-Decisions
|
|
|
|
This decision record does not yet close:
|
|
|
|
- the full diagnostics-code taxonomy,
|
|
- whether implementations expose one explicit user-facing `linking` label or a mapped equivalent wording class,
|
|
- the final artifact-facing phase vocabulary after lowering and verification specs close,
|
|
- and the exact implementation architecture of one compiler pipeline.
|
|
|
|
## 10. Spec Impact
|
|
|
|
This decision should feed at least:
|
|
|
|
- `docs/general/specs/14. Name Resolution and Module Linking Specification.md`
|
|
- `docs/pbs/specs/12. Diagnostics Specification.md`
|
|
- `docs/general/specs/13. Conformance Test Specification.md`
|
|
|
|
It should also constrain future work in:
|
|
|
|
- `docs/pbs/specs/13. Lowering IRBackend Specification.md`
|
|
- `docs/pbs/decisions/Name Resolution - Scope, Lookup, and Imports Decision.md`
|
|
- `docs/pbs/decisions/Name Resolution - Builtin Shells and Host Owners Decision.md`
|
|
- `docs/pbs/decisions/Name Resolution - Callable Sets and Cross-Module Linking Decision.md`
|
|
|
|
## 11. Validation Notes
|
|
|
|
The intended phase split is:
|
|
|
|
- `syntax` parses declaration and import shape,
|
|
- `manifest/import resolution` finds and loads modules,
|
|
- `linking` assembles visible names across modules and barrels,
|
|
- `static semantics` validates and types the already-linked visible program.
|
|
|
|
Illustrative examples:
|
|
|
|
```pbs
|
|
import { Missing } from @a:m;
|
|
```
|
|
|
|
If `@a:m` resolves successfully but does not export `Missing`, this is a `linking` failure.
|
|
|
|
```pbs
|
|
import { f } from @a:m;
|
|
import { f } from @b:n;
|
|
```
|
|
|
|
If the canonical origins differ, this is a `linking` failure and is rejected before any callsite analysis.
|
|
|
|
```pbs
|
|
import { Vec2 } from @core:math;
|
|
value.zero()
|
|
```
|
|
|
|
If `value` is already known to have builtin type `Vec2` and `.zero` is not a valid member on that receiver type, the failure is `static semantics`.
|