Merge remote-tracking branch 'origin/master' into swift-4.0-branch
diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
index d6d28ff..c1e3610 100644
--- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
+++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
@@ -254,6 +254,8 @@
 
 CF_EXPORT void _CFRuntimeBridgeTypeToClass(CFTypeID type, const void *isa);
 
+CF_EXPORT CFNumberType _CFNumberGetType2(CFNumberRef number);
+
 typedef	unsigned char __cf_uuid[16];
 typedef	char __cf_uuid_string[37];
 typedef __cf_uuid _cf_uuid_t;
diff --git a/Foundation/JSONEncoder.swift b/Foundation/JSONEncoder.swift
index 6ab18a3..59a3844 100644
--- a/Foundation/JSONEncoder.swift
+++ b/Foundation/JSONEncoder.swift
@@ -10,6 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+import CoreFoundation
+
 //===----------------------------------------------------------------------===//
 // JSON Encoder
 //===----------------------------------------------------------------------===//
@@ -1742,7 +1744,7 @@
         }
 
         // TODO: Add a flag to coerce non-boolean numbers into Bools?
-        guard number._objCType == .Bool else {
+        guard number._cfTypeID == CFBooleanGetTypeID() else {
             throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
         }
 
diff --git a/Foundation/NSCFBoolean.swift b/Foundation/NSCFBoolean.swift
index 90e223b..23577ff 100644
--- a/Foundation/NSCFBoolean.swift
+++ b/Foundation/NSCFBoolean.swift
@@ -78,7 +78,10 @@
     override var objCType: UnsafePointer<Int8> {
         // This must never be fixed to be "B", although that would
         // cause correct old-style archiving when this is unarchived.
-        return UnsafePointer<Int8>(bitPattern: UInt(_NSSimpleObjCType.Char.rawValue.value))!
+        func _objCType(_ staticString: StaticString) -> UnsafePointer<Int8> {
+            return UnsafeRawPointer(staticString.utf8Start).assumingMemoryBound(to: Int8.self)
+        }
+        return _objCType("c")
     }
     
     internal override func _cfNumberType() -> CFNumberType  {
diff --git a/Foundation/NSJSONSerialization.swift b/Foundation/NSJSONSerialization.swift
index ebc7bea..1518b79 100644
--- a/Foundation/NSJSONSerialization.swift
+++ b/Foundation/NSJSONSerialization.swift
@@ -459,8 +459,8 @@
             throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "Number cannot be infinity or NaN"])
         }
         
-        switch num._objCType {
-        case .Bool:
+        switch num._cfTypeID {
+        case CFBooleanGetTypeID():
             serializeBool(num.boolValue)
         default:
             writer(_serializationString(for: num))
diff --git a/Foundation/NSKeyedUnarchiver.swift b/Foundation/NSKeyedUnarchiver.swift
index 47fc2f8..b977cc8 100644
--- a/Foundation/NSKeyedUnarchiver.swift
+++ b/Foundation/NSKeyedUnarchiver.swift
@@ -683,10 +683,10 @@
     }
     
     open override func decodeBool(forKey key: String) -> Bool {
-        guard let result : NSNumber = _decodeValue(forKey: key) else {
+        guard let result : Bool = _decodeValue(forKey: key) else {
             return false
         }
-        return result.boolValue
+        return result
     }
     
     open override func decodeInt32(forKey key: String) -> Int32 {
diff --git a/Foundation/NSNumber.swift b/Foundation/NSNumber.swift
index 5cc73a6..c1a712f 100644
--- a/Foundation/NSNumber.swift
+++ b/Foundation/NSNumber.swift
@@ -198,14 +198,17 @@
 
 }
 
+private struct CFSInt128Struct {
+    var high: Int64
+    var low: UInt64
+}
+
 open class NSNumber : NSValue {
     typealias CFType = CFNumber
     // This layout MUST be the same as CFNumber so that they are bridgeable
     private var _base = _CFInfo(typeID: CFNumberGetTypeID())
     private var _pad: UInt64 = 0
 
-    internal let _objCType: _NSSimpleObjCType
-
     internal var _cfObject: CFType {
         return unsafeBitCast(self, to: CFType.self)
     }
@@ -230,93 +233,123 @@
     }
 
     open override var objCType: UnsafePointer<Int8> {
-        return UnsafePointer<Int8>(bitPattern: UInt(_objCType.rawValue.value))!
+        func _objCType(_ staticString: StaticString) -> UnsafePointer<Int8> {
+            return UnsafeRawPointer(staticString.utf8Start).assumingMemoryBound(to: Int8.self)
+        }
+        let numberType = _CFNumberGetType2(_cfObject)
+        switch numberType {
+        case kCFNumberSInt8Type:
+            return _objCType("c")
+        case kCFNumberSInt16Type:
+            return _objCType("s")
+        case kCFNumberSInt32Type:
+            return _objCType("i")
+        case kCFNumberSInt64Type:
+            return _objCType("q")
+        case kCFNumberFloat32Type:
+            return _objCType("f")
+        case kCFNumberFloat64Type:
+            return _objCType("d")
+        case kCFNumberSInt128Type:
+            return _objCType("Q")
+        default:
+            fatalError("unsupported CFNumberType: '\(numberType)'")
+        }
     }
     
     deinit {
         _CFDeinit(self)
     }
     
-    public init(value: Int8) {
-        _objCType = .Char
-        super.init()
-        _CFNumberInitInt8(_cfObject, value)
+    private convenience init(bytes: UnsafeRawPointer, numberType: CFNumberType) {
+        let cfnumber = CFNumberCreate(nil, numberType, bytes)
+        self.init(factory: { unsafeBitCast(cfnumber, to: NSNumber.self) })
     }
     
-    public init(value: UInt8) {
-        _objCType = .UChar
-        super.init()
-        _CFNumberInitUInt8(_cfObject, value)
+    public convenience init(value: Int8) {
+        var value = value
+        self.init(bytes: &value, numberType: kCFNumberSInt8Type)
     }
     
-    public init(value: Int16) {
-        _objCType = .Short
-        super.init()
-        _CFNumberInitInt16(_cfObject, value)
+    public convenience init(value: UInt8) {
+        var value = Int16(value)
+        self.init(bytes: &value, numberType: kCFNumberSInt16Type)
     }
     
-    public init(value: UInt16) {
-        _objCType = .UShort
-        super.init()
-        _CFNumberInitUInt16(_cfObject, value)
+    public convenience init(value: Int16) {
+        var value = value
+        self.init(bytes: &value, numberType: kCFNumberSInt16Type)
     }
     
-    public init(value: Int32) {
-        _objCType = .Long
-        super.init()
-        _CFNumberInitInt32(_cfObject, value)
+    public convenience init(value: UInt16) {
+        var value = Int32(value)
+        self.init(bytes: &value, numberType: kCFNumberSInt32Type)
     }
     
-    public init(value: UInt32) {
-        _objCType = .ULong
-        super.init()
-        _CFNumberInitUInt32(_cfObject, value)
+    public convenience init(value: Int32) {
+        var value = value
+        self.init(bytes: &value, numberType: kCFNumberSInt32Type)
     }
     
-    public init(value: Int) {
-        _objCType = .Int
-        super.init()
-        _CFNumberInitInt(_cfObject, value)
+    public convenience init(value: UInt32) {
+        var value = Int64(value)
+        self.init(bytes: &value, numberType: kCFNumberSInt64Type)
     }
     
-    public init(value: UInt) {
-        _objCType = .UInt
-        super.init()
-        _CFNumberInitUInt(_cfObject, value)
+    public convenience init(value: Int) {
+        var value = value
+        #if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
+            self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+        #elseif arch(i386) || arch(arm)
+            self.init(bytes: &value, numberType: kCFNumberSInt32Type)
+        #endif
     }
     
-    public init(value: Int64) {
-        _objCType = .LongLong
-        super.init()
-        _CFNumberInitInt64(_cfObject, value)
+    public convenience init(value: UInt) {
+    #if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
+        if value > UInt64(Int64.max) {
+            var value = CFSInt128Struct(high: 0, low: UInt64(value))
+            self.init(bytes: &value, numberType: kCFNumberSInt128Type)
+        } else {
+            var value = Int64(value)
+            self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+        }
+    #elseif arch(i386) || arch(arm)
+        var value = Int64(value)
+        self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+    #endif
     }
     
-    public init(value: UInt64) {
-        _objCType = .ULongLong
-        super.init()
-        _CFNumberInitUInt64(_cfObject, value)
+    public convenience init(value: Int64) {
+        var value = value
+        self.init(bytes: &value, numberType: kCFNumberSInt64Type)
     }
     
-    public init(value: Float) {
-        _objCType = .Float
-        super.init()
-        _CFNumberInitFloat(_cfObject, value)
+    public convenience init(value: UInt64) {
+        if value > UInt64(Int64.max) {
+            var value = CFSInt128Struct(high: 0, low: UInt64(value))
+            self.init(bytes: &value, numberType: kCFNumberSInt128Type)
+        } else {
+            var value = Int64(value)
+            self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+        }
     }
     
-    public init(value: Double) {
-        _objCType = .Double
-        super.init()
-        _CFNumberInitDouble(_cfObject, value)
+    public convenience init(value: Float) {
+        var value = value
+        self.init(bytes: &value, numberType: kCFNumberFloatType)
     }
     
-    public init(value: Bool) {
-        _objCType = .Bool
-        super.init()
-        _CFNumberInitBool(_cfObject, value)
+    public convenience init(value: Double) {
+        var value = value
+        self.init(bytes: &value, numberType: kCFNumberDoubleType)
+    }
+
+    public convenience init(value: Bool) {
+        self.init(factory: value._bridgeToObjectiveC)
     }
 
     override internal init() {
-        _objCType = .Undef
         super.init()
     }
 
@@ -381,83 +414,63 @@
     }
 
     open var int8Value: Int8 {
-        var val: Int8 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int8>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberCharType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
 
     open var uint8Value: UInt8 {
-        var val: UInt8 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt8>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberCharType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
     
     open var int16Value: Int16 {
-        var val: Int16 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int16>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberShortType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
     
     open var uint16Value: UInt16 {
-        var val: UInt16 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt16>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberShortType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
     
     open var int32Value: Int32 {
-        var val: Int32 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int32>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberIntType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
     
     open var uint32Value: UInt32 {
-        var val: UInt32 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt32>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberIntType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
     
     open var int64Value: Int64 {
-        var val: Int64 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int64>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberLongLongType, value)
-        }
-        return val
+        var value: Int64 = 0
+        CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+        return .init(extendingOrTruncating: value)
     }
     
     open var uint64Value: UInt64 {
-        var val: UInt64 = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt64>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberLongLongType, value)
-        }
-        return val
+        var value = CFSInt128Struct(high: 0, low: 0)
+        CFNumberGetValue(_cfObject, kCFNumberSInt128Type, &value)
+        return .init(extendingOrTruncating: value.low)
     }
     
     open var floatValue: Float {
-        var val: Float = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Float>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberFloatType, value)
-        }
-        return val
+        var value: Float = 0
+        CFNumberGetValue(_cfObject, kCFNumberFloatType, &value)
+        return value
     }
     
     open var doubleValue: Double {
-        var val: Double = 0
-        withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Double>) -> Void in
-            CFNumberGetValue(_cfObject, kCFNumberDoubleType, value)
-        }
-        return val
+        var value: Double = 0
+        CFNumberGetValue(_cfObject, kCFNumberDoubleType, &value)
+        return value
     }
     
     open var boolValue: Bool {
@@ -503,7 +516,24 @@
     }
 
     open func compare(_ otherNumber: NSNumber) -> ComparisonResult {
-        return ._fromCF(CFNumberCompare(_cfObject, otherNumber._cfObject, nil))
+        switch (objCType.pointee, otherNumber.objCType.pointee) {
+        case (0x66, _), (_, 0x66), (0x66, 0x66): fallthrough // 'f' float
+        case (0x64, _), (_, 0x64), (0x64, 0x64):             // 'd' double
+            let (lhs, rhs) = (doubleValue, otherNumber.doubleValue)
+            if lhs < rhs { return .orderedAscending }
+            if lhs > rhs { return .orderedDescending }
+            return .orderedSame
+        case (0x51, _), (_, 0x51), (0x51, 0x51):             // 'q' unsigned long long
+            let (lhs, rhs) = (uint64Value, otherNumber.uint64Value)
+            if lhs < rhs { return .orderedAscending }
+            if lhs > rhs { return .orderedDescending }
+            return .orderedSame
+        case (_, _):
+            let (lhs, rhs) = (int64Value, otherNumber.int64Value)
+            if lhs < rhs { return .orderedAscending }
+            if lhs > rhs { return .orderedDescending }
+            return .orderedSame
+        }
     }
 
     open func description(withLocale locale: Locale?) -> String {
@@ -612,7 +642,7 @@
             }
         }
     }
-    
+
     open override var classForCoder: AnyClass { return NSNumber.self }
 }
 
diff --git a/Foundation/NSValue.swift b/Foundation/NSValue.swift
index 6b255d0..3971b21 100644
--- a/Foundation/NSValue.swift
+++ b/Foundation/NSValue.swift
@@ -154,3 +154,14 @@
     }
 }
 
+extension NSValue : _Factory {}
+
+internal protocol _Factory {
+    init(factory: () -> Self)
+}
+
+extension _Factory {
+    init(factory: () -> Self) {
+        self = factory()
+    }
+}
diff --git a/TestFoundation/TestNSNumber.swift b/TestFoundation/TestNSNumber.swift
index 62e16c9..d3ddde8 100644
--- a/TestFoundation/TestNSNumber.swift
+++ b/TestFoundation/TestNSNumber.swift
@@ -21,6 +21,7 @@
     static var allTests: [(String, (TestNSNumber) -> () throws -> Void)] {
         return [
             ("test_NumberWithBool", test_NumberWithBool ),
+            ("test_CFBoolean", test_CFBoolean ),
             ("test_numberWithChar", test_numberWithChar ),
             ("test_numberWithUnsignedChar", test_numberWithUnsignedChar ),
             ("test_numberWithShort", test_numberWithShort ),
@@ -41,6 +42,7 @@
             ("test_compareNumberWithDouble", test_compareNumberWithDouble ),
             ("test_description", test_description ),
             ("test_descriptionWithLocale", test_descriptionWithLocale ),
+            ("test_objCType", test_objCType ),
         ]
     }
     
@@ -977,4 +979,44 @@
             XCTAssertEqual(receivedDesc, expectedDesc, "expected \(expectedDesc) but received \(receivedDesc)")
         }
     }
+
+    func test_objCType() {
+        let objCType: (NSNumber) -> UnicodeScalar = { number in
+            return UnicodeScalar(UInt8(number.objCType.pointee))
+        }
+
+        XCTAssertEqual("c" /* 0x63 */, objCType(NSNumber(value: true)))
+
+        XCTAssertEqual("c" /* 0x63 */, objCType(NSNumber(value: Int8.max)))
+        XCTAssertEqual("s" /* 0x73 */, objCType(NSNumber(value: UInt8(Int8.max))))
+        XCTAssertEqual("s" /* 0x73 */, objCType(NSNumber(value: UInt8(Int8.max) + 1)))
+
+        XCTAssertEqual("s" /* 0x73 */, objCType(NSNumber(value: Int16.max)))
+        XCTAssertEqual("i" /* 0x69 */, objCType(NSNumber(value: UInt16(Int16.max))))
+        XCTAssertEqual("i" /* 0x69 */, objCType(NSNumber(value: UInt16(Int16.max) + 1)))
+
+        XCTAssertEqual("i" /* 0x69 */, objCType(NSNumber(value: Int32.max)))
+        XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt32(Int32.max))))
+        XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt32(Int32.max) + 1)))
+
+        XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: Int64.max)))
+        // When value is lower equal to `Int64.max`, it returns 'q' even if using `UInt64`
+        XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt64(Int64.max))))
+        XCTAssertEqual("Q" /* 0x51 */, objCType(NSNumber(value: UInt64(Int64.max) + 1)))
+
+        // Depends on architectures
+        #if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
+            XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: Int.max)))
+            // When value is lower equal to `Int.max`, it returns 'q' even if using `UInt`
+            XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt(Int.max))))
+            XCTAssertEqual("Q" /* 0x51 */, objCType(NSNumber(value: UInt(Int.max) + 1)))
+        #elseif arch(i386) || arch(arm)
+            XCTAssertEqual("i" /* 0x71 */, objCType(NSNumber(value: Int.max)))
+            XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt(Int.max))))
+            XCTAssertEqual("q" /* 0x51 */, objCType(NSNumber(value: UInt(Int.max) + 1)))
+        #endif
+
+        XCTAssertEqual("f" /* 0x66 */, objCType(NSNumber(value: Float.greatestFiniteMagnitude)))
+        XCTAssertEqual("d" /* 0x64 */, objCType(NSNumber(value: Double.greatestFiniteMagnitude)))
+    }
 }
diff --git a/TestFoundation/TestNSPredicate.swift b/TestFoundation/TestNSPredicate.swift
index 641d605..4e88e33 100644
--- a/TestFoundation/TestNSPredicate.swift
+++ b/TestFoundation/TestNSPredicate.swift
@@ -101,6 +101,9 @@
         let predicateA = NSPredicate(value: true)
         let predicateB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: predicateA)) as! NSPredicate
         XCTAssertEqual(predicateA, predicateB, "Archived then unarchived uuid must be equal.")
+        let predicateC = NSPredicate(value: false)
+        let predicateD = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: predicateC)) as! NSPredicate
+        XCTAssertEqual(predicateC, predicateD, "Archived then unarchived uuid must be equal.")
     }
     
     func test_copy() {