Skip to content

Fix Database not resolving via import SQLiteData under whole-module builds#471

Open
jpsim wants to merge 1 commit into
pointfreeco:mainfrom
jpsim:jp/fix-database-reexport-under-wmo
Open

Fix Database not resolving via import SQLiteData under whole-module builds#471
jpsim wants to merge 1 commit into
pointfreeco:mainfrom
jpsim:jp/fix-database-reexport-under-wmo

Conversation

@jpsim
Copy link
Copy Markdown

@jpsim jpsim commented Jun 4, 2026

What

Two scoped imports of GRDB.Database are written as public import instead of @_exported import. Under whole-module compilation this causes Database to stop resolving via import SQLiteData in downstream modules:

error: cannot find type 'Database' in scope

Why it broke

Internal/Exports.swift intentionally re-exports selected GRDB types via scoped imports, e.g.:

@_exported import class GRDB.Database

#467 ("Modernize package.", first released in 1.6.3) adopted InternalImportsByDefault and added explicit access-level imports across the package, including two non-exported scoped imports of the same declaration:

  • Sources/SQLiteData/CloudKit/PrimaryKeyMigration.swift
  • Sources/SQLiteData/StructuredQueries+GRDB/CustomFunctions.swift

Both files sort before Internal/Exports.swift in compilation order.

Under whole-module compilation, swiftc dedupes scoped imports of the same (module, access-path) pair, keeping the first occurrence in file order. The non-exported import wins, so the @_exported flag is silently dropped from the serialized module. Sibling re-exports that are only scoped-imported once (Configuration, DatabasePool, DatabaseQueue, …) keep working.

This only reproduces under WMO — swift build -c release, or any build system that compiles library targets with -wmo. Debug builds compile incrementally (non-WMO), which is presumably why it wasn't caught.

The fix

Mark the two colliding scoped imports @_exported as well, so dedup keeps an exported entry regardless of file order. This is a no-op for consumers: GRDB.Database is already intentionally re-exported by Internal/Exports.swift.

A whole-module public import GRDB is not an option in CustomFunctions.swift: GRDB's DatabaseFunction class then collides with StructuredQueries' DatabaseFunction protocol used in that file (value of type 'some DatabaseFunction' has no member 'name').

Notes

The underlying swiftc behavior (WMO scoped-import dedup dropping @_exported based on file order) looks like a compiler bug worth a separate issue against swiftlang/swift; this PR works around it at the source level.

… builds

SQLiteData re-exports selected GRDB types via scoped imports in
`Internal/Exports.swift` (e.g. `@_exported import class GRDB.Database`).
1.6.3 also added non-exported scoped imports of the same declaration
(`public import class GRDB.Database`) in `CloudKit/PrimaryKeyMigration.swift`
and `StructuredQueries+GRDB/CustomFunctions.swift`, both of which sort
before `Internal/Exports.swift` in compilation order.

Under whole-module compilation, swiftc dedupes scoped imports of the same
declaration keeping the first occurrence in file order, which silently
drops the `@_exported` flag. Downstream modules then fail to resolve
`Database` via `import SQLiteData` with `cannot find type 'Database' in
scope`. This only reproduces under WMO (`swift build -c release`); debug
builds compile incrementally and are unaffected.

Mark those scoped imports `@_exported` as well so the dedup keeps an
exported entry regardless of file order. This is a no-op for consumers:
`GRDB.Database` is already intentionally re-exported by
`Internal/Exports.swift`. A whole-module `public import GRDB` is not an
option because GRDB's `DatabaseFunction` class would collide with
StructuredQueries' `DatabaseFunction` protocol used in `CustomFunctions.swift`.
@mbrandonw
Copy link
Copy Markdown
Member

Hey @jpsim, thanks for bringing this up. We didn't see this in our examples apps because they aren't WMO.

Would an alternative solution be to rename Exports.swift to _Exports.swift to force it to be considered first?

@mbrandonw
Copy link
Copy Markdown
Member

A whole-module public import GRDB is not an option in CustomFunctions.swift: GRDB's DatabaseFunction class then collides with StructuredQueries' DatabaseFunction protocol used in that file (value of type 'some DatabaseFunction' has no member 'name').

Well, we would just need to prefix DatabaseFunction with the appropriate model. And I do feel that we should indeed switch those imports to just public import GRDB.

@jpsim
Copy link
Copy Markdown
Author

jpsim commented Jun 5, 2026

Well, we would just need to prefix DatabaseFunction with the appropriate model. And I do feel that we should indeed switch those imports to just public import GRDB.

This seems better than renaming the file and hoping it gets considered first.

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.

2 participants