Bridge coverage is broad but thin: 2,593 generated entries, yet most everyday scripting tasks still hit a wall. Almost all of it traces to a handful of generator limitations rather than missing allowlist entries, so this is mostly one structural fix away from a much larger surface.
Measured against main (71605b2) by building swift-script and running probe scripts, plus diffing Apple's Foundation symbol graph against the emitted bridges.
What a script cannot do today
Each of these is a task someone would plausibly write a script for, and each currently fails:
| Task |
Fails with |
| Extract text with a regex |
cannot find 'NSRegularExpression' in scope; regex literals hit unsupported expression RegexLiteralExprSyntax; String.range(of:) missing |
| Copy/move a file, read its attributes |
'FileManager' has no method 'copyItem' (also attributesOfItem, createFile, enumerator, temporaryDirectory, every URL overload) |
| Parse or format a date |
cannot find 'DateFormatter' in scope, cannot find 'ISO8601DateFormatter' in scope; Date.formatted() is generated zero-arity only |
| Read untyped JSON |
type 'JSONSerialization' has no member 'jsonObject' — no bridge file at all |
| POST, or send a header |
cannot find 'URLRequest' in scope, cannot find 'URLQueryItem' in scope — HTTP is GET-only |
| Check an HTTP status properly |
response as? HTTPURLResponse fails: could not cast value of type 'URLResponse' to 'HTTPURLResponse' |
| Shell out |
Process constructs, but executableURL / launchPath / arguments are all has no settable member; Pipe unbridged |
| Sleep / poll / retry |
Task.sleep unsupported, Thread unbridged — no way to wait |
Append to Data |
no append, subdata(in:), subscript or range(of:) — 11 of 112 members bridged |
| Write to stderr |
FileHandle has no write; cannot find 'fputs' in scope |
| Set an encoder strategy |
has no settable member 'dateEncodingStrategy' (JSONEncoder 2/14 members, JSONDecoder 3/14) |
Root causes, in leverage order
These are generator-level, so each one unlocks a category rather than a symbol:
- Collection-shaped signatures are rejected outright.
extractType refuses any signature containing [, so no [String], [String: String] or Set<T> parameter or return ever bridges. This single rule removes a large fraction of Foundation. IdentityModule hand-rolls exactly these shapes, which shows the runtime already supports them — it is the generator that declines. Highest-leverage change available.
- Optional parameters are skipped (
if t.isOptional { return nil }) while optional returns already work. A lot of Foundation takes String? / URL?. The asymmetry reads as unfinished rather than deliberate.
- One bridge key per (receiver, name), labels excluded, so labelled overloads are structurally unreachable — which is why ~14
URLSession entries sit in the blocklist. Needs a signature-keyed dispatcher; blocklist edits cannot fix it.
mutating methods and struct property setters cannot bridge at all — writeback through an .opaque value is unmodelled, so the receiver arrives by value. This is why Data.append and every Process setter are missing.
- Only
Int and Double cross the boundary. No Int32, UInt8, Float — ProcessInfo.processIdentifier: Int32 had to be hand-rolled.
Two concrete bugs found while measuring
FileManager.default returns a sentinel, so 19 of its 23 generated bridges are dead code. Interpreter+StaticMembers.swift:89 returns fileManagerSentinel, and dispatch runs through a hardcoded switch in Interpreter+FileIO.swift supporting only fileExists, contentsOfDirectory, removeItem and createDirectory (String paths only) before throw RuntimeError.invalid("'FileManager' has no method '\(name)'"). The generated bridges exist and are unreachable. temporaryDirectory fails with the especially confusing expected FileManager, got FileManager.
Resources/foundation-allowlist.txt is dead. Tools/regen-foundation-bridge.sh passes --auto-allowlist and never --allowlist; the file is referenced nowhere else in the repo. All 80 of its entries are already covered by auto-harvest, so it is both unreferenced and subsumed — worth deleting so it stops implying it controls anything.
Also, Tools/bridge-metrics.sh greps StdlibBridge.generated.swift / FoundationBridge.generated.swift, which the generator now deletes — the dashboard silently reports total-bridges: 0.
Where the headline number is misleading
Of 2,593 Foundation entries, 1,405 (54%) are .staticValue constants, and 17 constant-bag types account for 974 of them (LocaleRegion alone is 263). Meanwhile 80 of 203 bridged types have ≤5 entries. Usable API surface is much smaller than the count suggests — worth tracking "types with a working method" as a separate metric.
Deliberately excluded — not proposed here
For completeness, so these are not re-litigated: the macOS 13 / iOS 16 availability floor (inherited from SwiftBash, excludes the post-2022 FormatStyle families), sandbox gating of IO through Shell.current, the 15-name hand-verified class allowlist (each addition risks NSObject method-name shadowing), and ObjC-runtime-dependent APIs.
Reproducing
swift build --scratch-path /tmp/ss
echo 'import Foundation
print(FileManager.default.temporaryDirectory)' > /tmp/p.swift
/tmp/ss/debug/swift-script /tmp/p.swift
Bridge coverage is broad but thin: 2,593 generated entries, yet most everyday scripting tasks still hit a wall. Almost all of it traces to a handful of generator limitations rather than missing allowlist entries, so this is mostly one structural fix away from a much larger surface.
Measured against
main(71605b2) by buildingswift-scriptand running probe scripts, plus diffing Apple's Foundation symbol graph against the emitted bridges.What a script cannot do today
Each of these is a task someone would plausibly write a script for, and each currently fails:
cannot find 'NSRegularExpression' in scope; regex literals hitunsupported expression RegexLiteralExprSyntax;String.range(of:)missing'FileManager' has no method 'copyItem'(alsoattributesOfItem,createFile,enumerator,temporaryDirectory, every URL overload)cannot find 'DateFormatter' in scope,cannot find 'ISO8601DateFormatter' in scope;Date.formatted()is generated zero-arity onlytype 'JSONSerialization' has no member 'jsonObject'— no bridge file at allcannot find 'URLRequest' in scope,cannot find 'URLQueryItem' in scope— HTTP is GET-onlyresponse as? HTTPURLResponsefails:could not cast value of type 'URLResponse' to 'HTTPURLResponse'Processconstructs, butexecutableURL/launchPath/argumentsare allhas no settable member;PipeunbridgedTask.sleepunsupported,Threadunbridged — no way to waitDataappend,subdata(in:), subscript orrange(of:)— 11 of 112 members bridgedFileHandlehas nowrite;cannot find 'fputs' in scopehas no settable member 'dateEncodingStrategy'(JSONEncoder 2/14 members, JSONDecoder 3/14)Root causes, in leverage order
These are generator-level, so each one unlocks a category rather than a symbol:
extractTyperefuses any signature containing[, so no[String],[String: String]orSet<T>parameter or return ever bridges. This single rule removes a large fraction of Foundation.IdentityModulehand-rolls exactly these shapes, which shows the runtime already supports them — it is the generator that declines. Highest-leverage change available.if t.isOptional { return nil }) while optional returns already work. A lot of Foundation takesString?/URL?. The asymmetry reads as unfinished rather than deliberate.URLSessionentries sit in the blocklist. Needs a signature-keyed dispatcher; blocklist edits cannot fix it.mutatingmethods and struct property setters cannot bridge at all — writeback through an.opaquevalue is unmodelled, so the receiver arrives by value. This is whyData.appendand everyProcesssetter are missing.IntandDoublecross the boundary. NoInt32,UInt8,Float—ProcessInfo.processIdentifier: Int32had to be hand-rolled.Two concrete bugs found while measuring
FileManager.defaultreturns a sentinel, so 19 of its 23 generated bridges are dead code.Interpreter+StaticMembers.swift:89returnsfileManagerSentinel, and dispatch runs through a hardcoded switch inInterpreter+FileIO.swiftsupporting onlyfileExists,contentsOfDirectory,removeItemandcreateDirectory(String paths only) beforethrow RuntimeError.invalid("'FileManager' has no method '\(name)'"). The generated bridges exist and are unreachable.temporaryDirectoryfails with the especially confusingexpected FileManager, got FileManager.Resources/foundation-allowlist.txtis dead.Tools/regen-foundation-bridge.shpasses--auto-allowlistand never--allowlist; the file is referenced nowhere else in the repo. All 80 of its entries are already covered by auto-harvest, so it is both unreferenced and subsumed — worth deleting so it stops implying it controls anything.Also,
Tools/bridge-metrics.shgrepsStdlibBridge.generated.swift/FoundationBridge.generated.swift, which the generator now deletes — the dashboard silently reportstotal-bridges: 0.Where the headline number is misleading
Of 2,593 Foundation entries, 1,405 (54%) are
.staticValueconstants, and 17 constant-bag types account for 974 of them (LocaleRegionalone is 263). Meanwhile 80 of 203 bridged types have ≤5 entries. Usable API surface is much smaller than the count suggests — worth tracking "types with a working method" as a separate metric.Deliberately excluded — not proposed here
For completeness, so these are not re-litigated: the macOS 13 / iOS 16 availability floor (inherited from SwiftBash, excludes the post-2022
FormatStylefamilies), sandbox gating of IO throughShell.current, the 15-name hand-verified class allowlist (each addition risksNSObjectmethod-name shadowing), and ObjC-runtime-dependent APIs.Reproducing