Skip to content

Commit 0df6b40

Browse files
committed
Clean up enum raw expression validation a bit
The distinction between the type checked raw value expression and the regular raw value expression was never important. Downstream clients were ignoring the type checked form and pulling the text out of the supposed "plain" form. Drop the distinction and simply don't set back into the raw value expr if we don't have to. Pushing this through naturally enables some cleanup in checkEnumRawValues. Factor out type checking the literal value into an helper on the typechecker and pull a common diagnostic into the decl checker.
1 parent 56edd08 commit 0df6b40

File tree

7 files changed

+34
-90
lines changed

7 files changed

+34
-90
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6329,9 +6329,7 @@ class EnumElementDecl : public DeclContext, public ValueDecl {
63296329

63306330
/// The raw value literal for the enum element, or null.
63316331
LiteralExpr *RawValueExpr;
6332-
/// The type-checked raw value expression.
6333-
Expr *TypeCheckedRawValueExpr = nullptr;
6334-
6332+
63356333
public:
63366334
EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name,
63376335
ParameterList *Params,
@@ -6364,13 +6362,6 @@ class EnumElementDecl : public DeclContext, public ValueDecl {
63646362
bool hasRawValueExpr() const { return RawValueExpr; }
63656363
LiteralExpr *getRawValueExpr() const { return RawValueExpr; }
63666364
void setRawValueExpr(LiteralExpr *e) { RawValueExpr = e; }
6367-
6368-
Expr *getTypeCheckedRawValueExpr() const {
6369-
return TypeCheckedRawValueExpr;
6370-
}
6371-
void setTypeCheckedRawValueExpr(Expr *e) {
6372-
TypeCheckedRawValueExpr = e;
6373-
}
63746365

63756366
/// Return the containing EnumDecl.
63766367
EnumDecl *getParentEnum() const {

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -415,15 +415,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
415415
visit(PL);
416416
}
417417

418-
// The getRawValueExpr should remain the untouched original LiteralExpr for
419-
// serialization and validation purposes. We only traverse the type-checked
420-
// form, unless we haven't populated it yet.
421-
if (auto *rawValueExpr = ED->getTypeCheckedRawValueExpr()) {
422-
if (auto newRawValueExpr = doIt(rawValueExpr))
423-
ED->setTypeCheckedRawValueExpr(newRawValueExpr);
424-
else
425-
return true;
426-
} else if (auto *rawLiteralExpr = ED->getRawValueExpr()) {
418+
if (auto *rawLiteralExpr = ED->getRawValueExpr()) {
427419
Expr *newRawExpr = doIt(rawLiteralExpr);
428420
if (auto newRawLiteralExpr = dyn_cast<LiteralExpr>(newRawExpr))
429421
ED->setRawValueExpr(newRawLiteralExpr);

lib/Sema/DerivedConformanceRawRepresentable.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,6 @@ deriveBodyRawRepresentable_raw(AbstractFunctionDecl *toRawDecl, void *) {
8383
assert(rawTy);
8484
rawTy = toRawDecl->mapTypeIntoContext(rawTy);
8585

86-
#ifndef NDEBUG
87-
for (auto elt : enumDecl->getAllElements()) {
88-
assert(elt->getTypeCheckedRawValueExpr() &&
89-
"Enum element has no literal - missing a call to checkEnumRawValues()");
90-
assert(elt->getTypeCheckedRawValueExpr()->getType()->isEqual(rawTy));
91-
}
92-
#endif
93-
9486
if (enumDecl->isObjC()) {
9587
// Special case: ObjC enums are represented by their raw value, so just use
9688
// a bitcast.
@@ -297,14 +289,6 @@ deriveBodyRawRepresentable_init(AbstractFunctionDecl *initDecl, void *) {
297289
assert(rawTy);
298290
rawTy = initDecl->mapTypeIntoContext(rawTy);
299291

300-
#ifndef NDEBUG
301-
for (auto elt : enumDecl->getAllElements()) {
302-
assert(elt->getTypeCheckedRawValueExpr() &&
303-
"Enum element has no literal - missing a call to checkEnumRawValues()");
304-
assert(elt->getTypeCheckedRawValueExpr()->getType()->isEqual(rawTy));
305-
}
306-
#endif
307-
308292
bool isStringEnum =
309293
(rawTy->getNominalOrBoundGenericNominal() == C.getStringDecl());
310294
llvm::SmallVector<Expr *, 16> stringExprs;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,7 +1432,6 @@ static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC,
14321432

14331433
static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
14341434
Type rawTy = ED->getRawType();
1435-
14361435
if (!rawTy) {
14371436
return;
14381437
}
@@ -1489,8 +1488,10 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
14891488

14901489
for (auto elt : ED->getAllElements()) {
14911490
// Skip if the raw value expr has already been checked.
1492-
if (elt->getTypeCheckedRawValueExpr())
1491+
if (elt->hasRawValueExpr() && elt->getRawValueExpr()->getType()) {
1492+
prevValue = elt->getRawValueExpr();
14931493
continue;
1494+
}
14941495

14951496
// Make sure the element is checked out before we poke at it.
14961497
// FIXME: Make isInvalid work with interface types
@@ -1508,15 +1509,7 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
15081509
continue;
15091510
}
15101511

1511-
// Check the raw value expr, if we have one.
1512-
if (auto *rawValue = elt->getRawValueExpr()) {
1513-
Expr *typeCheckedExpr = rawValue;
1514-
auto resultTy = TC.typeCheckExpression(typeCheckedExpr, ED,
1515-
TypeLoc::withoutLoc(rawTy),
1516-
CTP_EnumCaseRawValue);
1517-
if (resultTy) {
1518-
elt->setTypeCheckedRawValueExpr(typeCheckedExpr);
1519-
}
1512+
if (elt->hasRawValueExpr()) {
15201513
lastExplicitValueElt = elt;
15211514
} else {
15221515
// If the enum element has no explicit raw value, try to
@@ -1528,43 +1521,20 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
15281521
break;
15291522
}
15301523
elt->setRawValueExpr(nextValue);
1531-
Expr *typeChecked = nextValue;
1532-
auto resultTy = TC.typeCheckExpression(
1533-
typeChecked, ED, TypeLoc::withoutLoc(rawTy), CTP_EnumCaseRawValue);
1534-
if (resultTy)
1535-
elt->setTypeCheckedRawValueExpr(typeChecked);
15361524
}
15371525
prevValue = elt->getRawValueExpr();
15381526
assert(prevValue && "continued without setting raw value of enum case");
15391527

15401528
// If we didn't find a valid initializer (maybe the initial value was
15411529
// incompatible with the raw value type) mark the entry as being erroneous.
1542-
if (!elt->getTypeCheckedRawValueExpr()) {
1530+
TC.checkRawValueExpr(ED, elt);
1531+
if (!prevValue->getType() || prevValue->getType()->hasError()) {
15431532
elt->setInvalid();
15441533
continue;
15451534
}
15461535

1547-
TC.checkEnumElementErrorHandling(elt);
1548-
1549-
// Find the type checked version of the LiteralExpr used for the raw value.
1550-
// this is unfortunate, but is needed because we're digging into the
1551-
// literals to get information about them, instead of accepting general
1552-
// expressions.
1553-
LiteralExpr *rawValue = elt->getRawValueExpr();
1554-
if (!rawValue->getType()) {
1555-
elt->getTypeCheckedRawValueExpr()->forEachChildExpr([&](Expr *E)->Expr* {
1556-
if (E->getKind() == rawValue->getKind())
1557-
rawValue = cast<LiteralExpr>(E);
1558-
return E;
1559-
});
1560-
elt->setRawValueExpr(rawValue);
1561-
}
1562-
1563-
prevValue = rawValue;
1564-
assert(prevValue && "continued without setting raw value of enum case");
1565-
15661536
// Check that the raw value is unique.
1567-
RawValueKey key(rawValue);
1537+
RawValueKey key{prevValue};
15681538
RawValueSource source{elt, lastExplicitValueElt};
15691539

15701540
auto insertIterPair = uniqueRawValues.insert({key, source});
@@ -3053,6 +3023,13 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30533023
TC.checkDefaultArguments(PL, EED);
30543024
}
30553025

3026+
// Yell if our parent doesn't have a raw type but we have a raw value.
3027+
if (!EED->getParentEnum()->hasRawType() && EED->hasRawValueExpr()) {
3028+
TC.diagnose(EED->getRawValueExpr()->getLoc(),
3029+
diag::enum_raw_value_without_raw_type);
3030+
EED->setInvalid();
3031+
}
3032+
30563033
checkAccessControl(TC, EED);
30573034
}
30583035

@@ -4135,22 +4112,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41354112
TypeResolverContext::EnumElementDecl);
41364113
}
41374114

4138-
// If we have a raw value, make sure there's a raw type as well.
4139-
if (auto *rawValue = EED->getRawValueExpr()) {
4140-
if (!ED->hasRawType()) {
4141-
diagnose(rawValue->getLoc(),diag::enum_raw_value_without_raw_type);
4142-
// Recover by setting the raw type as this element's type.
4143-
Expr *typeCheckedExpr = rawValue;
4144-
if (!typeCheckExpression(typeCheckedExpr, ED)) {
4145-
EED->setTypeCheckedRawValueExpr(typeCheckedExpr);
4146-
checkEnumElementErrorHandling(EED);
4147-
}
4148-
} else {
4149-
// Wait until the second pass, when all the raw value expressions
4150-
// can be checked together.
4151-
}
4152-
}
4153-
41544115
// Now that we have an argument type we can set the element's declared
41554116
// type.
41564117
EED->computeType();

lib/Sema/TypeCheckError.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,9 +1663,9 @@ void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx,
16631663
/// perhaps accidentally, and (2) allows the verifier to assert that
16641664
/// all calls have been checked.
16651665
void TypeChecker::checkEnumElementErrorHandling(EnumElementDecl *elt) {
1666-
if (auto init = elt->getTypeCheckedRawValueExpr()) {
1666+
if (auto *rawValue = elt->getRawValueExpr()) {
16671667
CheckErrorCoverage checker(*this, Context::forEnumElementInitializer(elt));
1668-
init->walk(checker);
1668+
rawValue->walk(checker);
16691669
}
16701670
}
16711671

lib/Sema/TypeCheckStmt.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,20 @@ void TypeChecker::checkDefaultArguments(ParameterList *params,
19111911
}
19121912
}
19131913

1914+
void TypeChecker::checkRawValueExpr(EnumDecl *ED, EnumElementDecl *EED) {
1915+
Type rawTy = ED->getRawType();
1916+
Expr *rawValue = EED->getRawValueExpr();
1917+
assert((rawTy && rawValue) && "Cannot check missing raw value!");
1918+
1919+
if (ED->getGenericEnvironmentOfContext() != nullptr)
1920+
rawTy = ED->mapTypeIntoContext(rawTy);
1921+
1922+
if (typeCheckExpression(rawValue, ED, TypeLoc::withoutLoc(rawTy),
1923+
CTP_EnumCaseRawValue)) {
1924+
checkEnumElementErrorHandling(EED);
1925+
}
1926+
}
1927+
19141928
static Type getFunctionBuilderType(FuncDecl *FD) {
19151929
Type builderType = FD->getFunctionBuilderType();
19161930

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,8 @@ class TypeChecker final : public LazyResolver {
10101010

10111011
/// Check the default arguments that occur within this value decl.
10121012
void checkDefaultArguments(ParameterList *params, ValueDecl *VD);
1013+
/// Check the raw value expression in this enum element.
1014+
void checkRawValueExpr(EnumDecl *parent, EnumElementDecl *Elt);
10131015

10141016
virtual void resolveDeclSignature(ValueDecl *VD) override {
10151017
validateDecl(VD);

0 commit comments

Comments
 (0)