-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Handle unexpected raw values for @objc enums in derived conformances #17836
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@swift-ci Please test |
@swift-ci Please test source compatibility |
@swift-ci Please benchmark |
cc @allevato |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
Build failed |
|
||
public enum E: Int { | ||
case a, b, c | ||
} | ||
|
||
// CHECK-DAG: sil [serialized] @$S22enum_raw_representable1EO0B5ValueACSgSi_tcfC | ||
// CHECK-DAG: sil [serialized] @$S22enum_raw_representable1EO0B5ValueSivg | ||
@objc public enum CLike: Int { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer this was in its own file, like objc_enum_raw_representable.swift
This should be a small code size win too! |
@@ -90,6 +90,27 @@ static void deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl) { | |||
} | |||
#endif | |||
|
|||
if (enumDecl->isObjC()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good optimization but isn't safe to perform on types which override rawValue
for some reason, right?
@objc enum Foo : Int {
case a
var rawValue: Int {
return 5
}
}
let a = Foo.a
print(a.rawValue) // 5
print(unsafeBitCast(a, to: Int.self)) // 0
We should probably see if rawValue
was synthesized, and if so, bypass calling it with this, yeah?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the derived implementation of rawValue
; it'll only be used if the user didn't write one.
(If you're talking about the hash(into:)
change, I suppose you're right, but we're doomed either way in that case.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, yes! I was looking in the wrong place. Trying to do too many things at once 🙃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hash(into:)
could use the bitcast approach; isn't that what rawValue
does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose it could. I liked the semantic implications of this one, but bitcasting is a little more correct. Do you think it's important enough to be worth changing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having hashing use the bitcast value feels more inherently correct to me, since an @objc
enum can in fact be of any value of its raw type, and a hash implementation ought to feed all of the significant bits of the value to the hasher.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized that hash(into:)
should probably stay consistent with ==
, which has a default implementation for RawRepresentable types, so I'm going to leave this as is.
ba964d7
to
0bcd22d
Compare
Reorganized tests only. @swift-ci Please test Linux |
@swift-ci Please smoke test macOS |
Build failed |
(source compat bot is having a problem, so I'm going to hold off for a bit) |
0bcd22d
to
38e0a47
Compare
@swift-ci Please smoke test macOS |
@swift-ci Please test Linux |
Build failed |
Unrelated SwiftPM failure? @swift-ci Please test Linux |
Build comment file:Optimized (O)Regression (1)
Improvement (1)
No Changes (456)
Unoptimized (Onone)Regression (4)
Improvement (5)
No Changes (449)
Hardware Overview
|
Build failed |
Because people put all sorts of nonsense into @objc enums (most reasonably, "private cases", which represent valid values that are not API), the Swift-synthesized implementation of 'hash(into:)' needs to not expect a switch statement to be exhaustive. And since Swift-defined @objc enums are supposed to behave enough like C-defined enums, they should at least handle simple method calls with an invalid raw value, which means that 'rawValue' likewise should not use a switch. This patch provides alternate implementations that look like this: extension ImportedEnum { public var rawValue: Int { return unsafeBitCast(self, to: Int.self) } public func hash(into hasher: inout Hasher) { hasher.combine(self.rawValue) } } rdar://problem/41913284
38e0a47
to
a1d8acb
Compare
@swift-ci Please test |
(still waiting for the source compat bots to come back online) |
Build failed |
Build failed |
swiftlang/swift-source-compat-suite#213 |
Remaining source compat failures match the failures on master. Merging. |
…wiftlang#17836) Because people put all sorts of nonsense into @objc enums (most reasonably, "private cases", which represent valid values that are not API), the Swift-synthesized implementation of 'hash(into:)' needs to not expect a switch statement to be exhaustive. And since Swift-defined @objc enums are supposed to behave enough like C-defined enums, they should at least handle simple method calls with an invalid raw value, which means that 'rawValue' likewise should not use a switch. This patch provides alternate implementations that look like this: extension ImportedEnum { public var rawValue: Int { return unsafeBitCast(self, to: Int.self) } public func hash(into hasher: inout Hasher) { hasher.combine(self.rawValue) } } rdar://problem/41913284 (cherry picked from commit 357c7d6)
Because people put all sorts of nonsense into
@objc
enums (most reasonably, "private cases", which represent valid values that are not API), the Swift-synthesized implementation ofhash(into:)
needs to not expect a switch statement to be exhaustive. And since Swift-defined@objc
enums are supposed to behave enough like C-defined enums, they should at least handle simple method calls with an invalid raw value, which means thatrawValue
likewise should not use a switch.This patch provides alternate implementations that look like this:
rdar://problem/41913284