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-1999] Inconsistency when casting Optional to Any and downcasting to non-Optional #44608

Closed
swift-ci opened this issue Jul 6, 2016 · 6 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler itself runtime The Swift Runtime

Comments

@swift-ci
Copy link
Contributor

swift-ci commented Jul 6, 2016

Previous ID SR-1999
Radar None
Original Reporter hbr (JIRA User)
Type Bug
Status Resolved
Resolution Done
Environment

XCode 7.3
Swift 2.2
OSX 10.11.5
(also crashes with Swift 3)

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

md5: a4bc4c2e8aa88d6efc7c6a9cfcd04be5

relates to:

  • SR-6279 Failing cast from Any to Optional

Issue Description:

Description

Consider a concrete type T extending a protocol P (class T : protocol P)
Cast an instance of T? (optional) to Any, and then downcast it :

  • it seems valid to downcast to T (i.e : it works)

  • on the contrary, downcasting to P yields a runtime exception :

    Could not cast value of type 'Swift.Optional<T>' to 'P'

Is there any reason why downcasting to a class and downcasting to a protocol implemented by the same class should yield different results ?
I think one should either get an exception in both cases, or no exception at all.

Rmq : this issue is not purely theoretical ; I bumped into it when sending optional values to a Swift pod making heavy use of generics (and heavy use of downcasts...)

Test case

Paste this in the main.swift of an XCode 7.3 OSX Command Line Tool project :

protocol FooProtocol {
    func doSomething()
}

class Foo: FooProtocol {
    func doSomething() {
        print("hello")
    }
}

let optionalFoo : Foo? = Foo()
let anyValue: Any = optionalFoo
    
let foo1 = anyValue as! Foo
foo1.doSomething()                  // prints 'hello', ok

let foo2 = anyValue as! FooProtocol // Could not cast value of type 'Swift.Optional<Foo>' to 'FooProtocol'
foo2.doSomething()
@belkadan
Copy link
Contributor

belkadan commented Jul 6, 2016

@jckarter, @slavapestov, we've seen this before, yeah?

@slavapestov
Copy link
Contributor

Yeah, there are definitely some funny edge-cases around optionals. I would stay away from casts that inject or eliminate optionality altogether, and use other constructs, such as pattern matching, instead.

Having said that, we should definitely address these issues, it is just that at this point it is not even completely clear what the correct behavior should be.

@swift-ci
Copy link
Contributor Author

swift-ci commented Jul 7, 2016

Comment by Hervé Bérenger (JIRA)

Thanks a lot for your quick feedback.
I guess it's related to other issues such as SR-912.
I'll try to workaround this using pattern matching as you suggest.

@tbkka
Copy link
Contributor

tbkka commented Aug 27, 2020

#33561 should fix this for the non-optimized case (where the cast is being handled by the runtime). There may still be issues with optimized casts, though.

@swift-ci
Copy link
Contributor Author

Comment by Hervé Bérenger (JIRA)

@tbkka : thanks a lot for the follow-up !

@tbkka
Copy link
Contributor

tbkka commented Jan 5, 2021

After further testing, I believe this is fully fixed now.

@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 itself runtime The Swift Runtime
Projects
None yet
Development

No branches or pull requests

4 participants