Typechecker erroneously ignores non-optional return types in Generic Functions

Originator:lomax.lawrence
Number:rdar://18016157 Date Originated:14-Aug-2014
Status:Open Resolved:
Product:Swift Product Version:Xcode 6 Beta 5
Classification:Bug Reproducible:Yes
 
I believe I've found an issue with the application of Functions in the case of return values from Floating and Double Precision return types. As I was working with Higher-Order functions to produce a typesafe parser using Tagged Enums & Generics, I was finding that parsing of Double and Floating Point values would result in garbage values.

The attatched project will build on its own and has Unit Tests to verify the behaviour of the parsing, I've placed some additional print messages in order to show where the garbage value is introduced. Versions of the Bind and Fmap operators are used to chain Optional and Result (Value v | Error e) values together. The project uses the swiftz library for definitions of these fundemental functional operators.

The project has decode functions for Model objects, from a JSON enum tree. When parsing JSON number values I found that I wasn't getting the output I expected, so I broke the problem down into statements of linked expressions with logged output:

// Number is an NSNumber? as each apply of the bind operator could yield a .None value
let number = ((json >>= JSON.ParseValue("number")) >>= JSON.ParseNumber)
let forcedNumber: NSNumber! = number

let double = NSNumber.ParseDouble(forcedNumber)
let fMapDouble = NSNumber.ParseDouble <^> number
let bindDouble = number >>= NSNumber.ParseDouble //This should result in a compiler error as NSNumber.ParseDouble does not return an Optional value.
let appliedDouble = forcedNumber |> NSNumber.ParseDouble
println("Double \(double) fMap \(fMapDouble) bind \(bindDouble) applied \(appliedDouble)")

let float = NSNumber.ParseFloat(forcedNumber)
let fMapFloat = NSNumber.ParseFloat <^> number
let bindFloat = number >>= NSNumber.ParseFloat
let appliedFloat = forcedNumber |> NSNumber.ParseFloat
println("Float \(float) fMap \(fMapFloat) bind \(bindFloat) applied \(appliedFloat)")

let integer = NSNumber.ParseInt(forcedNumber)
let fMapInteger = NSNumber.ParseInt <^> number
let bindInteger = number >>= NSNumber.ParseInt
let appliedInteger = forcedNumber |> NSNumber.ParseInt
println("Integer \(integer) fMap \(fMapInteger) bind \(bindInteger) applied \(appliedInteger)")s

The Log Output shows
Double 1231.0 fMap 1231.0 bind 4.94065645841247e-324 applied 1231.0
Float 1231.0 fMap 1231.0 bind 1.40129846432482e-45 applied 1231.0
Integer 1231 fMap 1231 bind 1231 applied 1231

The Bind (>>=) operator is used to return the value of a function that returns an Optional Value, with an Unboxed Optional input, this makes it very suitable for chaining functions that may return Optional Values from a non-optional input. The definition for the overloaded bund function that the compiler is matching against and executing is:

public func >>=<A, B>(a: A?, f: A -> B?) -> B?

However, the ParseDouble/Int/Float functions do not have a non-optional output, so the typechecker should not permit the use of this function. Using fmap (<^>) and apply/thrush (|>) are suitable for use with functions that return non-

Steps to Reproduce:
1. Run the Unit Test Target in the Sample project
2. Observe the output of the Compiler and Logger for ComplexModel.decode

Expected Results:
The compiler to error when applying a function that expects an optional return type, to a function with a non-optional return type.

Actual Results:
The compiler allows mixing of optional and non-optional types, resulting in garbage values for Floating Point & Double Precision values, but correct values for Integers.

Version:
OS X 10.9.4

Notes:


Configuration:
Xcode 6 Beta 5 on a Retina MBP

Attachments:

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!