Skip to content

chore(concurrency): 라이브러리를 Swift 6 language mode 에서 빌드되게 + CI 게이트#25

Open
DevVenusK wants to merge 2 commits into
daangn:mainfrom
DevVenusK:chore/swift6-strict-concurrency
Open

chore(concurrency): 라이브러리를 Swift 6 language mode 에서 빌드되게 + CI 게이트#25
DevVenusK wants to merge 2 commits into
daangn:mainfrom
DevVenusK:chore/swift6-strict-concurrency

Conversation

@DevVenusK

Copy link
Copy Markdown

배경

라이브러리가 Swift 6 language mode 에서 컴파일되지 않았습니다. 다음이 비-Sendable 공유/전역 상태에서 실패합니다.

swift build -Xswiftc -swift-version -Xswiftc 6   # ← 에러로 실패

왜 -strict-concurrency=complete 로는 부족한가

처음엔 Swift 5 모드의 -strict-concurrency=complete 로 범위를 재려 했으나, 이는 근사치였습니다. 진짜 Swift 6 모드는 정적 전역(#MutableGlobalVariable)을 하드 에러로 처리하고 그 지점에서 빌드를 조기 중단해 하위 파일의 문제를 가립니다.

-strict-concurrency=complete (Swift 5 모드)     -swift-version 6 (Swift 6 모드)
  = 경고로 나열, 끝까지 진행                        = 에러, 첫 하드에러에서 중단
        │                                                 │
        └── 근사치(과소/과대 가능)                         └── 정본: "빌드 성공(exit 0)" 이 유일한 준비도 증거

그래서 정본 기준을 -swift-version 6 빌드 성공(exit 0) 으로 잡고, 매크로 타깃 정적부터 고쳐 라이브러리 에러가 드러나게 한 뒤 전부 해소했습니다.

변경사항

컴파일러로 범위 측정 ── swift build -swift-version 6
        │
   ┌────┴───────────────────────────────────┐
   ▼                                         ▼
정적 공유 상태                        불변 값/메타타입/에러 홀더
nonisolated(unsafe)                   @unchecked Sendable
   └────┬───────────────────────────────────┘
        ▼
 swift build -swift-version 6 ──(exit 0)──▶ CI 게이트 통과
대상 처리 근거
static ISO8601DateFormatter nonisolated(unsafe) 1회 설정 후 불변, 동시 읽기 안전
매크로 protocolType / macroType nonisolated(unsafe) 컴파일타임 상수 서술자
LosslessValueCodable / OptionalLosslessValueCodable @unchecked Sendable (조건부) type 은 불변 메타타입; where Strategy.Value: Sendable 유지
PolymorphicCodableError @unchecked Sendable 불변 에러 값
ArrayDecodingError / DictionaryDecodingError @unchecked Sendable (DEBUG 전용) 불변 진단 홀더
UnknownNovelValueError @unchecked Sendable novelValue 는 1회 캡처 후 읽기 전용
// 예시 1) 정적 포매터
- private static let formatter: ISO8601DateFormatter = {  }()
+ private nonisolated(unsafe) static let formatter: ISO8601DateFormatter = {  }()

// 예시 2) 조건부 Sendable 은 제약을 유지한 채 @unchecked 로
- extension LosslessValueCodable: Sendable where Strategy.Value: Sendable {}
+ extension LosslessValueCodable: @unchecked Sendable where Strategy.Value: Sendable {}

// 예시 3) 불변 에러/진단 홀더
+ extension PolymorphicCodableError: @unchecked Sendable {}
+ #if DEBUG
+ extension ResilientDecodingOutcome.ArrayDecodingError: @unchecked Sendable {}
+ #endif

또 회귀 방지를 위해 CI 잡을 추가했습니다.

  swift6-mode:
    name: Swift 6 Language Mode
    runs-on: macos-15
    steps:
      - uses: actions/checkout@v4
      - name: Select Xcode 16.4
        run: sudo xcode-select -s /Applications/Xcode_16.4.app
      - name: Build in Swift 6 language mode
        run: swift build -Xswiftc -swift-version -Xswiftc 6

변경 파일

  • 소스(7): ISO8601WithFractionalSecondsStrategy.swift, LosslessValue.swift, OptionalLosslessValue.swift, PolymorphicCodableError.swift, ArrayDecodingError.swift, DictionaryDecodingError.swift, ErrorReporting.swift
  • 매크로(2): UnnestedPolymorphicCodableMacro.swift, UnnestedPolymorphicDecodableMacro.swift
  • CI(1): .github/workflows/ci.yml

10 files changed, +40 / −8

변경했을 때의 트레이드 오프

  • @unchecked Sendable / nonisolated(unsafe)컴파일러 검사 우회 + 개발자 보증입니다. 대상이 전부 init 후 불변이라 안전하지만, 향후 이 타입들에 가변 상태가 추가되면 보증이 깨질 수 있어 각 지점에 근거 주석을 남겼습니다.
  • Package.swiftStrictConcurrency 를 켜지 않았습니다. 켜면 "기타"의 양성 warning 1건이 모든 기여자의 일반 빌드에 상시 노출됩니다. 대신 일반 빌드는 깨끗하게 두고, 회귀는 CI 의 -swift-version 6 게이트로 잡습니다. (트레이드: 로컬에서 즉시 strict 피드백은 못 받음)
  • swift-tools 5.9 유지 → 소비자 하위 호환 최대. 단 이 PR 의 목표는 "Swift 6 로 빌드 가능" 이지 "패키지를 Swift 6 언어 모드로 채택(tools 6.0 상향)" 은 아닙니다.

테스트 방법

  • swift build -Xswiftc -swift-version -Xswiftc 6exit 0 (정본 준비도 게이트, CI 에서 강제).
  • swift test -c debug / swift test -c release — 전부 통과(실패 0), 런타임 동작 변화 없음.

기타

  • 이 툴체인(macOS 26 SDK)에서 컴파일러가 플래그하지 않아 그대로 둔 항목: ResilientDecodingOutcome.recoveredFrom(any Error), 그리고 RFC3339 / RFC3339Nano 의 static DateFormatter. (SDK 가 DateFormatter 는 이미 Sendable 로 표기했고, ISO8601DateFormatter 만 아직 아님.)
  • -strict-concurrency=complete 에서만 남는 양성 진단 1건: Resilient/ErrorReporting.swift:68 — airbnb 유래 에러 리포터 왕복의 Any. Swift 6 language mode 에서도 warning 이며 Swift 6 빌드를 막지 않습니다.
  • 범위 외(후속 후보): MemberMacro deprecated API 경고 ~78건, validateFallbackCaseName unused-result 경고 몇 건.

- 불변·1회 설정 static 상태에 nonisolated(unsafe) 적용:
  static ISO8601DateFormatter, 매크로 타입 서술자(protocolType, macroType)
- 불변 값/메타타입/에러 홀더에 @unchecked Sendable 적용:
  LosslessValueCodable, OptionalLosslessValueCodable(조건부),
  PolymorphicCodableError, ArrayDecodingError, DictionaryDecodingError,
  UnknownNovelValueError
swift build -Xswiftc -swift-version -Xswiftc 6 를 실행하는 CI 잡을 추가해
Swift 6 언어 모드 에러 발생 시 실패하도록 한다.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@DevVenusK, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9e5dadf6-fb65-45d8-8508-ceac0534ca20

📥 Commits

Reviewing files that changed from the base of the PR and between 088c813 and 2c38148.

📒 Files selected for processing (10)
  • .github/workflows/ci.yml
  • Sources/KarrotCodableKit/BetterCodable/DateValue/Strategy/ISO8601WithFractionalSecondsStrategy.swift
  • Sources/KarrotCodableKit/BetterCodable/LosslessValue/LosslessValue.swift
  • Sources/KarrotCodableKit/BetterCodable/LosslessValue/OptionalLosslessValue.swift
  • Sources/KarrotCodableKit/PolymorphicCodable/Error/PolymorphicCodableError.swift
  • Sources/KarrotCodableKit/Resilient/ArrayDecodingError.swift
  • Sources/KarrotCodableKit/Resilient/DictionaryDecodingError.swift
  • Sources/KarrotCodableKit/Resilient/ErrorReporting.swift
  • Sources/KarrotCodableKitMacros/UnnestedPolymorphicCodableMacro/UnnestedPolymorphicCodableMacro.swift
  • Sources/KarrotCodableKitMacros/UnnestedPolymorphicCodableMacro/UnnestedPolymorphicDecodableMacro.swift
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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