Search code examples
swiftcompiler-bug

Swift EXC_BAD_INSTRUCTION on call to typealias / typed / defined closure w/o compiler error or warning


Given a struct, a class, and typed closure:

struct Vector3d {
    var X:Double
    var Y:Double
    var Z:Double
}

class Sprite {

    var mass: Double = 0.0

    init(mass: Double) {
        self.mass = mass
    }
}

typealias ForceComputation =
    (NSTimeInterval, Sprite) -> Vector3d?

The following code crashes with EXC_BAD_INSTRUCTION:

// Construct an instance of the class to call back with
var ball = Sprite(mass: 3.0)

// Create an instance of closure
var gravity:ForceComputation = { (projectile:Sprite) -> Vector3d in
    // use this line to close ball so it's available in debugger
    var mass1 = ball.mass

    // use mass1 in following line to ensure not optimized out
    // (ignore invalid gravity formula)
    var verticleAcceleration = -9.8 * projectile.mass * mass1

    return Vector3d(X:0.0, Y:verticleAcceleration, Z:0.0)
}

// activate the closure
gravity(ball)

The debugger shows two different values for projectile and ball. The field mass in projectile is invalid. However mass is valid for ball both inside and outside the closure. There are no compiler errors or warnings but EXC_BAD_INSTRUCTION is thrown when projectile.mass is executed?

Despite the misleading debug data, the problem has nothing to do with the parameter to the ForceComputation closure. The problem is the returned struct is defined as optional in the typealias:

typealias ForceComputation =
    (Sprite) -> Vector3d?

but constructed with a non-optional return type (note the lack of a ? after Vector3d):

// Create an instance of closure
var gravity:ForceComputation = { (projectile:Sprite) -> Vector3d in
    ....
}

Changing the above code to remove the typing:

// Create an instance of closure
var gravity = { (projectile:Sprite) -> Vector3d in
    ....
}

will fix the code or ensuring that the return type is optional (note ? after Vector3d):

// Create an instance of closure
var gravity:ForceComputation = { (projectile:Sprite) -> Vector3d? in
    ....
}

will also make this work. My question is if this is a compiler bug and should be reported to Apple or is there a reason the EXC_BAD_INSTRUCTION throwing code should compile?


Solution

  • This is a compiler bug (confirmed via Twitter here) but there are already a number of known issues around optional-ness to returns with Swift.