Skip to content

Commit a1501b3

Browse files
authored
Merge pull request #21381 from CodaFi/def-jam
[SE-0155] Default Arguments In Enum Cases
2 parents 61f57a0 + 944d8d0 commit a1501b3

15 files changed

+222
-69
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,6 @@ ERROR(no_default_arg_subscript,none,
823823
"default arguments are not allowed in subscripts", ())
824824
ERROR(no_default_arg_curried,none,
825825
"default arguments are not allowed in curried parameter lists", ())
826-
ERROR(no_default_arg_enum_elt,none,
827-
"default arguments are not allowed in enum cases", ())
828826
ERROR(var_pattern_in_var,none,
829827
"'%select{var|let}0' cannot appear nested inside another 'var' or "
830828
"'let' pattern", (unsigned))

lib/AST/DeclContext.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const {
314314
// Default argument initializer contexts have their resilience expansion
315315
// set when they're type checked.
316316
if (isa<DefaultArgumentInitializer>(dc)) {
317+
if (auto *EED = dyn_cast<EnumElementDecl>(dc->getParent())) {
318+
return EED->getDefaultArgumentResilienceExpansion();
319+
}
317320
return cast<AbstractFunctionDecl>(dc->getParent())
318321
->getDefaultArgumentResilienceExpansion();
319322
}

lib/Parse/ParseDecl.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5823,13 +5823,14 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags,
58235823
// See if there's a following argument type.
58245824
ParserResult<ParameterList> ArgParams;
58255825
SmallVector<Identifier, 4> argumentNames;
5826+
DefaultArgumentInfo DefaultArgs;
58265827
if (Tok.isFollowingLParen()) {
58275828
ArgParams = parseSingleParameterClause(ParameterContextKind::EnumElement,
5828-
&argumentNames);
5829+
&argumentNames, &DefaultArgs);
58295830
if (ArgParams.isNull() || ArgParams.hasCodeCompletion())
58305831
return ParserStatus(ArgParams);
58315832
}
5832-
5833+
58335834
// See if there's a raw value expression.
58345835
SourceLoc EqualsLoc;
58355836
ParserResult<Expr> RawValueExpr;
@@ -5896,6 +5897,8 @@ Parser::parseDeclEnumCase(ParseDeclOptions Flags,
58965897
LiteralRawValueExpr,
58975898
CurDeclContext);
58985899

5900+
DefaultArgs.setFunctionContext(result, result->getParameterList());
5901+
58995902
if (NameLoc == CaseLoc) {
59005903
result->setImplicit(); // Parse error
59015904
}

