swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.51k stars 10.35k forks source link

Compiler crash mixing `==` constraints with default implementations of protocol methods (Swift 6 regression) #74465

Closed KeithBauerANZ closed 3 months ago

KeithBauerANZ commented 4 months ago

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 {}
slavapestov commented 3 months ago

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