Skip to content

Commit 78b007f

Browse files
committed
Always create a DefaultArgumentInitializer for a parameter with a default argument.
As with pattern binding initializer contexts, we were trying to optimize away these contexts, leading to an unpredictable AST.
1 parent 85537fd commit 78b007f

File tree

11 files changed

+68
-94
lines changed

11 files changed

+68
-94
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -549,14 +549,6 @@ class ASTContext {
549549
addCleanup([&object]{ object.~T(); });
550550
}
551551

552-
/// Create a context for the initializer of the nth default argument
553-
/// of the given function. To reduce memory usage, if the context
554-
/// goes unused, it should be returned to the ASTContext with
555-
/// destroyDefaultArgumentContext.
556-
DefaultArgumentInitializer *createDefaultArgumentContext(DeclContext *fn,
557-
unsigned index);
558-
void destroyDefaultArgumentContext(DefaultArgumentInitializer *DC);
559-
560552
//===--------------------------------------------------------------------===//
561553
// Diagnostics Helper functions
562554
//===--------------------------------------------------------------------===//

include/swift/AST/Decl.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4275,8 +4275,13 @@ class ParamDecl : public VarDecl {
42754275
SourceLoc ArgumentNameLoc;
42764276
SourceLoc LetVarInOutLoc;
42774277

4278+
struct StoredDefaultArgument {
4279+
Expr *DefaultArg = nullptr;
4280+
Initializer *InitContext = nullptr;
4281+
};
4282+
42784283
/// The default value, if any, along with whether this is varargs.
4279-
llvm::PointerIntPair<Expr *, 1> DefaultValueAndIsVariadic;
4284+
llvm::PointerIntPair<StoredDefaultArgument *, 1> DefaultValueAndIsVariadic;
42804285

42814286
/// True if the type is implicitly specified in the source, but this has an
42824287
/// apparently valid typeRepr. This is used in accessors, which look like:
@@ -4322,13 +4327,22 @@ class ParamDecl : public VarDecl {
43224327
defaultArgumentKind = K;
43234328
}
43244329

4325-
void setDefaultValue(Expr *E) {
4326-
DefaultValueAndIsVariadic.setPointer(E);
4327-
}
43284330
Expr *getDefaultValue() const {
4329-
return DefaultValueAndIsVariadic.getPointer();
4331+
if (auto stored = DefaultValueAndIsVariadic.getPointer())
4332+
return stored->DefaultArg;
4333+
return nullptr;
43304334
}
43314335

4336+
void setDefaultValue(Expr *E);
4337+
4338+
Initializer *getDefaultArgumentInitContext() const {
4339+
if (auto stored = DefaultValueAndIsVariadic.getPointer())
4340+
return stored->InitContext;
4341+
return nullptr;
4342+
}
4343+
4344+
void setDefaultArgumentInitContext(Initializer *initContext);
4345+
43324346
/// Whether or not this parameter is varargs.
43334347
bool isVariadic() const { return DefaultValueAndIsVariadic.getInt(); }
43344348
void setVariadic(bool value = true) {DefaultValueAndIsVariadic.setInt(value);}

include/swift/AST/Expr.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -539,11 +539,6 @@ class alignas(8) Expr {
539539
/// walk into the body of it (unless it is single-expression).
540540
void forEachChildExpr(const std::function<Expr*(Expr*)> &callback);
541541

542-
/// findExistingInitializerContext - Given that this expression is
543-
/// an initializer that belongs in some sort of Initializer
544-
/// context, look through it for any existing context object.
545-
Initializer *findExistingInitializerContext();
546-
547542
/// Determine whether this expression refers to a type by name.
548543
///
549544
/// This distinguishes static references to types, like Int, from metatype

include/swift/AST/Initializer.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,8 @@ class DefaultArgumentInitializer : public Initializer {
155155
/// Change the parent of this context. This is necessary because
156156
/// the function signature is parsed before the function
157157
/// declaration/expression itself is built.
158-
void changeFunction(DeclContext *parent) {
159-
assert(parent->isLocalContext());
160-
setParent(parent);
161-
}
162-
158+
void changeFunction(AbstractFunctionDecl *parent);
159+
163160
static bool classof(const DeclContext *DC) {
164161
if (auto init = dyn_cast<Initializer>(DC))
165162
return classof(init);

include/swift/Parse/Parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ class Parser {
924924

925925
/// Set the parsed context for all the initializers to the given
926926
/// function.
927-
void setFunctionContext(DeclContext *DC);
927+
void setFunctionContext(AbstractFunctionDecl *AFD);
928928

929929
DefaultArgumentInfo(bool inTypeContext) {
930930
NextIndex = inTypeContext ? 1 : 0;

lib/AST/ASTContext.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,6 @@ struct ASTContext::Implementation {
258258
llvm::DenseMap<Decl *, std::pair<LazyMemberLoader *, uint64_t>>
259259
ConformanceLoaders;
260260

261-
/// \brief A cached unused default-argument initializer context.
262-
DefaultArgumentInitializer *UnusedDefaultArgumentContext = nullptr;
263-
264261
/// Mapping from archetypes with lazily-resolved nested types to the
265262
/// archetype builder and potential archetype corresponding to that
266263
/// archetype.
@@ -1559,22 +1556,6 @@ void ValueDecl::setLocalDiscriminator(unsigned index) {
15591556
getASTContext().Impl.LocalDiscriminators.insert({this, index});
15601557
}
15611558

1562-
DefaultArgumentInitializer *
1563-
ASTContext::createDefaultArgumentContext(DeclContext *fn, unsigned index) {
1564-
// Check for an existing context we can re-use.
1565-
if (auto existing = Impl.UnusedDefaultArgumentContext) {
1566-
Impl.UnusedDefaultArgumentContext = nullptr;
1567-
existing->reset(fn, index);
1568-
return existing;
1569-
}
1570-
1571-
return new (*this) DefaultArgumentInitializer(fn, index);
1572-
}
1573-
void ASTContext::destroyDefaultArgumentContext(DefaultArgumentInitializer *DC) {
1574-
// There isn't much value in caching more than one of these.
1575-
Impl.UnusedDefaultArgumentContext = DC;
1576-
}
1577-
15781559
NormalProtocolConformance *
15791560
ASTContext::getBehaviorConformance(Type conformingType,
15801561
Type conformingInterfaceType,

lib/AST/Decl.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3681,7 +3681,7 @@ ParamDecl::ParamDecl(ParamDecl *PD)
36813681
ArgumentName(PD->getArgumentName()),
36823682
ArgumentNameLoc(PD->getArgumentNameLoc()),
36833683
LetVarInOutLoc(PD->getLetVarInOutLoc()),
3684-
DefaultValueAndIsVariadic(PD->DefaultValueAndIsVariadic),
3684+
DefaultValueAndIsVariadic(nullptr, PD->DefaultValueAndIsVariadic.getInt()),
36853685
IsTypeLocImplicit(PD->IsTypeLocImplicit),
36863686
defaultArgumentKind(PD->defaultArgumentKind) {
36873687
typeLoc = PD->getTypeLoc();
@@ -3851,6 +3851,39 @@ Type ParamDecl::getVarargBaseTy(Type VarArgT) {
38513851
return T;
38523852
}
38533853

3854+
void ParamDecl::setDefaultValue(Expr *E) {
3855+
if (!DefaultValueAndIsVariadic.getPointer()) {
3856+
if (!E) return;
3857+
3858+
DefaultValueAndIsVariadic.setPointer(
3859+
getASTContext().Allocate<StoredDefaultArgument>());
3860+
}
3861+
3862+
DefaultValueAndIsVariadic.getPointer()->DefaultArg = E;
3863+
}
3864+
3865+
void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
3866+
assert(DefaultValueAndIsVariadic.getPointer());
3867+
DefaultValueAndIsVariadic.getPointer()->InitContext = initContext;
3868+
}
3869+
3870+
void DefaultArgumentInitializer::changeFunction(AbstractFunctionDecl *parent) {
3871+
assert(parent->isLocalContext());
3872+
setParent(parent);
3873+
3874+
unsigned offset = getIndex();
3875+
for (auto list : parent->getParameterLists()) {
3876+
if (offset < list->size()) {
3877+
auto param = list->get(offset);
3878+
if (param->getDefaultValue())
3879+
param->setDefaultArgumentInitContext(this);
3880+
return;
3881+
}
3882+
3883+
offset -= list->size();
3884+
}
3885+
}
3886+
38543887
/// Determine whether the given Swift type is an integral type, i.e.,
38553888
/// a type that wraps a builtin integer.
38563889
static bool isIntegralType(Type type) {

lib/AST/Expr.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -567,22 +567,6 @@ void Expr::forEachChildExpr(const std::function<Expr*(Expr*)> &callback) {
567567
this->walk(ChildWalker(callback));
568568
}
569569

570-
Initializer *Expr::findExistingInitializerContext() {
571-
struct FindExistingInitializer : ASTWalker {
572-
Initializer *TheInitializer = nullptr;
573-
std::pair<bool,Expr*> walkToExprPre(Expr *E) override {
574-
assert(!TheInitializer && "continuing to walk after finding context?");
575-
if (auto closure = dyn_cast<AbstractClosureExpr>(E)) {
576-
TheInitializer = cast<Initializer>(closure->getParent());
577-
return { false, nullptr };
578-
}
579-
return { true, E };
580-
}
581-
} finder;
582-
walk(finder);
583-
return finder.TheInitializer;
584-
}
585-
586570
bool Expr::isTypeReference() const {
587571
// If the result isn't a metatype, there's nothing else to do.
588572
if (!getType()->is<AnyMetatypeType>())

lib/AST/Parameter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ ParameterList *ParameterList::clone(const ASTContext &C,
9090

9191
// Remap the ParamDecls inside of the ParameterList.
9292
for (auto &decl : params) {
93+
bool hadDefaultArgument =decl->getDefaultValue() != nullptr;
94+
9395
decl = new (C) ParamDecl(decl);
9496
if (options & Implicit)
9597
decl->setImplicit();
@@ -101,9 +103,8 @@ ParameterList *ParameterList::clone(const ASTContext &C,
101103
decl->setName(C.getIdentifier("argument"));
102104

103105
// If we're inheriting a default argument, mark it as such.
104-
if (decl->isDefaultArgument() && (options & Inherited)) {
106+
if (hadDefaultArgument && (options & Inherited)) {
105107
decl->setDefaultArgumentKind(DefaultArgumentKind::Inherited);
106-
decl->setDefaultValue(nullptr);
107108
}
108109
}
109110

lib/Parse/ParsePattern.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,9 @@ static DefaultArgumentKind getDefaultArgKind(Expr *init) {
4747
}
4848
}
4949

50-
void Parser::DefaultArgumentInfo::setFunctionContext(DeclContext *DC) {
51-
assert(DC->isLocalContext());
50+
void Parser::DefaultArgumentInfo::setFunctionContext(AbstractFunctionDecl *AFD){
5251
for (auto context : ParsedContexts) {
53-
context->changeFunction(DC);
52+
context->changeFunction(AFD);
5453
}
5554
}
5655

@@ -64,19 +63,15 @@ static ParserStatus parseDefaultArgument(Parser &P,
6463
// Enter a fresh default-argument context with a meaningless parent.
6564
// We'll change the parent to the function later after we've created
6665
// that declaration.
67-
auto initDC =
68-
P.Context.createDefaultArgumentContext(P.CurDeclContext, argIndex);
66+
auto initDC = new (P.Context) DefaultArgumentInitializer(P.CurDeclContext,
67+
argIndex);
6968
Parser::ParseFunctionBody initScope(P, initDC);
7069

7170
ParserResult<Expr> initR = P.parseExpr(diag::expected_init_value);
7271

73-
// Give back the default-argument context if we didn't need it.
74-
if (!initScope.hasClosures()) {
75-
P.Context.destroyDefaultArgumentContext(initDC);
76-
77-
// Otherwise, record it if we're supposed to accept default
72+
// Record the default-argument context if we're supposed to accept default
7873
// arguments here.
79-
} else if (defaultArgs) {
74+
if (defaultArgs) {
8075
defaultArgs->ParsedContexts.push_back(initDC);
8176
}
8277

lib/Sema/TypeCheckStmt.cpp

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,26 +1206,13 @@ static void checkDefaultArguments(TypeChecker &tc, ParameterList *params,
12061206
assert(dc->isLocalContext());
12071207

12081208
for (auto &param : *params) {
1209-
unsigned curArgIndex = nextArgIndex++;
1209+
++nextArgIndex;
12101210
if (!param->getDefaultValue() || !param->hasType() ||
12111211
param->getType()->is<ErrorType>())
12121212
continue;
12131213

12141214
Expr *e = param->getDefaultValue();
1215-
1216-
// Re-use an existing initializer context if possible.
1217-
auto existingContext = e->findExistingInitializerContext();
1218-
DefaultArgumentInitializer *initContext;
1219-
if (existingContext) {
1220-
initContext = cast<DefaultArgumentInitializer>(existingContext);
1221-
assert(initContext->getIndex() == curArgIndex);
1222-
assert(initContext->getParent() == dc);
1223-
1224-
// Otherwise, allocate one temporarily.
1225-
} else {
1226-
initContext =
1227-
tc.Context.createDefaultArgumentContext(dc, curArgIndex);
1228-
}
1215+
auto initContext = param->getDefaultArgumentInitContext();
12291216

12301217
// Type-check the initializer, then flag that we did so.
12311218
if (!tc.typeCheckExpression(e, initContext,
@@ -1237,12 +1224,7 @@ static void checkDefaultArguments(TypeChecker &tc, ParameterList *params,
12371224

12381225
// Walk the checked initializer and contextualize any closures
12391226
// we saw there.
1240-
bool hasClosures = tc.contextualizeInitializer(initContext, e);
1241-
1242-
// If we created a new context and didn't run into any autoclosures
1243-
// during the walk, give the context back to the ASTContext.
1244-
if (!hasClosures && !existingContext)
1245-
tc.Context.destroyDefaultArgumentContext(initContext);
1227+
(void)tc.contextualizeInitializer(initContext, e);
12461228
}
12471229
}
12481230

0 commit comments

Comments
 (0)