swiftlang / swift

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

Compiler Crash on nested associatedtype (5.7 XCode beta6) #60900

Open arshiacont opened 1 year ago

arshiacont commented 1 year ago

Describe the bug Compiler Crash using Swift 5.7 (XCode 14-Beta6) on the following code snippet. Just run swift test.swift (use v5.7 on XCode14-beta6).

Steps to reproduce: Compile the attached code using Swift 5.7 - Xcode14-beta6. Compiles fine on 5.6 & before.

Expected behavior The compiler should not crash but emit a diagnostic error.

Code

import Foundation

class Object { init(){} }
class GlobalSettings {init(){}}
class RealmGlobalSettings: Object {}

protocol DomainConvertibleType {
    associatedtype DomainType

    var toDomainObject: DomainType { get }
}

protocol RealmConvertible {
    associatedtype RealmType: DomainConvertibleType

    var identifier: String { get }

    func toRealmObject(realm: String?) -> RealmType
}

public protocol RepositoryType {
    associatedtype T

    func save(entity: T) 
}

class Repository<T: RealmConvertible>: RepositoryType where T == T.RealmType.DomainType, T.RealmType: Object {
    public func save(entity: T)  {
        print("Test")
    }
}

extension Repository: SetGlobalSettingsUseCase where T == GlobalSettings {
    func save(globalSettings entity: GlobalSettings) {}
}

extension RealmGlobalSettings: DomainConvertibleType {
    var toDomainObject: GlobalSettings {
        GlobalSettings()
    }
}

public protocol SetGlobalSettingsUseCase {
    func save(globalSettings: GlobalSettings)
}

extension GlobalSettings: RealmConvertible {
    typealias RealmType = RealmGlobalSettings

    func toRealmObject(realm: String?) -> RealmGlobalSettings {
        return RealmGlobalSettings()
    }
}

Environment (please fill out the following information)

Crash Dump

Cannot build interface type for term τ_0_0.[RealmConvertible:RealmType].[DomainConvertibleType:DomainType]
Prefix term does not not have a nested type named RealmType: τ_0_0
Property map entry: τ_0_0 => { layout: _NativeClass superclass: [superclass: GlobalSettings] concrete_type: [concrete: GlobalSettings] }

