diff --git a/docs/architecture/0002-execution-plan.md b/docs/architecture/0002-execution-plan.md index cc4d3a3..f18ffe8 100644 --- a/docs/architecture/0002-execution-plan.md +++ b/docs/architecture/0002-execution-plan.md @@ -602,7 +602,7 @@ interface SymbolSource // --- Added JIT, when the step that needs them lands (NOT built in Step 2) --- // Step 3b (functions/constants gain project reach; a second searchable kind exists): // lookupFunction(FunctionName): ?FunctionInfo - // lookupConstant(ConstantName): ?ConstantInfo + // lookupConstant(GlobalConstantName): ?ConstantInfo // searchClassLikes generalizes to search(string $prefix, NameKind $kind) // Future (workspace scope, #264): // locate(QualifiedName, NameKind): ?SymbolDefinition // kind-neutral def-site, only if a feature needs it @@ -641,12 +641,27 @@ To stop the two typing models fighting before they are built: - `QualifiedName` is the base FQN value type — a namespace path plus a short name, **kind-neutral**. -- `ClassLikeName`, `FunctionName`, `ConstantName`, `NamespaceName` extend / wrap it - and **carry their kind intrinsically** (each exposes `kind(): NameKind`). These are +- `ClassLikeName`, `FunctionName`, `GlobalConstantName`, `NamespaceName` extend / wrap + it and **carry their kind intrinsically** (each exposes `kind(): NameKind`). These are the primary currency; the per-kind `lookup*` methods take the matching one, so the kind is implicit and `NameKind` is not passed. `ClassLikeName` is today's `ClassName` (which per CLAUDE.md also serves as the class `Type`); whether it is reused as-is, renamed, or wrapped is an open decision (§7). The other three are new. +- **`GlobalConstantName`, because `ConstantName` is the class constant member name** + beside `MethodName` and `PropertyName`. A bare member name is not an FQN, and one type + holding both would report `NameKind::Constant` for a member name. Unlike + `ClassLikeName` versus `ClassName` in §7, these are two concepts, not two names. +- **One `ConstantInfo` serves both**, with `?ClassName` for `declaringClass`; its absence + is what makes a constant global, and `format()` branches on that alone. `visibility` + and `isFinal` carry true values — a redeclared `const` is fatal, a repeated `define()` + a no-op. The nullable is a conscious exception to the no-nullable rule: the + alternatives are a second metadata type differing in one field, or a sentinel + `ClassName` the type system cannot catch as a lie. +- A global constant is **not** a `ResolvedMember` — that interface means *reached through + a class*, which is a path it does not have. Whether it instead gets a fifth wrapper or + `ConstantInfo` carries `ResolvedSymbol` itself is #416's, and turns on SC.13: + `ResolvedSymbol` is in `Resolution` and returns an `Index\Location`, so a `Domain` + object carrying it adds edges the layer contract denies. - `locate(QualifiedName, NameKind)` is the kind-agnostic entry, used when the caller has an FQN whose kind is known only from syntactic position and has not minted a typed subtype. `NameKind` is **not** redundant here precisely because the input is @@ -656,7 +671,7 @@ To stop the two typing models fighting before they are built: is about identifiers, not search fragments. `kind` (once the parameter exists in Step 3b) selects which namespace to search. - **JIT:** Step 2 uses only `ClassLikeName` (today's `ClassName`) and `NamespaceName`. - `QualifiedName`, `NameKind`, `FunctionName`, and `ConstantName` land with the methods + `QualifiedName`, `NameKind`, `FunctionName`, and `GlobalConstantName` land with the methods that first use them (Step 3b, and `locate` in the workspace scope) — an unused type is not carried ahead of its method. This whole model is the *target*; it is introduced piecewise. @@ -814,7 +829,7 @@ once Step P is green. **Resolved — see Section 8.** - Whether `ClassLikeName` is the existing `ClassName` reused as-is, renamed, or a wrapper — it must coexist with `ClassName`'s dual role as the class `Type` (§5.3). -- Whether `FunctionName` / `ConstantName` / `NamespaceName` land in Step 2 as prep +- Whether `FunctionName` / `GlobalConstantName` / `NamespaceName` land in Step 2 as prep or in Step 3 with their lookups (lean: Step 3, to avoid an unused-type commit; `NamespaceName` is needed by `childrenOf` in Step 2, so it lands then). - Whether completion detail after the `search` migration comes from a follow-up diff --git a/docs/architecture/build-manifest.md b/docs/architecture/build-manifest.md index 1f822b5..ffc4729 100644 --- a/docs/architecture/build-manifest.md +++ b/docs/architecture/build-manifest.md @@ -182,11 +182,11 @@ Notes: of it. `NameKind` already exists (it predates Wave 2, as the catalog's coarse kind); Step 2 carries `ClassLikeName` / `NamespaceName`; `QualifiedName` lands in **S3.7b**, whose `DeclarationScanner` is its first caller; `FunctionName` in **S3.8a** and - `ConstantName` in **S3.8b**, with their lookups. - - **`ConstantName` is already taken.** `Domain\ConstantName` wraps a *class* constant - name; §5.3's `ConstantName` is a *global* constant FQN. Decide the naming before - S3.8b rather than inside it — this is the same coexistence question §7 leaves open - for `ClassLikeName` versus `ClassName`. + `GlobalConstantName` in **S3.8b**, with their lookups. + - **The `ConstantName` collision is settled (0002 §5.3):** the global FQN type is + `GlobalConstantName`, `Domain\ConstantName` stays the class member name, and one + `ConstantInfo` serves both kinds. The *resolved* shape stays open — it is #416's and + turns on SC.13, so take SC.13 first. - **Steps 3 and 4 both edit `SymbolResolver` (§6).** S4.2 (positional extraction) is gated on S3.8 (the 3b lookup migration) so the two never run concurrently; manifest order keeps Step 3 ahead of Step 4 regardless. S4.1 (`TypeClassifier` + the §4.5/§4.6