swiftlang/swift

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

Open

#87 218 ouverte le 13 févr. 2026

Voir sur GitHub
 (3 commentaires) (0 réactions) (0 assignés)Swift (10 719 forks)batch import
compilerdiagnostics qualityexpressionsgood first issuemutatingtype checker

Métriques du dépôt

Stars
 (69 989 stars)
Métriques de merge PR
 (Merge moyen 7j 6h) (556 PRs mergées en 30 j)

Description

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'
}

Guide contributeur