Plan 03: Lexical Scope Tree & Symbol Object Model
Goal: Unify disjoint symbol tables into a polymorphic
Symbolhierarchy, implement a first-class lexicalScopetree, and manage checking state via an RAIIEnvironmentGuard. Inspiration: Go'sgo/types/object.go,go/types/scope.go, andgo/types/check.go.
1. Problem Statement & Root Cause
Currently in compiler/kyna_typecheck/include/kyna/semantics/program_analyzer.hpp:
- Symbols Bypassing Scope:
Top-level symbols live in disconnected global maps:
Functions and classes declared in nested blocks cannot be properly resolved or tracked.
std::map<std::string, FunctionDecl> functions; std::map<std::string, ClassDecl> classes; InterfaceCatalog interfaces; - Primitive Local Scope:
Scopeonly maps names toTypeRefandbool:It has no child links, source spans, or symbol kind tags.struct Scope { std::map<std::string, TypeRef> types; std::map<std::string, bool> mutability; Scope* parent = nullptr; }; - Fragile Mutable State Machine in Analyzer:
These fields are manually overwritten when checking nested classes/functions. If analysis encounters an error, state is corrupted.
std::string currentClass; TypeRef currentReturn; bool inFunction = false; std::vector<std::string> activeLoopLabels; int switchDepth = 0;
2. Target Architecture
2.1 The Symbol (Object) Hierarchy
namespace kyna::semantics {
enum class SymbolKind : uint8_t {
Variable,
Constant,
Function,
Class,
Interface,
Package,
TypeParam
};
class Scope;
class Symbol {
public:
virtual ~Symbol() = default;
virtual SymbolKind kind() const = 0;
virtual const std::string& name() const = 0;
virtual types::TypePtr type() const = 0;
virtual SourceLocation location() const = 0;
virtual Scope* parentScope() const = 0;
virtual bool isExported() const = 0;
};
using SymbolPtr = std::shared_ptr<Symbol>;
class VarSymbol : public Symbol { /* ... */ };
class FuncSymbol : public Symbol { /* ... */ };
class ClassSymbol : public Symbol { /* ... */ };
class InterfaceSymbol : public Symbol { /* ... */ };
} // namespace kyna::semantics2.2 The Lexical Scope Tree
class Scope {
private:
Scope* parent_{nullptr};
std::vector<std::unique_ptr<Scope>> children_;
std::unordered_map<std::string, SymbolPtr> symbols_;
SourceSpan extent_;
public:
explicit Scope(Scope* parent = nullptr) : parent_(parent) {}
Scope* parent() const { return parent_; }
Scope* createChild(SourceSpan extent = {});
// Returns existing conflicting symbol if already defined in THIS scope
SymbolPtr insert(SymbolPtr symbol);
// Looks up identifier, searching up the parent chain
SymbolPtr lookup(const std::string& name) const;
// Looks up only in the immediate scope
SymbolPtr lookupLocal(const std::string& name) const;
};2.3 RAII EnvironmentGuard
struct Environment {
SymbolPtr currentFunc{nullptr};
SymbolPtr currentClass{nullptr};
types::TypePtr expectedReturn{nullptr};
uint32_t loopDepth{0};
uint32_t switchDepth{0};
bool allowBreak{false};
bool allowContinue{false};
};
class EnvironmentGuard {
private:
Analyzer& analyzer_;
Environment previous_;
public:
EnvironmentGuard(Analyzer& analyzer, Environment newEnv)
: analyzer_(analyzer), previous_(analyzer.env_) {
analyzer_.env_ = std::move(newEnv);
}
~EnvironmentGuard() {
analyzer_.env_ = std::move(previous_);
}
};3. Implementation Steps
- Step 1: Create
compiler/kyna_typecheck/include/kyna/semantics/symbol.hpp- Implement
Symbolbase interface and concreteVarSymbol,FuncSymbol,ClassSymbol.
- Implement
- Step 2: Upgrade
Scopeincompiler/kyna_typecheck/include/kyna/semantics/scope.hpp- Implement
Scope::insert(symbol)with duplicate detection. - Implement parent-walking
Scope::lookup(name).
- Implement
- Step 3: Implement
EnvironmentGuard- Encapsulate mutable analyzer fields in
Environment. - Guard all function, method, and loop checks with RAII guards.
- Encapsulate mutable analyzer fields in
- Step 4: Three-Color Cycle Detection for Declarations
- Track
Checker.declPathstack: markWhite(unresolved),Grey(resolving),Black(resolved). - Detect circular class inheritance or type alias loops cleanly.
- Track
4. Verification Plan
- Unit Tests:
- Write tests for lexical scope shadowing, duplicate declaration diagnostics, and inheritance cycle detection.
- Automated Verification:
- Run
ctest --test-dir build-debug -R semantic. - Run
python3 build_tools/verify_repository_architecture.py.
- Run
Source captured: 2026-10-11