Skip to content

Handle Boolean literals as enum raw values. #28274

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

Merged
merged 2 commits into from
Nov 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/Sema/DerivedConformanceRawRepresentable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ static LiteralExpr *cloneRawLiteralExpr(ASTContext &C, LiteralExpr *expr) {
/*implicit*/ true);
if (floatLit->isNegative())
cast<FloatLiteralExpr>(clone)->setNegative(expr->getLoc());
} else if (auto boolLit = dyn_cast<BooleanLiteralExpr>(expr)) {
clone = new (C) BooleanLiteralExpr(boolLit->getValue(), expr->getLoc(),
/*implicit*/true);
} else {
llvm_unreachable("invalid raw literal expr");
}
Expand Down
14 changes: 13 additions & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ namespace {
/// Float and integer literals are additionally keyed by numeric equivalence.
struct RawValueKey {
enum class Kind : uint8_t {
String, Float, Int, Tombstone, Empty
String, Float, Int, Bool, Tombstone, Empty
} kind;

struct IntValueTy {
Expand All @@ -101,6 +101,7 @@ struct RawValueKey {
StringRef stringValue;
IntValueTy intValue;
FloatValueTy floatValue;
bool boolValue;
};

explicit RawValueKey(LiteralExpr *expr) {
Expand Down Expand Up @@ -136,6 +137,12 @@ struct RawValueKey {
kind = Kind::String;
stringValue = cast<StringLiteralExpr>(expr)->getValue();
return;

case ExprKind::BooleanLiteral:
kind = Kind::Bool;
boolValue = cast<BooleanLiteralExpr>(expr)->getValue();
return;

default:
llvm_unreachable("not a valid literal expr for raw value");
}
Expand Down Expand Up @@ -183,6 +190,8 @@ class DenseMapInfo<RawValueKey> {
DenseMapInfo<uint64_t>::getHashValue(k.intValue.v1);
case RawValueKey::Kind::String:
return DenseMapInfo<StringRef>::getHashValue(k.stringValue);
case RawValueKey::Kind::Bool:
return DenseMapInfo<uint64_t>::getHashValue(k.boolValue);
case RawValueKey::Kind::Empty:
case RawValueKey::Kind::Tombstone:
return 0;
Expand All @@ -204,6 +213,8 @@ class DenseMapInfo<RawValueKey> {
a.intValue.v1 == b.intValue.v1;
case RawValueKey::Kind::String:
return a.stringValue.equals(b.stringValue);
case RawValueKey::Kind::Bool:
return a.boolValue == b.boolValue;
case RawValueKey::Kind::Empty:
case RawValueKey::Kind::Tombstone:
return true;
Expand Down Expand Up @@ -1682,6 +1693,7 @@ EnumRawValuesRequest::evaluate(Evaluator &eval, EnumDecl *ED,
continue;
}


// If the raw values of the enum case are fixed, then we trust our callers
// to have set things up correctly. This comes up with imported enums
// and deserialized @objc enums which always have their raw values setup
Expand Down
26 changes: 26 additions & 0 deletions test/decl/enum/bool_raw_value.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// RUN: %target-typecheck-verify-swift
extension Bool: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
self = value != 0
}
}

enum IsDefinitelyRecursive : Bool, Equatable, Hashable {
case recursive=false
}

// expected-error@+1{{'IsRecursive' declares raw type 'Bool', but does not conform to RawRepresentable and conformance could not be synthesized}}
enum IsRecursive : Bool, Equatable, Hashable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some more tests: an @objc enum (and if we allow this, an IRGen test), an enum with an invalid raw value expression.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@objc enums are banned; I've added more tests

case recursive=false
case nonrecursive // expected-error{{enum case must declare a raw value when the preceding raw value is not an integer}}
}

enum IsRecursiveBad1Integral : Bool, Equatable, Hashable {
case recursive = 0
case nonrecursive
}

// expected-error @+1{{'IsRecursiveBad2' declares raw type 'Int', but does not conform to RawRepresentable and conformance could not be synthesized}}
enum IsRecursiveBad2 : Int, Equatable, Hashable {
case recursive = false // expected-error{{cannot convert value of type 'Bool' to raw type 'Int'}}
}
12 changes: 12 additions & 0 deletions test/decl/enum/objc_bool_raw_value.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %target-typecheck-verify-swift
// REQUIRES: objc_interop

extension Bool: ExpressibleByIntegerLiteral {
public init(integerLiteral value: Int) {
self = value != 0
}
}

@objc enum IsDefinitelyRecursive : Bool, Equatable, Hashable { // expected-error{{'@objc' enum raw type 'Bool' is not an integer type}}
case recursive=false
}