Reputation: 19722
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?
Upvotes: 21
Views: 10169
Reputation: 347
I think instead check the type and get the value in a tuple, you check the value of the condition. This is my example
switch result {
case let .error(err):
// Do something
case let .value(staff, locations): // <-- error on this line
// Do something
}
Upvotes: 0
Reputation: 19722
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
//
}
Upvotes: 21
Reputation: 3053
Swift 5.3
A clean way using typealias because may you have a lot of value in tuple so typealias make the switch case more cleaner
public typealias StaffLocationsData = (let staff, let locations)
switch result {
case .error(let err):
//
case .value(let data):
let staffLocationsData: StaffLocationsData = data
print(staffLocationsData.staff)
print(staffLocationsData.locations)
}
Upvotes: 0
Reputation: 535860
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.
Upvotes: 3
Reputation: 10329
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
}
Upvotes: 1
Reputation: 51
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.
...
}
Upvotes: 5
Reputation: 1098
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)):
//
}
Upvotes: 22