Skip to content

Feature/split serialize#2460

Merged
borisbat merged 6 commits intoGaijinEntertainment:masterfrom
aleksisch:feature/split-serialize
May 6, 2026
Merged

Feature/split serialize#2460
borisbat merged 6 commits intoGaijinEntertainment:masterfrom
aleksisch:feature/split-serialize

Conversation

@aleksisch
Copy link
Copy Markdown
Collaborator

@aleksisch aleksisch commented Apr 22, 2026

PR #2460 — feature/split-serialize

Summary

This PR fixes AST serialization roundtrip correctness and re-enables --ser/--deser CI testing.

Architectural changes

Virtual dispatch for AST nodes (compiler: add virtual dispatch)

Added Expression::dispatch(Visitor&) — a non-recursive virtual shim that routes a single node to the most-specific visitor overload for its concrete type. Previously the only way to drive visitor logic was the full recursive visit() traversal; now a single node can be processed in isolation.

Serialize extracted from AST (compiler: extract serialize from ast)

Expression::serialize (and related serialize methods on expression subclasses) moved out of ast_expressions.h / ast.h into src/builtin/module_builtin_ast_serialize.cpp as a SerializeVisitor that uses the new dispatch shim. AST types no longer include serialization headers or carry serialization logic — the compiler core is now independent of the serializer.

Correctness fixes

Stable node IDs (serialization: stable id in serialization)

The dedup maps in AstSerializer previously keyed on raw uintptr_t(ptr). Pointer addresses are reused across Program lifetimes and during short-lived AST construction, causing two logically-distinct nodes to collide on the same key — the writer deduped them into one, the reader reconstructed only one, and tag() tripped on a misaligned hash word. Maps now key on SerializeNodeId{ptr, epoch} (raw pointer + per-serialize-call epoch), which eliminates cross-call collisions.

g_Program stale pointer after deserialization

finalizeModule sets g_Program to a temporary Program then calls thisModule.release(), leaving g_Program pointing at a program with null thisModule. Fixed by saving/restoring g_Program around the block invocation in rtti_ast_serializer_deserialize_program so that compiling_module() sees the correct module during simulate and test execution.

Function::fromGeneric now serialized

fromGeneric was commented out in Function::serialize. After deserialization, qm_call_name_matches in daslib/ast_match couldn't match generic call names because the fallback call.func.fromGeneric.name path was always null. fromGeneric is now serialized via the existing FunctionPtr dedup path.

Macro module context leak

Non-promoted [call_macro] modules get a macroContext (smart_ptr, rc=1) during finalizeModule. Program::library is plain ModuleLibrary whose destructor does not delete modules, so those modules and their contexts were abandoned. Fixed by calling prog->thisModule.release() + prog->library.reset() after the block invocation returns.

Test infrastructure

Expected-failure file naming unified (serialization: unify failed tests naming)

Nine test files that were expected to fail compilation but didn't follow the failed_/cant_/invalid_ prefix convention were renamed. dastest's --ser pass now skips files with these prefixes (nothing to serialize for a program that doesn't compile). Naming convention documented in tests/README.md.

CI re-enabled (serialization: stable id in serialization)

extended_checks.yml gains a Test ser/deser step that serializes the full test suite then deserializes and re-runs it. Previously dropped because --deser crashed inside AstSerializer::tag.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors AST expression serialization by removing per-node serialize(AstSerializer&) virtual methods from Expression subclasses and replacing them with a visitor-based serialization path driven by a new Expression::dispatch(Visitor&) shim.

Changes:

  • Replace Expression::serialize/ExprXxx::serialize with Expression::dispatch/ExprXxx::dispatch and route expression serialization through SerializeVisitor.
  • Add src/ast/ast_dispatch.cpp implementing dispatch for expression classes.
  • Wire the new dispatch TU into the build and update headers accordingly.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/builtin/module_builtin_ast_serialize.cpp Moves expression serialization into SerializeVisitor and updates AstSerializer::operator<<(ExpressionPtr&) to use dispatch.
src/ast/ast_dispatch.cpp Adds per-class dispatch shims to call the correct Visitor::preVisit(...) overloads.
include/daScript/ast/ast_expressions.h Replaces serialize overrides with dispatch declarations for expression types.
include/daScript/ast/ast.h Replaces Expression::serialize with Expression::dispatch and forward-declares Visitor.
CMakeLists.txt Adds src/ast/ast_dispatch.cpp to AST_SRC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ast/ast_dispatch.cpp Outdated
Comment thread src/builtin/module_builtin_ast_serialize.cpp Outdated
Comment thread src/builtin/module_builtin_ast_serialize.cpp
Comment thread src/ast/ast_dispatch.cpp Outdated
@borisbat borisbat self-assigned this Apr 23, 2026
@aleksisch aleksisch force-pushed the feature/split-serialize branch from c9af88f to cfd618d Compare May 2, 2026 19:47
@aleksisch aleksisch marked this pull request as draft May 2, 2026 19:47
Now we can reuse visitor to just visit one node, not recursively.
It will be used in following commit to extract serialize from
Expression.
@aleksisch aleksisch force-pushed the feature/split-serialize branch from cfd618d to c6385f9 Compare May 5, 2026 21:11
@aleksisch aleksisch marked this pull request as ready for review May 5, 2026 21:12
@borisbat borisbat requested a review from Copilot May 5, 2026 21:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/builtin/module_builtin_ast_serialize.cpp
Comment thread src/builtin/module_builtin_ast_serialize.cpp
Ast should not know anything about serialization. Now serializer
is separate visitor declared in
src/builtin/module_builtin_ast_serialize.cpp
@aleksisch aleksisch force-pushed the feature/split-serialize branch from c6385f9 to e85bcc5 Compare May 6, 2026 21:19
aleksisch added 2 commits May 7, 2026 00:27
We need to skip expected failures in serialization. To do so
their naming should be unified.
Fix module leaks. Now this all memory ownership is confusing and
error-prone. To supress leak we should manually release module.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 22 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

src/builtin/module_builtin_ast_serialize.cpp:900

  • serializeSmartPtr is still keyed on uint64_t, but getSerializeId(obj.get()) now returns SerializeNodeId. As written this won’t compile (type mismatch) and also doesn’t match the updated smart*Map member key types. Update serializeSmartPtr (both declaration and definition) to use SerializeNodeId for id and for the objMap key type, and adjust the null check accordingly (e.g., id.ptr == nullptr).
    // This method creates concrete (i.e. non-polymorphic types without duplications)
    template<typename T>
    void AstSerializer::serializeSmartPtr( smart_ptr<T> & obj, das_hash_map<uint64_t, smart_ptr<T>> & objMap) {
        uint64_t id = getSerializeId(obj.get());
        *this << id;
        if ( id == 0 ) {
            if ( !writing ) obj = nullptr;
            return;
        }

Comment thread src/builtin/module_builtin_ast_serialize.cpp Outdated
Comment thread src/builtin/module_builtin_ast_serialize.cpp
We should never use print() inside daslib/. And we should
always prefer to_log everywhere, not only in daslib.

Also made logs in serialize more clear.
@aleksisch aleksisch force-pushed the feature/split-serialize branch 2 times, most recently from 6fb5aba to bf75106 Compare May 6, 2026 22:48
@aleksisch
Copy link
Copy Markdown
Collaborator Author

Pull request overview

Copilot reviewed 13 out of 22 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)

src/builtin/module_builtin_ast_serialize.cpp:900

* `serializeSmartPtr` is still keyed on `uint64_t`, but `getSerializeId(obj.get())` now returns `SerializeNodeId`. As written this won’t compile (type mismatch) and also doesn’t match the updated `smart*Map` member key types. Update `serializeSmartPtr` (both declaration and definition) to use `SerializeNodeId` for `id` and for the `objMap` key type, and adjust the null check accordingly (e.g., `id.ptr == nullptr`).
    // This method creates concrete (i.e. non-polymorphic types without duplications)
    template<typename T>
    void AstSerializer::serializeSmartPtr( smart_ptr<T> & obj, das_hash_map<uint64_t, smart_ptr<T>> & objMap) {
        uint64_t id = getSerializeId(obj.get());
        *this << id;
        if ( id == 0 ) {
            if ( !writing ) obj = nullptr;
            return;
        }

Valid, removed this method at all. It's unused.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 22 changed files in this pull request and generated 3 comments.

Comment thread src/builtin/module_builtin_ast_serialize.cpp
Comment thread src/builtin/module_builtin_ast_serialize.cpp
Comment thread dastest/dastest.das Outdated
@aleksisch aleksisch force-pushed the feature/split-serialize branch from bf75106 to 683c8d2 Compare May 6, 2026 23:14
Make ids unique and stable.

Enable serialization in dastest and added to CI.
@aleksisch aleksisch force-pushed the feature/split-serialize branch from 683c8d2 to 98cb658 Compare May 6, 2026 23:25
@borisbat borisbat merged commit e8b94a1 into GaijinEntertainment:master May 6, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants