Skip to content

[5.1] Synthesize default values for the memberwise initializer #23752

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4910,7 +4910,7 @@ class ParamDecl : public VarDecl {
SourceLoc SpecifierLoc;

struct StoredDefaultArgument {
Expr *DefaultArg = nullptr;
PointerUnion<Expr *, VarDecl *> DefaultArg;
Initializer *InitContext = nullptr;
StringRef StringRepresentation;
};
Expand Down Expand Up @@ -4967,12 +4967,20 @@ class ParamDecl : public VarDecl {

Expr *getDefaultValue() const {
if (auto stored = DefaultValueAndFlags.getPointer())
return stored->DefaultArg;
return stored->DefaultArg.dyn_cast<Expr *>();
return nullptr;
}

VarDecl *getStoredProperty() const {
if (auto stored = DefaultValueAndFlags.getPointer())
return stored->DefaultArg.dyn_cast<VarDecl *>();
return nullptr;
}

void setDefaultValue(Expr *E);

void setStoredProperty(VarDecl *var);

Initializer *getDefaultArgumentInitContext() const {
if (auto stored = DefaultValueAndFlags.getPointer())
return stored->InitContext;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DefaultArgumentKind.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ enum class DefaultArgumentKind : uint8_t {
EmptyArray,
/// An empty dictionary literal.
EmptyDictionary,
/// A reference to the stored property. This is a special default argument
/// kind for the synthesized memberwise constructor to emit a call to the
// property's initializer.
StoredProperty,
};
enum { NumDefaultArgumentKindBits = 4 };

Expand Down
3 changes: 2 additions & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 478; // Last change: import control
const uint16_t SWIFTMODULE_VERSION_MINOR = 479; // stored property default arg

using DeclIDField = BCFixed<31>;

Expand Down Expand Up @@ -379,6 +379,7 @@ enum class DefaultArgumentKind : uint8_t {
NilLiteral,
EmptyArray,
EmptyDictionary,
StoredProperty,
};
using DefaultArgumentField = BCFixed<4>;

Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ static StringRef getDefaultArgumentKindString(DefaultArgumentKind value) {
case DefaultArgumentKind::EmptyArray: return "[]";
case DefaultArgumentKind::EmptyDictionary: return "[:]";
case DefaultArgumentKind::Normal: return "normal";
case DefaultArgumentKind::StoredProperty: return "stored property";
}

llvm_unreachable("Unhandled DefaultArgumentKind in switch.");
Expand Down
27 changes: 25 additions & 2 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5286,6 +5286,17 @@ void ParamDecl::setDefaultValue(Expr *E) {
DefaultValueAndFlags.getPointer()->DefaultArg = E;
}

void ParamDecl::setStoredProperty(VarDecl *var) {
if (!DefaultValueAndFlags.getPointer()) {
if (!var) return;

DefaultValueAndFlags.setPointer(
getASTContext().Allocate<StoredDefaultArgument>());
}

DefaultValueAndFlags.getPointer()->DefaultArg = var;
}

void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) {
assert(DefaultValueAndFlags.getPointer());
DefaultValueAndFlags.getPointer()->InitContext = initContext;
Expand Down Expand Up @@ -5314,6 +5325,17 @@ ParamDecl::getDefaultValueStringRepresentation(
return extractInlinableText(getASTContext().SourceMgr, getDefaultValue(),
scratch);
}
case DefaultArgumentKind::StoredProperty: {
assert(DefaultValueAndFlags.getPointer() &&
"default value not provided yet");
auto existing = DefaultValueAndFlags.getPointer()->StringRepresentation;
if (!existing.empty())
return existing;
auto var = getStoredProperty();
return extractInlinableText(getASTContext().SourceMgr,
var->getParentInitializer(),
scratch);
}
case DefaultArgumentKind::Inherited:
// FIXME: This needs /some/ kind of textual representation, but this isn't
// a great one.
Expand All @@ -5332,7 +5354,8 @@ ParamDecl::getDefaultValueStringRepresentation(

void
ParamDecl::setDefaultValueStringRepresentation(StringRef stringRepresentation) {
assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal);
assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal ||
getDefaultArgumentKind() == DefaultArgumentKind::StoredProperty);
assert(!stringRepresentation.empty());

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

auto param = paramList->get(getIndex());
if (param->getDefaultValue())
if (param->getDefaultValue() || param->getStoredProperty())
param->setDefaultArgumentInitContext(this);
}

Expand Down
2 changes: 2 additions & 0 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2069,6 +2069,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
for (auto param : *func->getParameters()) {
switch (param->getDefaultArgumentKind()) {
case DefaultArgumentKind::Normal:
case DefaultArgumentKind::StoredProperty:
case DefaultArgumentKind::Inherited: // FIXME: include this?
return true;
default:
Expand Down Expand Up @@ -2096,6 +2097,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
return false;

case DefaultArgumentKind::Normal:
case DefaultArgumentKind::StoredProperty:
case DefaultArgumentKind::Inherited:
case DefaultArgumentKind::NilLiteral:
case DefaultArgumentKind::EmptyArray:
Expand Down
50 changes: 31 additions & 19 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,19 +1060,41 @@ void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) {
}
}

void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, Expr *arg,
DefaultArgumentKind kind,
DeclContext *initDC) {
switch (kind) {
void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant,
ParamDecl *param) {
auto initDC = param->getDefaultArgumentInitContext();

switch (param->getDefaultArgumentKind()) {
case DefaultArgumentKind::None:
llvm_unreachable("No default argument here?");

case DefaultArgumentKind::Normal:
break;
case DefaultArgumentKind::Normal: {
auto arg = param->getDefaultValue();
emitOrDelayFunction(*this, constant,
[this,constant,arg,initDC](SILFunction *f) {
preEmitFunction(constant, arg, f, arg);
PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f);
SILGenFunction SGF(*this, *f, initDC);
SGF.emitGeneratorFunction(constant, arg);
postEmitFunction(constant, f);
});
return;
}

case DefaultArgumentKind::Inherited:
case DefaultArgumentKind::StoredProperty: {
auto arg = param->getStoredProperty();
emitOrDelayFunction(*this, constant,
[this,constant,arg,initDC](SILFunction *f) {
preEmitFunction(constant, arg, f, arg);
PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f);
SILGenFunction SGF(*this, *f, initDC);
SGF.emitGeneratorFunction(constant, arg);
postEmitFunction(constant, f);
});
return;
}

case DefaultArgumentKind::Inherited:
case DefaultArgumentKind::Column:
case DefaultArgumentKind::File:
case DefaultArgumentKind::Line:
Expand All @@ -1083,15 +1105,6 @@ void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, Expr *arg,
case DefaultArgumentKind::EmptyDictionary:
return;
}

emitOrDelayFunction(*this, constant,
[this,constant,arg,initDC](SILFunction *f) {
preEmitFunction(constant, arg, f, arg);
PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f);
SILGenFunction SGF(*this, *f, initDC);
SGF.emitGeneratorFunction(constant, arg);
postEmitFunction(constant, f);
});
}

void SILGenModule::
Expand Down Expand Up @@ -1160,10 +1173,9 @@ void SILGenModule::emitDefaultArgGenerators(SILDeclRef::Loc decl,
ParameterList *paramList) {
unsigned index = 0;
for (auto param : *paramList) {
if (auto defaultArg = param->getDefaultValue())
if (param->isDefaultArgument())
emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl, index),
defaultArg, param->getDefaultArgumentKind(),
param->getDefaultArgumentInitContext());
param);
++index;
}
}
Expand Down
3 changes: 1 addition & 2 deletions lib/SILGen/SILGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
void emitEnumConstructor(EnumElementDecl *decl);

/// Emits the default argument generator with the given expression.
void emitDefaultArgGenerator(SILDeclRef constant, Expr *arg,
DefaultArgumentKind kind, DeclContext *DC);
void emitDefaultArgGenerator(SILDeclRef constant, ParamDecl *param);

/// Emits the stored property initializer for the given pattern.
void emitStoredPropertyInitialization(PatternBindingDecl *pd, unsigned i);
Expand Down
3 changes: 2 additions & 1 deletion lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Module.h"
Expand Down Expand Up @@ -3345,7 +3346,7 @@ void DelayedArgument::emitDefaultArgument(SILGenFunction &SGF,
info.destIndex,
info.resultType,
info.origResultType);

SmallVector<ManagedValue, 4> loweredArgs;
SmallVector<DelayedArgument, 4> delayedArgs;
Optional<ForeignErrorConvention> errorConvention = None;
Expand Down
50 changes: 50 additions & 0 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,56 @@ void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value) {
emitEpilog(Loc);
}

void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) {
MagicFunctionName = SILGenModule::getMagicFunctionName(function);

RegularLocation loc(var);
loc.markAutoGenerated();

auto decl = function.getAbstractFunctionDecl();
auto *dc = decl->getInnermostDeclContext();
auto interfaceType = var->getValueInterfaceType();
emitProlog(/*paramList*/ nullptr, /*selfParam*/ nullptr, interfaceType, dc,
false);
prepareEpilog(var->getType(), false, CleanupLocation::get(loc));

auto pbd = var->getParentPatternBinding();
auto entry = pbd->getPatternEntryForVarDecl(var);
auto subs = getForwardingSubstitutionMap();
auto resultType = decl->mapTypeIntoContext(interfaceType)->getCanonicalType();
auto origResultType = AbstractionPattern(resultType);

SmallVector<SILValue, 4> directResults;

if (F.getConventions().hasIndirectSILResults()) {
Scope scope(Cleanups, CleanupLocation(var));

SmallVector<CleanupHandle, 4> cleanups;
auto init = prepareIndirectResultInit(resultType, directResults, cleanups);

emitApplyOfStoredPropertyInitializer(loc, entry, subs, resultType,
origResultType,
SGFContext(init.get()));

for (auto cleanup : cleanups) {
Cleanups.forwardCleanup(cleanup);
}
} else {
Scope scope(Cleanups, CleanupLocation(var));

// If we have no indirect results, just return the result.
auto result = emitApplyOfStoredPropertyInitializer(loc, entry, subs,
resultType,
origResultType,
SGFContext())
.ensurePlusOne(*this, loc);
std::move(result).forwardAll(*this, directResults);
}

Cleanups.emitBranchAndCleanups(ReturnDest, loc, directResults);
emitEpilog(loc);
}

static SILLocation getLocation(ASTNode Node) {
if (auto *E = Node.dyn_cast<Expr *>())
return E;
Expand Down
9 changes: 9 additions & 0 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
// be in a different scope.
}

std::unique_ptr<Initialization>
prepareIndirectResultInit(CanType formalResultType,
SmallVectorImpl<SILValue> &directResultsBuffer,
SmallVectorImpl<CleanupHandle> &cleanups);

//===--------------------------------------------------------------------===//
// Entry points for codegen
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -624,6 +629,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
/// Generate a nullary function that returns the given value.
void emitGeneratorFunction(SILDeclRef function, Expr *value);

/// Generate a nullary function that returns the value of the given variable's
/// expression initializer.
void emitGeneratorFunction(SILDeclRef function, VarDecl *var);

/// Generate an ObjC-compatible destructor (-dealloc).
void emitObjCDestructor(SILDeclRef dtor);

Expand Down
20 changes: 10 additions & 10 deletions lib/SILGen/SILGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,22 +425,22 @@ prepareIndirectResultInit(SILGenFunction &SGF, CanType resultType,
/// components of the result
/// \param cleanups - will be filled (after initialization completes)
/// with all the active cleanups managing the result values
static std::unique_ptr<Initialization>
prepareIndirectResultInit(SILGenFunction &SGF, CanType formalResultType,
SmallVectorImpl<SILValue> &directResultsBuffer,
SmallVectorImpl<CleanupHandle> &cleanups) {
auto fnConv = SGF.F.getConventions();
std::unique_ptr<Initialization>
SILGenFunction::prepareIndirectResultInit(CanType formalResultType,
SmallVectorImpl<SILValue> &directResultsBuffer,
SmallVectorImpl<CleanupHandle> &cleanups) {
auto fnConv = F.getConventions();

// Make space in the direct-results array for all the entries we need.
directResultsBuffer.append(fnConv.getNumDirectSILResults(), SILValue());

ArrayRef<SILResultInfo> allResults = fnConv.funcTy->getResults();
MutableArrayRef<SILValue> directResults = directResultsBuffer;
ArrayRef<SILArgument*> indirectResultAddrs = SGF.F.getIndirectResults();
ArrayRef<SILArgument*> indirectResultAddrs = F.getIndirectResults();

auto init = prepareIndirectResultInit(SGF, formalResultType, allResults,
directResults, indirectResultAddrs,
cleanups);
auto init = ::prepareIndirectResultInit(*this, formalResultType, allResults,
directResults, indirectResultAddrs,
cleanups);

assert(allResults.empty());
assert(directResults.empty());
Expand All @@ -460,7 +460,7 @@ void SILGenFunction::emitReturnExpr(SILLocation branchLoc,
// Build an initialization which recursively destructures the tuple.
SmallVector<CleanupHandle, 4> resultCleanups;
InitializationPtr resultInit =
prepareIndirectResultInit(*this, ret->getType()->getCanonicalType(),
prepareIndirectResultInit(ret->getType()->getCanonicalType(),
directResults, resultCleanups);

// Emit the result expression into the initialization.
Expand Down
1 change: 1 addition & 0 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4842,6 +4842,7 @@ getCallerDefaultArg(ConstraintSystem &cs, DeclContext *dc,
case DefaultArgumentKind::None:
llvm_unreachable("No default argument here?");

case DefaultArgumentKind::StoredProperty:
case DefaultArgumentKind::Normal:
return {nullptr, param->getDefaultArgumentKind()};

Expand Down
Loading