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-15038] Incorrect "conditional downcast from ... does nothing" diagnostic #57365

Closed
keith opened this issue Aug 6, 2021 · 10 comments
Closed
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior.

Comments

@keith
Copy link
Collaborator

keith commented Aug 6, 2021

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

% swift -version
swift-driver version: 1.26.7 Apple Swift version 5.5 (swiftlang-1300.0.27.6 clang-1300.0.27.2)
Target: arm64-apple-macosx11.0

Xcode 13.0 beta 4 (13A5201i)

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

md5: d316ac620e0645b1843c3a363229a922

relates to:

  • SR-15082 Forced checked cast runtime crash on optional to T in array element position

Issue Description:

With this code:

protocol ExperimentDeserializable {
    static func deserializeExperiment(_ value: Any) -> Self?
}

extension String: ExperimentDeserializable {
    static func deserializeExperiment(_ value: Any) -> String? { value as? String }
}

extension Int: ExperimentDeserializable {
    static func deserializeExperiment(_ value: Any) -> Int? { value as? Int }
}

class Constant<T> {
    private init(getUnderlyingValue: @escaping () -> T) {
        print(getUnderlyingValue())
    }
}

extension Constant where T: Sequence, T.Element: ExperimentDeserializable {
    static func foo<U>(thing: Thing, defaultValue: T) -> T where T == [U] {
        guard let array = thing.storage["foo"] as? [Any] else {
            fatalError()
        }

        let value = array.map(T.Element.deserializeExperiment) as? [T.Element] ?? defaultValue
        return value
    }
}

struct Thing {
    let storage: [String: Any]
}

let thing = Thing(storage: ["foo": ["x", 1]])
let result = Constant.foo(thing: thing, defaultValue: ["a", "b"])
assert(result == ["a", "b"])

You get this warning:

invalidwarning.swift:25:64: warning: conditional downcast from 'Array<U>.Element?' (aka 'Optional<U>') to 'Array<U>.Element' (aka 'U') does nothing
        let value = array.map(T.Element.deserializeExperiment) as? [T.Element] ?? defaultValue
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~

Which is invalid because `[Any] as? [T.Element]` does not do nothing, it will return `nil` in this example because `[Any] as? [String]` for `["x", 1]` will not cast.

@jpsim
Copy link
Contributor

jpsim commented Aug 6, 2021

Also note that replacing as? [T.Element] with as! [T.Element]? crashes at runtime with the following output:

Could not cast value of type 'Swift.Optional<Swift.String>' (0x7fff8170fd50) to 'Swift.String' (0x7fff81709120).
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
Stack dump:
0.  Program arguments: /Applications/Xcode-13.0.0-Beta.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -interpret file.swift -enable-objc-interop -stack-check -sdk /Applications/Xcode-13.0.0-Beta.4.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk -color-diagnostics -new-driver-path /Applications/Xcode-13.0.0-Beta.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-driver -resource-dir /Applications/Xcode-13.0.0-Beta.4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -module-name file -target-sdk-version 12.0.0
1.  Apple Swift version 5.5 (swiftlang-1300.0.27.6 clang-1300.0.27.2)
2.  
3.  While running user code "file.swift"
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0  swift-frontend           0x0000000113ba0187 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 39
1  swift-frontend           0x0000000113b9f118 llvm::sys::RunSignalHandlers() + 248
2  swift-frontend           0x0000000113ba0796 SignalHandler(int) + 278
3  libsystem_platform.dylib 0x00007fff2056fd7d _sigtramp + 29
4  libsystem_malloc.dylib   0x00007fff2036bff4 _malloc_zone_calloc + 59
5  libsystem_c.dylib        0x00007fff2047f406 abort + 125
6  libswiftCore.dylib       0x00007fff2cbf37b5 swift::fatalError(unsigned int, char const*, ...) + 149
7  libswiftCore.dylib       0x00007fff2cbebb27 swift::swift_dynamicCastFailure(void const*, char const*, void const*, char const*, char const*) + 71
8  libswiftCore.dylib       0x00007fff2cbebb9a swift::swift_dynamicCastFailure(swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, char const*) + 106
9  libswiftCore.dylib       0x00007fff2cbefecb swift_dynamicCast + 251
10 libswiftCore.dylib       0x00007fff2c8f1ba4 $ss15_arrayForceCastySayq_GSayxGr0_lF + 676
11 libswiftCore.dylib       0x00007fff2c8f0f7d _swift_arrayDownCastIndirect + 45
12 libswiftCore.dylib       0x00007fff2cbf0e88 tryCastToArray(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) + 104
13 libswiftCore.dylib       0x00007fff2cbf01d5 tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) + 565
14 libswiftCore.dylib       0x00007fff2cbf056f tryCast(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*&, swift::TargetMetadata<swift::InProcess> const*&, bool, bool) + 1487
15 libswiftCore.dylib       0x00007fff2cbefe6c swift_dynamicCast + 156
16 libswiftCore.dylib       0x0000000118fec797 swift_dynamicCast + 18446603344479766983
17 libswiftCore.dylib       0x0000000118fec18a swift_dynamicCast + 18446603344479765434
18 swift-frontend           0x000000010edc5e40 llvm::orc::runAsMain(int (*)(int, char**), llvm::ArrayRef<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, llvm::Optional<llvm::StringRef>) + 1408
19 swift-frontend           0x000000010ed26cb7 swift::RunImmediately(swift::CompilerInstance&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, swift::IRGenOptions const&, swift::SILOptions const&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >&&) + 12839
20 swift-frontend           0x000000010ece5eac performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 2604
21 swift-frontend           0x000000010ecd7cae swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 14398
22 swift-frontend           0x000000010ec19718 main + 1032
23 libdyld.dylib            0x00007fff20545f3d start + 1
[1]    91009 abort      DEVELOPER_DIR=/Applications/Xcode-13.0.0-Beta.4.app/Contents/Developer swift 

@keith
Copy link
Collaborator Author

keith commented Aug 6, 2021

Here's a much smaller example:

func decodeStringOrInt<T: FixedWidthInteger>() -> [T] {
    let stringWrapped = [String]()
    if let values = stringWrapped.map({ $0.isEmpty ? 0 : T($0) }) as? [T] {
        return values
    } else {
        fatalError()
    }
}

@LucianoPAlmeida
Copy link
Collaborator

I'll try take a look at this as well =]
theindigamer (JIRA User) Do you think make sense to have the runtime crash reported as a separated issue?

@typesanitizer
Copy link

It depends. If the bug is that we're doing incorrect codegen because of something that was passed in incorrectly from sema, then the runtime is not really at fault for not doing the impossible.

@LucianoPAlmeida
Copy link
Collaborator

Sure, I'll try take a look soon to see what is happening

@LucianoPAlmeida
Copy link
Collaborator

Here is a PR #38884

theindigamer (JIRA User) After taking a look at it, I think this runtime issue could be another ticket, even if this is a Sema issue I think is not related to this incorrect warning problem.

@LucianoPAlmeida
Copy link
Collaborator

Fixed on main, @keith Can you please verify on the next available snapshot and close. Thanks 🙂

@typesanitizer
Copy link

Sounds good, please feel free to file another ticket for the runtime issue and we can see who can work on it.

@LucianoPAlmeida
Copy link
Collaborator

Done theindigamer (JIRA User) SR-15082 =]

@keith
Copy link
Collaborator Author

keith commented Aug 18, 2021

Sorry for the confusion, my original point about how `as![](caused a crash was to show that theas?case was _not_ unnecessary, because if it wasas)` should always succeed.

@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.
Projects
None yet
Development

No branches or pull requests

4 participants