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-2022] Better fixit for type checking in switch statements #44631

Open
karwa opened this issue Jul 7, 2016 · 10 comments
Open

[SR-2022] Better fixit for type checking in switch statements #44631

karwa opened this issue Jul 7, 2016 · 10 comments
Labels
compiler The Swift compiler in itself diagnostics QoI Bug: Diagnostics Quality of Implementation good first issue Good for newcomers improvement parser Area → compiler: The legacy C++ parser

Comments

@karwa
Copy link
Collaborator

karwa commented Jul 7, 2016

Previous ID SR-2022
Radar None
Original Reporter @karwa
Type Improvement
Status In Progress
Resolution
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Improvement, DiagnosticsQoI, Parser, StarterBug
Assignee None
Priority Medium

md5: 9b53adc1e41e34c46ad044ffe4bfbac9

Issue Description:

Switch myVariable {
    case let intValue as? Int: print("Hello, I'm an int: \(intValue)")
    case let stringValue as? String: print("Hello, I'm a string: \(stringValue)")
    default: print("Some other value...")
}

Gives you an error on the casting lines saying "Invalid pattern". It would be better if it told you to make the casts non-conditional, I.e.:

Switch myVariable {
    case let intValue *as Int*: print("Hello, I'm an int: \(intValue)")
    case let stringValue *as String*: print("Hello, I'm a string: \(stringValue)")
    default: print("Some other value...")
}
@modocache
Copy link
Mannequin

modocache mannequin commented Sep 10, 2016

The reported issue still occurs on Swift master as of this morning:

$ cat ~/GitHub/tmp/ParserExamples/BasketCase.swift
protocol IntOrString {}

extension Int: IntOrString {}
extension String: IntOrString {}

func foo(bar: IntOrString) {
  switch bar {
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
    default: print("Some other value...")
  }
}

$ swift -frontend -parse ~/tmp/AsQuestionMark.swift
/home/modocache/tmp/AsQuestionMark.swift:3:14: error: pattern variable binding cannot appear in an expression
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ^
/home/modocache/tmp/AsQuestionMark.swift:3:23: warning: cast from '<<error type>>' to unrelated type 'Int' always fails
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ~~~~~~~~ ^   ~~~
/home/modocache/tmp/AsQuestionMark.swift:3:14: error: pattern variable binding cannot appear in an expression
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ^
/home/modocache/tmp/AsQuestionMark.swift:3:23: warning: cast from '<<error type>>' to unrelated type 'Int' always fails
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ~~~~~~~~ ^   ~~~
/home/modocache/tmp/AsQuestionMark.swift:3:23: error: expression pattern of type 'Int?' cannot match values of type 'Int'
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ~~~~~~~~~^~~~~~~
/home/modocache/tmp/AsQuestionMark.swift:4:14: error: pattern variable binding cannot appear in an expression
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ^
/home/modocache/tmp/AsQuestionMark.swift:4:26: warning: cast from '<<error type>>' to unrelated type 'String' always fails
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ~~~~~~~~~~~ ^   ~~~~~~
/home/modocache/tmp/AsQuestionMark.swift:4:14: error: pattern variable binding cannot appear in an expression
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ^
/home/modocache/tmp/AsQuestionMark.swift:4:26: warning: cast from '<<error type>>' to unrelated type 'String' always fails
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ~~~~~~~~~~~ ^   ~~~~~~
/home/modocache/tmp/AsQuestionMark.swift:4:26: error: expression pattern of type 'String?' cannot match values of type 'Int'
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ~~~~~~~~~~~~^~~~~~~~~~
$ cat ~/GitHub/tmp/ParserExamples/Case.swift
protocol IntOrString {}

extension Int: IntOrString {}
extension String: IntOrString {}

func foo(bar: IntOrString) {
  switch bar {
    case let intValue as Int: print("Hello, I'm an Int: \(intValue)")
    case let stringValue as String: print("Hello, I'm a String: \(stringValue)")
    default: print("Some other value...")
  }
}

$ ../build/Ninja-ReleaseAssert/swift-linux-x86_64/bin/swift -frontend -parse ~/GitHub/tmp/ParserExamples/Case.swift

The output is pretty confusing. I suspect "pattern variable binding cannot appear in an expression" doesn't make a ton of sense to an end user. The fixit @karwa describes would be very helpful.

@modocache
Copy link
Mannequin

modocache mannequin commented Sep 10, 2016

I'd like to try my hand at adding a fix-it here. 🙂

@modocache
Copy link
Mannequin

modocache mannequin commented Sep 11, 2016

On second thought, at a first glance it looks like this logic might be in Sema. I don't know a lot about those yet, so I'll drop this for now. Maybe sometime in late October. Sorry for the noise! 🙂

@swift-ci
Copy link
Collaborator

swift-ci commented Nov 6, 2018

Comment by Christopher Ian Stern (JIRA)

While perhaps this should be caught by the parser, the parser doesn't seem to have the context to do it. Either a bunch of parser methods would need addl. arguments or class Parser needs another InThisKindOfStructure variable.

Sema only needs 20some lines of code to detect and give a clear diagnostic.

@belkadan
Copy link
Contributor

Resetting assignee on all Starter Bugs not modified since 2018.

@swift-ci
Copy link
Collaborator

Comment by Christopher Ian Stern (JIRA)

Conflicts have developed between master and PR-20456, which aims to resolve this issue.

Looks like the code that was to be patched in lib/Sema/TypeCheckStmt.cpp moved to a new function `visitSwitchStmt(SwitchStmt *S)`.

@belkadan
Copy link
Contributor

Oops, looks like we missed that PR at the time. Sorry about that.

@belkadan
Copy link
Contributor

#20456

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@gregomni
Copy link
Collaborator

gregomni commented Jun 7, 2024

In the last 5 years the error message has improved here:

 8 |     case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
   |                           `- error: expression pattern of type 'Int?' cannot match values of type 'any IntOrString'

I think that's clear enough what's happening.

@karwa
Copy link
Collaborator Author

karwa commented Jun 7, 2024

I still don't think it's very good, to be honest. Testing on 5.10:

protocol IntOrString {}

extension Int: IntOrString {}
extension String: IntOrString {}

func foo(bar: IntOrString) {
  switch bar {
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
    default: print("Some other value...")
  }
}
<source>:8:14: error: pattern variable binding cannot appear in an expression
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ^
<source>:8:27: error: expression pattern of type 'Int?' cannot match values of type 'any IntOrString'
    case let intValue as? Int: print("Hello, I'm an Int: \(intValue)")
             ~~~~~~~~~~~~~^~~
<source>:9:14: error: pattern variable binding cannot appear in an expression
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ^
<source>:9:30: error: expression pattern of type 'String?' cannot match values of type 'any IntOrString'
    case let stringValue as? String: print("Hello, I'm a String: \(stringValue)")
             ~~~~~~~~~~~~~~~~^~~~~~

I think that at the very least, there should be an explicit suggestion (e.g. a fix-it) that the developer turn the as? in to an as.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler The Swift compiler in itself diagnostics QoI Bug: Diagnostics Quality of Implementation good first issue Good for newcomers improvement parser Area → compiler: The legacy C++ parser
Projects
None yet
Development

No branches or pull requests

4 participants