swiftlang/swift

Suboptimal diagnostics on mutating on immutable + optional value on non-optional parameter

開放

#87,218 建立於 2026年2月13日

 (3 則留言) (0 個反應) (0 位負責人)Swift (10,719 個分叉)batch import
compilerdiagnostics qualityexpressionsgood first issuemutatingtype checker

倉庫指標

星標
 (69,989 顆星)
PR 合併指標
 (平均合併 8天 17小時) (30 天內合併 510 個 PR)

描述

Description

Trying to use a mutating method on an immutable value and an optional argument in place for a non-optional parameter may produce worse diagnostics than what would be emitted independently:

  • "error: cannot use mutating member on immutable value" → isn't emitted.
  • "error: no exact matches in call to instance method 'X'" → emitted instead of the more accurate "error: value of optional type 'T?' must be unwrapped to a value of type 'T'".

Reproduction

func buildThing() {
    let dictionary = [String: [String]]()
    var optionalValue: String?
    if let array = dictionary["foo"] {
        array.append(optionalValue) 
            // ❌ No exact matches in call to instance method 'append'
                // ℹ️ Found candidate with type '(__owned String) -> ()'
    }
}

Expected behavior

I think it should be possible to diagnose the "Cannot use mutating member on immutable value" in this scenario. All overloads of append on Array are mutating.

Environment

swift-driver version: 1.127.14.1 Apple Swift version 6.2 (swiftlang-6.2.0.19.9 clang-1700.3.19.1) Target: arm64-apple-macosx26.0

Additional information

By itself, this emits the right diagnostic:

func buildThingB() {
    let dictionary = [String: [String]]()
    if let array = dictionary["foo"] {
        array.append("bar")
           // ❌ Cannot use mutating member on immutable value: 'array' is a 'let' constant
    }
}

And so does this:

func buildThingC() {
    var dictionary = [String: [String]]()
    var optionalValue: String?
    dictionary["foo"]!.append(optionalValue)
        // ❌ Value of optional type 'String?' must be unwrapped to a value of type 'String'
            // ℹ️ Coalesce using '??' to provide a default when the optional value contains 'nil'
            // ℹ️ Force-unwrap using '!' to abort execution if the optional value contains 'nil'
}

And the compiler is able to emit both diagnostics at once under other (similar) circumstances:

func buildThingD() {
    let dictionary = [String: [String]]()
    var optionalValue: String?
    dictionary["foo"]!.append(optionalValue)
        // ❌ Cannot use mutating member on immutable value: 'dictionary' is a 'let' constant
        // ❌ Value of optional type 'String?' must be unwrapped to a value of type 'String'
            // ℹ️ Coalesce using '??' to provide a default when the optional value contains 'nil'
            // ℹ️ Force-unwrap using '!' to abort execution if the optional value contains 'nil'
}

貢獻者指南