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

Compiler crash with cast involving any existentials #71000

Open
GeorgeElsham opened this issue Jan 19, 2024 · 6 comments
Open

Compiler crash with cast involving any existentials #71000

GeorgeElsham opened this issue Jan 19, 2024 · 6 comments
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 crash Bug: A crash, i.e., an abnormal termination of software existentials Feature: values of types like `any Collection`, `Any` and `AnyObject`; type-erased values expressions Feature: expressions parameterized protocols Feature → protocol: protocols with primary associated types protocol compositions Feature → types: protocol composition types swift 6.0 type checker Area → compiler: Semantic analysis types Feature: types

Comments

@GeorgeElsham
Copy link

Description

It appears that casting a wrapped any existential to another one can cause a compiler crash.

Reproduction

protocol A<T> {
    associatedtype T
}
protocol B {}
typealias C = A & B
typealias D<T> = A<T> & B

struct Foo<Value> {
    let value: Value
}

@available(iOS 16, *)
func run(a: Foo<any C>) {
    _ = a as Foo<any D<Int>>
}

Stack dump

error: compile command failed due to signal 5 (use -v to see invocation)
fromType->getCanonicalType() = (bound_generic_struct_type decl=bugreport.(file).Foo@bugreport.swift:8:8
  (existential_type
    (protocol_composition_type
      (protocol_type decl=bugreport.(file).A@bugreport.swift:1:10)
      (protocol_type decl=bugreport.(file).B@bugreport.swift:4:10))))
toType->getCanonicalType() = (bound_generic_struct_type decl=bugreport.(file).Foo@bugreport.swift:8:8
  (existential_type
    (protocol_composition_type
      (parameterized_protocol_type
        (base=protocol_type decl=bugreport.(file).A@bugreport.swift:1:10)
        (struct_type decl=Swift.(file).Int))
      (protocol_type decl=bugreport.(file).B@bugreport.swift:4:10))))
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the crash backtrace.
Stack dump:
0.	Program arguments: /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file bugreport.swift -target arm64-apple-macosx14.0 -Xllvm -aarch64-use-tbi -enable-objc-interop -stack-check -sdk /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk -color-diagnostics -new-driver-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-driver -empty-abi-descriptor -resource-dir /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -module-name bugreport -disable-clang-spi -target-sdk-version 14.2 -target-sdk-name macosx14.2 -external-plugin-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/lib/swift/host/plugins#/Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/local/lib/swift/host/plugins#/Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/lib/swift/host/plugins#/Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/local/lib/swift/host/plugins#/Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/usr/bin/swift-plugin-server -plugin-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins -plugin-path /Applications/Xcode-15.2.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/local/lib/swift/host/plugins -o /var/folders/tz/qd43l62d02n828rbr1rkf4bh0000gn/T/TemporaryDirectory.JTaMoA/bugreport-1.o
1.	Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
2.	Compiling with the current language version
3.	While evaluating request TypeCheckSourceFileRequest(source_file "bugreport.swift")
4.	While evaluating request TypeCheckFunctionBodyRequest(bugreport.(file).run(a:)@bugreport.swift:13:6)
5.	While type-checking statement at [bugreport.swift:13:25 - line:15:1] RangeText="{
    _ = a as Foo<any D<Int>>
