Skip to content

Commit 7f236db

Browse files
tkremenekAzoy
authored andcommitted
Merge pull request #19743 from Azoy/smarter-struct-init
[Sema] Synthesize default values for memberwise init module minor version
1 parent 6c58acd commit 7f236db

19 files changed

+259
-30
lines changed

include/swift/AST/Decl.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4910,7 +4910,7 @@ class ParamDecl : public VarDecl {
49104910
SourceLoc SpecifierLoc;
49114911

49124912
struct StoredDefaultArgument {
4913-
Expr *DefaultArg = nullptr;
4913+
PointerUnion<Expr *, VarDecl *> DefaultArg;
49144914
Initializer *InitContext = nullptr;
49154915
StringRef StringRepresentation;
49164916
};
@@ -4967,12 +4967,20 @@ class ParamDecl : public VarDecl {
49674967

49684968
Expr *getDefaultValue() const {
49694969
if (auto stored = DefaultValueAndFlags.getPointer())
4970-
return stored->DefaultArg;
4970+
return stored->DefaultArg.dyn_cast<Expr *>();
4971+
return nullptr;
4972+
}
4973+
4974+
VarDecl *getStoredProperty() const {
4975+
if (auto stored = DefaultValueAndFlags.getPointer())
4976+
return stored->DefaultArg.dyn_cast<VarDecl *>();
49714977
return nullptr;
49724978
}
49734979

49744980
void setDefaultValue(Expr *E);
49754981

4982+
void setStoredProperty(VarDecl *var);
4983+
49764984
Initializer *getDefaultArgumentInitContext() const {
49774985
if (auto stored = DefaultValueAndFlags.getPointer())
49784986
return stored->InitContext;

include/swift/AST/DefaultArgumentKind.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ enum class DefaultArgumentKind : uint8_t {
5252
EmptyArray,
5353
/// An empty dictionary literal.
5454
EmptyDictionary,
55+
/// A reference to the stored property. This is a special default argument
56+
/// kind for the synthesized memberwise constructor to emit a call to the
57+
// property's initializer.
58+
StoredProperty,
5559
};
5660
enum { NumDefaultArgumentKindBits = 4 };
5761

include/swift/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 478; // Last change: import control
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 479; // stored property default arg
5656

5757
using DeclIDField = BCFixed<31>;
5858

@@ -379,6 +379,7 @@ enum class DefaultArgumentKind : uint8_t {
379379
NilLiteral,
380380
EmptyArray,
381381
EmptyDictionary,
382+
StoredProperty,
382383
};
383384
using DefaultArgumentField = BCFixed<4>;
384385

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ static StringRef getDefaultArgumentKindString(DefaultArgumentKind value) {
305305
case DefaultArgumentKind::EmptyArray: return "[]";
306306
case DefaultArgumentKind::EmptyDictionary: return "[:]";
307307
case DefaultArgumentKind::Normal: return "normal";
308+
case DefaultArgumentKind::StoredProperty: return "stored property";
308309
}
309310

310311
llvm_unreachable("Unhandled DefaultArgumentKind in switch.");

lib/AST/Decl.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5286,6 +5286,17 @@ void ParamDecl::setDefaultValue(Expr *E) {
52865286
DefaultValueAndFlags.getPointer()->DefaultArg = E;
52875287
}
52885288

5289+
void ParamDecl::setStoredProperty(VarDecl *var) {
5290+
if (!DefaultValueAndFlags.getPointer()) {
5291+
if (!var) return;
5292+
5293+
DefaultValueAndFlags.setPointer(
5294+
getASTContext().Allocate<StoredDefaultArgument>());
5295+
}
5296+
5297+
DefaultValueAndFlags.getPointer()->DefaultArg = var;
5298+
}
5299+
52895300
void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
52905301
assert(DefaultValueAndFlags.getPointer());
52915302
DefaultValueAndFlags.getPointer()->InitContext = initContext;
@@ -5314,6 +5325,17 @@ ParamDecl::getDefaultValueStringRepresentation(
53145325
return extractInlinableText(getASTContext().SourceMgr, getDefaultValue(),
53155326
scratch);
53165327
}
5328+
case DefaultArgumentKind::StoredProperty: {
5329+
assert(DefaultValueAndFlags.getPointer() &&
5330+
"default value not provided yet");
5331+
auto existing = DefaultValueAndFlags.getPointer()->StringRepresentation;
5332+
if (!existing.empty())
5333+
return existing;
5334+
auto var = getStoredProperty();
5335+
return extractInlinableText(getASTContext().SourceMgr,
5336+
var->getParentInitializer(),
5337+
scratch);
5338+
}
53175339
case DefaultArgumentKind::Inherited:
53185340
// FIXME: This needs /some/ kind of textual representation, but this isn't
53195341
// a great one.
@@ -5332,7 +5354,8 @@ ParamDecl::getDefaultValueStringRepresentation(
53325354

53335355
void
53345356
ParamDecl::setDefaultValueStringRepresentation(StringRef stringRepresentation) {
5335-
assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal);
5357+
assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal ||
5358+
getDefaultArgumentKind() == DefaultArgumentKind::StoredProperty);
53365359
assert(!stringRepresentation.empty());
53375360

53385361
if (!DefaultValueAndFlags.getPointer()) {
@@ -5351,7 +5374,7 @@ void DefaultArgumentInitializer::changeFunction(
53515374
}
53525375

53535376
auto param = paramList->get(getIndex());
5354-
if (param->getDefaultValue())
5377+
if (param->getDefaultValue() || param->getStoredProperty())
53555378
param->setDefaultArgumentInitContext(this);
53565379
}
53575380

lib/IDE/CodeCompletion.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,6 +2069,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
20692069
for (auto param : *func->getParameters()) {
20702070
switch (param->getDefaultArgumentKind()) {
20712071
case DefaultArgumentKind::Normal:
2072+
case DefaultArgumentKind::StoredProperty:
20722073
case DefaultArgumentKind::Inherited: // FIXME: include this?
20732074
return true;
20742075
default:
@@ -2096,6 +2097,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
20962097
return false;
20972098

20982099
case DefaultArgumentKind::Normal:
2100+
case DefaultArgumentKind::StoredProperty:
20992101
case DefaultArgumentKind::Inherited:
21002102
case DefaultArgumentKind::NilLiteral:
21012103
case DefaultArgumentKind::EmptyArray:

lib/SILGen/SILGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,7 @@ void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, Expr *arg,
10811081
case DefaultArgumentKind::NilLiteral:
10821082
case DefaultArgumentKind::EmptyArray:
10831083
case DefaultArgumentKind::EmptyDictionary:
1084+
case DefaultArgumentKind::StoredProperty:
10841085
return;
10851086
}
10861087

lib/SILGen/SILGenApply.cpp

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/ASTContext.h"
2626
#include "swift/AST/DiagnosticsSIL.h"
2727
#include "swift/AST/ForeignErrorConvention.h"
28+
#include "swift/AST/GenericEnvironment.h"
2829
#include "swift/AST/GenericSignature.h"
2930
#include "swift/AST/ParameterList.h"
3031
#include "swift/AST/Module.h"
@@ -3340,12 +3341,41 @@ void DelayedArgument::emitDefaultArgument(SILGenFunction &SGF,
33403341
const DefaultArgumentStorage &info,
33413342
SmallVectorImpl<ManagedValue> &args,
33423343
size_t &argIndex) {
3343-
auto value = SGF.emitApplyOfDefaultArgGenerator(info.loc,
3344-
info.defaultArgsOwner,
3345-
info.destIndex,
3346-
info.resultType,
3347-
info.origResultType);
3348-
3344+
RValue value;
3345+
bool isStoredPropertyDefaultArg = false;
3346+
3347+
// Check if this is a synthesized memberwise constructor for stored property
3348+
// default values
3349+
if (auto ctor = dyn_cast<ConstructorDecl>(info.defaultArgsOwner.getDecl())) {
3350+
if (ctor->isMemberwiseInitializer() && ctor->isImplicit()) {
3351+
auto param = ctor->getParameters()->get(info.destIndex);
3352+
3353+
if (auto var = param->getStoredProperty()) {
3354+
// This is a stored property default arg. Do not emit a call to the
3355+
// default arg generator, but rather the variable initializer expression
3356+
isStoredPropertyDefaultArg = true;
3357+
3358+
auto pbd = var->getParentPatternBinding();
3359+
auto entry = pbd->getPatternEntryForVarDecl(var);
3360+
auto subs = info.defaultArgsOwner.getSubstitutions();
3361+
3362+
value = SGF.emitApplyOfStoredPropertyInitializer(info.loc,
3363+
entry, subs,
3364+
info.resultType,
3365+
info.origResultType,
3366+
SGFContext());
3367+
}
3368+
}
3369+
}
3370+
3371+
if (!isStoredPropertyDefaultArg) {
3372+
value = SGF.emitApplyOfDefaultArgGenerator(info.loc,
3373+
info.defaultArgsOwner,
3374+
info.destIndex,
3375+
info.resultType,
3376+
info.origResultType);
3377+
}
3378+
33493379
SmallVector<ManagedValue, 4> loweredArgs;
33503380
SmallVector<DelayedArgument, 4> delayedArgs;
33513381
Optional<ForeignErrorConvention> errorConvention = None;

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4842,6 +4842,7 @@ getCallerDefaultArg(ConstraintSystem &cs, DeclContext *dc,
48424842
case DefaultArgumentKind::None:
48434843
llvm_unreachable("No default argument here?");
48444844

4845+
case DefaultArgumentKind::StoredProperty:
48454846
case DefaultArgumentKind::Normal:
48464847
return {nullptr, param->getDefaultArgumentKind()};
48474848

lib/Sema/CodeSynthesis.cpp

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,52 @@ void synthesizeAccessorBody(AbstractFunctionDecl *fn, void *) {
16431643
llvm_unreachable("bad synthesized function kind");
16441644
}
16451645

1646+
static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
1647+
SmallVectorImpl<DefaultArgumentInitializer *> &defaultInits,
1648+
unsigned paramSize, ASTContext &ctx) {
1649+
// First and foremost, if this is a constant don't bother.
1650+
if (var->isLet())
1651+
return;
1652+
1653+
// We can only provide default values for patterns binding a single variable.
1654+
// i.e. var (a, b) = getSomeTuple() is not allowed.
1655+
if (!var->getParentPattern()->getSingleVar())
1656+
return;
1657+
1658+
// If we don't have an expression initializer or silgen can't assign a default
1659+
// initializer, then we can't generate a default value. An example of where
1660+
// silgen can assign a default is var x: Int? where the default is nil.
1661+
// If the variable is lazy, go ahead and give it a default value.
1662+
if (!var->getAttrs().hasAttribute<LazyAttr>() &&
1663+
!var->getParentPatternBinding()->isDefaultInitializable())
1664+
return;
1665+
1666+
// We can add a default value now.
1667+
1668+
// Give this some bogus context right now, we'll fix it after making
1669+
// the constructor.
1670+
auto *initDC = new (ctx) DefaultArgumentInitializer(
1671+
arg->getDeclContext(), paramSize);
1672+
1673+
defaultInits.push_back(initDC);
1674+
1675+
// If the variable has a type T? and no initial value, return a nil literal
1676+
// default arg. All lazy variables return a nil literal as well. *Note* that
1677+
// the type will always be a sugared T? because we don't default init an
1678+
// explicit Optional<T>.
1679+
if ((isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
1680+
!var->getParentInitializer()) ||
1681+
var->getAttrs().hasAttribute<LazyAttr>()) {
1682+
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
1683+
return;
1684+
}
1685+
1686+
// Set the default value to the variable. When we emit this in silgen
1687+
// we're going to call the variable's initializer expression.
1688+
arg->setStoredProperty(var);
1689+
arg->setDefaultArgumentKind(DefaultArgumentKind::StoredProperty);
1690+
}
1691+
16461692
/// Create an implicit struct or class constructor.
16471693
///
16481694
/// \param decl The struct or class for which a constructor will be created.
@@ -1655,12 +1701,13 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
16551701
ImplicitConstructorKind ICK) {
16561702
assert(!decl->hasClangNode());
16571703

1658-
ASTContext &context = tc.Context;
1704+
ASTContext &ctx = tc.Context;
16591705
SourceLoc Loc = decl->getLoc();
16601706
auto accessLevel = AccessLevel::Internal;
16611707

16621708
// Determine the parameter type of the implicit constructor.
16631709
SmallVector<ParamDecl*, 8> params;
1710+
SmallVector<DefaultArgumentInitializer *, 8> defaultInits;
16641711
if (ICK == ImplicitConstructorKind::Memberwise) {
16651712
assert(isa<StructDecl>(decl) && "Only struct have memberwise constructor");
16661713

@@ -1693,28 +1740,30 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
16931740
// If var is a lazy property, its value is provided for the underlying
16941741
// storage. We thus take an optional of the properties type. We only
16951742
// need to do this because the implicit constructor is added before all
1696-
// the properties are type checked. Perhaps init() synth should be moved
1743+
// the properties are type checked. Perhaps init() synth should be moved
16971744
// later.
16981745
if (var->getAttrs().hasAttribute<LazyAttr>())
16991746
varInterfaceType = OptionalType::get(varInterfaceType);
17001747

17011748
// Create the parameter.
1702-
auto *arg = new (context)
1749+
auto *arg = new (ctx)
17031750
ParamDecl(VarDecl::Specifier::Default, SourceLoc(), Loc,
17041751
var->getName(), Loc, var->getName(), decl);
17051752
arg->setInterfaceType(varInterfaceType);
17061753
arg->setImplicit();
17071754

1755+
maybeAddMemberwiseDefaultArg(arg, var, defaultInits, params.size(), ctx);
1756+
17081757
params.push_back(arg);
17091758
}
17101759
}
17111760

1712-
auto paramList = ParameterList::create(context, params);
1761+
auto paramList = ParameterList::create(ctx, params);
17131762

17141763
// Create the constructor.
1715-
DeclName name(context, DeclBaseName::createConstructor(), paramList);
1764+
DeclName name(ctx, DeclBaseName::createConstructor(), paramList);
17161765
auto *ctor =
1717-
new (context) ConstructorDecl(name, Loc,
1766+
new (ctx) ConstructorDecl(name, Loc,
17181767
OTK_None, /*FailabilityLoc=*/SourceLoc(),
17191768
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
17201769
paramList, /*GenericParams=*/nullptr, decl);
@@ -1723,15 +1772,21 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
17231772
ctor->setImplicit();
17241773
ctor->setAccess(accessLevel);
17251774

1726-
if (ICK == ImplicitConstructorKind::Memberwise)
1775+
if (ICK == ImplicitConstructorKind::Memberwise) {
17271776
ctor->setIsMemberwiseInitializer();
17281777

1778+
// Fix default argument init contexts now that we have a constructor.
1779+
for (auto initDC : defaultInits) {
1780+
initDC->changeFunction(ctor, paramList);
1781+
}
1782+
}
1783+
17291784
// If we are defining a default initializer for a class that has a superclass,
17301785
// it overrides the default initializer of its superclass. Add an implicit
17311786
// 'override' attribute.
17321787
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
17331788
if (classDecl->getSuperclass())
1734-
ctor->getAttrs().add(new (tc.Context) OverrideAttr(/*IsImplicit=*/true));
1789+
ctor->getAttrs().add(new (ctx) OverrideAttr(/*IsImplicit=*/true));
17351790
}
17361791

17371792
return ctor;

lib/Serialization/Deserialization.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ getActualDefaultArgKind(uint8_t raw) {
238238
return swift::DefaultArgumentKind::EmptyArray;
239239
case serialization::DefaultArgumentKind::EmptyDictionary:
240240
return swift::DefaultArgumentKind::EmptyDictionary;
241+
case serialization::DefaultArgumentKind::StoredProperty:
242+
return swift::DefaultArgumentKind::StoredProperty;
241243
}
242244
return None;
243245
}

lib/Serialization/Serialization.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,7 @@ static uint8_t getRawStableDefaultArgumentKind(swift::DefaultArgumentKind kind)
11711171
CASE(NilLiteral)
11721172
CASE(EmptyArray)
11731173
CASE(EmptyDictionary)
1174+
CASE(StoredProperty)
11741175
#undef CASE
11751176
}
11761177

@@ -3290,11 +3291,13 @@ void Serializer::writeDecl(const Decl *D) {
32903291
auto contextID = addDeclContextRef(param->getDeclContext());
32913292
Type interfaceType = param->getInterfaceType();
32923293

3293-
// Only save the text for normal default arguments, not any of the special
3294-
// ones.
3294+
// Only save the text for normal and stored property default arguments, not
3295+
// any of the special ones.
32953296
StringRef defaultArgumentText;
32963297
SmallString<128> scratch;
3297-
if (param->getDefaultArgumentKind() == swift::DefaultArgumentKind::Normal)
3298+
swift::DefaultArgumentKind argKind = param->getDefaultArgumentKind();
3299+
if (argKind == swift::DefaultArgumentKind::Normal ||
3300+
argKind == swift::DefaultArgumentKind::StoredProperty)
32983301
defaultArgumentText =
32993302
param->getDefaultValueStringRepresentation(scratch);
33003303

@@ -3307,7 +3310,7 @@ void Serializer::writeDecl(const Decl *D) {
33073310
addTypeRef(interfaceType),
33083311
param->isVariadic(),
33093312
param->isAutoClosure(),
3310-
getRawStableDefaultArgumentKind(param->getDefaultArgumentKind()),
3313+
getRawStableDefaultArgumentKind(argKind),
33113314
defaultArgumentText);
33123315

33133316
if (interfaceType->hasError()) {

test/IDE/complete_at_top_level.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ func resyncParser7() {}
263263
var topLevelVar2 = FooStruct#^TOP_LEVEL_VAR_INIT_2^#
264264
// TOP_LEVEL_VAR_INIT_2: Begin completions
265265
// TOP_LEVEL_VAR_INIT_2-NEXT: Decl[InstanceMethod]/CurrNominal: .instanceFunc({#(self): FooStruct#})[#(Int) -> Void#]{{; name=.+$}}
266+
// TOP_LEVEL_VAR_INIT_2-NEXT: Decl[Constructor]/CurrNominal: ()[#FooStruct#]{{; name=.+$}}
266267
// TOP_LEVEL_VAR_INIT_2-NEXT: Decl[Constructor]/CurrNominal: ({#instanceVar: Int#})[#FooStruct#]{{; name=.+$}}
267268
// TOP_LEVEL_VAR_INIT_2-NEXT: Decl[Constructor]/CurrNominal: ()[#FooStruct#]{{; name=.+$}}
268269
// TOP_LEVEL_VAR_INIT_2-NEXT: Keyword[self]/CurrNominal: .self[#FooStruct.Type#]; name=self

test/IDE/complete_constructor.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ struct ImplicitConstructors2 {
8080

8181
func testImplicitConstructors2() {
8282
ImplicitConstructors2#^IMPLICIT_CONSTRUCTORS_2^#
83-
// IMPLICIT_CONSTRUCTORS_2: Begin completions, 4 items
83+
// IMPLICIT_CONSTRUCTORS_2: Begin completions, 5 items
84+
// IMPLICIT_CONSTRUCTORS_2-DAG: Decl[Constructor]/CurrNominal: ()[#ImplicitConstructors2#]{{; name=.+$}}
8485
// IMPLICIT_CONSTRUCTORS_2-DAG: Decl[Constructor]/CurrNominal: ({#instanceVar: Int#})[#ImplicitConstructors2#]{{; name=.+$}}
8586
// IMPLICIT_CONSTRUCTORS_2-DAG: Decl[Constructor]/CurrNominal: ()[#ImplicitConstructors2#]{{; name=.+$}}
8687
// IMPLICIT_CONSTRUCTORS_2-DAG: Keyword[self]/CurrNominal: .self[#ImplicitConstructors2.Type#]; name=self

0 commit comments

Comments
 (0)