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?
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.
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.
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.
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.
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)):
//
}
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):
//
}
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
//
}
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.
...
}
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.
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With