Skip to content

Shared modules: failed compilations split later programs onto mixed module generations ("expecting 'X const', passing 'X const'") #3383

Description

@borisbat

Found while landing #3382; repro verified at master 6e46795ca (Windows, Release, dastest default non-isolated mode).

Symptom

In a single dastest process, after certain intentionally-failing compile tests, a later program can fail overload resolution with a type that rejects itself:

error[30341]: no matching functions or generics: _::_migration_stream_key(sqlite_boost::SqlRunner const)
candidate function:
    sqlite_migrate::_migration_stream_key(db: sqlite_boost::SqlRunner const): string const
        invalid argument 'db' (0). expecting 'sqlite_boost::SqlRunner const', passing 'sqlite_boost::SqlRunner const'

Identical spelling on both sides — the two sqlite_boost module instances differ by identity. The same file compiles clean standalone.

Minimal repro

Save as probe_boost_first.das (note the require order — sqlite_boost before sqlite_migrate):

options gen2
options indenting = 4

require dastest/testing_boost public
require sqlite/sqlite_boost
require sqlite/sqlite_migrate
require daslib/sql_linq

[sql_migration(version = 1, description = "probe alpha")]
def pm1(db : SqlRunner) {
    db |> exec("CREATE TABLE px (a INT)")
}

[test]
def test_probe(t : T?) {
    t |> run("migrate inside a run-lambda") @(t : T?) {
        var inscope db = open_sqlite(":memory:")
        t |> equal(db |> migrate_to_latest(), 1)
    }
}

Run it after two expected-failure tests in one process:

bin/Release/daslang.exe dastest/dastest.das -- ^
  --test tests/dasSQLITE/failed_create_index_unknown_field.das ^
  --test tests/dasSQLITE/failed_create_view.das ^
  --test probe_boost_first.das

→ the probe fails to compile with the error above.

Bisected boundary conditions (each verified)

  • The probe alone: passes.
  • One failing test + probe (either failing test alone): passes.
  • failed_create_view.das + any one other failing test (either order) + probe: fails. Six failing tests without failed_create_view (failed_add_column_* + failed_create_index_empty_fields): passes — so it is not just "N failed compiles".
  • Require order flips it: the same probe with require sqlite/sqlite_migrate before require sqlite/sqlite_boost passes in the identical poisoned process.
  • Direct chain unaffected: tests/dasSQLITE/migrate_35_history_after_migrate.das (requires only sqlite/sqlite_migrate, which pulls sqlite_boost itself) passes in the same process immediately before the probe fails.

Reading

All modules involved are shared (sqlite_boost, sqlite_migrate, daslib/sql_migrate). The evidence is consistent with a failed compilation leaving the promoted shared-module set in a state where a later program's require graph binds two generations of the same module — one reached directly by the top-level require, one reached through another shared module's own requires — so cross-module typed surfaces (here the migration glue's SqlRunner parameters) mismatch on identity while printing identically. Which side is stale I haven't pinned down; the order-dependence and the failed_create_view sensitivity (a _create_view / sql_linq macro-phase failure, vs. the harmless sql_boost-phase failed_add_column_* failures) are the strongest clues for whoever digs into promoteToBuiltin / the module-library reuse path.

Current mitigation

tests/sql_conformance/_conformance_provider.das requires the migration glue before the boost (comment points at this issue's repro), which keeps the whole chain on one generation per program. That protects the in-tree suite but any user program with the boost-first order is exposed after a failed compile in the same process (embedders that compile scripts repeatedly and tolerate failures would hit this hardest).

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions