Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Compiler Error: The enum case has a single tuple as an associated value, but there are several patterns here

Tags:

swift

Building a project in Xcode 11.4 beta 3, I'm getting this Swift Compiler error on an enum:

The enum case has a single tuple as an associated value, but there are several patterns here, implicitly tupling the patterns and trying to match that instead

Source code:

switch result {
case .error(let err):
    //
case .value(let staff, let locations):  // <-- error on this line
    //
}

Result is an generic enum with associated values for .error and .value. In this case, the associated value is a tupple.

public enum Result<T> {
    case value(T)
    case error(Error)
}

Don't recall seeing this error before, and searching for it did not yield any results. Any ideas?

like image 921
Eneko Alonso Avatar asked Mar 11 '20 18:03

Eneko Alonso


People also ask

What is an enumeration case in Swift?

Swift enumeration cases don’t have an integer value set by default, unlike languages like C and Objective-C. In the CompassPoint example above, north, south, east and west don’t implicitly equal 0, 1, 2 and 3. Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint.

What are raw values in Swift enum?

Since the value matches with case let .suv, the statement inside the case is executed. In Swift, raw values are predefined constant values provided to each enum value. For example, Here, we have provided the raw values: "Four Wheeler" and "Two Wheeler" to car and bike respectively.

What is the difference between Raw and associated values in Swift?

In Swift, raw values are predefined constant values provided to each enum value. For example, Here, we have provided the raw values: "Four Wheeler" and "Two Wheeler" to car and bike respectively. However, associated values are more like variables associated with the enum values.

What are enumeration cases and raw values?

If a value (known as a raw value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type. Alternatively, enumeration cases can specify associated values of any type to be stored along with each different case value, much as unions or variants do in other languages.


5 Answers

I found you can also silence this error by treating the associated value more like a tuple by wrapping it in an extra set of brackets:

switch result {
case .error(let err):
    //
case .value((let staff, let locations)):  
    //
}
like image 199
Wernzy Avatar answered Oct 19 '22 19:10

Wernzy


Ok, figured it out. Seems like enum with associated values, where the value type is a tuple, can no longer be matched on a switch statement like that:

// Works on Xcode 11.3.1, yields error on 11.4 (Swift 5.2)
switch result {
case .error(let err):
    //
case .value(let staff, let locations):  
    //
}

Solution

Values from tuple have to be manually extracted in Xcode 11.4 (Swift 5.2):

// Works on Xcode 11.4
switch result {
case .error(let err):
    //
case .value(let tuple):  
    let (staff, locations) = tuple
    // 
}
like image 23
Eneko Alonso Avatar answered Oct 19 '22 19:10

Eneko Alonso


This is a known issue: https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_release_notes

Code that relies on the compiler automatically tupling a pattern may lead to a compiler error when upgrading to Xcode 11.4, even though the code compiled before. (58425942)

For example, leaving out parentheses when switching on an Optional of a tuple type causes a compiler error:

switch x { // error: switch must be exhaustive
case .some((let a, let b), let c): // warning: the enum case has a
     // single tuple as an associated value, but there are several
     // patterns here, implicitly tupling the patterns and trying
     // to match that instead
...

}

Workaround: Add extra parentheses to explicitly tuple the pattern:

switch x {
case .some(((let a, let b), let c)): // Notice the extra pair of parentheses.
...

}

like image 5
bolinhalouise Avatar answered Oct 19 '22 20:10

bolinhalouise


In Xcode 12 / Swift 5.3, the warning message is greatly improved:

Enum case 'value' has one associated value that is a tuple of 2 elements. Replace (let staff, let locations) with ((let staff, let locations)).

That's far clearer. It tells you what to do, and offers to do it, as a Fix-It. Of course the alternative is to say (let tuple) and pass the tuple into the case's code and deal with it there, but there seems no need to say that explicitly in the warning.

like image 2
matt Avatar answered Oct 19 '22 19:10

matt


If I may, I'd like to add an answer for the if case version too.

if case let .value(staff, error) = result {
    // Do something
}

and then of course ignoring case:

if case let .value(staff, _) = result {
    // Do something
}
like image 1
Paul Peelen Avatar answered Oct 19 '22 19:10

Paul Peelen