Cannot call type(of:) on mutating method

Currently, type(of:) cannot be called on a mutating method:

type(of: Bool.toggle)   // error: partial application of 'mutating' method is not allowed

However, if we wrap the function in a closure, then it can:

let toggle = { (x: inout Bool) in x.toggle() }
type(of: toggle)        // (inout Bool) -> ()

The same thing applies to instance-bound methods:

var x = true
let y = x.toggle        // error: partial application of 'mutating' method is not allowed
let z = { x.toggle() }  // works, capturing x

type(of: x.toggle)      // error: partial application of 'mutating' method is not allowed
type(of: z)             // () -> ()

Should we lift these restrictions and allow referencing a mutating method directly?

Your two snippets are not equivalent. The type of Bool.toggle, if you could reference it, would be (inout Bool) -> () -> (). Here the problem should be more apparent - the inout access has to “outlast” the call of the first closure since the second closure, of type () -> () has to capture the inout argument. This is not supported in the language.

We could lift this restriction specifically for the immediate operand of a type(of:), but that would be a bit weird. Note that type(of:) still evaluates it’s argument, so we’d still be generating and executing code that forms an invalid closure.

2 Likes

The very first example works just fine in Swift Playgrounds on iOS. Otherwise I would imagine that you could trick the compiler by casting the method reference to Any first.