lib/Parse/ParsePattern.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ static ParserStatus parseDefaultArgument(
9191
case Parser::ParameterContextKind::Function:
9292
case Parser::ParameterContextKind::Operator:
9393
case Parser::ParameterContextKind::Initializer:
94+
case Parser::ParameterContextKind::EnumElement:
9495
break;
9596
case Parser::ParameterContextKind::Closure:
9697
diagID = diag::no_default_arg_closure;
@@ -101,9 +102,6 @@ static ParserStatus parseDefaultArgument(
101102
case Parser::ParameterContextKind::Curried:
102103
diagID = diag::no_default_arg_curried;
103104
break;
104-
case Parser::ParameterContextKind::EnumElement:
105-
diagID = diag::no_default_arg_enum_elt;
106-
break;
107105
}
108106

109107
assert((diagID.ID != DiagID()) == !defaultArgs &&

lib/SIL/SILDeclRef.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,8 +467,14 @@ IsSerialized_t SILDeclRef::isSerialized() const {
467467
// Default argument generators are serialized if the function was
468468
// type-checked in Swift 4 mode.
469469
if (isDefaultArgGenerator()) {
470-
auto *afd = cast<AbstractFunctionDecl>(d);
471-
switch (afd->getDefaultArgumentResilienceExpansion()) {
470+
ResilienceExpansion expansion;
471+
if (auto *EED = dyn_cast<EnumElementDecl>(d)) {
472+
expansion = EED->getDefaultArgumentResilienceExpansion();
473+
} else {
474+
expansion = cast<AbstractFunctionDecl>(d)
475+
->getDefaultArgumentResilienceExpansion();
476+
}
477+
switch (expansion) {
472478
case ResilienceExpansion::Minimal:
473479
return IsSerialized;
474480
case ResilienceExpansion::Maximal:
@@ -770,7 +776,7 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {
770776
case SILDeclRef::Kind::DefaultArgGenerator:
771777
assert(!isCurried);
772778
return mangler.mangleDefaultArgumentEntity(
773-
cast<AbstractFunctionDecl>(getDecl()),
779+
cast<DeclContext>(getDecl()),
774780
defaultArgIndex,
775781
SKind);
776782

lib/SILGen/SILGenApply.cpp

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ class Callee {
588588
case Kind::IndirectValue:
589589
assert(Substitutions.empty());
590590
return IndirectValue;
591-
591+
case Kind::EnumElement:
592592
case Kind::StandaloneFunction: {
593593
auto constantInfo = SGF.getConstantInfo(*constant);
594594
SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo);
@@ -600,8 +600,6 @@ class Callee {
600600
SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo, true);
601601
return ManagedValue::forUnmanaged(ref);
602602
}
603-
case Kind::EnumElement:
604-
llvm_unreachable("Should have been curried");
605603
case Kind::ClassMethod: {
606604
auto methodTy = SGF.SGM.Types.getConstantOverrideType(*constant);
607605

@@ -704,8 +702,11 @@ class Callee {
704702
auto constantInfo = SGF.getConstantInfo(*constant);
705703
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
706704
}
707-
case Kind::EnumElement:
708-
llvm_unreachable("Should have been curried");
705+
case Kind::EnumElement: {
706+
// Emit a direct call to the element constructor thunk.
707+
auto constantInfo = SGF.getConstantInfo(*constant);
708+
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
709+
}
709710
case Kind::ClassMethod: {
710711
auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo(*constant);
711712
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
@@ -4526,18 +4527,23 @@ CallEmission::applyEnumElementConstructor(SGFContext C) {
45264527
ArgumentSource payload;
45274528
if (element->hasAssociatedValues()) {
45284529
assert(uncurriedSites.size() == 2);
4530+
SmallVector<ManagedValue, 4> argVals;
4531+
auto resultFnType = cast<FunctionType>(formalResultType);
4532+
auto arg = SGF.prepareEnumPayload(element, resultFnType,
4533+
std::move(uncurriedSites[1]).forward());
4534+
payload = ArgumentSource(element, std::move(arg));
45294535
formalResultType = firstLevelResult.formalType.getResult();
45304536
origFormalType = origFormalType.getFunctionResultType();
45314537
claimNextParamClause(firstLevelResult.formalType);
4532-
payload = std::move(uncurriedSites[1]).forward();
45334538
} else {
45344539
assert(uncurriedSites.size() == 1);
45354540
}
45364541

45374542
assert(substFnType->getNumResults() == 1);
45384543
(void)substFnType;
45394544
ManagedValue resultMV = SGF.emitInjectEnum(
4540-
uncurriedLoc, std::move(payload), SGF.getLoweredType(formalResultType),
4545+
uncurriedLoc, std::move(payload),
4546+
SGF.getLoweredType(formalResultType),
45414547
element, uncurriedContext);
45424548
firstLevelResult.value =
45434549
RValue(SGF, uncurriedLoc, formalResultType, resultMV);
@@ -5247,7 +5253,7 @@ void SILGenFunction::emitRawYield(SILLocation loc,
52475253
/// unnecessary copies by emitting the payload directly into the enum
52485254
/// payload, or into the box in the case of an indirect payload.
52495255
ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc,
5250-
ArgumentSource payload,
5256+
ArgumentSource &&payload,
52515257
SILType enumTy,
52525258
EnumElementDecl *element,
52535259
SGFContext C) {
@@ -5290,8 +5296,8 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc,
52905296
CleanupHandle uninitCleanup = enterDeallocBoxCleanup(box);
52915297

52925298
BoxInitialization dest(box, addr, uninitCleanup, initCleanup);
5293-
5294-
std::move(payload).forwardInto(*this, origFormalType, &dest, payloadTL);
5299+
std::move(payload).forwardInto(*this, origFormalType, &dest,
5300+
payloadTL);
52955301

52965302
payloadMV = dest.getManagedBox();
52975303
loweredPayloadType = payloadMV.getType();
@@ -5325,8 +5331,7 @@ ManagedValue SILGenFunction::emitInjectEnum(SILLocation loc,
53255331
} else if (payloadTL.isLoadable()) {
53265332
// The payload of this specific enum case might be loadable
53275333
// even if the overall enum is address-only.
5328-
payloadMV =
5329-
std::move(payload).getAsSingleValue(*this, origFormalType);
5334+
payloadMV = std::move(payload).getAsSingleValue(*this, origFormalType);
53305335
B.emitStoreValueOperation(loc, payloadMV.forward(*this), resultData,
53315336
StoreOwnershipQualifier::Init);
53325337
} else {
@@ -5967,6 +5972,36 @@ static void collectFakeIndexParameters(SILGenModule &SGM,
59675972
convention});
59685973
}
59695974

5975+
static void emitPseudoFunctionArguments(SILGenFunction &SGF,
5976+
CanFunctionType substFnType,
5977+
SmallVectorImpl<ManagedValue> &outVals,
5978+
ArgumentSource &&source) {
5979+
auto substParams = substFnType->getParams();
5980+
5981+
SmallVector<SILParameterInfo, 4> substParamTys;
5982+
for (auto substParam : substParams) {
5983+
auto substParamType = substParam.getParameterType()->getCanonicalType();
5984+
collectFakeIndexParameters(SGF.SGM, substParamType, substParamTys);
5985+
}
5986+
5987+
SmallVector<ManagedValue, 4> argValues;
5988+
SmallVector<DelayedArgument, 2> delayedArgs;
5989+
5990+
ArgEmitter emitter(SGF, SILFunctionTypeRepresentation::Thin,
5991+
/*yield*/ false,
5992+
/*isForCoroutine*/ false, ClaimedParamsRef(substParamTys),
5993+
argValues, delayedArgs,
5994+
/*foreign error*/ None, ImportAsMemberStatus());
5995+
5996+
emitter.emitTopLevel(std::move(source), AbstractionPattern(substFnType));
5997+
5998+
// TODO: do something to preserve LValues in the delayed arguments?
5999+
if (!delayedArgs.empty())
6000+
emitDelayedArguments(SGF, delayedArgs, argValues);
6001+
6002+
outVals.swap(argValues);
6003+
}
6004+
59706005
PreparedArguments
59716006
SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript,
59726007
SubstitutionMap subs,
@@ -5992,26 +6027,8 @@ SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript,
59926027

59936028
auto substParams = substFnType->getParams();
59946029

5995-
SmallVector<SILParameterInfo, 4> substParamTys;
5996-
for (auto substParam : substParams) {
5997-
auto substParamType = substParam.getParameterType()->getCanonicalType();
5998-
collectFakeIndexParameters(SGM, substParamType, substParamTys);
5999-
}
6000-
60016030
SmallVector<ManagedValue, 4> argValues;
6002-
SmallVector<DelayedArgument, 2> delayedArgs;
6003-
6004-
ArgEmitter emitter(*this, SILFunctionTypeRepresentation::Thin,
6005-
/*yield*/ false,
6006-
/*isForCoroutine*/ false, ClaimedParamsRef(substParamTys),
6007-
argValues, delayedArgs,
6008-
/*foreign error*/ None, ImportAsMemberStatus());
6009-
6010-
emitter.emitTopLevel(indexExpr, AbstractionPattern(substFnType));
6011-
6012-
// TODO: do something to preserve LValues in the delayed arguments?
6013-
if (!delayedArgs.empty())
6014-
emitDelayedArguments(*this, delayedArgs, argValues);
6031+
emitPseudoFunctionArguments(*this, substFnType, argValues, indexExpr);
60156032

60166033
PreparedArguments result(substParams, /*isScalar=*/false);
60176034

@@ -6029,6 +6046,19 @@ SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript,
60296046
return result;
60306047
}
60316048

6049+
RValue
6050+
SILGenFunction::prepareEnumPayload(EnumElementDecl *element,
6051+
CanFunctionType substFnType,
6052+
ArgumentSource &&args) {
6053+
SmallVector<ManagedValue, 4> argValues;
6054+
emitPseudoFunctionArguments(*this, substFnType, argValues, std::move(args));
6055+
6056+
auto payloadTy = AnyFunctionType::composeInput(getASTContext(),
6057+
substFnType.getParams(),
6058+
/*canonicalVararg*/ true);
6059+
return RValue(*this, argValues, payloadTy->getCanonicalType());
6060+
}
6061+
60326062
SILDeclRef SILGenModule::getAccessorDeclRef(AccessorDecl *accessor) {
60336063
return SILDeclRef(accessor, SILDeclRef::Kind::Func)
60346064
.asForeign(requiresForeignEntryPoint(accessor));

lib/SILGen/SILGenConstructor.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,9 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
411411
// Emit the exploded constructor argument.
412412
ArgumentSource payload;
413413
if (element->hasAssociatedValues()) {
414-
RValue arg = emitImplicitValueConstructorArg
415-
(*this, Loc, element->getArgumentInterfaceType()->getCanonicalType(),
416-
element->getDeclContext());
417-
payload = ArgumentSource(Loc, std::move(arg));
414+
auto eltArgTy = element->getArgumentInterfaceType()->getCanonicalType();
415+
RValue arg = emitImplicitValueConstructorArg(*this, Loc, eltArgTy, element);
416+
payload = ArgumentSource(Loc, std::move(arg));
418417
}
419418

420419
// Emit the metatype argument.

lib/SILGen/SILGenFunction.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ DeclName SILGenModule::getMagicFunctionName(DeclContext *dc) {
9797
assert(e->getExtendedNominal() && "extension for nonnominal");
9898
return e->getExtendedNominal()->getName();
9999
}
100+
if (auto EED = dyn_cast<EnumElementDecl>(dc)) {
101+
return EED->getFullName();
102+
}
100103
llvm_unreachable("unexpected #function context");
101104
}
102105

@@ -115,7 +118,7 @@ DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
115118
case SILDeclRef::Kind::GlobalAccessor:
116119
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
117120
case SILDeclRef::Kind::DefaultArgGenerator:
118-
return getMagicFunctionName(cast<AbstractFunctionDecl>(ref.getDecl()));
121+
return getMagicFunctionName(cast<DeclContext>(ref.getDecl()));
119122
case SILDeclRef::Kind::StoredPropertyInitializer:
120123
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
121124
case SILDeclRef::Kind::IVarInitializer:

lib/SILGen/SILGenFunction.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
849849
//===--------------------------------------------------------------------===//
850850

851851
ManagedValue emitInjectEnum(SILLocation loc,
852-
ArgumentSource payload,
852+
ArgumentSource &&payload,
853853
SILType enumTy,
854854
EnumElementDecl *element,
855855
SGFContext C);
@@ -1220,6 +1220,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
12201220
AccessStrategy strategy,
12211221
Expr *indices);
12221222

1223+
RValue prepareEnumPayload(EnumElementDecl *element,
1224+
CanFunctionType substFnType,
1225+
ArgumentSource &&indexExpr);
1226+
12231227
ArgumentSource prepareAccessorBaseArg(SILLocation loc, ManagedValue base,
12241228
CanType baseFormalType,
12251229
SILDeclRef accessor);

lib/SILGen/SILGenType.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,13 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
10061006
}
10071007

10081008
void visitEnumCaseDecl(EnumCaseDecl *ecd) {}
1009-
void visitEnumElementDecl(EnumElementDecl *ued) {}
1009+
void visitEnumElementDecl(EnumElementDecl *EED) {
1010+
if (!EED->hasAssociatedValues())
1011+
return;
1012+
1013+
// Emit any default argument generators.
1014+
SGM.emitDefaultArgGenerators(EED, EED->getParameterList());
1015+
}
10101016

10111017
void visitPatternBindingDecl(PatternBindingDecl *pd) {
10121018
// Emit initializers.

test/IRGen/enum_resilience.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,23 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium {
151151
// CHECK-NEXT: [[METADATA_ADDR:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
152152
// CHECK-NEXT: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA_ADDR]], [[INT]] -1
153153
// CHECK-NEXT: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
154+
// CHECK-NEXT: [[VWT_CAST:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
155+
156+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT_CAST]], i32 0, i32 8
157+
// CHECK-NEXT: [[WITNESS_FOR_SIZE:%size]] = load [[INT]], [[INT]]* [[WITNESS_ADDR]]
158+
// CHECK-NEXT: [[ALLOCA:%.*]] = alloca i8, {{.*}} [[WITNESS_FOR_SIZE]], align 16
159+
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8({{(i32|i64)}} -1, i8* [[ALLOCA]])
160+
// CHECK-NEXT: [[ENUM_STORAGE:%.*]] = bitcast i8* [[ALLOCA]] to %swift.opaque*
154161

155162
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 2
156-
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
157-
// CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]]
158-
// CHECK-NEXT: [[COPY:%.*]] = call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias %1, %swift.type* [[METADATA]])
163+
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
164+
// CHECK-NEXT: [[WITNESS_FN:%initializeWithCopy]] = bitcast i8* [[WITNESS]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
165+
// CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias [[ENUM_STORAGE]], %swift.opaque* noalias %1, %swift.type* [[METADATA]])
166+
167+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 4
168+
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
169+
// CHECK-NEXT: [[WITNESS_FN:%initializeWithTake]] = bitcast i8* [[WITNESS]] to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)*
170+
// CHECK-NEXT: call %swift.opaque* [[WITNESS_FN]](%swift.opaque* noalias %0, %swift.opaque* noalias [[ENUM_STORAGE]], %swift.type* [[METADATA]])
159171

160172
// CHECK-NEXT: [[TAG:%.*]] = load i32, i32* @"$s14resilient_enum6MediumO8PostcardyAC0A7_struct4SizeVcACmFWC"
161173
// CHECK-NEXT: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s14resilient_enum6MediumOMa"([[INT]] 0)
@@ -170,6 +182,8 @@ public func constructResilientEnumPayload(_ s: Size) -> Medium {
170182
// CHECK-NEXT: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ADDR]]
171183
// CHECK-NEXT: [[WITNESS_FN:%destructiveInjectEnumTag]] = bitcast i8* [[WITNESS]]
172184
// CHECK-NEXT: call void [[WITNESS_FN]](%swift.opaque* noalias %0, i32 [[TAG]], %swift.type* [[METADATA2]])
185+
// CHECK-NEXT: [[STORAGE_ALLOCA:%.*]] = bitcast %swift.opaque* [[ENUM_STORAGE]] to i8*
186+
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8({{(i32|i64)}} -1, i8* [[STORAGE_ALLOCA]])
173187

174188
// CHECK-NEXT: ret void
175189

0 commit comments

Comments
 (0)