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
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!
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...
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