Skip to content

Commit 233f864

Browse files
committed
Move some more common enum diagnostics into the decl checker
In preparation for checkEnumRawValues being turned into a request, move the common diagnostics to the decl checker so they're always emitted at the right time.
1 parent 02b5e56 commit 233f864

File tree

8 files changed

+74
-45
lines changed

8 files changed

+74
-45
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,55 +1431,57 @@ static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC,
14311431
llvm_unreachable("Unhandled AutomaticEnumValueKind in switch.");
14321432
}
14331433

1434-
static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
1434+
static Optional<AutomaticEnumValueKind>
1435+
computeAutomaticEnumValueKind(TypeChecker &TC, EnumDecl *ED) {
14351436
Type rawTy = ED->getRawType();
1436-
if (!rawTy) {
1437-
return;
1438-
}
1439-
1437+
assert(rawTy && "Cannot compute value kind without raw type!");
1438+
14401439
if (ED->getGenericEnvironmentOfContext() != nullptr)
14411440
rawTy = ED->mapTypeIntoContext(rawTy);
1442-
if (rawTy->hasError())
1443-
return;
1444-
1445-
AutomaticEnumValueKind valueKind;
1441+
14461442
// Swift enums require that the raw type is convertible from one of the
14471443
// primitive literal protocols.
14481444
auto conformsToProtocol = [&](KnownProtocolKind protoKind) {
1449-
ProtocolDecl *proto = TC.getProtocol(ED->getLoc(), protoKind);
1450-
return TypeChecker::conformsToProtocol(rawTy, proto,
1451-
ED->getDeclContext(), None);
1445+
ProtocolDecl *proto = TC.getProtocol(ED->getLoc(), protoKind);
1446+
return TypeChecker::conformsToProtocol(rawTy, proto,
1447+
ED->getDeclContext(), None);
14521448
};
1453-
1449+
14541450
static auto otherLiteralProtocolKinds = {
14551451
KnownProtocolKind::ExpressibleByFloatLiteral,
14561452
KnownProtocolKind::ExpressibleByUnicodeScalarLiteral,
14571453
KnownProtocolKind::ExpressibleByExtendedGraphemeClusterLiteral,
14581454
};
1459-
1455+
14601456
if (conformsToProtocol(KnownProtocolKind::ExpressibleByIntegerLiteral)) {
1461-
valueKind = AutomaticEnumValueKind::Integer;
1457+
return AutomaticEnumValueKind::Integer;
14621458
} else if (conformsToProtocol(KnownProtocolKind::ExpressibleByStringLiteral)){
1463-
valueKind = AutomaticEnumValueKind::String;
1459+
return AutomaticEnumValueKind::String;
14641460
} else if (std::any_of(otherLiteralProtocolKinds.begin(),
14651461
otherLiteralProtocolKinds.end(),
14661462
conformsToProtocol)) {
1467-
valueKind = AutomaticEnumValueKind::None;
1463+
return AutomaticEnumValueKind::None;
14681464
} else {
1469-
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
1470-
diag::raw_type_not_literal_convertible,
1471-
rawTy);
1472-
ED->getInherited().front().setInvalidType(TC.Context);
1473-
return;
1465+
return None;
14741466
}
1467+
}
14751468

1476-
// We need at least one case to have a raw value.
1477-
if (ED->getAllElements().empty()) {
1478-
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
1479-
diag::empty_enum_raw_type);
1469+
static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
1470+
Type rawTy = ED->getRawType();
1471+
if (!rawTy) {
14801472
return;
14811473
}
14821474

1475+
if (ED->getGenericEnvironmentOfContext() != nullptr)
1476+
rawTy = ED->mapTypeIntoContext(rawTy);
1477+
if (rawTy->hasError())
1478+
return;
1479+
1480+
// If we don't have a value kind, the decl checker will provide a diagnostic.
1481+
auto valueKind = computeAutomaticEnumValueKind(TC, ED);
1482+
if (!valueKind.hasValue())
1483+
return;
1484+
14831485
// Check the raw values of the cases.
14841486
LiteralExpr *prevValue = nullptr;
14851487
EnumElementDecl *lastExplicitValueElt = nullptr;
@@ -1499,24 +1501,14 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
14991501
(void)elt->getInterfaceType();
15001502
if (elt->isInvalid())
15011503
continue;
1502-
1503-
// We don't yet support raw values on payload cases.
1504-
if (elt->hasAssociatedValues()) {
1505-
TC.diagnose(elt->getLoc(),
1506-
diag::enum_with_raw_type_case_with_argument);
1507-
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
1508-
diag::enum_raw_type_here, rawTy);
1509-
elt->setInvalid();
1510-
continue;
1511-
}
15121504

15131505
if (elt->hasRawValueExpr()) {
15141506
lastExplicitValueElt = elt;
15151507
} else {
15161508
// If the enum element has no explicit raw value, try to
15171509
// autoincrement from the previous value, or start from zero if this
15181510
// is the first element.
1519-
auto nextValue = getAutomaticRawValueExpr(TC, valueKind, elt, prevValue);
1511+
auto nextValue = getAutomaticRawValueExpr(TC, *valueKind, elt, prevValue);
15201512
if (!nextValue) {
15211513
elt->setInvalid();
15221514
break;
@@ -2535,11 +2527,26 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25352527
checkAccessControl(TC, ED);
25362528

25372529
TC.checkPatternBindingCaptures(ED);
2538-
2539-
if (ED->hasRawType() && !ED->isObjC()) {
2530+
2531+
if (auto rawTy = ED->getRawType()) {
2532+
// The raw type must be one of the blessed literal convertible types.
2533+
if (!computeAutomaticEnumValueKind(TC, ED)) {
2534+
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
2535+
diag::raw_type_not_literal_convertible,
2536+
rawTy);
2537+
ED->getInherited().front().setInvalidType(TC.Context);
2538+
}
2539+
2540+
// We need at least one case to have a raw value.
2541+
if (ED->getAllElements().empty()) {
2542+
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
2543+
diag::empty_enum_raw_type);
2544+
}
2545+
25402546
// ObjC enums have already had their raw values checked, but pure Swift
25412547
// enums haven't.
2542-
checkEnumRawValues(TC, ED);
2548+
if (!ED->isObjC())
2549+
checkEnumRawValues(TC, ED);
25432550
}
25442551

25452552
checkExplicitAvailability(ED);
@@ -2992,6 +2999,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29922999

29933000
void visitEnumElementDecl(EnumElementDecl *EED) {
29943001
(void)EED->getInterfaceType();
3002+
auto *ED = EED->getParentEnum();
29953003

29963004
TC.checkDeclAttributes(EED);
29973005

@@ -3000,8 +3008,19 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30003008
TC.checkDefaultArguments(PL, EED);
30013009
}
30023010

3011+
// We don't yet support raw values on payload cases.
3012+
if (EED->hasAssociatedValues()) {
3013+
if (auto rawTy = ED->getRawType()) {
3014+
TC.diagnose(EED->getLoc(),
3015+
diag::enum_with_raw_type_case_with_argument);
3016+
TC.diagnose(ED->getInherited().front().getSourceRange().Start,
3017+
diag::enum_raw_type_here, rawTy);
3018+
EED->setInvalid();
3019+
}
3020+
}
3021+
30033022
// Yell if our parent doesn't have a raw type but we have a raw value.
3004-
if (!EED->getParentEnum()->hasRawType() && EED->hasRawValueExpr()) {
3023+
if (EED->hasRawValueExpr() && !ED->hasRawType()) {
30053024
TC.diagnose(EED->getRawValueExpr()->getLoc(),
30063025
diag::enum_raw_value_without_raw_type);
30073026
EED->setInvalid();

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,11 @@ static bool isEnumObjC(EnumDecl *enumDecl) {
13721372
return false;
13731373
}
13741374

1375+
// We need at least one case to have a raw value.
1376+
if (enumDecl->getAllElements().empty()) {
1377+
enumDecl->diagnose(diag::empty_enum_raw_type);
1378+
}
1379+
13751380
return true;
13761381
}
13771382

test/IDE/print_ast_tc_decls_errors.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ class ClassWithInheritance9 : FooClass, BarClass, FooProtocol, BarProtocol, FooN
109109
//===--- Inheritance list in enums.
110110
//===---
111111

112-
enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{use of undeclared type 'FooNonExistentProtocol'}}
112+
enum EnumWithInheritance1 : FooNonExistentProtocol {} // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} expected-error {{raw type}} expected-error {{an enum with no cases}}
113113
// NO-TYREPR: {{^}}enum EnumWithInheritance1 : <<error type>> {{{$}}
114114
// TYREPR: {{^}}enum EnumWithInheritance1 : FooNonExistentProtocol {{{$}}
115115

116-
enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} expected-error {{use of undeclared type 'BarNonExistentProtocol'}}
116+
enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {} // expected-error {{use of undeclared type 'FooNonExistentProtocol'}} expected-error {{use of undeclared type 'BarNonExistentProtocol'}} expected-error {{raw type}} expected-error {{an enum with no cases}}
117117
// NO-TYREPR: {{^}}enum EnumWithInheritance2 : <<error type>>, <<error type>> {{{$}}
118118
// TYREPR: {{^}}enum EnumWithInheritance2 : FooNonExistentProtocol, BarNonExistentProtocol {{{$}}
119119

test/Sema/accessibility_private.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ extension Container {
197197
// expected-error@-1 {{raw type 'Container.VeryPrivateStruct' is not expressible by a string, integer, or floating-point literal}}
198198
// expected-error@-2 {{'Container.PrivateRawValue' declares raw type 'Container.VeryPrivateStruct', but does not conform to RawRepresentable and conformance could not be synthesized}}
199199
// expected-error@-3 {{RawRepresentable conformance cannot be synthesized because raw type 'Container.VeryPrivateStruct' is not Equatable}}
200+
// expected-error@-4 {{an enum with no cases cannot declare a raw type}}
200201
fileprivate enum PrivatePayload {
201202
case A(VeryPrivateStruct) // expected-error {{enum case in an internal enum uses a private type}} {{none}}
202203
}

test/Sema/enum_raw_representable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,4 @@ enum ArrayOfNewEquatable : Array<NotEquatable> { }
189189
// expected-error@-2{{'ArrayOfNewEquatable' declares raw type 'Array<NotEquatable>', but does not conform to RawRepresentable and conformance could not be synthesized}}
190190
// expected-error@-3{{RawRepresentable conformance cannot be synthesized because raw type 'Array<NotEquatable>' is not Equatable}}
191191
// expected-note@-4{{do you want to add protocol stubs?}}
192+
// expected-error@-5 {{an enum with no cases cannot declare a raw type}}

test/decl/enum/objc_enum_multi_file.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
}
2525

2626
#elseif NO_CASES
27-
// NO_CASES: :[[@LINE+1]]:22: error: an enum with no cases cannot declare a raw type
27+
// NO_CASES: :[[@LINE+1]]:12: error: an enum with no cases cannot declare a raw type
2828
@objc enum TheEnum : Int32 {
2929
static var A: TheEnum! { return nil }
3030
}

test/decl/nested/protocol.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ protocol Racoon {
5151
}
5252
}
5353

54-
enum SillyRawEnum : SillyProtocol.InnerClass {}
54+
enum SillyRawEnum : SillyProtocol.InnerClass {} // expected-error {{an enum with no cases cannot declare a raw type}}
55+
// expected-error@-1 {{raw type}}
5556

5657
protocol SillyProtocol {
5758
class InnerClass<T> {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}}

test/decl/overload.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class mixed_redecl3 {} // expected-note {{previously declared here}}
7676
enum mixed_redecl3 {} // expected-error {{invalid redeclaration}}
7777
// expected-note @-1 2{{found this candidate}}
7878
enum mixed_redecl3a : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}}
79+
// expected-error@-1 {{an enum with no cases cannot declare a raw type}}
80+
// expected-error@-2 {{raw type}}
7981
class mixed_redecl3b : mixed_redecl3 {} // expected-error {{'mixed_redecl3' is ambiguous for type lookup in this context}}
8082

8183
class mixed_redecl4 {} // expected-note {{previously declared here}}

0 commit comments

Comments
 (0)