"
6.	While type-checking expression at [bugreport.swift:14:5 - line:14:28] RangeText="_ = a as Foo<any D<Int>"
7.	While type-checking-target starting at bugreport.swift:14:5
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           0x000000010703dabc llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x0000000109ca3cb0 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x0000000109a0d054 SignalHandler(int) + 352
3  libsystem_platform.dylib 0x0000000187b5da24 _sigtramp + 56
4  swift-frontend           0x00000001086d24e8 (anonymous namespace)::ExprRewriter::coerceToType(swift::Expr*, swift::Type, swift::constraints::ConstraintLocatorBuilder) + 9152
5  swift-frontend           0x0000000105561724 swift::constraints::Solution::coerceToType(swift::Expr*, swift::Type, swift::constraints::ConstraintLocator*) + 176
6  swift-frontend           0x00000001065e5eac (anonymous namespace)::ExprRewriter::walkToExprPost(swift::Expr*) + 17760
7  swift-frontend           0x00000001065ce64c (anonymous namespace)::ExprWalker::walkToExprPost(swift::Expr*) + 24
8  swift-frontend           0x0000000105d04a70 (anonymous namespace)::Traversal::visitAssignExpr(swift::AssignExpr*) + 236
9  swift-frontend           0x00000001048b8020 (anonymous namespace)::Traversal::visit(swift::Expr*) (.llvm.15054325256744354582) + 1052
10 swift-frontend           0x00000001086ca88c (anonymous namespace)::ExprWalker::rewriteTarget(swift::constraints::SyntacticElementTarget) + 2688
11 swift-frontend           0x00000001065c579c swift::constraints::ConstraintSystem::applySolution(swift::constraints::Solution&, swift::constraints::SyntacticElementTarget) + 6956
12 swift-frontend           0x0000000106c09b1c swift::TypeChecker::typeCheckTarget(swift::constraints::SyntacticElementTarget&, swift::OptionSet<swift::TypeCheckExprFlags, unsigned int>) + 756
13 swift-frontend           0x00000001093a2e4c swift::TypeChecker::typeCheckExpression(swift::constraints::SyntacticElementTarget&, swift::OptionSet<swift::TypeCheckExprFlags, unsigned int>) + 436
14 swift-frontend           0x00000001099c9460 (anonymous namespace)::StmtChecker::typeCheckASTNode(swift::ASTNode&) (.llvm.7275418743163107908) + 396
15 swift-frontend           0x0000000106ec0840 swift::ASTVisitor<(anonymous namespace)::StmtChecker, void, swift::Stmt*, void, void, void, void>::visit(swift::Stmt*) (.llvm.7275418743163107908) + 296
16 swift-frontend           0x00000001099d49d8 bool (anonymous namespace)::StmtChecker::typeCheckStmt<swift::BraceStmt>(swift::BraceStmt*&) (.llvm.7275418743163107908) + 316
17 swift-frontend           0x00000001099d1614 swift::TypeCheckFunctionBodyRequest::evaluate(swift::Evaluator&, swift::AbstractFunctionDecl*) const + 2200
18 swift-frontend           0x00000001075bce58 swift::TypeCheckFunctionBodyRequest::OutputType swift::evaluateOrDefault<swift::TypeCheckFunctionBodyRequest>(swift::Evaluator&, swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType) + 884
19 swift-frontend           0x0000000106f6a9a8 swift::TypeCheckSourceFileRequest::evaluate(swift::Evaluator&, swift::SourceFile*) const + 608
20 swift-frontend           0x0000000106f70658 llvm::Expected<swift::TypeCheckSourceFileRequest::OutputType> swift::Evaluator::getResultUncached<swift::TypeCheckSourceFileRequest>(swift::TypeCheckSourceFileRequest const&) + 664
21 swift-frontend           0x0000000106f4ea4c swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefault<swift::TypeCheckSourceFileRequest>(swift::Evaluator&, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType) + 228
22 swift-frontend           0x0000000107625a8c swift::CompilerInstance::performSema() + 160
23 swift-frontend           0x0000000109580504 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 464
24 swift-frontend           0x0000000109584854 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 4568
25 swift-frontend           0x00000001095ebd44 swift::mainEntry(int, char const**) + 4408
26 dyld                     0x00000001877ad0e0 start + 2360
error: fatalError

Expected behavior

The code should either compile or produce a diagnostic, instead of crashing.

Interestingly, if you use a force-cast as! rather than as you get the following warning:

Forced cast from 'Foo<any C>' (aka 'Foo<any A & B>') to 'Foo<any D<Int>>' (aka 'Foo<any A<Int> & B>') always succeeds; did you mean to use 'as'?

