Drux
Drux

Reputation: 12670

Swift compiler crashes: Illegal instruction: 4, non-canonical or unchecked type

The Swift compiler (Xcode 7.0 beta 5) crashes with "Illegal instruction: 4", "non-canonical or unchecked type" when fed this specific source line (inside a larger piece of code):

let z = y.filter() { (_, x) in x.type == .A(_) }

The elements of y are tuples. Their first elements extend NSObject. Their second elements have a property type, which is an enumeration that includes A(Int).

Is there an (obvious) mistake in my code?

UPDATE If I attempt this work-around I run into errors "Use of unresolved identifier 'x'" in the lines that contain if and append respectively:

var z = []
for (_, x: X) in y {
    if x.type == .A(_) {
        z.append((_, x))
    }
}

Again, is there an (obvious) mistake in this code?

Upvotes: 0

Views: 259

Answers (1)

zrzka
zrzka

Reputation: 21259

let z = y.filter() { (_, x) in x.type == .A(_) }

If your array is array of tuples, as you wrote, closure signature is ...

(t) -> Bool

... where t is your tuple and Bool is return value. If true is returned, t is included in result otherwise it's not. You have to access elements of your tuple with t.0 and t.1.

for (_, x: X) in y {
    if x.type == .A(_) {
        z.append((_, x))
    }
}

It's not possible to check .type with == .A like you do. Also you're saying that you're not interested in first elements of your tuples (_ in for ... in loop) and later you're trying to use first element with _, which is not going to work as well.


Let's define some types first ...

enum MyType {
  case A(Int)
  case B(Float)
}

class Dummy: NSObject {}

class DummyValue {
  var type: MyType

  init(_ type: MyType) {
    self.type = type
  }
}

... and now some DummyValue ...

let dv = DummyValue(.A(1))

You're trying to check type with ...

if dv.type == .A(_) { ... }

... which is not going to work. You can use switch ...

switch dv.type {
  case .A(_): print(".A")
  default: print("Other")
}

... or pattern matching with if & case ...

if case .A(_) = dv.type {
  print(".A")
}

Let's transform your for in loop to a working form ...

let y = [
  (Dummy(), DummyValue(.A(1))),
  (Dummy(), DummyValue(.B(3.0))),
  (Dummy(), DummyValue(.A(2)))
]

var z = [(Dummy,DummyValue)]()
for (a, b) in y {
  if case .A(_) = b.type {
    z.append((a,b))
  }
}

print(z.count) // Output = 2

It's not nice and we don't want to have if case ... or switch ... in our filter ...

z = y.filter { if case .A(_) = $0.1.type { return true }; return false }

... so, we can extend MyType with computed property isA ...

extension MyType {
  var isA: Bool {
    switch self {
      case .A(_): return true
      default: return false
    }
  }
}

... and transform filter into this simple form ...

z = y.filter { $0.1.type.isA }

I can dream of nicer solution, but since there're still some limitations in pattern matching in current beta ... :-)

Upvotes: 1

Related Questions