Property map: {
  τ_0_0 => { layout: _NativeClass superclass: [superclass: GlobalSettings] concrete_type: [concrete: GlobalSettings] }
}
Stack dump:
0.  Program arguments: /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -interpret test.swift -enable-objc-interop -stack-check -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk -color-diagnostics -new-driver-path /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-driver -empty-abi-descriptor -resource-dir /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -module-name test -disable-clang-spi -target-sdk-version 12.3
1.  Apple Swift version 5.7 (swiftlang-5.7.0.123.8 clang-1400.0.29.50)
2.  Compiling with the current language version
3.  While evaluating request TypeCheckSourceFileRequest(source_file "test.swift")
4.  While type-checking extension of Repository (at test.swift:33:1)
5.  While evaluating request GenericSignatureRequest(extension of Repository)
6.  While evaluating request InferredGenericSignatureRequest(test, NULL, <T>, extension of Repository, {}, {(Repository<T>, null)}, 1)
7.  While evaluating request InferredGenericSignatureRequestRQM(NULL, <T>, extension of Repository, {}, {(Repository<T>, null)}, 1)
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           0x000000010a777827 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 39
1  swift-frontend           0x000000010a776858 llvm::sys::RunSignalHandlers() + 248
2  swift-frontend           0x000000010a777e40 SignalHandler(int) + 288
3  libsystem_platform.dylib 0x00007ff810b77dfd _sigtramp + 29
4  swift-frontend           0x00000001068feb97 swift::rewriting::Symbol::dump(llvm::raw_ostream&) const + 2423
5  libsystem_c.dylib        0x00007ff810aadd24 abort + 123
6  swift-frontend           0x00000001068bc861 getTypeForSymbolRange(swift::rewriting::Symbol const*, swift::rewriting::Symbol const*, swift::ArrayRefView<swift::Type, swift::GenericTypeParamType*, swift::GenericTypeParamType* swift::staticCastHelper<swift::GenericTypeParamType>(swift::Type const&), true>, swift::rewriting::PropertyMap const&) + 2465
7  swift-frontend           0x00000001068d00be swift::rewriting::RequirementMachine::buildRequirementsFromRules(llvm::ArrayRef<unsigned int>, llvm::ArrayRef<unsigned int>, swift::ArrayRefView<swift::Type, swift::GenericTypeParamType*, swift::GenericTypeParamType* swift::staticCastHelper<swift::GenericTypeParamType>(swift::Type const&), true>, bool, std::__1::vector<swift::Requirement, std::__1::allocator<swift::Requirement> >&, std::__1::vector<swift::ProtocolTypeAlias, std::__1::allocator<swift::ProtocolTypeAlias> >&) const + 718
8  swift-frontend           0x00000001068deea4 swift::rewriting::RequirementMachine::computeMinimalGenericSignature(bool) + 244
9  swift-frontend           0x00000001068e1b3d swift::InferredGenericSignatureRequestRQM::evaluate(swift::Evaluator&, swift::GenericSignatureImpl const*, swift::GenericParamList*, swift::WhereClauseOwner, llvm::SmallVector<swift::Requirement, 2u>, llvm::SmallVector<swift::TypeLoc, 2u>, bool) const + 3213
10 swift-frontend           0x000000010633f0b7 swift::SimpleRequest<swift::InferredGenericSignatureRequestRQM, llvm::PointerIntPair<swift::GenericSignature, 3u, swift::OptionSet<swift::GenericSignatureErrorFlags, unsigned int>, llvm::PointerLikeTypeTraits<swift::GenericSignature>, llvm::PointerIntPairInfo<swift::GenericSignature, 3u, llvm::PointerLikeTypeTraits<swift::GenericSignature> > > (swift::GenericSignatureImpl const*, swift::GenericParamList*, swift::WhereClauseOwner, llvm::SmallVector<swift::Requirement, 2u>, llvm::SmallVector<swift::TypeLoc, 2u>, bool), (swift::RequestFlags)2>::evaluateRequest(swift::InferredGenericSignatureRequestRQM const&, swift::Evaluator&) + 343
11 swift-frontend           0x0000000106816a2e llvm::Expected<swift::InferredGenericSignatureRequestRQM::OutputType> swift::Evaluator::getResultCached<swift::InferredGenericSignatureRequestRQM, (void*)0>(swift::InferredGenericSignatureRequestRQM const&) + 2158
12 swift-frontend           0x00000001068095d5 swift::InferredGenericSignatureRequest::evaluate(swift::Evaluator&, swift::ModuleDecl*, swift::GenericSignatureImpl const*, swift::GenericParamList*, swift::WhereClauseOwner, llvm::SmallVector<swift::Requirement, 2u>, llvm::SmallVector<swift::TypeLoc, 2u>, bool) const + 421
13 swift-frontend           0x000000010633ef1f swift::SimpleRequest<swift::InferredGenericSignatureRequest, llvm::PointerIntPair<swift::GenericSignature, 3u, swift::OptionSet<swift::GenericSignatureErrorFlags, unsigned int>, llvm::PointerLikeTypeTraits<swift::GenericSignature>, llvm::PointerIntPairInfo<swift::GenericSignature, 3u, llvm::PointerLikeTypeTraits<swift::GenericSignature> > > (swift::ModuleDecl*, swift::GenericSignatureImpl const*, swift::GenericParamList*, swift::WhereClauseOwner, llvm::SmallVector<swift::Requirement, 2u>, llvm::SmallVector<swift::TypeLoc, 2u>, bool), (swift::RequestFlags)2>::evaluateRequest(swift::InferredGenericSignatureRequest const&, swift::Evaluator&) + 351
14 swift-frontend           0x000000010621454d llvm::Expected<swift::InferredGenericSignatureRequest::OutputType> swift::Evaluator::getResultUncached<swift::InferredGenericSignatureRequest>(swift::InferredGenericSignatureRequest const&) + 733
15 swift-frontend           0x000000010621415e llvm::Expected<swift::InferredGenericSignatureRequest::OutputType> swift::Evaluator::getResultCached<swift::InferredGenericSignatureRequest, (void*)0>(swift::InferredGenericSignatureRequest const&) + 702
16 swift-frontend           0x00000001062da36c swift::GenericSignatureRequest::evaluate(swift::Evaluator&, swift::GenericContext*) const + 2380
17 swift-frontend           0x00000001066de60e swift::GenericContext::getGenericSignature() const + 1934
18 swift-frontend           0x00000001062af581 swift::ASTVisitor<(anonymous namespace)::DeclChecker, void, void, void, void, void, void>::visit(swift::Decl*) + 2193
19 swift-frontend           0x00000001062ab629 (anonymous namespace)::DeclChecker::visit(swift::Decl*) + 441
20 swift-frontend           0x00000001062ab461 swift::TypeChecker::typeCheckDecl(swift::Decl*, bool) + 193
21 swift-frontend           0x0000000106387cf7 swift::TypeCheckSourceFileRequest::evaluate(swift::Evaluator&, swift::SourceFile*) const + 567
22 swift-frontend           0x000000010638ae9d llvm::Expected<swift::TypeCheckSourceFileRequest::OutputType> swift::Evaluator::getResultUncached<swift::TypeCheckSourceFileRequest>(swift::TypeCheckSourceFileRequest const&) + 669
23 swift-frontend           0x0000000106387a72 swift::performTypeChecking(swift::SourceFile&) + 114
24 swift-frontend           0x00000001053b3a84 swift::CompilerInstance::performSema() + 292
25 swift-frontend           0x0000000105336e17 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 4711
26 swift-frontend           0x00000001052cd12a swift::mainEntry(int, char const**) + 3082
27 dyld                     0x000000011c40e52e start + 462
[1]    19966 abort       test.swift
arshiacont commented 1 year ago

This is also FB11427468

xedin commented 1 year ago

/cc @slavapestov

AnthonyLatsis commented 1 year ago

The following reduction attempt does not reach the more descriptive abortion, and hits an immediately preceding assert instead:

protocol P {
  associatedtype A
}
protocol Q {
  associatedtype B: P
}

class C1 {}
class C2: C1, P, Q {
  typealias A = C2
  typealias B = C2
}

class Foo<T: Q> where T == T.B.A, T.B: C1 {}

extension Foo where T == C2 {}
arshiacont commented 1 year ago

I just checked XCode 14 RC and it seems like it is shipped with this bug... Is there any workaround? Just trying not to ship late for iOS 16 launch! Many thanks in advance, and I'll check in more depth generic news to figure out if there's anyway around.

arshiacont commented 1 year ago

This note in XCode RC Release seems to be the work around for this issue as well: image

slavapestov commented 1 year ago

That release note is out of date. rdar://91594361 was fixed in beta 3. The bug you're seeing here is a different bug.

slavapestov commented 1 year ago

rdar://99438489

arshiacont commented 1 year ago

Thanks @slavapestov for the detail. Strangely adding that flag to XCode makes the code compile/link without any issues! 🤔

slavapestov commented 1 year ago

Yes that flag also works around this bug too. Is this code example also reduced from Realm-swift?

arshiacont commented 1 year ago

It is originally from a wrapper for RealmSwift but the code I attached has nothing to do with realmSwift and crashes the 5.7 (XCode 14 RC, without that flag) as standalone.

You can just copy the snippet in a test.swift and call swift on it from terminal.

slavapestov commented 1 year ago

The bug is in the 'concrete contraction' pass of the requirement machine, which I need to remove at some point... in the mean time I'll come up with a fix.

ThomasD-WL commented 1 year ago

The bug is in the 'concrete contraction' pass of the requirement machine, which I need to remove at some point... in the mean time I'll come up with a fix.

When can we expect this fix ?

MaxenceMottard commented 1 year ago

Hi, do you have any news ?

slavapestov commented 1 year ago

Not yet, sorry. Does the workaround of building with OTHER_SWIFT_FLAGS=-Xfrontend -requirement-machine-inferred-signatures=off work for you?

arshiacont commented 1 year ago

Not yet, sorry. Does the workaround of building with OTHER_SWIFT_FLAGS=-Xfrontend -requirement-machine-inferred-signatures=off work for you?

I confirm that the workaround works. We have production code using it.

ThomasD-WL commented 1 year ago

Not yet, sorry. Does the workaround of building with OTHER_SWIFT_FLAGS=-Xfrontend -requirement-machine-inferred-signatures=off work for you?

This workaround does not works for us. We still have this kind of errors with your OTHER_SWIFT_FLAGS value.

Cannot build interface type for term τ_0_1.[Setupable:SetupModel]
Prefix term does not not have a nested type named SetupModel: τ_0_1
Property map entry: τ_0_1 => { layout: AnyObject superclass: [superclass: FaqCell] }

Property map: {
  [BaseFAQViewModeling] => { conforms_to: [BaseFAQViewModeling ViewModelling DataSourced FeatureFlipping Featuring UserTyped] }
  [BaseFAQViewModeling:Section] => { conforms_to: [SectionModeling] layout: _NativeClass superclass: [superclass: FAQSectionModel] concrete_type: [concrete: FAQSectionModel] }
  [Setupable] => { conforms_to: [Setupable] }
  [ViewModelling] => { conforms_to: [ViewModelling FeatureFlipping Featuring UserTyped] }
  [DataSourced] => { conforms_to: [DataSourced] }
  [DataSourced:Section] => { conforms_to: [SectionModeling] }
  [FeatureFlipping] => { conforms_to: [FeatureFlipping] }
  [Featuring] => { conforms_to: [Featuring] }
  [UserTyped] => { conforms_to: [UserTyped] }
  [SectionModeling] => { conforms_to: [SectionModeling] }
  [SectionModeling:SectionHeaderModel] => { conforms_to: [Nullable] }
  [SectionModeling:SectionFooterModel] => { conforms_to: [Nullable] }
  [Nullable] => { conforms_to: [Nullable] }
  τ_0_0 => { conforms_to: [BaseFAQViewModeling ViewModelling DataSourced FeatureFlipping Featuring UserTyped] }
  τ_0_1 => { layout: AnyObject superclass: [superclass: FaqCell] }
  τ_0_2 => { conforms_to: [Setupable] layout: AnyObject superclass: [superclass: UIView] }
  [BaseFAQViewModeling:Section].[SectionModeling:SectionHeaderModel] => { conforms_to: [Nullable] layout: _NativeClass superclass: [superclass: StringSectionModel] concrete_type: [concrete: StringSectionModel] }
  [BaseFAQViewModeling:Section].[SectionModeling:SectionFooterModel] => { conforms_to: [Nullable] concrete_type: [concrete: EmptySectionModel] }
  [BaseFAQViewModeling:Section].[SectionModeling:CellModel] => { layout: _NativeClass superclass: [superclass: FaqCellModel] concrete_type: [concrete: FaqCellModel] }
  τ_0_1.[Setupable:SetupModel] => { layout: _NativeClass superclass: [superclass: FaqCellModel] concrete_type: [concrete: FaqCellModel] }
  τ_0_2.[Setupable:SetupModel] => { layout: _NativeClass superclass: [superclass: StringSectionModel] concrete_type: [concrete: StringSectionModel] }
}
slavapestov commented 1 year ago

@ThomasD-WL this looks like a different example judging by the protocol names in the debug output. Can you share a test case?

arshiacont commented 1 year ago

@slavapestov the existing workaround seems to be broken in XCode 14.3 ! The -requirement-machine-signature flag no longer exists... Any hints?!

AnthonyLatsis commented 1 year ago

the existing workaround seems to be broken in XCode 14.3

Because the old generics implementation was completely removed in 5.8. The best thing that comes to mind now that switching off the requirement machine is no longer an option is to locate the offending same-type constraint (T == T.RealmType.DomainType) and either (1) move it to a constructor (seems to work), or (2) replace it with a dynamic check until this issue is resolved. Hopefully Slava has a more seasoned suggestion.