Skip to content

Commit c9f4df8

Browse files
authored
[stdlib] Fix FloatingPoint.init(exactly:) (swiftlang#11311)
* [stdlib] Fix FloatingPoint.init(exactly:) This initializer wasn't actually checking the exact conversion. Corrects the tests as well.
1 parent b571dd8 commit c9f4df8

File tree

4 files changed

+48
-80
lines changed

4 files changed

+48
-80
lines changed

stdlib/public/core/FloatingPointTypes.swift.gyb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,8 +1503,9 @@ extension ${Self} {
15031503
public init?(exactly value: ${That}) {
15041504
_value = Builtin.${sign}itofp_${ThatBuiltinName}_FPIEEE${bits}(value._value)
15051505

1506-
% if srcBits < SignificandBitCount:
1507-
if ${That}(self) != value {
1506+
% if srcBits >= SignificandBitCount:
1507+
guard let roundTrip = ${That}(exactly: self),
1508+
roundTrip == value else {
15081509
return nil
15091510
}
15101511
% end

test/stdlib/TestNSNumberBridging.swift

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -658,16 +658,12 @@ func testNSNumberBridgeFromUInt() {
658658
let uint = (number!) as? UInt
659659
expectEqual(UInt(exactly: interestingValue), uint)
660660

661-
// these are disabled because of https://bugs.swift.org/browse/SR-4634
662-
if uint! != UInt(UInt32.max) && uint! != UInt(UInt32.max - 1) {
663-
let float = (number!) as? Float
664-
let expectedFloat = Float(uint!)
665-
testFloat(expectedFloat, float)
666-
}
667-
668-
661+
let float = (number!) as? Float
662+
let expectedFloat = Float(exactly: uint!)
663+
testFloat(expectedFloat, float)
664+
669665
let double = (number!) as? Double
670-
let expectedDouble = Double(uint!)
666+
let expectedDouble = Double(exactly: uint!)
671667
testDouble(expectedDouble, double)
672668
}
673669
let bridged = interestingValue as NSNumber

validation-test/stdlib/FloatingPointConversion.swift.gyb

Lines changed: 35 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -115,74 +115,49 @@ FloatingPointConversionFailures.test("${OtherFloat}To${Self}Conversion/AlwaysSuc
115115

116116
% end # for in all_floating_point_types (Other)
117117

118-
%{
118+
#if arch(i386) || arch(arm)
119+
% int_types = all_integer_types(32)
120+
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
121+
% int_types = all_integer_types(64)
122+
#else
123+
_UnimplementedError()
124+
#endif
119125

120-
float_to_int_conversion_template = gyb.parse_template("float_to_int_conversion",
121-
"""
122-
% for int_ty in all_integer_types(word_bits):
126+
% for int_ty in int_types:
123127
% OtherInt = int_ty.stdlib_name
124128
% OtherMin = int_ty.min
125129
% OtherMax = int_ty.max
126130
% (FloatMin, FloatMax) = getFtoIBounds(self_type.bits, int_ty.bits, int_ty.is_signed)
127131

128-
% for testValue in [0, FloatMin, FloatMax, FloatMin - 1, FloatMax + 1, OtherMin, OtherMax]:
129-
130-
% if testValue < OtherMin or testValue > OtherMax:
131-
% # Can't construct `other` value, do nothing and continue.
132-
133-
% elif testValue >= FloatMin and testValue <= FloatMax:
134-
135-
FixedPointConversionTruncations.test("${OtherInt}to${Self}Conversion/${testValue}") {
136-
expectEqual(${Self}(${testValue} as ${OtherInt}), ${testValue})
137-
}
138-
139-
FixedPointConversionFailures.test("${OtherInt}to${Self}FailableConversion/${testValue}") {
140-
expectEqual(${Self}(exactly: ${testValue} as ${OtherInt}), ${testValue})
141-
}
142-
143-
% else:
144-
145-
FixedPointConversionTruncations.test("${OtherInt}to${Self}Truncation/${testValue}") {
146-
let value: ${OtherInt} = ${testValue}
147-
let result = ${Self}(value)
148-
expectNotEqual(${OtherInt}(result), value)
149-
}
150-
151-
FixedPointConversionFailures.test("${OtherInt}to${Self}Failure/${testValue}") {
152-
let value: ${OtherInt} = ${testValue}
153-
let result = ${Self}(exactly: value)
154-
expectEqual(result, ${OtherMin} as ${Self})
155-
expectEqual(${OtherInt}(result!), value)
132+
FixedPointConversionTruncations.test("${OtherInt}to${Self}")
133+
.forEach(in: [
134+
(0, 0, 0),
135+
% if int_ty.bits > self_type.significand_bits + 1:
136+
% limit = ~(~0 << (self_type.significand_bits + 1))
137+
% over = ~(~0 << (self_type.significand_bits + 2))
138+
(${limit}, ${limit}, ${limit}),
139+
(${over}, ${over + 1}, nil),
140+
% if int_ty.is_signed:
141+
(-${limit}, -${limit}, -${limit}),
142+
(-${over}, -${over + 1}, nil),
143+
% end
144+
% else:
145+
(${OtherInt}.min, ${OtherInt}.min, ${OtherInt}.min),
146+
(${OtherInt}.max, ${OtherInt}.max, ${OtherInt}.max),
147+
% end
148+
] as [(${OtherInt}, ${OtherInt}, ${OtherInt}?)]) { value, roundedExpectation, exactExpectation in
149+
let roundedResult = ${Self}(value)
150+
expectEqual(roundedResult, ${Self}(roundedExpectation))
151+
152+
let exactResult = ${Self}(exactly: value)
153+
if let expectation = exactExpectation {
154+
expectEqual(exactResult!, ${Self}(expectation))
155+
} else {
156+
expectNil(exactResult)
157+
}
156158
}
157159

158-
% end
159-
160-
% end # testValue in testValues
161-
% end # for in all_integer_types (Other)
162-
""")
163-
}%
164-
165-
#if arch(i386) || arch(arm)
166-
167-
${gyb.execute_template(
168-
float_to_int_conversion_template,
169-
word_bits=32,
170-
**locals()
171-
)}
172-
173-
#elseif arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x)
174-
175-
${gyb.execute_template(
176-
float_to_int_conversion_template,
177-
word_bits=64,
178-
**locals()
179-
)}
180-
181-
#else
182-
183-
_UnimplementedError()
184-
185-
#endif
160+
% end # for in int_types
186161

187162
% if Self == 'Float80':
188163
#endif

validation-test/stdlib/ValidationNSNumberBridging.swift

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -652,16 +652,12 @@ func testNSNumberBridgeFromUInt() {
652652
let uint = (number!) as? UInt
653653
expectEqual(UInt(exactly: interestingValue), uint)
654654

655-
// these are disabled because of https://bugs.swift.org/browse/SR-4634
656-
if uint! != UInt(UInt32.max) && uint! != UInt(UInt32.max - 1) {
657-
let float = (number!) as? Float
658-
let expectedFloat = Float(uint!)
659-
testFloat(expectedFloat, float)
660-
}
661-
662-
655+
let float = (number!) as? Float
656+
let expectedFloat = Float(exactly: uint!)
657+
testFloat(expectedFloat, float)
658+
663659
let double = (number!) as? Double
664-
let expectedDouble = Double(uint!)
660+
let expectedDouble = Double(exactly: uint!)
665661
testDouble(expectedDouble, double)
666662
}
667663
let bridged = interestingValue as NSNumber

0 commit comments

Comments
 (0)