Skip to content

Commit 9b7ab6b

Browse files
authored
Merge pull request #27403 from CodaFi/thursday-night-raw
Requestify the Raw Value Accessor
2 parents 8c5dcc0 + 6f3d610 commit 9b7ab6b

19 files changed

+270
-119
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ SWIFT_TYPEID(Type)
2626
SWIFT_TYPEID(TypePair)
2727
SWIFT_TYPEID_NAMED(CustomAttr *, CustomAttr)
2828
SWIFT_TYPEID_NAMED(Decl *, Decl)
29+
SWIFT_TYPEID_NAMED(EnumDecl *, EnumDecl)
2930
SWIFT_TYPEID_NAMED(GenericParamList *, GenericParamList)
3031
SWIFT_TYPEID_NAMED(GenericTypeParamType *, GenericTypeParamType)
3132
SWIFT_TYPEID_NAMED(InfixOperatorDecl *, InfixOperatorDecl)

include/swift/AST/ASTTypeIDs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class AbstractFunctionDecl;
2525
class BraceStmt;
2626
class CustomAttr;
2727
class Decl;
28+
class EnumDecl;
2829
class GenericParamList;
2930
class GenericSignature;
3031
class GenericTypeParamType;

include/swift/AST/Decl.h

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,12 +3519,37 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
35193519
class EnumDecl final : public NominalTypeDecl {
35203520
SourceLoc EnumLoc;
35213521

3522+
enum SemanticInfoFlags : uint8_t {
3523+
// Is the raw type valid?
3524+
HasComputedRawType = 1 << 0,
3525+
// Is the complete set of (auto-incremented) raw values available?
3526+
HasFixedRawValues = 1 << 1,
3527+
// Is the complete set of raw values type checked?
3528+
HasFixedRawValuesAndTypes = 1 << 2,
3529+
};
3530+
35223531
struct {
35233532
/// The raw type and a bit to indicate whether the
35243533
/// raw was computed yet or not.
3525-
llvm::PointerIntPair<Type, 1, bool> RawType;
3534+
llvm::PointerIntPair<Type, 3, OptionSet<SemanticInfoFlags>> RawTypeAndFlags;
3535+
3536+
bool hasRawType() const {
3537+
return RawTypeAndFlags.getInt().contains(HasComputedRawType);
3538+
}
3539+
void cacheRawType(Type ty) {
3540+
auto flags = RawTypeAndFlags.getInt() | HasComputedRawType;
3541+
RawTypeAndFlags.setPointerAndInt(ty, flags);
3542+
}
3543+
3544+
bool hasFixedRawValues() const {
3545+
return RawTypeAndFlags.getInt().contains(HasFixedRawValues);
3546+
}
3547+
bool hasCheckedRawValues() const {
3548+
return RawTypeAndFlags.getInt().contains(HasFixedRawValuesAndTypes);
3549+
}
35263550
} LazySemanticInfo;
35273551

3552+
friend class EnumRawValuesRequest;
35283553
friend class EnumRawTypeRequest;
35293554
friend class TypeChecker;
35303555

@@ -3583,6 +3608,9 @@ class EnumDecl final : public NominalTypeDecl {
35833608
Bits.EnumDecl.Circularity = static_cast<unsigned>(circularity);
35843609
}
35853610

3611+
/// Record that this enum has had all of its raw values computed.
3612+
void setHasFixedRawValues();
3613+
35863614
// Implement isa/cast/dyncast/etc.
35873615
static bool classof(const Decl *D) {
35883616
return D->getKind() == DeclKind::Enum;
@@ -3612,9 +3640,11 @@ class EnumDecl final : public NominalTypeDecl {
36123640

36133641
/// Set the raw type of the enum from its inheritance clause.
36143642
void setRawType(Type rawType) {
3615-
LazySemanticInfo.RawType.setPointerAndInt(rawType, true);
3643+
auto flags = LazySemanticInfo.RawTypeAndFlags.getInt();
3644+
LazySemanticInfo.RawTypeAndFlags.setPointerAndInt(
3645+
rawType, flags | HasComputedRawType);
36163646
}
3617-
3647+
36183648
/// True if none of the enum cases have associated values.
36193649
///
36203650
/// Note that this is true for enums with absolutely no cases.
@@ -6354,6 +6384,8 @@ class EnumCaseDecl final : public Decl,
63546384
/// parent EnumDecl, although syntactically they are subordinate to the
63556385
/// EnumCaseDecl.
63566386
class EnumElementDecl : public DeclContext, public ValueDecl {
6387+
friend class EnumRawValuesRequest;
6388+
63576389
/// This is the type specified with the enum element, for
63586390
/// example 'Int' in 'case Y(Int)'. This is null if there is no type
63596391
/// associated with this element, as in 'case Z' or in all elements of enum
@@ -6394,9 +6426,20 @@ class EnumElementDecl : public DeclContext, public ValueDecl {
63946426

63956427
ParameterList *getParameterList() const { return Params; }
63966428

6397-
bool hasRawValueExpr() const { return RawValueExpr; }
6398-
LiteralExpr *getRawValueExpr() const { return RawValueExpr; }
6399-
void setRawValueExpr(LiteralExpr *e) { RawValueExpr = e; }
6429+
/// Retrieves a fully typechecked raw value expression associated
6430+
/// with this enum element, if it exists.
6431+
LiteralExpr *getRawValueExpr() const;
6432+
6433+
/// Retrieves a "structurally" checked raw value expression associated
6434+
/// with this enum element, if it exists.
6435+
///
6436+
/// The structural raw value may or may not have a type set, but it is
6437+
/// guaranteed to be suitable for retrieving any non-semantic information
6438+
/// like digit text for an integral raw value or user text for a string raw value.
6439+
LiteralExpr *getStructuralRawValueExpr() const;
6440+
6441+
/// Reset the raw value expression.
6442+
void setRawValueExpr(LiteralExpr *e);
64006443

64016444
/// Return the containing EnumDecl.
64026445
EnumDecl *getParentEnum() const {
@@ -6419,6 +6462,10 @@ class EnumElementDecl : public DeclContext, public ValueDecl {
64196462
bool isIndirect() const {
64206463
return getAttrs().hasAttribute<IndirectAttr>();
64216464
}
6465+
6466+
/// Do not call this!
6467+
/// It exists to let the AST walkers get the raw value without forcing a request.
6468+
LiteralExpr *getRawValueUnchecked() const { return RawValueExpr; }
64226469

64236470
static bool classof(const Decl *D) {
64246471
return D->getKind() == DeclKind::EnumElement;

include/swift/AST/TypeCheckRequests.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,31 @@ class OperatorPrecedenceGroupRequest
12301230
bool isCached() const { return true; }
12311231
};
12321232

1233+
class EnumRawValuesRequest :
1234+
public SimpleRequest<EnumRawValuesRequest,
1235+
bool (EnumDecl *, TypeResolutionStage),
1236+
CacheKind::SeparatelyCached> {
1237+
public:
1238+
using SimpleRequest::SimpleRequest;
1239+
1240+
private:
1241+
friend SimpleRequest;
1242+
1243+
// Evaluation.
1244+
llvm::Expected<bool>
1245+
evaluate(Evaluator &evaluator, EnumDecl *ED, TypeResolutionStage stage) const;
1246+
1247+
public:
1248+
// Cycle handling.
1249+
void diagnoseCycle(DiagnosticEngine &diags) const;
1250+
void noteCycleStep(DiagnosticEngine &diags) const;
1251+
1252+
// Separate caching.
1253+
bool isCached() const;
1254+
Optional<bool> getCachedResult() const;
1255+
void cacheResult(bool value) const;
1256+
};
1257+
12331258
// Allow AnyValue to compare two Type values, even though Type doesn't
12341259
// support ==.
12351260
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ SWIFT_REQUEST(TypeChecker, DefaultTypeRequest,
3636
NoLocationInfo)
3737
SWIFT_REQUEST(TypeChecker, EmittedMembersRequest, DeclRange(ClassDecl *),
3838
SeparatelyCached, NoLocationInfo)
39+
SWIFT_REQUEST(TypeChecker, EnumRawValuesRequest,
40+
bool (EnumDecl *, TypeResolutionStage), SeparatelyCached,
41+
NoLocationInfo)
3942
SWIFT_REQUEST(TypeChecker, EnumRawTypeRequest,
4043
Type(EnumDecl *, TypeResolutionStage), SeparatelyCached,
4144
NoLocationInfo)

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2893,7 +2893,7 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) {
28932893
break;
28942894
}
28952895

2896-
auto *raw = elt->getRawValueExpr();
2896+
auto *raw = elt->getStructuralRawValueExpr();
28972897
if (!raw || raw->isImplicit())
28982898
return;
28992899

lib/AST/ASTScopeCreation.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,8 +1346,12 @@ void EnumElementScope::expandAScopeThatDoesNotCreateANewInsertionPoint(
13461346
if (auto *pl = decl->getParameterList())
13471347
scopeCreator.constructExpandAndInsertUncheckable<ParameterListScope>(
13481348
this, pl, nullptr);
1349-
// might contain a closure
1350-
scopeCreator.addToScopeTree(decl->getRawValueExpr(), this);
1349+
// The invariant that the raw value expression can never introduce a new scope
1350+
// is checked in Parse. However, this guarantee is not future-proof. Compute
1351+
// and add the raw value expression anyways just to be defensive.
1352+
//
1353+
// FIXME: Re-enable this. It currently crashes for malformed enum cases.
1354+
// scopeCreator.addToScopeTree(decl->getStructuralRawValueExpr(), this);
13511355
}
13521356

13531357
void AbstractFunctionBodyScope::expandAScopeThatDoesNotCreateANewInsertionPoint(

lib/AST/ASTWalker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
403403
visit(PL);
404404
}
405405

406-
if (auto *rawLiteralExpr = ED->getRawValueExpr()) {
406+
if (auto *rawLiteralExpr = ED->getRawValueUnchecked()) {
407407
Expr *newRawExpr = doIt(rawLiteralExpr);
408408
if (auto newRawLiteralExpr = dyn_cast<LiteralExpr>(newRawExpr))
409409
ED->setRawValueExpr(newRawLiteralExpr);

lib/AST/Decl.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4292,6 +4292,12 @@ bool EnumDecl::isEffectivelyExhaustive(ModuleDecl *M,
42924292
"these should match up");
42934293
return !isResilient(M, expansion);
42944294
}
4295+
4296+
void EnumDecl::setHasFixedRawValues() {
4297+
auto flags = LazySemanticInfo.RawTypeAndFlags.getInt() |
4298+
EnumDecl::HasFixedRawValues;
4299+
LazySemanticInfo.RawTypeAndFlags.setInt(flags);
4300+
}
42954301

42964302
ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
42974303
SourceLoc NameLoc, Identifier Name,
@@ -7197,6 +7203,32 @@ EnumCaseDecl *EnumElementDecl::getParentCase() const {
71977203

71987204
llvm_unreachable("enum element not in case of parent enum");
71997205
}
7206+
7207+
LiteralExpr *EnumElementDecl::getRawValueExpr() const {
7208+
// The return value of this request is irrelevant - it exists as
7209+
// a cache-warmer.
7210+
(void)evaluateOrDefault(
7211+
getASTContext().evaluator,
7212+
EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Interface},
7213+
true);
7214+
return RawValueExpr;
7215+
}
7216+
7217+
LiteralExpr *EnumElementDecl::getStructuralRawValueExpr() const {
7218+
// The return value of this request is irrelevant - it exists as
7219+
// a cache-warmer.
7220+
(void)evaluateOrDefault(
7221+
getASTContext().evaluator,
7222+
EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Structural},
7223+
true);
7224+
return RawValueExpr;
7225+
}
7226+
7227+
void EnumElementDecl::setRawValueExpr(LiteralExpr *e) {
7228+
assert((!RawValueExpr || e == RawValueExpr || e->getType()) &&
7229+
"Illegal mutation of raw value expr");
7230+
RawValueExpr = e;
7231+
}
72007232

72017233
SourceRange ConstructorDecl::getSourceRange() const {
72027234
if (isImplicit())

lib/AST/TypeCheckRequests.cpp

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,15 @@ bool EnumRawTypeRequest::isCached() const {
167167

168168
Optional<Type> EnumRawTypeRequest::getCachedResult() const {
169169
auto enumDecl = std::get<0>(getStorage());
170-
if (enumDecl->LazySemanticInfo.RawType.getInt())
171-
return enumDecl->LazySemanticInfo.RawType.getPointer();
170+
if (enumDecl->LazySemanticInfo.hasRawType())
171+
return enumDecl->LazySemanticInfo.RawTypeAndFlags.getPointer();
172172

173173
return None;
174174
}
175175

176176
void EnumRawTypeRequest::cacheResult(Type value) const {
177177
auto enumDecl = std::get<0>(getStorage());
178-
enumDecl->LazySemanticInfo.RawType.setPointerAndInt(value, true);
178+
enumDecl->LazySemanticInfo.cacheRawType(value);
179179
}
180180

181181
//----------------------------------------------------------------------------//
@@ -839,7 +839,7 @@ void InferredGenericSignatureRequest::noteCycleStep(DiagnosticEngine &d) const {
839839
}
840840

841841
//----------------------------------------------------------------------------//
842-
// IsImplicitlyUnwrappedOptionalRequest computation.
842+
// UnderlyingTypeRequest computation.
843843
//----------------------------------------------------------------------------//
844844

845845
Optional<Type>
@@ -854,3 +854,36 @@ void UnderlyingTypeRequest::cacheResult(Type value) const {
854854
auto *typeAlias = std::get<0>(getStorage());
855855
typeAlias->UnderlyingTy.setType(value);
856856
}
857+
858+
//----------------------------------------------------------------------------//
859+
// EnumRawValuesRequest computation.
860+
//----------------------------------------------------------------------------//
861+
862+
bool EnumRawValuesRequest::isCached() const {
863+
return std::get<1>(getStorage()) == TypeResolutionStage::Interface;
864+
}
865+
866+
Optional<bool> EnumRawValuesRequest::getCachedResult() const {
867+
auto *ED = std::get<0>(getStorage());
868+
if (ED->LazySemanticInfo.hasCheckedRawValues())
869+
return true;
870+
return None;
871+
}
872+
873+
void EnumRawValuesRequest::cacheResult(bool) const {
874+
auto *ED = std::get<0>(getStorage());
875+
auto flags = ED->LazySemanticInfo.RawTypeAndFlags.getInt() |
876+
EnumDecl::HasFixedRawValues |
877+
EnumDecl::HasFixedRawValuesAndTypes;
878+
ED->LazySemanticInfo.RawTypeAndFlags.setInt(flags);
879+
}
880+
881+
void EnumRawValuesRequest::diagnoseCycle(DiagnosticEngine &diags) const {
882+
// This request computes the raw type, and so participates in cycles involving
883+
// it. For now, the raw type provides a rich enough circularity diagnostic
884+
// that we can silence ourselves.
885+
}
886+
887+
void EnumRawValuesRequest::noteCycleStep(DiagnosticEngine &diags) const {
888+
889+
}

lib/IDE/SyntaxModel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ bool ModelASTWalker::walkToDeclPre(Decl *D) {
916916
EnumElemD->getName().getLength());
917917
}
918918

919-
if (auto *E = EnumElemD->getRawValueExpr()) {
919+
if (auto *E = EnumElemD->getRawValueUnchecked()) {
920920
SourceRange ElemRange = E->getSourceRange();
921921
SN.Elements.emplace_back(SyntaxStructureElementKind::InitExpr,
922922
charSourceRangeFromSourceRange(SM, ElemRange));

lib/IRGen/GenEnum.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,7 @@ namespace {
11281128
int64_t getDiscriminatorIndex(EnumElementDecl *target) const override {
11291129
// The elements are assigned discriminators ABI-compatible with their
11301130
// raw values from C.
1131-
assert(target->hasRawValueExpr()
1131+
assert(target->getRawValueExpr()
11321132
&& "c-compatible enum elt has no raw value?!");
11331133
auto intExpr = cast<IntegerLiteralExpr>(target->getRawValueExpr());
11341134
auto intType = getDiscriminatorType();

lib/PrintAsObjC/DeclAndTypePrinter.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -393,12 +393,12 @@ class DeclAndTypePrinter::Implementation
393393
os << " SWIFT_COMPILE_NAME(\"" << Elt->getName() << "\")";
394394
}
395395

396-
if (auto ILE = cast_or_null<IntegerLiteralExpr>(Elt->getRawValueExpr())) {
397-
os << " = ";
398-
if (ILE->isNegative())
399-
os << "-";
400-
os << ILE->getDigitsText();
401-
}
396+
// Print the raw values, even the ones that we synthesize.
397+
auto *ILE = cast<IntegerLiteralExpr>(Elt->getStructuralRawValueExpr());
398+
os << " = ";
399+
if (ILE->isNegative())
400+
os << "-";
401+
os << ILE->getDigitsText();
402402
os << ",\n";
403403
}
404404
os << "};\n";

0 commit comments

Comments
 (0)