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
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:
Identical spelling on both sides — the two
sqlite_boostmodule instances differ by identity. The same file compiles clean standalone.Minimal repro
Save as
probe_boost_first.das(note the require order —sqlite_boostbeforesqlite_migrate):Run it after two expected-failure tests in one process:
→ the probe fails to compile with the error above.
Bisected boundary conditions (each verified)
failed_create_view.das+ any one other failing test (either order) + probe: fails. Six failing tests withoutfailed_create_view(failed_add_column_*+failed_create_index_empty_fields): passes — so it is not just "N failed compiles".require sqlite/sqlite_migratebeforerequire sqlite/sqlite_boostpasses in the identical poisoned process.tests/dasSQLITE/migrate_35_history_after_migrate.das(requires onlysqlite/sqlite_migrate, which pullssqlite_boostitself) 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-levelrequire, one reached through another shared module's own requires — so cross-module typed surfaces (here the migration glue'sSqlRunnerparameters) mismatch on identity while printing identically. Which side is stale I haven't pinned down; the order-dependence and thefailed_create_viewsensitivity (a_create_view/ sql_linq macro-phase failure, vs. the harmless sql_boost-phasefailed_add_column_*failures) are the strongest clues for whoever digs intopromoteToBuiltin/ the module-library reuse path.Current mitigation
tests/sql_conformance/_conformance_provider.dasrequires 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