Fix Xcode 27 "switch must be exhaustive" build error#7
Open
maipeera wants to merge 2 commits into
Open
Conversation
The Xcode 27 SDK adds new cases to non-frozen Foundation Models enums: - Transcript.Entry gains `.reasoning` - Transcript.Segment gains `.attachment` and `.custom` These broke the exhaustive switch statements in mapTranscriptEntries and serializeSegment, causing a hard "switch must be exhaustive" compile error. Add `@unknown default` clauses to all switches over non-frozen Apple framework enums (Transcript.Entry, Transcript.Segment, and LanguageModelSession.GenerationError) so the plugin keeps compiling as Apple adds enum cases in future SDKs. Applied to both the iOS and macOS plugin sources. Bump version to 0.2.2 and update CHANGELOG. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Layer explicit handling of the new non-frozen enum cases on top of the `@unknown default` compile fix, gated behind `#if compiler(>=6.4)`: - Transcript.Entry `.reasoning` -> serialized with a dedicated "reasoning" role and its segments mapped like other entries. - Transcript.Segment `.attachment` / `.custom` -> serialized explicitly. The `#if compiler(>=6.4)` gate (Swift 6.4 ships with Xcode 27) keeps the plugin building on Xcode 26, where these cases do not exist in the SDK; older toolchains fall back to the `@unknown default` branch. `@unknown default` is retained on all switches since the enums remain non-frozen. Verified against the iOS 27 SDK: gate-on path typechecks with zero diagnostics; gate-off path has zero errors. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Building the plugin with Xcode 27 fails with:
The Xcode 27 SDK adds new cases to several non-frozen Foundation Models enums:
Transcript.Segment.attachment,.customTranscript.Entry.reasoningBecause these enums are not
@frozen, the previously-exhaustiveswitchstatements inserializeSegment(_:)andmapTranscriptEntries(_:)no longer cover every case — a hard compile error under the newer SDK. Apps depending on this plugin can no longer build once they move to Xcode 27.Fix
Two layers, so the plugin builds everywhere and makes use of the new data where available:
1. Compile fix (works on every toolchain). Added
@unknown defaultto everyswitchover a non-frozen Apple framework enum:mapTranscriptEntries—switch entry(Transcript.Entry)serializeSegment—switch segment(Transcript.Segment)sanitizeGenerationError—switch generationError(LanguageModelSession.GenerationError), added defensively for the same class of issueThis matches the pattern already used in this file for
SystemLanguageModel.Availability.UnavailableReasonand is Apple's recommended approach for non-frozen library enums.2. First-class handling on Xcode 27+. The new cases are serialized explicitly, gated behind
#if compiler(>=6.4)(Swift 6.4 ships with Xcode 27):Transcript.Entry.reasoning→ dedicated"reasoning"role, segments mapped like any other entryTranscript.Segment.attachment/.custom→ serialized explicitlyThe gate keeps the plugin building on Xcode 26, where these cases don't exist in the SDK — there it simply falls back to the
@unknown defaultbranch.@unknown defaultis retained on every switch because the enums remain non-frozen (future SDKs will add more cases).Switches intentionally left unchanged:
switch model.availability—SystemLanguageModel.Availabilityis@frozen, so@unknown defaultis neither allowed nor needed.switch level—GuardrailLevelis a local enum defined in this package.Applied identically to both the iOS and macOS plugin sources.
Verification
Against the real iOS 27 SDK (
iPhoneOS27.0.sdk, Xcode 27.0, Swift 6.4):serializeSegmentswitch reproduceserror: switch must be exhaustive(typecheck exits non-zero).mapTranscriptEntries+serializeSegmentbodies typecheck with 0 diagnostics, including binding.reasoning(let reasoning)and accessingreasoning.segments— noif #availableneeded.xcodebuildof the example app's plugin sources compiles with zero errors.Compatibility note
The
#if compiler(>=6.4)gate keys off the Swift toolchain version as a proxy for "does this SDK contain the new cases." Apple ships each major SDK together with a matching Swift minor bump (Xcode 26 = Swift 6.2, Xcode 27 = Swift 6.4), so this is reliable in practice; Swift has no per-symbol "does this case exist" check.Changes
ios/Classes/FoundationModelsFrameworkPlugin.swift—@unknown default+ compiler-gated explicit casesmacos/Classes/FoundationModelsFrameworkPlugin.swift— sameCHANGELOG.md—0.2.2entrypubspec.yaml— bump version0.2.1→0.2.2🤖 Generated with Claude Code