Skip to content

Commit 7ae3d1f

Browse files
committed
Requestify default initializer context creation
This commit adds a request that computes the initializer context for a parameter with a default expr or stored property default. This avoids having to compute them for synthesized decls and is a step towards requestifying default argument parsing.
1 parent 4d216c7 commit 7ae3d1f

File tree

8 files changed

+112
-21
lines changed

8 files changed

+112
-21
lines changed

include/swift/AST/ASTTypeIDZone.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ SWIFT_TYPEID_NAMED(OpaqueTypeDecl *, OpaqueTypeDecl)
4545
SWIFT_TYPEID_NAMED(OperatorDecl *, OperatorDecl)
4646
SWIFT_TYPEID_NAMED(Optional<PropertyWrapperMutability>,
4747
PropertyWrapperMutability)
48+
SWIFT_TYPEID_NAMED(ParamDecl *, ParamDecl)
4849
SWIFT_TYPEID_NAMED(PatternBindingEntry *, PatternBindingEntry)
4950
SWIFT_TYPEID_NAMED(PrecedenceGroupDecl *, PrecedenceGroupDecl)
5051
SWIFT_TYPEID_NAMED(ProtocolDecl *, ProtocolDecl)

include/swift/AST/Decl.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5175,6 +5175,8 @@ enum class ParamSpecifier : uint8_t {
51755175

51765176
/// A function parameter declaration.
51775177
class ParamDecl : public VarDecl {
5178+
friend class DefaultArgumentInitContextRequest;
5179+
51785180
llvm::PointerIntPair<Identifier, 1, bool> ArgumentNameAndDestructured;
51795181
SourceLoc ParameterNameLoc;
51805182
SourceLoc ArgumentNameLoc;
@@ -5189,6 +5191,10 @@ class ParamDecl : public VarDecl {
51895191
CaptureInfo Captures;
51905192
};
51915193

5194+
/// Retrieve the cached initializer context for the parameter's default
5195+
/// argument without triggering a request.
5196+
Initializer *getDefaultArgumentInitContextCached() const;
5197+
51925198
enum class Flags : uint8_t {
51935199
/// Whether or not this parameter is vargs.
51945200
IsVariadic = 1 << 0,
@@ -5262,11 +5268,8 @@ class ParamDecl : public VarDecl {
52625268

52635269
void setStoredProperty(VarDecl *var);
52645270

5265-
Initializer *getDefaultArgumentInitContext() const {
5266-
if (auto stored = DefaultValueAndFlags.getPointer())
5267-
return stored->InitContext;
5268-
return nullptr;
5269-
}
5271+
/// Retrieve the initializer context for the parameter's default argument.
5272+
Initializer *getDefaultArgumentInitContext() const;
52705273

52715274
void setDefaultArgumentInitContext(Initializer *initContext);
52725275

include/swift/AST/TypeCheckRequests.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,28 @@ class HasCircularRawValueRequest
18431843
bool isCached() const { return true; }
18441844
};
18451845

1846+
/// Computes an initializer context for a parameter with a default argument.
1847+
class DefaultArgumentInitContextRequest
1848+
: public SimpleRequest<DefaultArgumentInitContextRequest,
1849+
Initializer *(ParamDecl *),
1850+
CacheKind::SeparatelyCached> {
1851+
public:
1852+
using SimpleRequest::SimpleRequest;
1853+
1854+
private:
1855+
friend SimpleRequest;
1856+
1857+
// Evaluation.
1858+
llvm::Expected<Initializer *> evaluate(Evaluator &evaluator,
1859+
ParamDecl *param) const;
1860+
1861+
public:
1862+
// Separate caching.
1863+
bool isCached() const { return true; }
1864+
Optional<Initializer *> getCachedResult() const;
1865+
void cacheResult(Initializer *init) const;
1866+
};
1867+
18461868
// Allow AnyValue to compare two Type values, even though Type doesn't
18471869
// support ==.
18481870
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest,
3232
SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest,
3333
bool (DeclContext *, ValueDecl *, ValueDecl *, bool), Cached,
3434
NoLocationInfo)
35+
SWIFT_REQUEST(TypeChecker, DefaultArgumentInitContextRequest,
36+
Initializer *(ParamDecl *), SeparatelyCached, NoLocationInfo)
3537
SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest,
3638
Type(AssociatedTypeDecl *), Cached, NoLocationInfo)
3739
SWIFT_REQUEST(TypeChecker, DefaultTypeRequest,

lib/AST/Decl.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6046,6 +6046,24 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const {
60466046
return AnyFunctionType::Param(type, label, flags);
60476047
}
60486048

6049+
Initializer *ParamDecl::getDefaultArgumentInitContextCached() const {
6050+
if (auto *defaultInfo = DefaultValueAndFlags.getPointer())
6051+
return defaultInfo->InitContext;
6052+
6053+
return nullptr;
6054+
}
6055+
6056+
Initializer *ParamDecl::getDefaultArgumentInitContext() const {
6057+
// If this param doesn't need a context, don't bother kicking off a request.
6058+
if (!getDefaultValue() && !getStoredProperty())
6059+
return nullptr;
6060+
6061+
auto &ctx = getASTContext();
6062+
auto *mutableThis = const_cast<ParamDecl *>(this);
6063+
return evaluateOrDefault(
6064+
ctx.evaluator, DefaultArgumentInitContextRequest{mutableThis}, nullptr);
6065+
}
6066+
60496067
void ParamDecl::setDefaultValue(Expr *E) {
60506068
if (!DefaultValueAndFlags.getPointer()) {
60516069
if (!E) return;
@@ -6093,8 +6111,13 @@ CustomAttr *ValueDecl::getAttachedFunctionBuilder() const {
60936111
}
60946112

60956113
void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
6096-
assert(DefaultValueAndFlags.getPointer());
6097-
DefaultValueAndFlags.getPointer()->InitContext = initContext;
6114+
auto *oldContext = getDefaultArgumentInitContextCached();
6115+
assert((!oldContext || oldContext == initContext) &&
6116+
"Cannot change init context after setting");
6117+
6118+
auto *defaultInfo = DefaultValueAndFlags.getPointer();
6119+
assert(defaultInfo);
6120+
defaultInfo->InitContext = initContext;
60986121
}
60996122

61006123
void ParamDecl::setDefaultArgumentCaptureInfo(CaptureInfo captures) {

lib/AST/TypeCheckRequests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,3 +1181,21 @@ void HasCircularRawValueRequest::noteCycleStep(DiagnosticEngine &diags) const {
11811181
diags.diagnose(decl, diag::kind_declname_declared_here,
11821182
decl->getDescriptiveKind(), decl->getName());
11831183
}
1184+
1185+
//----------------------------------------------------------------------------//
1186+
// DefaultArgumentInitContextRequest computation.
1187+
//----------------------------------------------------------------------------//
1188+
1189+
Optional<Initializer *>
1190+
DefaultArgumentInitContextRequest::getCachedResult() const {
1191+
auto *param = std::get<0>(getStorage());
1192+
if (auto *init = param->getDefaultArgumentInitContextCached())
1193+
return init;
1194+
1195+
return None;
1196+
}
1197+
1198+
void DefaultArgumentInitContextRequest::cacheResult(Initializer *init) const {
1199+
auto *param = std::get<0>(getStorage());
1200+
param->setDefaultArgumentInitContext(init);
1201+
}

lib/Sema/CodeSynthesis.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ Expr *swift::buildArgumentForwardingExpr(ArrayRef<ParamDecl*> params,
107107
}
108108

109109
static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
110-
SmallVectorImpl<DefaultArgumentInitializer *> &defaultInits,
111110
unsigned paramSize, ASTContext &ctx) {
112111
// First and foremost, if this is a constant don't bother.
113112
if (var->isLet())
@@ -138,13 +137,6 @@ static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
138137

139138
// We can add a default value now.
140139

141-
// Give this some bogus context right now, we'll fix it after making
142-
// the constructor.
143-
auto *initDC = new (ctx) DefaultArgumentInitializer(
144-
arg->getDeclContext(), paramSize);
145-
146-
defaultInits.push_back(initDC);
147-
148140
// If the variable has a type T? and no initial value, return a nil literal
149141
// default arg. All lazy variables return a nil literal as well. *Note* that
150142
// the type will always be a sugared T? because we don't default init an
@@ -244,7 +236,7 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
244236
// Don't allow the parameter to accept temporary pointer conversions.
245237
arg->setNonEphemeralIfPossible();
246238

247-
maybeAddMemberwiseDefaultArg(arg, var, defaultInits, params.size(), ctx);
239+
maybeAddMemberwiseDefaultArg(arg, var, params.size(), ctx);
248240

249241
params.push_back(arg);
250242
}
@@ -266,11 +258,6 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl,
266258

267259
if (ICK == ImplicitConstructorKind::Memberwise) {
268260
ctor->setIsMemberwiseInitializer();
269-
270-
// Fix default argument init contexts now that we have a constructor.
271-
for (auto initDC : defaultInits) {
272-
initDC->changeFunction(ctor, paramList);
273-
}
274261
}
275262

276263
// If we are defining a default initializer for a class that has a superclass,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,6 +2035,41 @@ static void checkDefaultArguments(ParameterList *params) {
20352035
}
20362036
}
20372037

2038+
llvm::Expected<Initializer *>
2039+
DefaultArgumentInitContextRequest::evaluate(Evaluator &eval,
2040+
ParamDecl *param) const {
2041+
auto &ctx = param->getASTContext();
2042+
auto *parentDC = param->getDeclContext();
2043+
auto *paramList = getParameterList(cast<ValueDecl>(parentDC->getAsDecl()));
2044+
2045+
// In order to compute the initializer context for this parameter, we need to
2046+
// know its index in the parameter list. Therefore iterate over the parameters
2047+
// looking for it and fill in the other parameter's contexts while we're here.
2048+
Initializer *result = nullptr;
2049+
for (auto idx : indices(*paramList)) {
2050+
auto *otherParam = paramList->get(idx);
2051+
2052+
// If this param doesn't need a context, we're done.
2053+
if (!otherParam->getDefaultValue() && !otherParam->getStoredProperty())
2054+
continue;
2055+
2056+
// If this param already has a context, continue using it.
2057+
if (otherParam->getDefaultArgumentInitContextCached())
2058+
continue;
2059+
2060+
// Create a new initializer context. If this is for the parameter that
2061+
// kicked off the request, make a note of it for when we return. Otherwise
2062+
// cache the result ourselves.
2063+
auto *initDC = new (ctx) DefaultArgumentInitializer(parentDC, idx);
2064+
if (param == otherParam)
2065+
result = initDC;
2066+
else
2067+
eval.cacheOutput(DefaultArgumentInitContextRequest{otherParam}, initDC);
2068+
}
2069+
assert(result && "Didn't create init context?");
2070+
return result;
2071+
}
2072+
20382073
PrecedenceGroupDecl *TypeChecker::lookupPrecedenceGroup(DeclContext *dc,
20392074
Identifier name,
20402075
SourceLoc nameLoc) {

0 commit comments

Comments
 (0)