Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-1121] Custom pattern matching with enum types in Swift 2.2 not working as expected #43734

Open
swift-ci opened this issue Apr 1, 2016 · 16 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 1, 2016

Previous ID SR-1121
Radar rdar://problem/25485364
Original Reporter Zaphod (JIRA User)
Type Bug
Environment

Xcode 7.3 (7D175)

Additional Detail from JIRA
Votes 10
Component/s Compiler
Labels Bug
Assignee @xedin
Priority Medium

md5: b3520825d1f44d2b00094ba8bbb81280

relates to:

  • SR-3568 Cannot write custom pattern matching operator with enum pattern type

Issue Description:

When using the ~= operator to create custom pattern matching with an enum type, the compiler raises an error instead of calling the righteous function.

Steps to Reproduce:
Example of code not compiling, copy and paste it in a playground:

enum LineType : String {
    case Event = "event:"
    case Data = "data:"
}

extension String {
    func isOfType(type: LineType) -> Bool {
        return self.hasPrefix(type.rawValue)
    }
}

func ~= (pattern: LineType, value: String) -> Bool {
    return value.isOfType(pattern)
}

let testLine = "event:yada-yada-yada"

switch testLine {
case _ where testLine.characters.count == 0:
    print("Empty")
case LineType.Event: // <--- Causes the error Enum case 'Event' is not a member of type 'String'
    print("Event")
case LineType.Data: // <--- Causes the error Enum case 'Data' is not a member of type 'String'
    print("Data")
default:
    print("Unknown Type")
}
@belkadan
Copy link
Contributor

belkadan commented Apr 1, 2016

Ah, yeah, when we see an enum case we short-circuit into Pattern Mode rather than Expression Mode for switch case matching.

@sharplet
Copy link

Just came across this in Xcode 9.2. Example:

enum APIRoute {
  case foo
  case bar
}

extension APIRoute {
  static func ~= (pattern: APIRoute, value: URL) -> Bool {
    // ...
  }
}

switch url {
case APIRoute.foo: // error: enum case 'foo' is not a member of type 'URL'
  // ... 
}

@sharplet
Copy link

More specifically, I'm using it in an optional context:

let response: HTTPURLResponse

switch response.url { // of type URL?
case APIRoute.foo?:
  // ...
}

@belkadan
Copy link
Contributor

Stupid workaround: make the case not look like a pattern:

switch url {
case APIRoute.foo.self?:
  break
}

@sharplet
Copy link

Ha, wow, I did not know that was legal. I ended up using passing the value through an identity function named pattern:

case pattern(APIRoute.foo)?:

@swift-ci
Copy link
Collaborator Author

Comment by Sergey Galezdinov (JIRA)

@belkadan, any ETA on this? facing this on 9.3 with swift 4.1

@PSchmiedmayer
Copy link

@belkadan , @xedin , Zaphod (JIRA User)

I can also reproduce the error in a Playground using Swift 4.2 and Xcode version 10.1 (10B61).

enum A: Int {
    case zero
    case one

    static func ~= (pattern: B, value: A) -> Bool {
         return pattern.rawValue == value.rawValue
    }
} 

enum B: Int {
    case one = 1
    case two
}

switch A.one {
case B.one: print("1")
default: break
}

Produces the error message "Enum case 'one' is not a member of type 'A'"

The suggested workaround by @belkadan using `.self` still works. The following switch statement compiles without a problem.

switch A.one {
case B.one.self: print("1")
default: break
}

@belkadan & @xedin is there any update regarding this bug? Is there any way I can help with resolving this issue?

@xedin
Copy link
Member

xedin commented Nov 2, 2018

Sorry I was unable to get to this and probably wouldn't be able for some time still, because of amount of diagnostic work I need to handle...

Code contributions are always welcome if you up to try and figure out what is going on here, I can help you out with suggestions etc.!

@PSchmiedmayer
Copy link

@xedin Thanks for your response!
I would be very interested in trying to figure where this bug is located and what I can do to fix it.
As I have never contributed to the Swift compiler, I would be grateful if you can provide help and input on this subject. Do you think the bug will be manageable and fixable by me with effort from my side and support from your side?

@xedin
Copy link
Member

xedin commented Nov 7, 2018

I really would like to think so! It seems like a good place to start would be to figure out how and when `~=` is generated implicitly for case statements.

@xedin
Copy link
Member

xedin commented Nov 7, 2018

Looks like it happens in TypeChecker::coercePatternToType, just need to figure out how to make it so `B.one` could considered expression pattern I think if it didn't match otherwise?

@PSchmiedmayer
Copy link

@xedin Thanks for the input. I will take a look at the code and issue next week, sounds like a great challenge for me.

@xedin
Copy link
Member

xedin commented Nov 8, 2018

Sounds good!

@swift-ci
Copy link
Collaborator Author

Comment by Mikhail Isaev (JIRA)

Will it ever be fixed? We're waiting three years already 🙁

@PSchmiedmayer
Copy link

Hi mikeisaev (JIRA User), I took a look at the problem a few months ago but was a bit overwhelmed with the complexity. I learned a lot in the last months and would like to retake a look at it as soon as I have a bit more time around August.
Would you be interested in looking at the problem together? Maybe two brains can figure out more than I can alone 😃👍

@swift-ci
Copy link
Collaborator Author

Comment by André Huyghues-Beaufond (JIRA)

Hello, I just found this old issue. It is still open but this now compiles :

import Foundation


enum LineType : String {
    case Event = "event:"
    case Data = "data:"
}


extension String {
    func isOfType(type: LineType) -> Bool {
        return self.hasPrefix(type.rawValue)
    }
}


func ~= (pattern: LineType, value: String) -> Bool {
    return value.isOfType(type: pattern)
}


let testLine = "event:yada-yada-yada"


switch testLine {
case _ where testLine.count == 0:
    print("Empty")
case .Event:
    print("Event") // "Event\n"
case .Data:
    print("Data")
default:
    print("Unknown Type")
}

Does this mean that this bug is now fixed ?

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

5 participants