Fix #665 (nested namespace bare-name → enclosing scope); complete #639#748
Merged
Conversation
…complete #639 #665 (type-checker name resolution): a function in a NESTED namespace could not reference a member of its ENCLOSING namespace by bare name (the issue repro: `O.I.f` calling `O`'s non-exported `outerHelp()`), rejected as "Undefined variable" in both modes. Root cause: `CheckNamespace` fully checks any nested namespace during the enclosing namespace's FIRST pass (CollectNamespaceMemberType → recursive CheckNamespace), but member functions were only registered in the SECOND pass — so nested bodies saw nothing. CheckNamespace now hoists function declarations (HoistFunctionDeclarations) before the first pass, mirroring the top-level order. var/const/class/enum already resolved (hoisted as `any` / first-pass source-order registration). Compiled codegen: a bare reference to a sibling/enclosing NAMESPACE OBJECT (`A.g()` from `O.B.f`, where A is `O.A`) type-checked (namespaces register eagerly) but threw at runtime — namespace fields are keyed by full dotted path (`$ns_O_A`), so the simple name never matched. New `CompilationContext.ResolveNamespaceField` walks the current namespace path innermost→outermost (mirroring ResolveFunctionName), wired into both bare-variable resolution sites (ILEmitter.Expressions + ExpressionEmitterBase) so the sync and state-machine paths stay in sync. Also covers `new A.X()` from a sibling namespace. 6 new both-mode tests in SharedTests/NamespaceTests.cs (issue repro, forward reference, enclosing class, sibling namespace, 3-level nesting, inner-shadows-outer). #639 (branded-target collector): the substantive collector fix already landed on main in #655 (CollectAllInstanceMembers folds a generic-instantiation superclass; CollectGenericClassMembers gained an all-members mode) with tests. This completes the issue's remaining "minor/related" note: the MutableClass branch of GetMemberType (signature-collection-time) walked frozen.Superclass with unsubstituted GetFieldTypes/GetMethods, surfacing an inherited generic-base member as the bare type parameter. Routed it through the existing substitution-aware ResolveClassMemberTypeSubstituted, unifying it with the frozen-instance path and the member-set collectors. Equivalent for a non-generic superclass; not independently observable (matches the issue's "transient" framing), validated by the full suite. Filed follow-ups: #745 (nested ns cannot name its enclosing ns by its own name — the namespace self-binds only at the END of CheckNamespace), #746 (interpreter mis-resolves a nested ns shadowing a same-named top-level ns; compiled is correct). Full suite: 13033 passed / 0 failed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#665 — nested namespace member cannot reference an enclosing namespace's member by bare name
A function in a nested namespace could not reference a member of its enclosing namespace by bare (unqualified) name — rejected at type-check as
Undefined variablein both modes.tscaccepts it (enclosing members are in lexical scope of nested bodies).Root cause (type checker):
CheckNamespacefully checks any nested namespace during the enclosing namespace's first pass (CollectNamespaceMemberType→ recursiveCheckNamespace), but member functions were only registered in the second pass — so nested bodies saw nothing. Fix:CheckNamespacenowHoistFunctionDeclarations(ns.Members)before the first pass, mirroring the top-level hoisting order. (var/const/class/enum already resolved.)Compiled codegen: a bare reference to a sibling/enclosing namespace object (
A.g()fromO.B.f, whereAisO.A) type-checked but threw at runtime — namespace fields are keyed by full dotted path ($ns_O_A), so the simple name never matched. NewCompilationContext.ResolveNamespaceFieldwalks the current namespace path innermost→outermost (mirroringResolveFunctionName), wired into both bare-variable sites (ILEmitter.Expressions+ExpressionEmitterBase) so the sync and state-machine paths stay in sync. Also coversnew A.X()from a sibling namespace.6 new both-mode tests (
SharedTests/NamespaceTests.cs): issue repro, forward reference, enclosing class, sibling namespace, 3-level nesting, inner-shadows-outer.#639 — branded-target collector with a generic-instantiation superclass
The substantive collector fix already landed on
main(#655). This completes the issue's remaining minor/related note: theMutableClassbranch ofGetMemberType(signature-collection-time) walkedfrozen.Superclasswith unsubstitutedGetFieldTypes/GetMethods, surfacing an inherited generic-base member as the bare type parameter. Routed it through the existing substitution-awareResolveClassMemberTypeSubstituted, unifying it with the frozen-instance path and the member-set collectors. Equivalent for a non-generic superclass; not independently observable (matches the issue's "transient" framing), validated by the full suite.Follow-ups filed
O.A.g()from insideO); the namespace self-binds only at the end ofCheckNamespace.Testing
assignmentCompatibility+conditional) does not cover namespaces; the CollectAllInstanceMembers (branded-target member enumeration) doesn't walk a generic-instantiation superclass #639 refactor is provably equivalent for the non-generic case — skipped per the project's conformance-scope guidance.Closes #665. Closes #639.