Environment

swift-driver version: 1.87.3 Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
Target: arm64-apple-macosx14.0

Additional information

No response

@GeorgeElsham GeorgeElsham added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. crash Bug: A crash, i.e., an abnormal termination of software triage needed This issue needs more specific labels labels Jan 19, 2024
@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis parameterized protocols Feature → protocol: protocols with primary associated types casting Feature: explicit casting (is, as, as? and as!) existentials Feature: values of types like `any Collection`, `Any` and `AnyObject`; type-erased values expressions Feature: expressions types Feature: types swift 6.0 and removed triage needed This issue needs more specific labels labels Jan 19, 2024
@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Jan 19, 2024

Thanks! This is supposed to be rejected; Foo<A> and Foo<B> are generally unrelated types.

Revision update: 6d66211.

@AnthonyLatsis AnthonyLatsis added the protocol compositions Feature → types: protocol composition types label Jan 19, 2024
@GeorgeElsham
Copy link
Author

Good to know. Also, what does the revision update mean? Is that a version in which this is fixed?

@AnthonyLatsis
Copy link
Collaborator

Just a more recent dev revision containing the bug.

@GeorgeElsham
Copy link
Author

GeorgeElsham commented Jan 19, 2024

Foo<A> and Foo<B> are generally unrelated types.

@AnthonyLatsis Just to clarify, shouldn't it be possible in the end (with as? or as!) to cast Foo<any C> to Foo<any D<Int>>? My intuition says that should be possible, and succeeds in the case where the associated type T of A is an Int.

In the other direction, I believe that Foo<any D<Int>> should always be castable with as to Foo<any C>. However, this code also crashes the compiler:

/* ... */

@available(iOS 16, *)
func run(a: Foo<any D<Int>>) {
    _ = a as Foo<any C>
}

@tbkka
Copy link
Contributor

tbkka commented Jan 19, 2024

... shouldn't it be possible in the end (with as? or as!) to cast Foo to Foo<any D>?

No. This is not sound in general. You can search the web for "contravariance and covariance of generics" for many explanations of why this does not work in general.

A few programming languages allow you to explicitly state whether your types are covariant and/or contravariant. Swift does not currently have any such capability, though it does have special logic in the compiler and runtime to support this for specific types (such as Array and function types).

Regardless, the compiler should not crash here, of course. It should issue an error message.

@AnthonyLatsis
Copy link
Collaborator

AnthonyLatsis commented Jan 19, 2024

Just to clarify, shouldn't it be possible in the end (with as? or as!) to cast Foo<any C> to Foo<any D<Int>>? My intuition says that should be possible, and succeeds in the case where the associated type T of A is an Int.

With the right feature—sure. The status quo is that Swift does not support Foo<A> to Foo<B> casts because generally, there is no definite answer for how to perform such casts or how the relation between A and B maps to the relation between Foo<A> and Foo<B>. Optional, Array, Dictionary, and Set are covariant exceptions because either the compiler itself or the standard library defines custom casting logic for them.

Note that coercions (as)—you may as well call them static casts—differ from dynamic casts in that their right hand-side contributes to type inference in the left hand-side. The expression below looks like a cast of the result of evaluating G(t: B()) (G<B>) to G<A>, but is actually a simple upcast of B() (B) to A:

class A {}
class B: A {}

struct G<T> {
  let t: T
}

let _ = G(t: B()) as G<A> // Equivalent to 'let _: G<A> = G(t: B())'

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 crash Bug: A crash, i.e., an abnormal termination of software existentials Feature: values of types like `any Collection`, `Any` and `AnyObject`; type-erased values expressions Feature: expressions parameterized protocols Feature → protocol: protocols with primary associated types protocol compositions Feature → types: protocol composition types swift 6.0 type checker Area → compiler: Semantic analysis types Feature: types
Projects
None yet
Development

No branches or pull requests

3 participants