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-11421] Checked Cast Diagnostics Should Be More Specific When Literals Are Involved #53822

Closed
CodaFi opened this issue Sep 5, 2019 · 18 comments · Fixed by #64846
Closed
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. casting Feature: explicit casting (is, as, as? and as!) compiler The Swift compiler in itself diagnostics QoI Bug: Diagnostics Quality of Implementation good first issue Good for newcomers improvement literals Feature → expressions: Literals such as an integer or string literal swift 5.9 type checker Area → compiler: Semantic analysis

Comments

@CodaFi
Copy link
Member

CodaFi commented Sep 5, 2019

Previous ID SR-11421
Radar None
Original Reporter @CodaFi
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, DiagnosticsQoI, StarterBug
Assignee mohit.athwani (JIRA)
Priority Medium

md5: 54d2d8b997d41666f9024642eb576483

cloned to:

  • SR-12093 Checked Casts With Literals Are Deeply Unintuitive

Issue Description:

Checked casts on literals can have surprising effects at face value

let character = "A" as Character
let bad = "A" as? Character

The former is a character literal and is statically coerced. The latter is a String literal that is being dynamically cast to a Character. This cast will always fail, and we note as much - this also works with as! force casts.

warning: cast from 'String' to unrelated type 'Character' always fails

We could definitely do a better job phrasing this warning to let the user know what went wrong and can even offer a fixit that changes the dynamic cast to a static cast if it's going to succeed.

@swift-ci
Copy link
Collaborator

Comment by Mohit Athwani (JIRA)

@CodaFi I'd like to contribute to this with your assistance.

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

@CodaFi Let me try this!

@Rajveer100
Copy link
Contributor

Rajveer100 commented Feb 14, 2023

Hey @CodaFi I have ran the exact same code, I have got this output:

warning: conditional downcast from literal to 'Character' always fails; consider using 'as' coercion
let bad = "A" as? Character
              ^

What exact type of phrasing are you looking for, because the above seems very clear and is also giving a suggestion to use the as statically coerced cast, instead of as?.

@AnthonyLatsis
Copy link
Collaborator

@Rajveer100 This is definitely an improvement, but I think we can take another step forward and mention the inferred type of the literal as well. I can imagine people wondering why their supposed Character literal does not want to downcast to a Character. It is not immediately clear that the destination type of a dynamic cast does not participate in the inference of the left-hand side.

@AnthonyLatsis AnthonyLatsis added type checker Area → compiler: Semantic analysis casting Feature: explicit casting (is, as, as? and as!) literals Feature → expressions: Literals such as an integer or string literal swift 5.9 labels Feb 19, 2023
@Rajveer100
Copy link
Contributor

Yeah I understand that, could you exactly specify to what it could be potentially changed to, what would be your suggestion?

@AnthonyLatsis
Copy link
Collaborator

Do you have any ideas in mind? Of course, I could just throw in a suggestion without asking you first, but to me that defeats the purpose of a good first issue.

@Rajveer100
Copy link
Contributor

So overall, the fix is to change the diagnosed message to a more better phrasing and provide a fix it to it if the casting is possible. While I am solving another issue, I will get back to this.

@Rajveer100
Copy link
Contributor

@AnthonyLatsis Back into this issue!
I guess we were discussing about the suggestions?

@AnthonyLatsis
Copy link
Collaborator

Hey Rajveer, got any ideas on how to improve the message yet? Suppose you compile "A" as? Character, and the compiler reacts with conditional downcast from literal to 'Character' always fails. But why does the cast fail?

@Rajveer100
Copy link
Contributor

Rajveer100 commented Mar 20, 2023

In my understanding, considering the three cases of as, as? and as!:

  • as is used for upcasting for bridged type
  • as? is used for safe down casting (optional)
  • as! is forced down casting

Considering the String case, here String is the superior type, and we are trying to downcast to a non superior Character type, which leads to failure for the last 2 cases, while the first one succeeds in doing so.

@tbkka
Copy link
Contributor

tbkka commented Mar 20, 2023

as?, as!, and is are variants of the same runtime operation. In fact, you can define as! and is in terms of as?:

  • x as! T is defined to be (x as? T)!
  • x is T is defined to be (x as? T) != nil

as? supports a variety of casting and conversion operations, including bridging conversions (which are not really "casting" in the traditional OO sense) as well as both up and down casting.

@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Mar 20, 2023

as is special because it is not necessarily a run-time operation, or even a conversion as such. It can act as both a known-to-succeed bridging conversion and a type inference hint or coercion, as in 0 as Double, where as simply means that 0 should be inferred to have type Double.


Okay, so the reason the cast fails is that String and Character are unrelated types. The problem is, the error message says nothing about String (the inferred type of the literal), it only says that the literal cannot be cast to Character.

@Rajveer100
Copy link
Contributor

Rajveer100 commented Mar 21, 2023

Okay, so the reason the cast fails is that String and Character are unrelated types. The problem is, the error message says nothing about String (the inferred type of the literal), it only says that the literal cannot be cast to Character.

In which perspective are they 'unrelated', since a String essentially is a stream / buffer of multiple Character types, i.e., String.Element.

@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Mar 21, 2023

They are "unrelated" in the type system, not logically. "Unrelated" in this sense means that neither is a descendent (subtype) of the other. With the exception of bridging conversions and some other edge cases, Swift’s type safety implies that a type cast/coercion fails if the types are "unrelated".

@Rajveer100
Copy link
Contributor

That makes sense.

@Rajveer100
Copy link
Contributor

So we can probably update the diagnostic warning to, warning: {literal_in_context} literal and %0 are 'unrelated' to each other, consider using 'as' coercion, which in our case would be, warning: 'String' literal and 'Character' are 'unrelated' to each other, consider using 'as' coercion.

@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Mar 23, 2023

I suggest we use the same phrasing as in downcast_to_unrelated for the second half: ... to unrelated type <to_type> always fails. from <from_type> literal sounds good, but I think we can still do better by emphasizing that we are not simply describing the literal, but that the literal was inferred to that type (and only then cast), which also adds some contrast between casting (as?) and coercing (as). For example, from literal of inferred type <from_type>.

@Rajveer100
Copy link
Contributor

Right...

Rajveer100 added a commit to Rajveer100/swift that referenced this issue Apr 2, 2023
Rajveer100 added a commit to Rajveer100/swift that referenced this issue Apr 2, 2023
Rajveer100 added a commit to Rajveer100/swift that referenced this issue Apr 3, 2023
Rajveer100 added a commit to Rajveer100/swift that referenced this issue Apr 5, 2023
Rajveer100 added a commit to Rajveer100/swift that referenced this issue Apr 6, 2023
Rajveer100 added a commit to Rajveer100/swift that referenced this issue Apr 6, 2023
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. casting Feature: explicit casting (is, as, as? and as!) compiler The Swift compiler in itself diagnostics QoI Bug: Diagnostics Quality of Implementation good first issue Good for newcomers improvement literals Feature → expressions: Literals such as an integer or string literal swift 5.9 type checker Area → compiler: Semantic analysis
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants