Skip to content

Commit d933bbd

Browse files
committed
NSNumber already preserves whether a value was originally boolean.
Use that instead of rolling it up in _SwiftTypePreservingNSNumber so that we get the right behavior when we go to write plists. https://bugs.swift.org/browse/SR-2381
1 parent 73dbfcb commit d933bbd

File tree

3 files changed

+29
-23
lines changed

3 files changed

+29
-23
lines changed

stdlib/public/SDK/Foundation/Foundation.swift

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,6 @@ internal func _swift_Foundation_TypePreservingNSNumberWithCGFloat(
158158
_ value: CGFloat
159159
) -> NSNumber
160160

161-
@_silgen_name("_swift_Foundation_TypePreservingNSNumberWithBool")
162-
internal func _swift_Foundation_TypePreservingNSNumberWithBool(
163-
_ value: Bool
164-
) -> NSNumber
165-
166161
@_silgen_name("_swift_Foundation_TypePreservingNSNumberGetKind")
167162
internal func _swift_Foundation_TypePreservingNSNumberGetKind(
168163
_ value: NSNumber
@@ -204,11 +199,6 @@ internal func _swift_Foundation_TypePreservingNSNumberGetAsCGFloat(
204199
_ value: NSNumber
205200
) -> CGFloat
206201

207-
@_silgen_name("_swift_Foundation_TypePreservingNSNumberGetAsBool")
208-
internal func _swift_Foundation_TypePreservingNSNumberGetAsBool(
209-
_ value: NSNumber
210-
) -> Bool
211-
212202
// Conversions between NSNumber and various numeric types. The
213203
// conversion to NSNumber is automatic (auto-boxing), while conversion
214204
// back to a specific numeric type requires a cast.
@@ -348,7 +338,7 @@ extension Bool: _ObjectiveCBridgeable {
348338

349339
@_semantics("convertToObjectiveC")
350340
public func _bridgeToObjectiveC() -> NSNumber {
351-
return _swift_Foundation_TypePreservingNSNumberWithBool(self)
341+
return NSNumber(value: self)
352342
}
353343

354344
public static func _forceBridgeFromObjectiveC(
@@ -456,7 +446,7 @@ extension NSNumber : _HasCustomAnyHashableRepresentation {
456446
case .CoreGraphicsCGFloat:
457447
return AnyHashable(_swift_Foundation_TypePreservingNSNumberGetAsCGFloat(self))
458448
case .SwiftBool:
459-
return AnyHashable(_swift_Foundation_TypePreservingNSNumberGetAsBool(self))
449+
return AnyHashable(self.boolValue)
460450
}
461451
}
462452
}

stdlib/public/SDK/Foundation/TypePreservingNSNumber.mm

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,13 @@ - (const char *)objCType {
7676
case SwiftCGFloat:
7777
return @encode(CGFloat);
7878
case SwiftBool:
79-
return @encode(bool);
79+
// Bool is represented by CFBoolean.
80+
break;
8081
}
8182
swift::swift_reportError(
8283
/* flags = */ 0,
8384
"_SwiftTypePreservingNSNumber.tag is corrupted.\n");
85+
abort();
8486
}
8587

8688
- (void)getValue:(void *)value {
@@ -102,12 +104,13 @@ - (void)getValue:(void *)value {
102104
memcpy(value, self->storage, sizeof(CGFloat));
103105
return;
104106
case SwiftBool:
105-
memcpy(value, self->storage, sizeof(bool));
106-
return;
107+
// Bool is represented by CFBoolean.
108+
break;
107109
}
108110
swift::swift_reportError(
109111
/* flags = */ 0,
110112
"_SwiftTypePreservingNSNumber.tag is corrupted.\n");
113+
abort();
111114
}
112115

113116
#define DEFINE_ACCESSOR(C_TYPE, METHOD_NAME) \
@@ -139,14 +142,14 @@ - (C_TYPE)METHOD_NAME { \
139142
return result; \
140143
} \
141144
case SwiftBool: { \
142-
bool result; \
143-
memcpy(&result, self->storage, sizeof(result)); \
144-
return result; \
145+
/* Bool is represented by CFBoolean. */ \
146+
break; \
145147
} \
146148
} \
147149
swift::swift_reportError( \
148150
/* flags = */ 0, \
149151
"_SwiftTypePreservingNSNumber.tag is corrupted.\n"); \
152+
abort(); \
150153
}
151154

152155
DEFINE_ACCESSOR(char, charValue)
@@ -178,16 +181,17 @@ - (Class)classForCoder {
178181
DEFINE_INIT(float, Float)
179182
DEFINE_INIT(double, Double)
180183
DEFINE_INIT(CGFloat, CGFloat)
181-
DEFINE_INIT(bool, Bool)
182184

183185
#undef DEFINE_INIT
184186

185187
SWIFT_CC(swift) extern "C" uint32_t
186188
_swift_Foundation_TypePreservingNSNumberGetKind(
187189
NSNumber *NS_RELEASES_ARGUMENT _Nonnull self_) {
188190
uint32_t result = 0;
189-
if ([self_ isKindOfClass: [_SwiftTypePreservingNSNumber class]]) {
191+
if ([self_ isKindOfClass:[_SwiftTypePreservingNSNumber class]]) {
190192
result = ((_SwiftTypePreservingNSNumber *) self_)->tag;
193+
} else if (CFGetTypeID(self_) == CFBooleanGetTypeID()) {
194+
result = SwiftBool;
191195
}
192196
[self_ release];
193197
return result;
@@ -212,7 +216,6 @@ - (Class)classForCoder {
212216
DEFINE_GETTER(float, Float)
213217
DEFINE_GETTER(double, Double)
214218
DEFINE_GETTER(CGFloat, CGFloat)
215-
DEFINE_GETTER(bool, Bool)
216219

217220
#undef DEFINE_GETTER
218221

validation-test/stdlib/NSNumberBridging.swift.gyb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ NSNumberTests.test("_SwiftTypePreservingNSNumber.init(coder:)")
128128
NSNumberTests.test("_SwiftTypePreservingNSNumber.copy(zone:)") {
129129
let n: NSNumber = (42 as Int)._bridgeToObjectiveC()
130130
expectTrue(isTypePreservingNSNumber(n))
131-
let copy = n.copy() as! AnyObject
131+
let copy = n.copy() as AnyObject
132132
expectTrue(n === copy)
133133
}
134134

@@ -197,7 +197,11 @@ NSNumberTests.test("_SwiftTypePreservingNSNumber(${Self}).getValue(_:), objCType
197197
.forEach(in: ${Self}._interestingValues) {
198198
input in
199199
let bridgedNSNumber = input._bridgeToObjectiveC()
200+
% if Self == 'Bool':
201+
expectTrue(CFGetTypeID(bridgedNSNumber) == CFBooleanGetTypeID())
202+
% else:
200203
expectTrue(isTypePreservingNSNumber(bridgedNSNumber))
204+
% end
201205

202206
let expectedObjCType: String
203207
% if Self == 'Int':
@@ -229,7 +233,9 @@ NSNumberTests.test("_SwiftTypePreservingNSNumber(${Self}).getValue(_:), objCType
229233
_UnknownArchError()
230234
#endif
231235
% elif Self == 'Bool':
232-
expectedObjCType = "B"
236+
// NSNumber always encodes booleans as 'signed char', even on platforms where
237+
// ObjCBool is a true Bool. This is a very old compatibility concern.
238+
expectedObjCType = "c"
233239
% else:
234240
_UnknownTypeError()
235241
% end
@@ -247,13 +253,20 @@ NSNumberTests.test("${Self} bridges to NSNumber (actually _SwiftTypePreservingNS
247253
input in
248254
// Bridged NSNumbers preserve the Swift type when put into AnyHashable.
249255
let bridgedNSNumber = input._bridgeToObjectiveC()
256+
% if Self == 'Bool':
257+
expectTrue(CFGetTypeID(bridgedNSNumber) == CFBooleanGetTypeID())
258+
% else:
250259
expectTrue(isTypePreservingNSNumber(bridgedNSNumber))
260+
% end
251261
expectNotEmpty(bridgedNSNumber._toCustomAnyHashable())
252262

253263
// Explicitly constructed NSNumbers don't have a special AnyHashable
254264
// representation.
255265
% if Self == 'CGFloat':
256266
let explicitNSNumber = NSNumber(value: input.native)
267+
% elif Self == 'Bool':
268+
// Bool actually /is/ type-preserving for NSNumber. Use a dummy value instead.
269+
let explicitNSNumber = NSNumber(value: (input ? 1 : 0) as Int8)
257270
% else:
258271
let explicitNSNumber = NSNumber(value: input)
259272
% end

0 commit comments

Comments
 (0)