Sunday, June 15, 2014

Crashity crash crash

As I've been going along trying to port itertools to Swift, I've gotten a lot of compiler crashes (see radar 5057608666841088 for details), which look like this:

teetest.swift:8:9: error: unimplemented IR generation feature non-fixed class layout
    var helper: TeeHelper<S, T>
        ^
LLVM ERROR: unimplemented IRGen feature! non-fixed class layout
retina:swift-itertools abarnert$ swift teetest.swift
0  swift                    0x00000001058b6608 llvm::sys::PrintStackTrace(__sFILE*) + 40
1  swift                    0x00000001058b6af4 SignalHandler(int) + 452
2  libsystem_platform.dylib 0x00007fff888b35aa _sigtramp + 26
3  swift                    0x0000000104d045e7 profileArchetypeConstraints(swift::Type, llvm::FoldingSetNodeID&, llvm::DenseMap<swift::ArchetypeType*, unsigned int, llvm::DenseMapInfo<swift::ArchetypeType*> >&, unsigned int) + 295
4  swift                    0x00000001057b31bf llvm::StoreInst::StoreInst(llvm::Value*, llvm::Value*, bool, llvm::Instruction*) + 63
5  swift                    0x0000000104d07e32 swift::irgen::IRBuilder::CreateStore(llvm::Value*, llvm::Value*, swift::irgen::Alignment) + 66
6  swift                    0x0000000104cc5b4c emitNominalMetadataRef(swift::irgen::IRGenFunction&, swift::NominalTypeDecl*, swift::CanType) + 1724
7  swift                    0x0000000104cb441c llvm::Value* swift::CanTypeVisitor<(anonymous namespace)::EmitTypeMetadataRef, llvm::Value*>::visit<>(swift::CanType) + 124
8  swift                    0x0000000104cb4395 swift::irgen::IRGenFunction::emitTypeMetadataRef(swift::CanType) + 21
9  swift                    0x0000000104cf76a4 swift::irgen::WitnessSizedTypeInfo<(anonymous namespace)::NonFixedStructTypeInfo>::getAlignmentMask(swift::irgen::IRGenFunction&, swift::CanType) const + 20
10 swift                    0x0000000104cae562 swift::irgen::HeapArrayInfo::getLayout(swift::irgen::IRGenFunction&) const + 226
11 swift                    0x0000000104cae938 swift::irgen::HeapArrayInfo::getPrivateMetadata(swift::irgen::IRGenModule&) const + 504
12 swift                    0x0000000104caf9a9 swift::irgen::HeapArrayInfo::emitUnmanagedAlloc(swift::irgen::IRGenFunction&, llvm::Value*, swift::irgen::Address&, llvm::Twine const&) const + 73
13 swift                    0x0000000104d23304 swift::SILVisitor<(anonymous namespace)::IRGenSILFunction, void>::visit(swift::ValueBase*) + 30884
14 swift                    0x0000000104d1b266 swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 8678
15 swift                    0x0000000104c9c6f8 swift::irgen::IRGenModule::emitGlobalTopLevel() + 184
16 swift                    0x0000000104d086e3 performIRGeneration(swift::IRGenOptions&, swift::Module*, swift::SILModule*, llvm::StringRef, llvm::LLVMContext&, swift::SourceFile*, unsigned int) + 1859
17 swift                    0x0000000104d09033 swift::performIRGeneration(swift::IRGenOptions&, swift::SourceFile&, swift::SILModule*, llvm::StringRef, llvm::LLVMContext&, unsigned int) + 51
18 swift                    0x0000000104c7b65a frontend_main(llvm::ArrayRef<char const*>, char const*, void*) + 4842
19 swift                    0x0000000104c7a35d main + 1533
20 libdyld.dylib            0x00007fff894c55fd start + 1
Stack dump:
0. Program arguments: /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -c -primary-file teetest.swift -enable-objc-attr-requires-objc-module -target x86_64-apple-darwin13.2.0 -module-name teetest -color-diagnostics -o /var/folders/gx/cs8knrj93rlc76rz7rg706dm0000gn/T/teetest-4b2ff9.o
1. While emitting IR SIL function @_TF7teetest3teeUSs8Sequence__USs9Generator__FTQ_1nSi_GSaGVS_3TeeQ_Q0___ for 'tee' at teetest.swift:30:1
<unknown>:0: error: unable to execute command: Segmentation fault: 11
<unknown>:0: error: swift frontend command failed due to signal (use -v to see invocation)
Apparently the compiler is trying to either infer or check my types, in this case in the tee function shown here:
struct TeeHelper<S: Sequence, T where T == S.GeneratorType.Element> {
    var gen: S.GeneratorType
    var queues: T[][]
}

struct Tee<S: Sequence, T where T == S.GeneratorType.Element>
        : Sequence, Generator {
    var helper: TeeHelper<S, T>
    var i: Int
    func generate() -> Tee<S, T> { return self }
    mutating func next() -> T? {
        return nil
        /*
        if helper.queues[i].isEmpty {
            if let val = helper.gen.next() {
                /* iterating over queues gives us immutable copies of each! */
                for i in 0..helper.queues.count {
                    helper.queues[i].append(val)
                }
            } else {
                return nil
            }
        }
        return helper.queues[i].removeAtIndex(0)
        */
    }
}

func tee<S: Sequence, T where T == S.GeneratorType.Element>
        (sequence: S, n: Int = 2) -> Tee<S, T>[] {
    return []
/*
    var gen = sequence.generate()
    var queues: T[][] = []
    var helper = TeeHelper<S, T>(gen: gen, queues: queues)
    var tees: Tee<S, T>[] = []
    for i in 0..n {
        tees.append(Tee(helper: helper, i: i))
        helper.queues.append([])
    }
    return tees
*/
}
Notice that I've commented out all the code that looks like it should matter.

When the functions are simple enough, I can often figure out what I've done wrong, or what I've done right that apparently doesn't work right but I can change easily, or what actually isn't possible if you think it through. (Most commonly, the fix is to replace a Sequence type with S, which is a generic type parameter that's restricted to Sequence but also has a where clause on it.)

But in this case, I'm baffled. Maybe I'm missing something stupid, but I don't see anything here that's any different from what I've done in a dozen other functions that all work, except for returning my Tee objects in an array. If you change the type of tee to Tee<S, T>? and return nil, the crash does go away, but why should it? Especially since I've stored Count, TakeWhile, etc. objects in arrays (even arrays of less exact types, like the Generator protocol) with no problem. (Anyway, that obviously wouldn't be a solution here; the whole point of tee is to return n separate generators…)

If I change the tee function to return a Generator[] or Sequence[] instead of an array of my specific type, the compiler crash goes away, but then you can't actually use the values. The error message when you try is misleading: "could not find member 'next'" (or 'generate'). As far as I can tell, the problem is that protocols that have associated types can't be used to call any methods (or access any values) that refer to those associated types, unless you've bound them somehow in the local (generic) type or function. (Which seems to be a pretty serious problem in its own right, assuming they actually intended protocols to be as usable as ObjC protocols, Java interfaces, etc.—as in things you can store, pass around, and actually call methods on… But let's ignore that.)

It may or may not be relevant that changing either struct to a class (for Tee of course you also need to remove the mutable keyword on next and add an explicit initializer) replaces the compiler crash with a compiler data error ("unimplemented IR generation feature non-fixed class layout"), both in this case and in most of the other crashes I've been before.

I could deal with any one of incomplete documentation, an incomplete standard library, or a buggy compiler that crashes on me, but all three at once is starting to make this seem like a fool's errand.

No comments:

Post a Comment