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-510] case Foo = {!@#$!@#$} compiles and drops the case #43127

Closed
lilyball mannequin opened this issue Jan 9, 2016 · 9 comments
Closed

[SR-510] case Foo = {!@#$!@#$} compiles and drops the case #43127

lilyball mannequin opened this issue Jan 9, 2016 · 9 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@lilyball
Copy link
Mannequin

lilyball mannequin commented Jan 9, 2016

Previous ID SR-510
Radar None
Original Reporter @lilyball
Type Bug
Status Resolved
Resolution Done
Environment

Apple Swift version 2.1.1 (swiftlang-700.1.101.15 clang-700.1.81)
Apple Swift version 2.2-dev (LLVM 3ebdbb2c7e, Clang f66c5bb67b, Swift 54dcd16)

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee @dduan
Priority Medium

md5: 33eddeb732f3259b9a84f18bc9c2048f

Issue Description:

The following compiles just fine:

enum Testing: String {
    case Thing = "thing"
    case Bob = {"test"}
}

but the actual case Bob is dropped from the AST entirely, as seen by swiftc -print-ast:

internal enum Testing : String {
  case Thing
  internal typealias RawValue = String
  internal var hashValue: Int { get }
  internal init?(rawValue: String)
  internal var rawValue: String { get }
}

Even more interestingly, it doesn't matter what's inside the brackets. The following behaves identically:

enum Testing: String {
    case Thing = "thing"
    case Bob = {!@#$!@#%!@}
}

And in fact, you can actually write this case anywhere, not just inside of enums:

case Bob = {!@#!@#}

The only requirements seem to be that the characters inside the braces must be valid Swift source characters, so e.g. you can't put an apostrophe in there. And whatever's inside must pass the tokenizer, so e.g. string literals must be valid, and floating-point literals must be as well.

It also appears that the rest of the line past the closing brace is also discarded after tokenizing. Unless there's an open brace, which causes it to emit a few errors about closure expressions. And if this case is at the top-level, it actually discards the rest of the file as well, although a few keywords like break and if can trigger errors:

print("hello")
case X = { blah blah blah };

Two households, both alike in dignity,
In fair Verona, where we lay our scene,
//From ancient grudge break to new mutiny,
Where civil blood makes civil hands unclean
From forth the fatal loins of these two foes
A pair of star-cross`d lovers take their life;
Whose misadventured piteous overthrows
Do with their death bury their parents` strife
The fearful passage of their death-mark`d love,
And the continuance of their parents` rage,
Which, but their children`s end, nought could remove,
Is now the two hours` traffic of our stage;
//The which if you with patient ears attend,
What here shall miss, our toil shall strive to mend

This issue was first discovered by nuclearace (JIRA User), and a lot of the subsequent info was found by @mikeash.

@dduan
Copy link
Collaborator

dduan commented Jan 10, 2016

#931

@swift-ci
Copy link
Collaborator

Comment by Jesse Rusak (JIRA)

@dduan In the future, it'd be great if you'd assign the bug to yourself before starting work on it so there aren't multiple people trying to solve it. I've actually been working on this as well, and have a branch up here I was about to submit as a PR which solves the same issue in a different way:

master...jder:diagnose-static-closures

I think your solution might produce duplicate diagnostics in some cases, because parseExpr will emit the passed diagnostic and return nullptr for some errors. For example:

enum Foo: Float {
case Bar = @
}

Now produces the "error: expected expression after '=' in 'case'" twice.

@dduan
Copy link
Collaborator

dduan commented Jan 11, 2016

Just for the record, when I submitted the PR, the status of this ticket was still "unassigned".

That being said, jder (JIRA User), I like your solution better than mine. I'll close my PR.

@swift-ci
Copy link
Collaborator

Comment by Jesse Rusak (JIRA)

Thanks, Daniel. I didn't see your PR when I grabbed the ticket; sorry!

@swift-ci
Copy link
Collaborator

Comment by Jesse Rusak (JIRA)

PR here: #934

@swift-ci
Copy link
Collaborator

Comment by Erik Little (JIRA)

Just as an aside: The way I came about discovering this bug was trying to concatenate another case with a string literal. Since I assumed the compiler would be able to reason that it was dealing with string literals.

enum Test : String {
  case First = "some string"
  case Second = .First + " another string"
}

@swift-ci
Copy link
Collaborator

Comment by Jesse Rusak (JIRA)

Thanks, nuclearace (JIRA User) – I don't think the compiler currently has any notion of a "compile time constant" like that, though I believe it has been discussed as something desirable to add.

@swift-ci
Copy link
Collaborator

Comment by Jesse Rusak (JIRA)

PR being discussed here: #987

@dduan
Copy link
Collaborator

dduan commented Jan 26, 2016

When the parser tries to parse an expression as the raw value of a enum case, it simply calls the function that parses all expressions. This function, parseExpr() , accepts a diagnosis from its caller. If it sees anything wrong in the expression, the diagnosis gets issued.

parseExpr(), seeing that the expression starts with an "{", will call parseExprClosure() . The latter normally would attempt to parse an closure and complain if anything is wrong. However, if the variable CurLocalContext’s value is nullptr, which can be true in some valid situations, parseExprClosure() will skip the closure parsing entirely, consume the tokens until “}” and set a global error state for the parser. A nullptr gets propagate back up the call stack as the parsing result and parseExpr() never gets a chance to issue the diagnosis passed in for enum case raw value.

This had been the cause of this bug: CurLocalContext is set to nullptr for enum raw values. So all we needed is to preempt the call to parseExpr() with a dummy context value.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
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

2 participants