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 mixing == constraints with default implementations of protocol methods (Swift 6 regression) #74465

Closed
KeithBauerANZ opened this issue Jun 16, 2024 · 1 comment · Fixed by #74828
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler itself conformances Feature → protocol: protocol conformances crash Bug: A crash, i.e., an abnormal termination of software generics Feature: generic declarations and types

Comments

@KeithBauerANZ
Copy link

Description

Not quite sure what's going on here, but the code compiles with Swift 5.10/Xcode 15.4, and crashes the compiler with Swift 6/Xcode 16.0b1. Replacing where RawValue == String constraints with where RawValue: ExpressibleByXXXLiteral constraints also solves the problem.

Reproduction

protocol TaggedValue: RawRepresentable {
    init(rawValue: RawValue)
}

struct Tagged<Tag, RawValue>: TaggedValue {
    var rawValue: RawValue
}

extension TaggedValue where RawValue == String {
    typealias UnicodeScalarLiteralType = RawValue.UnicodeScalarLiteralType
    init(unicodeScalarLiteral: UnicodeScalarLiteralType) {
        self.init(rawValue: RawValue(unicodeScalarLiteral: unicodeScalarLiteral))
    }
}

extension TaggedValue where RawValue == String {
    typealias ExtendedGraphemeClusterLiteralType = RawValue.ExtendedGraphemeClusterLiteralType
    init(extendedGraphemeClusterLiteral: ExtendedGraphemeClusterLiteralType) {
        self.init(rawValue: RawValue(extendedGraphemeClusterLiteral: extendedGraphemeClusterLiteral))
    }
}

extension TaggedValue where RawValue == String {
    typealias StringLiteralType = RawValue.StringLiteralType
    init(stringLiteral: StringLiteralType) {
        self.init(rawValue: RawValue(stringLiteral: stringLiteral))
    }
}

extension Tagged: Equatable where RawValue: Equatable {}
extension Tagged: ExpressibleByUnicodeScalarLiteral where RawValue == String {}
extension Tagged: ExpressibleByExtendedGraphemeClusterLiteral where RawValue == String {}
extension Tagged: ExpressibleByStringLiteral where RawValue == String {}
import XCTest
@testable import Tagged

class TaggedTests: XCTestCase {

    func testExample() {
        let value = Tagged<(test: (), value: ()), String>(rawValue: "whatever")
        let value2: Tagged<(test: (), value: ()), String> = "whatever"
        XCTAssertEqual(value, value2)
    }

}

Stack dump

1.	Apple Swift version 6.0 (swiftlang-6.0.0.3.300 clang-1600.0.20.10)
2.	Compiling with effective version 5.10
3.	While evaluating request ASTLoweringRequest(Lowering AST to SIL for file "/Users/<me>/Source/SwiftExperiments/Tagged/TaggedTests/TaggedTests.swift")
4.	While silgen emitFunction SIL function "@$s11TaggedTestsAAC11testExampleyyF".
 for 'testExample()' (at /Users/<me>/Source/SwiftExperiments/Tagged/TaggedTests/TaggedTests.swift:13: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           0x000000010882acd0 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1  swift-frontend           0x0000000108828f44 llvm::sys::RunSignalHandlers() + 112
2  swift-frontend           0x000000010882b2d8 SignalHandler(int) + 352
3  libsystem_platform.dylib 0x000000018514f584 _sigtramp + 56
4  libsystem_pthread.dylib  0x000000018511ec20 pthread_kill + 288
5  libsystem_c.dylib        0x000000018502ba30 abort + 180
6  swift-frontend           0x0000000103202078 PrettyStackTraceFrontend::~PrettyStackTraceFrontend() + 0
7  swift-frontend           0x0000000108799a28 llvm::report_fatal_error(llvm::Twine const&, bool) + 280
8  swift-frontend           0x0000000108799910 llvm::report_fatal_error(llvm::Twine const&, bool) + 0
9  swift-frontend           0x0000000103cc5bec std::__1::deque<llvm::Function*, std::__1::allocator<llvm::Function*>>::push_back(llvm::Function* const&) + 0
10 swift-frontend           0x0000000103cc5a48 swift::Lowering::SILGenModule::useConformance(swift::ProtocolConformanceRef) + 244
11 swift-frontend           0x0000000103cc7548 LazyConformanceEmitter::visitPartialApplyInst(swift::PartialApplyInst*) + 300
12 swift-frontend           0x0000000103c0ba84 swift::Lowering::SILGenModule::postEmitFunction(swift::SILDeclRef, swift::SILFunction*) + 96
13 swift-frontend           0x0000000103c0b3f8 swift::Lowering::SILGenModule::emitFunctionDefinition(swift::SILDeclRef, swift::SILFunction*) + 8292
14 swift-frontend           0x0000000103c0bc2c swift::Lowering::SILGenModule::emitOrDelayFunction(swift::SILDeclRef) + 212
15 swift-frontend           0x0000000103c09380 swift::Lowering::SILGenModule::emitFunction(swift::FuncDecl*) + 172
16 swift-frontend           0x0000000103d40440 (anonymous namespace)::SILGenType::visitFuncDecl(swift::FuncDecl*) + 32
17 swift-frontend           0x0000000103d3c948 (anonymous namespace)::SILGenType::emitType() + 424
18 swift-frontend           0x0000000103c09078 swift::ASTVisitor<swift::Lowering::SILGenModule, void, void, void, void, void, void>::visit(swift::Decl*) + 104
19 swift-frontend           0x0000000103c0f200 swift::ASTLoweringRequest::evaluate(swift::Evaluator&, swift::ASTLoweringDescriptor) const + 1804
20 swift-frontend           0x0000000103d26e68 swift::SimpleRequest<swift::ASTLoweringRequest, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>> (swift::ASTLoweringDescriptor), (swift::RequestFlags)9>::evaluateRequest(swift::ASTLoweringRequest const&, swift::Evaluator&) + 196
21 swift-frontend           0x0000000103c140f4 swift::ASTLoweringRequest::OutputType swift::Evaluator::getResultUncached<swift::ASTLoweringRequest, swift::ASTLoweringRequest::OutputType swift::evaluateOrFatal<swift::ASTLoweringRequest>(swift::Evaluator&, swift::ASTLoweringRequest)::'lambda'()>(swift::ASTLoweringRequest const&, swift::ASTLoweringRequest::OutputType swift::evaluateOrFatal<swift::ASTLoweringRequest>(swift::Evaluator&, swift::ASTLoweringRequest)::'lambda'()) + 524
22 swift-frontend           0x00000001031f4fdc swift::performCompileStepsPostSema(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 744
23 swift-frontend           0x00000001031f9468 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1672
24 swift-frontend           0x00000001031f7438 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 4752
25 swift-frontend           0x000000010317d2d8 swift::mainEntry(int, char const**) + 2812
26 dyld                     0x0000000184d960e0 start + 2360

Expected behavior

A diagnostic, if the code is invalid, but probably it should compile?

Environment

xcodebuild -version
Xcode 16.0
Build version 16A5171c

Additional information

Working version:

protocol TaggedValue: RawRepresentable {
    init(rawValue: RawValue)
}

struct Tagged<Tag, RawValue>: TaggedValue {
    var rawValue: RawValue
}

extension TaggedValue where RawValue: ExpressibleByUnicodeScalarLiteral {
    typealias UnicodeScalarLiteralType = RawValue.UnicodeScalarLiteralType
    init(unicodeScalarLiteral: UnicodeScalarLiteralType) {
        self.init(rawValue: RawValue(unicodeScalarLiteral: unicodeScalarLiteral))
    }
}

extension TaggedValue where RawValue: ExpressibleByExtendedGraphemeClusterLiteral {
    typealias ExtendedGraphemeClusterLiteralType = RawValue.ExtendedGraphemeClusterLiteralType
    init(extendedGraphemeClusterLiteral: ExtendedGraphemeClusterLiteralType) {
        self.init(rawValue: RawValue(extendedGraphemeClusterLiteral: extendedGraphemeClusterLiteral))
    }
}

extension TaggedValue where RawValue: ExpressibleByStringLiteral {
    typealias StringLiteralType = RawValue.StringLiteralType
    init(stringLiteral: StringLiteralType) {
        self.init(rawValue: RawValue(stringLiteral: stringLiteral))
    }
}

extension Tagged: Equatable where RawValue: Equatable {}
extension Tagged: ExpressibleByUnicodeScalarLiteral where RawValue: ExpressibleByUnicodeScalarLiteral {}
extension Tagged: ExpressibleByExtendedGraphemeClusterLiteral where RawValue: ExpressibleByExtendedGraphemeClusterLiteral {}
extension Tagged: ExpressibleByStringLiteral where RawValue: ExpressibleByStringLiteral {}
@KeithBauerANZ KeithBauerANZ 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 Jun 16, 2024
@KeithBauerANZ KeithBauerANZ changed the title Compiler crash mixing == constraints with default implementations of protocol methods Compiler crash mixing == constraints with default implementations of protocol methods (Swift 6 regression) Jun 23, 2024
@hamishknight hamishknight added compiler The Swift compiler itself conformances Feature → protocol: protocol conformances generics Feature: generic declarations and types and removed triage needed This issue needs more specific labels labels Jun 24, 2024
@slavapestov slavapestov self-assigned this Jun 27, 2024
@slavapestov
Copy link
Contributor

Nice catch:

public protocol P {
  associatedtype A
}

public struct G<A>: P {}

extension P where A == Int {
  public init(integerLiteral: Int) {
    fatalError()
  }
}

extension G: ExpressibleByIntegerLiteral where A == Int {}

let _: G<Int> = 123

slavapestov added a commit to slavapestov/swift that referenced this issue Jun 28, 2024
Adding `T == Int` to

    G1 := <T where T: Equatable>

gives us

    G2 := <T where T == Int>

which means that if I have this substitution map for G2:

    S2 := { Int }

then `SubstitutionMap::get(G1, S2)` should give me this substitution map
for G1:

    S2 := { Int, [Int: Equatable] }

But it didn't, instead returning a substitution map with an invalid
conformance.

The problem is that local conformance lookup alone cannot recover
`[Int: Equatable]` in this case, because there is no "concrete
conformance requirement" `[T == Int: Equatable]` recorded anywhere
in G2.

This is of course a legacy of the GenericSignatureBuilder. It would have
been better to not drop conformance requirements made concrete. But oh
well.

Fixes swiftlang#74465
Fixes rdar://130404629.
slavapestov added a commit to slavapestov/swift that referenced this issue Jun 28, 2024
Adding `T == Int` to

    G1 := <T where T: Equatable>

gives us

    G2 := <T where T == Int>

which means that if I have this substitution map for G2:

    S2 := { Int }

then `SubstitutionMap::get(G1, S2)` should give me this substitution map
for G1:

    S2 := { Int, [Int: Equatable] }

But it didn't, instead returning a substitution map with an invalid
conformance.

The problem is that local conformance lookup alone cannot recover
`[Int: Equatable]` in this case, because there is no "concrete
conformance requirement" `[T == Int: Equatable]` recorded anywhere
in G2.

This is of course a legacy of the GenericSignatureBuilder. It would have
been better to not drop conformance requirements made concrete. But oh
well.

Fixes swiftlang#74465
Fixes rdar://130404629.
slavapestov added a commit to slavapestov/swift that referenced this issue Jun 28, 2024
Adding `T == Int` to

    G1 := <T where T: Equatable>

gives us

    G2 := <T where T == Int>

which means that if I have this substitution map for G2:

    S2 := { Int }

then `SubstitutionMap::get(G1, S2)` should give me this substitution map
for G1:

    S2 := { Int, [Int: Equatable] }

But it didn't, instead returning a substitution map with an invalid
conformance.

The problem is that local conformance lookup alone cannot recover
`[Int: Equatable]` in this case, because there is no "concrete
conformance requirement" `[T == Int: Equatable]` recorded anywhere
in G2.

This is of course a legacy of the GenericSignatureBuilder. It would have
been better to not drop conformance requirements made concrete. But oh
well.

Fixes swiftlang#74465
Fixes rdar://130404629.
slavapestov added a commit to slavapestov/swift that referenced this issue Jun 28, 2024
Adding `T == Int` to

    G1 := <T where T: Equatable>

gives us

    G2 := <T where T == Int>

which means that if I have this substitution map for G2:

    S2 := { Int }

then `SubstitutionMap::get(G1, S2)` should give me this substitution map
for G1:

    S2 := { Int, [Int: Equatable] }

But it didn't, instead returning a substitution map with an invalid
conformance.

The problem is that local conformance lookup alone cannot recover
`[Int: Equatable]` in this case, because there is no "concrete
conformance requirement" `[T == Int: Equatable]` recorded anywhere
in G2.

This is of course a legacy of the GenericSignatureBuilder. It would have
been better to not drop conformance requirements made concrete. But oh
well.

Fixes swiftlang#74465
Fixes rdar://130404629.
slavapestov added a commit to slavapestov/swift that referenced this issue Jul 1, 2024
Adding `T == Int` to

    G1 := <T where T: Equatable>

gives us

    G2 := <T where T == Int>

which means that if I have this substitution map for G2:

    S2 := { Int }

then `SubstitutionMap::get(G1, S2)` should give me this substitution map
for G1:

    S2 := { Int, [Int: Equatable] }

But it didn't, instead returning a substitution map with an invalid
conformance.

The problem is that local conformance lookup alone cannot recover
`[Int: Equatable]` in this case, because there is no "concrete
conformance requirement" `[T == Int: Equatable]` recorded anywhere
in G2.

This is of course a legacy of the GenericSignatureBuilder. It would have
been better to not drop conformance requirements made concrete. But oh
well.

Fixes swiftlang#74465
Fixes rdar://130404629.
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 conformances Feature → protocol: protocol conformances crash Bug: A crash, i.e., an abnormal termination of software generics Feature: generic declarations and types
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants