ReactiveX / RxSwift

Reactive Programming in Swift

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Found a bug when using keypath as function feature of Swift.

OriTheElf opened this issue · comments

commented

Short description of the issue:

I wrote en extension of Reactive, here is the code:

extension UITableView {
	
    var numberOfRows: Int {
        (0..<numberOfSections).reduce(0) { rowCount, section in
            rowCount + numberOfRows(inSection: section)
        }
    }
}
extension ObservableConvertibleType where Element: Collection {
    
    var ifEmptyEmitNil: Observable<Element?> {
        asObservable()
            .map { collection in
                if collection.isEmpty { return nil }
                return collection
            }
    }
}
extension Reactive where Base: UITableView {
    
    var isAllRowsSelected: Observable<Bool> {
        didReloadData
            .flatMapLatest(\.rx.latestSelectedIndexPaths)
            .ifEmptyEmitNil
            .withUnretained(base)
            .map { table, selectedIndexPaths in
                guard let selectedIndexPaths else { return false }
                return selectedIndexPaths.count == table.numberOfRows
            }
    }
    
    var selectedIndexPaths: Observable<[IndexPath]> {
        willReloadData.flatMapLatest(\.rx.latestSelectedIndexPaths)
    }
    
    var didReloadData: Observable<Base> {
        methodInvoked(#selector(UITableView.reloadData))
            .withUnretained(base)
            .map(\.0)
    }
    
    var willReloadData: Observable<Base> {
        sentMessage(#selector(UITableView.reloadData))
            .withUnretained(base)
            .map(\.0)
    }
    
    fileprivate var latestSelectedIndexPaths: Observable<[IndexPath]> {
        rowSelectionChanged
            .withUnretained(base)
            .map { tableview, _ in
                tableview.indexPathsForSelectedRows ?? []
            }
            .startWith(base.indexPathsForSelectedRows ?? [])
    }
    
    private var rowSelectionChanged: Observable<IndexPath> {
        Observable.of(selectRowAt, itemSelected.asObservable(), itemDeselected.asObservable()).merge()
    }
    
    private var selectRowAt: Observable<IndexPath> {
        base.rx.methodInvoked(#selector(UITableView.selectRow(at:animated:scrollPosition:)))
            .map(\.first)
            .compactMap { $0 }
            .as(IndexPath.self)
    }
}

the code above buit with error:

  1. While evaluating request IRGenRequest(IR Generation for file "/Users/choi/Developer/zeniko/zeniko/Source/Vendors/Playground/RxPlayground/RxExtensions/UITableView+Rx.swift")
  2. While emitting IR SIL function "@$s7RxSwift8ReactiveV6zenikoSo11UITableViewCRbzlE17isAllRowsSelectedAA10ObservableCySbGvg".
    for getter for isAllRowsSelected (at /Users/choi/Developer/zeniko/zeniko/Source/Vendors/Playground/RxPlayground/RxExtensions/UITableView+Rx.swift:20:9)
    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 0x00000001058567f7 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 39
    1 swift-frontend 0x0000000105855828 llvm::sys::RunSignalHandlers() + 248
    2 swift-frontend 0x0000000105856e10 SignalHandler(int) + 288
    3 libsystem_platform.dylib 0x00007ff8055a6dfd _sigtramp + 29
    4 libsystem_platform.dylib 0x0000000000010101 _sigtramp + 18446603370491188001
    5 libsystem_c.dylib 0x00007ff8054dcd24 abort + 123
    6 swift-frontend 0x0000000101995a4f swift::rewriting::RequirementMachine::getConformanceAccessPath(swift::Type, swift::ProtocolDecl*) + 2975
    7 swift-frontend 0x000000010172f3de swift::Mangle::ASTMangler::appendAnyProtocolConformance(swift::GenericSignature, swift::CanType, swift::ProtocolConformanceRef) + 222
    8 swift-frontend 0x0000000100887fda swift::irgen::IRGenMangler::mangleSymbolNameForMangledConformanceAccessorString(char const*, swift::CanGenericSignature, swift::CanType, swift::ProtocolConformanceRef) + 202
    9 swift-frontend 0x000000010081af69 swift::irgen::IRGenModule::emitWitnessTableRefString(swift::CanType, swift::ProtocolConformanceRef, swift::GenericSignature, bool) + 553
    10 swift-frontend 0x00000001007cf10e void llvm::function_ref<void (swift::irgen::GenericRequirement)>::callback_fn<emitKeyPathComponent(swift::irgen::IRGenModule&, swift::irgen::ConstantStructBuilder&, swift::KeyPathPatternComponent const&, bool, swift::GenericEnvironment*, llvm::ArrayRefswift::irgen::GenericRequirement, swift::CanType, llvm::ArrayRef, bool)::$_5>(long, swift::irgen::GenericRequirement) + 382
    11 swift-frontend 0x000000010080a86f swift::irgen::enumerateGenericSignatureRequirements(swift::CanGenericSignature, llvm::function_ref<void (swift::irgen::GenericRequirement)> const&) + 415
    12 swift-frontend 0x00000001007c8e8e emitKeyPathComponent(swift::irgen::IRGenModule&, swift::irgen::ConstantStructBuilder&, swift::KeyPathPatternComponent const&, bool, swift::GenericEnvironment*, llvm::ArrayRefswift::irgen::GenericRequirement, swift::CanType, llvm::ArrayRef, bool) + 1358
    13 swift-frontend 0x00000001007c8329 swift::irgen::IRGenModule::getAddrOfKeyPathPattern(swift::KeyPathPattern*, swift::SILLocation) + 2201
    14 swift-frontend 0x000000010089be83 swift::SILInstructionVisitor<(anonymous namespace)::IRGenSILFunction, void>::visit(swift::SILInstruction*) + 7587
    15 swift-frontend 0x00000001008950e2 swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 10706
    16 swift-frontend 0x000000010073c257 swift::irgen::IRGenerator::emitGlobalTopLevel(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator > > > const&) + 1623
    17 swift-frontend 0x00000001008618a0 swift::IRGenRequest::evaluate(swift::Evaluator&, swift::IRGenDescriptor) const + 10272
    18 swift-frontend 0x00000001008923ec swift::SimpleRequest<swift::IRGenRequest, swift::GeneratedModule (swift::IRGenDescriptor), (swift::RequestFlags)9>::evaluateRequest(swift::IRGenRequest const&, swift::Evaluator&) + 204
    19 swift-frontend 0x000000010086c740 llvm::Expectedswift::IRGenRequest::OutputType swift::Evaluator::getResultUncachedswift::IRGenRequest(swift::IRGenRequest const&) + 832
    20 swift-frontend 0x0000000100865fcc swift::performIRGeneration(swift::FileUnit*, swift::IRGenOptions const&, swift::TBDGenOptions const&, std::__1::unique_ptr<swift::SILModule, std::__1::default_deleteswift::SILModule >, llvm::StringRef, swift::PrimarySpecificPaths const&, llvm::StringRef, llvm::GlobalVariable**) + 348
    21 swift-frontend 0x0000000100413c5b performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_deleteswift::SILModule >, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 2539
    22 swift-frontend 0x00000001004159b5 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 5701
    23 swift-frontend 0x00000001003ab8ea swift::mainEntry(int, char const**) + 3082
    24 dyld 0x000000011273952e start + 462

I have to write another extension for UITableView:

extension UITableView {

    var latestSelectedIndexPaths: Observable<[IndexPath]> {
        rx.latestSelectedIndexPaths
    }
}

and remove the .rx part in the computed properties:

var isAllRowsSelected: Observable<Bool> {
    didReloadData
        .flatMapLatest(\.latestSelectedIndexPaths)
        .ifEmptyEmitNil
        .withUnretained(base)
        .map { table, selectedIndexPaths in
            guard let selectedIndexPaths else { return false }
            return selectedIndexPaths.count == table.numberOfRows
        }
}

var selectedIndexPaths: Observable<[IndexPath]> {
    willReloadData.flatMapLatest(\.latestSelectedIndexPaths)
}

then the code builds.

Expected outcome:

Code build without error.

What actually happens:

Code build with error.

RxSwift/RxCocoa/RxBlocking/RxTest version/commit

RxCocoa (6.5.0):
- RxRelay (= 6.5.0)
- RxSwift (= 6.5.0)

  • RxRelay (6.5.0):
    • RxSwift (= 6.5.0)
  • RxSwift (6.5.0)

Platform/Environment

  • iOS
  • macOS
  • tvOS
  • watchOS
  • playgrounds

How easy is to reproduce? (chances of successful reproduce after running the self contained code)

  • easy, 100% repro
  • sometimes, 10%-100%
  • hard, 2% - 10%
  • extremely hard, %0 - 2%

Xcode version:

Xcode 14.0.1

commented

I'm not sure if it is a RxSwift bug, maybe it has something to do with the compiler, hoping to get some help.😊

Hey, based on the failure it seems like a Swift compiler issue which isn't something we can help with unfortunately :(