ci(next): check-concurrency refuses a generic main-actor class with no nonisolated deinit (the #23050 Release crash)

Merged
TE
16d ago
+141-1

Summary

A crash-class rule so #23050's Release-compile crash can't come back (coord-deputy, 2026-10-21).

  • scripts/cmux-next/check-concurrency.sh: in a uiSwiftSettings target (main actor by default), a generic class must declare nonisolated deinit. Without one its implicit deinit is isolated, and the Release compile's optimizer crashes on it (EarlyPerfInliner on FirstMouseHostingView's deinit, swift-frontend 6.3, macOS 14 target). #23050 (7d2ee977) added that class, every Release compile failed with compiler crash while optimizing 'deinit' until #23233 (230cc72b) added nonisolated deinit {}, and #20408 fixed the same crash before. A reviewed // concurrency-allow: <why> escapes the rule, like the file's other rules.
  • It is a crash-class rule, so CI's crash-class job (cmux-next-crash-class.yml) blocks on it, and the pre-push gate and the cmux-next checks job run it with the rest of the file.
  • tests/test_check_concurrency_generic_deinit.py runs the script on a fixture package with a UI and a non-UI target. Cases: #23050's exact shape, red; with nonisolated deinit, green; in a non-UI target, green; an inner type's deinit doesn't count, red; the reviewed escape, green. The crash-class workflow runs it.

Out of scope: generic classes in non-UI targets

These 6 have no nonisolated deinit and sit in targets that aren't main actor by default, so the rule leaves them alone (base 4a6ef5b9):

  • CmuxNextCompat/Mutex.swift:44 LockedStorage<Value: ~Copyable>
  • CmuxNextCompat/ObservedItems.swift:5 @MainActor public final class ObservedItems<Model, Item>
  • CmuxNextCompat/ObservedMap.swift:15 ObservedMap<Key, Value>
  • CmuxNextControl/Concurrency/ControlDeadline.swift:44 Race<T>
  • CmuxNextServerHelper/ServerHelperDeadline.swift:44 Race<T>
  • CmuxNextWakeups/FirstOutcome.swift:6 FirstOutcome<Value>

(My first count to coord-deputy said 7; it is 6.) ObservedItems is explicitly @MainActor but lives in CmuxNextCompat, a non-UI target, so it's outside the rule's stated scope. The 5 generic classes in UI targets already declare nonisolated deinit: ImmediateRun, FirstMouseHostingView, CEFReplyWaiters, and the Once in BrowserHistoryWriter and in PageCallDeadline.

Testing

  • The rule on the real tree, CHECK_CONCURRENCY_ONLY=crash-class scripts/cmux-next/check-concurrency.sh:
    • red with BrowserDownloadsPopup.swift from 7d2ee977 (#23050): Sources/CmuxNextApp/Handlers/BrowserDownloadsPopup.swift:459: generic main-actor class with no nonisolated deinit, exit 1.
    • green on base 4a6ef5b9 (check-concurrency: ok), and the full check (no CHECK_CONCURRENCY_ONLY) is green too.
  • The fixture test: red on 8b30fd2b (test only) and green on the head, both in the crash-class job.

Observed / Not run

  • Observed: the two script runs above.
  • Not run here: the fixture test itself (running test files is blocked on this Mac); CI's crash-class job runs it on both commits.

Changelog

none

Agent session: cosmic-gray

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds a crash-class rule to check-concurrency.sh so #23050's Release-compile crash can't come back: a generic main-actor class in a UI target must declare nonisolated deinit, since its implicit isolated deinit crashes the Release optimizer (fixed in #23233, previously #20408). A reviewed // concurrency-allow: escapes the rule, and non-UI targets stay out of scope.

  • Adds a fixture test covering the #23050 shape (red), the fix (green), non-UI targets (green), inner-type deinits (red), braces in string literals (green), and the escape (green).
  • Runs the test from the crash-class CI job and registers it in tests/test-execution.toml.