Skip to content

Spurious "Switch condition evaluates to a constant" on mutable local variable #83206

@rnapier

Description

@rnapier

Description

The following Swift code produces a "Switch condition evaluates to a constant" on the line switch state. However, state is a locally mutate variable and is not constant. The diagnostic indicates that case .lineBody will never be executed, but runtime tests demonstrate that it is.

Reproduction

import Foundation

private let endOfMessage = UInt8(0x03)
private let newline = UInt8(ascii: "\n")

enum LedgerError: Error {
    case unexpectedEnd(bytes: [[UInt8]], lineBytes: [UInt8])
}

public struct LedgerResponse: Sendable {
    public var bytes: [[UInt8]] = []
    public var lines: [String] { bytes.map { String(decoding: $0, as: UTF8.self) } }
    public var string: String { lines.joined(separator: "\n") }
    public var lastLine: String { String(decoding: bytes.last ?? [], as: UTF8.self) }
    public var lastDollars: Double { Double(lastLine) ?? 0 }
}

private final class LedgerResponseIterator {
    var reader: FileHandle.AsyncBytes.AsyncIterator

    init(reader: FileHandle) {
        self.reader = reader.bytes.makeAsyncIterator()
    }

    func next() async throws -> LedgerResponse {
        var bytes: [[UInt8]] = []
        var lineBytes: [UInt8] = []

        enum State { case lineStart, lineBody }

        var state = State.lineStart
        func handleNewline() {
            bytes.append(lineBytes)
            lineBytes.removeAll(keepingCapacity: true)
            state = .lineStart
        }

        func handleBodyCharacter(_ c: UInt8) {
            lineBytes.append(c)
            state = .lineBody
        }

        while let c = try await reader.next() {
            switch state {  // <--- incorrect "Switch condition evaluates to a constant"
            case .lineStart:
                switch c {
                case endOfMessage:
                    _ = try await reader.next() // Consume newline
                    return LedgerResponse(bytes: bytes)
                case newline: handleNewline()
                default: handleBodyCharacter(c)
                }

            case .lineBody:
                switch c {
                case newline: handleNewline()
                default: handleBodyCharacter(c)
                }
            }
        }

        throw LedgerError.unexpectedEnd(bytes: bytes, lineBytes: lineBytes)
    }
}

Expected behavior

This code should compile without warnings.

Environment

swift-driver version: 1.127.8 Apple Swift version 6.2 (swiftlang-6.2.0.13.10 clang-1700.3.13.4)
Target: arm64-apple-macosx15.0

(This behavior is not new with 6.2. I don't remember when I first started seeing it.)

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    SILSILOptimizerArea → compiler: SIL optimization passesbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itself

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions