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

[SR-15038] Incorrect "conditional downcast from ... does nothing" diagnostic #57365

keith opened this issue Aug 6, 2021 · 10 comments
Assignees
Labels

Comments

@keith
Copy link
Collaborator

@keith 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 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 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

@LucianoPAlmeida LucianoPAlmeida commented Aug 10, 2021

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

@typesanitizer typesanitizer commented Aug 10, 2021

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

@LucianoPAlmeida LucianoPAlmeida commented Aug 11, 2021

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

@LucianoPAlmeida
Copy link
Collaborator

@LucianoPAlmeida LucianoPAlmeida commented Aug 14, 2021

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

@LucianoPAlmeida LucianoPAlmeida commented Aug 17, 2021

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

@typesanitizer
Copy link

@typesanitizer typesanitizer commented Aug 17, 2021

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

@LucianoPAlmeida LucianoPAlmeida commented Aug 17, 2021

Done theindigamer (JIRA User) SR-15082 =]

@keith
Copy link
Collaborator Author

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

No branches or pull requests

4 participants