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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions