Swift/Xcode 6.1.1: Type inference & @autoclosure gone wrong

Originator:weissismail
Number:rdar://19510182 Date Originated:2015-01-17
Status:Open Resolved:
Product:Developer Tools Product Version:
Classification: Reproducible:always
 
Summary:
A specific instance of type inference and @autoclosure that produces a different and wrong output from the same program with a manually added type signature. The effect is as if a function parameter would be a plain normal value and wouldn't be @autoclosure at all.

More specifically: In the Swift program below (also attached as main.swift) the lines marked as [L2] and [L3] should have exactly the same effect as the are the same except that L2 has the additional type annotation "as Result<String>" which should not be needed. As expected, line L2 runs just fine and the constant x gets set to 'let x : Result<String> = Result.Failure(...)'. L3 however does evaluate the expression 'undefined()' which crashes the program. But it should not have evaluated 'undefined()' as it should be wrapped in an @autoclosure and the chain() function does not use the right argument in this case (because the first argument (failure) pattern matches the 'case .Failure(let f)' case in chain() ).

import Foundation

enum Result<T> {
    case Success(@autoclosure () -> T);
    case Failure(@autoclosure () -> NSError)
}

func undefined<T>(file:StaticString=__FILE__, line:UWord=__LINE__) -> T {
    fatalError("undefined", file:file, line:line)
}

func chain<L,R>(l : Result<L>, r : @autoclosure () -> Result<R>) -> Result<R> {
    switch(l) {
    case .Failure(let f):
        return .Failure(f())
    case .Success(let _):
        return r()
    }
}

func testEvaluation() {
    let error = NSError(domain: NSPOSIXErrorDomain, code: Int(ENOENT), userInfo: nil)
    let failure : Result<String> = .Failure(error)
    assert(true || undefined() as Bool) // [L1]: works
    let x : Result<String> = chain(failure, undefined() as Result<String>) // [L2]: works
    print("x = \(x)\n")
    let y : Result<String> = chain(failure, undefined()) // [L3]: CRASHES THE PROGRAM EVALUATING undefined()
    print("y = \(y)\n")
}

testEvaluation()

Steps to Reproduce:

1. Download the attached file main.swift
2. Compile and run it with "xcrun -sdk macosx swiftc main.swift && ./main"

Expected Results:

The output should be:

x = (Enum Value)
y = (Enum Value)

Actual Results:

The output is:

x = (Enum Value)
fatal error: undefined: file main.swift, line 27
Illegal instruction: 4

Regression:

n/a

Notes:

[1]: http://stackoverflow.com/questions/28004126/swift-autoclosure-evaluation-influenced-by-type-annotations-compiler-bug

Comments

Johannes Weiß 20-Jan-2015 11:04 AM

The type-inference seems to go wrong indeed an that seems to remove @autoclosure.

In L2 (changing 'chain(failure, undefined())' to 'chain(.Success(()), undefined())' the debugger shows

$swift.type.T Builtin.RawPointer TyDDSwift.Result

In L3 however

$swift.type.T Builtin.RawPointer () -> TyDDSwift.Result

so it inferred T as a closure instead of Result...

By weissismail at Jan. 20, 2015, 11:07 a.m. (reply...)

Johannes Weiß18-Jan-2015 00:12 AM

would be appreciated if you could mainly deal with rdar://19510188 || openradar.appspot.com/radar?id=4811986399395840 . I misfiled this issue here under my work account (johannes.weiss@bromium.com) but I would like it on my personal one (apple@tux4u.de). Many thanks, Johannes

By weissismail at Jan. 20, 2015, 11:07 a.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!