Skip to content

Commit dd7d925

Browse files
authored
Merge pull request #27364 from CodaFi/raw-smackdown
Clean up enum raw expression validation a bit
2 parents 7189c09 + 0df6b40 commit dd7d925

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
@@ -1433,7 +1433,6 @@ static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC,
14331433

14341434
static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
14351435
Type rawTy = ED->getRawType();
1436-
14371436
if (!rawTy) {
14381437
return;
14391438
}
@@ -1490,8 +1489,10 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
14901489

14911490
for (auto elt : ED->getAllElements()) {
14921491
// Skip if the raw value expr has already been checked.
1493-
if (elt->getTypeCheckedRawValueExpr())
1492+
if (elt->hasRawValueExpr() && elt->getRawValueExpr()->getType()) {
1493+
prevValue = elt->getRawValueExpr();
14941494
continue;
1495+
}
14951496

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

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

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

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

15711541
auto insertIterPair = uniqueRawValues.insert({key, source});
@@ -3030,6 +3000,13 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
30303000
TC.checkDefaultArguments(PL, EED);
30313001
}
30323002

3003+
// Yell if our parent doesn't have a raw type but we have a raw value.
3004+
if (!EED->getParentEnum()->hasRawType() && EED->hasRawValueExpr()) {
3005+
TC.diagnose(EED->getRawValueExpr()->getLoc(),
3006+
diag::enum_raw_value_without_raw_type);
3007+
EED->setInvalid();
3008+
}
3009+
30333010
checkAccessControl(TC, EED);
30343011
}
30353012

@@ -4112,22 +4089,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
41124089
TypeResolverContext::EnumElementDecl);
41134090
}
41144091

4115-
// If we have a raw value, make sure there's a raw type as well.
4116-
if (auto *rawValue = EED->getRawValueExpr()) {
4117-
if (!ED->hasRawType()) {
4118-
diagnose(rawValue->getLoc(),diag::enum_raw_value_without_raw_type);
4119-
// Recover by setting the raw type as this element's type.
4120-
Expr *typeCheckedExpr = rawValue;
4121-
if (!typeCheckExpression(typeCheckedExpr, ED)) {
4122-
EED->setTypeCheckedRawValueExpr(typeCheckedExpr);
4123-
checkEnumElementErrorHandling(EED);
4124-
}
4125-
} else {
4126-
// Wait until the second pass, when all the raw value expressions
4127-
// can be checked together.
4128-
}
4129-
}
4130-
41314092
// Now that we have an argument type we can set the element's declared
41324093
// type.
41334094
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
@@ -1008,6 +1008,8 @@ class TypeChecker final : public LazyResolver {
10081008

10091009
/// Check the default arguments that occur within this value decl.
10101010
void checkDefaultArguments(ParameterList *params, ValueDecl *VD);
1011+
/// Check the raw value expression in this enum element.
1012+
void checkRawValueExpr(EnumDecl *parent, EnumElementDecl *Elt);
10111013

10121014
virtual void resolveDeclSignature(ValueDecl *VD) override {
10131015
validateDecl(VD);

0 commit comments

Comments
 (0)