Skip to content

Commit 43a428c

Browse files
authored
Merge pull request #11126 from CodaFi/param-a-rama
2 parents 538be50 + e5918f7 commit 43a428c

15 files changed

+180
-165
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5045,21 +5045,6 @@ class AbstractFunctionDecl : public ValueDecl, public GenericContext {
50455045
return getParameterLists()[i];
50465046
}
50475047

5048-
/// \brief If this is a method in a type or extension thereof, compute
5049-
/// and return the type to be used for the 'self' argument of the interface
5050-
/// type, or an empty Type() if no 'self' argument should exist. This can
5051-
/// only be used after name binding has resolved types.
5052-
///
5053-
/// \param isInitializingCtor Specifies whether we're computing the 'self'
5054-
/// type of an initializing constructor, which accepts an instance 'self'
5055-
/// rather than a metatype 'self'.
5056-
///
5057-
/// \param wantDynamicSelf Specifies whether the 'self' type should be
5058-
/// wrapped in a DynamicSelfType, which is the case for the 'self' parameter
5059-
/// type inside a class method returning 'Self'.
5060-
Type computeInterfaceSelfType(bool isInitializingCtor=false,
5061-
bool wantDynamicSelf=false);
5062-
50635048
/// \brief This method returns the implicit 'self' decl.
50645049
///
50655050
/// Note that some functions don't have an implicit 'self' decl, for example,

include/swift/AST/Types.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4807,6 +4807,22 @@ ParameterTypeFlags::fromParameterType(Type paramTy, bool isVariadic) {
48074807
bool inOut = paramTy->is<InOutType>();
48084808
return {isVariadic, autoclosure, escaping, inOut};
48094809
}
4810+
4811+
/// \brief If this is a method in a type or extension thereof, compute
4812+
/// and return a parameter to be used for the 'self' argument. The type of
4813+
/// the parameter is the empty Type() if no 'self' argument should exist. This
4814+
/// can only be used after name binding has resolved types.
4815+
///
4816+
/// \param isInitializingCtor Specifies whether we're computing the 'self'
4817+
/// type of an initializing constructor, which accepts an instance 'self'
4818+
/// rather than a metatype 'self'.
4819+
///
4820+
/// \param wantDynamicSelf Specifies whether the 'self' type should be
4821+
/// wrapped in a DynamicSelfType, which is the case for the 'self' parameter
4822+
/// type inside a class method returning 'Self'.
4823+
AnyFunctionType::Param computeSelfParam(AbstractFunctionDecl *AFD,
4824+
bool isInitializingCtor=false,
4825+
bool wantDynamicSelf=false);
48104826

48114827
#define TYPE(id, parent)
48124828
#define SUGARED_TYPE(id, parent) \

lib/AST/ASTContext.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2775,6 +2775,61 @@ Type AnyFunctionType::Param::getType() const {
27752775
return Ty;
27762776
}
27772777

2778+
AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
2779+
bool isInitializingCtor,
2780+
bool wantDynamicSelf) {
2781+
auto *dc = AFD->getDeclContext();
2782+
auto &Ctx = dc->getASTContext();
2783+
2784+
// Determine the type of the container.
2785+
auto containerTy = dc->getDeclaredInterfaceType();
2786+
if (!containerTy || containerTy->hasError())
2787+
return AnyFunctionType::Param(ErrorType::get(Ctx), Identifier(),
2788+
ParameterTypeFlags());
2789+
2790+
// Determine the type of 'self' inside the container.
2791+
auto selfTy = dc->getSelfInterfaceType();
2792+
if (!selfTy || selfTy->hasError())
2793+
return AnyFunctionType::Param(ErrorType::get(Ctx), Identifier(),
2794+
ParameterTypeFlags());
2795+
2796+
bool isStatic = false;
2797+
bool isMutating = false;
2798+
2799+
if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
2800+
isStatic = FD->isStatic();
2801+
isMutating = FD->isMutating();
2802+
2803+
if (wantDynamicSelf && FD->hasDynamicSelf())
2804+
selfTy = DynamicSelfType::get(selfTy, Ctx);
2805+
} else if (isa<ConstructorDecl>(AFD)) {
2806+
if (isInitializingCtor) {
2807+
// initializing constructors of value types always have an implicitly
2808+
// inout self.
2809+
isMutating = true;
2810+
} else {
2811+
// allocating constructors have metatype 'self'.
2812+
isStatic = true;
2813+
}
2814+
} else if (isa<DestructorDecl>(AFD)) {
2815+
// destructors of value types always have an implicitly inout self.
2816+
isMutating = true;
2817+
}
2818+
2819+
// 'static' functions have 'self' of type metatype<T>.
2820+
if (isStatic)
2821+
return AnyFunctionType::Param(MetatypeType::get(selfTy, Ctx), Identifier(),
2822+
ParameterTypeFlags());
2823+
2824+
// Reference types have 'self' of type T.
2825+
if (containerTy->hasReferenceSemantics())
2826+
return AnyFunctionType::Param(selfTy, Identifier(),
2827+
ParameterTypeFlags());
2828+
2829+
return AnyFunctionType::Param(selfTy, Identifier(),
2830+
ParameterTypeFlags().withInOut(isMutating));
2831+
}
2832+
27782833
void UnboundGenericType::Profile(llvm::FoldingSetNodeID &ID,
27792834
GenericTypeDecl *TheDecl, Type Parent) {
27802835
ID.AddPointer(TheDecl);

lib/AST/Decl.cpp

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4417,61 +4417,6 @@ SourceRange SubscriptDecl::getSourceRange() const {
44174417
return { getSubscriptLoc(), ElementTy.getSourceRange().End };
44184418
}
44194419

4420-
Type AbstractFunctionDecl::computeInterfaceSelfType(bool isInitializingCtor,
4421-
bool wantDynamicSelf) {
4422-
auto *dc = getDeclContext();
4423-
auto &Ctx = dc->getASTContext();
4424-
4425-
// Determine the type of the container.
4426-
auto containerTy = dc->getDeclaredInterfaceType();
4427-
if (!containerTy || containerTy->hasError())
4428-
return ErrorType::get(Ctx);
4429-
4430-
// Determine the type of 'self' inside the container.
4431-
auto selfTy = dc->getSelfInterfaceType();
4432-
if (!selfTy || selfTy->hasError())
4433-
return ErrorType::get(Ctx);
4434-
4435-
bool isStatic = false;
4436-
bool isMutating = false;
4437-
4438-
if (auto *FD = dyn_cast<FuncDecl>(this)) {
4439-
isStatic = FD->isStatic();
4440-
isMutating = FD->isMutating();
4441-
4442-
if (wantDynamicSelf && FD->hasDynamicSelf())
4443-
selfTy = DynamicSelfType::get(selfTy, Ctx);
4444-
} else if (isa<ConstructorDecl>(this)) {
4445-
if (isInitializingCtor) {
4446-
// initializing constructors of value types always have an implicitly
4447-
// inout self.
4448-
isMutating = true;
4449-
} else {
4450-
// allocating constructors have metatype 'self'.
4451-
isStatic = true;
4452-
}
4453-
} else if (isa<DestructorDecl>(this)) {
4454-
// destructors of value types always have an implicitly inout self.
4455-
isMutating = true;
4456-
}
4457-
4458-
// 'static' functions have 'self' of type metatype<T>.
4459-
if (isStatic)
4460-
return MetatypeType::get(selfTy, Ctx);
4461-
4462-
// Reference types have 'self' of type T.
4463-
if (containerTy->hasReferenceSemantics())
4464-
return selfTy;
4465-
4466-
// Mutating methods are always passed inout so we can receive the side
4467-
// effect.
4468-
if (isMutating)
4469-
return InOutType::get(selfTy);
4470-
4471-
// Nonmutating methods on structs and enums pass the receiver by value.
4472-
return selfTy;
4473-
}
4474-
44754420
DeclName AbstractFunctionDecl::getEffectiveFullName() const {
44764421
if (getFullName())
44774422
return getFullName();

lib/SIL/SILFunctionType.cpp

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -511,48 +511,76 @@ enum class ConventionsKind : uint8_t {
511511
void visitTopLevelParams(AbstractionPattern origType,
512512
CanAnyFunctionType::CanParamArrayRef params,
513513
AnyFunctionType::ExtInfo extInfo) {
514-
// If we don't have 'self', we don't need to do anything special.
515-
if (!extInfo.hasSelfParam() && !Foreign.Self.isImportAsMember()) {
516-
// Add any leading foreign parameters.
517-
maybeAddForeignParameters();
518-
519-
if (params.empty()) {
520-
visit(origType, M.getASTContext().TheEmptyTupleType);
521-
} else {
522-
CanType ty = AnyFunctionType::composeInput(M.getASTContext(), params,
523-
/*canonicalVararg*/true)
524-
->getCanonicalType();
525-
visit(origType, ty);
526-
}
527-
return;
528-
}
529-
530-
// Okay, handle 'self'.
531-
532514
unsigned numEltTypes = params.size();
533-
assert(numEltTypes > 0);
534515
unsigned numNonSelfParams = numEltTypes - 1;
535-
516+
536517
// We have to declare this out here so that the lambda scope lasts for
537518
// the duration of the loop below.
538519
auto handleForeignSelf = [&] {
539520
visit(origType.getTupleElementType(numNonSelfParams),
540521
params[numNonSelfParams].getType());
541522
};
542-
523+
543524
// If we have a foreign-self, install handleSelf as the handler.
544525
if (Foreign.Self.isInstance()) {
526+
assert(numEltTypes > 0);
545527
// This is safe because function_ref just stores a pointer to the
546528
// existing lambda object.
547529
HandleForeignSelf = handleForeignSelf;
548530
}
549-
550-
// Now we can add any leading foreign parameters.
531+
532+
// Add any leading foreign parameters.
551533
maybeAddForeignParameters();
534+
535+
// If we have no parameters, even 'self' parameters, bail unless we need
536+
// to substitute.
537+
if (params.empty()) {
538+
if (origType.isTypeParameter())
539+
visit(origType, M.getASTContext().TheEmptyTupleType);
540+
return;
541+
}
542+
543+
assert(numEltTypes > 0);
544+
545+
// If we don't have 'self', we don't need to do anything special.
546+
if (!extInfo.hasSelfParam() && !Foreign.Self.isImportAsMember()) {
547+
CanType ty = AnyFunctionType::composeInput(M.getASTContext(), params,
548+
/*canonicalVararg*/true)
549+
->getCanonicalType();
550+
CanTupleType tty = dyn_cast<TupleType>(ty);
551+
if (!tty || (origType.isTypeParameter() && !tty->hasInOutElement())) {
552+
visit(origType, ty);
553+
return;
554+
}
555+
556+
// If the abstraction pattern is opaque, and the tuple type is
557+
// materializable -- if it doesn't contain an l-value type -- then it's
558+
// a valid target for substitution and we should not expand it.
559+
for (auto i : indices(tty.getElementTypes())) {
560+
visit(origType.getTupleElementType(i), tty.getElementType(i));
561+
}
562+
return;
563+
}
564+
565+
// Okay, handle 'self'.
552566

553567
// Process all the non-self parameters.
554568
for (unsigned i = 0; i != numNonSelfParams; ++i) {
555-
visit(origType.getTupleElementType(i), params[i].getType());
569+
CanType ty = params[i].getType();
570+
CanTupleType tty = dyn_cast<TupleType>(ty);
571+
AbstractionPattern eltPattern = origType.getTupleElementType(i);
572+
if (!tty || (eltPattern.isTypeParameter() && !tty->hasInOutElement())) {
573+
visit(eltPattern, ty);
574+
continue;
575+
}
576+
577+
assert(eltPattern.isTuple());
578+
// If the abstraction pattern is opaque, and the tuple type is
579+
// materializable -- if it doesn't contain an l-value type -- then it's
580+
// a valid target for substitution and we should not expand it.
581+
for (unsigned j = 0; j < eltPattern.getNumTupleElements(); ++j) {
582+
visit(eltPattern.getTupleElementType(j), tty.getElementType(j));
583+
}
556584
}
557585

558586
// Process the self parameter. Note that we implicitly drop self
@@ -568,15 +596,10 @@ enum class ConventionsKind : uint8_t {
568596
}
569597

570598
void visit(AbstractionPattern origType, CanType substType) {
571-
// Expand tuples. But if the abstraction pattern is opaque, and
572-
// the tuple type is materializable -- if it doesn't contain an
573-
// l-value type -- then it's a valid target for substitution and
574-
// we should not expand it.
599+
// Expand tuples.
575600
CanTupleType substTupleTy = dyn_cast<TupleType>(substType);
576-
if (substTupleTy &&
577-
(!origType.isTypeParameter() || substTupleTy->hasInOutElement())) {
578-
assert(origType.isTypeParameter() ||
579-
origType.getNumTupleElements() == substTupleTy->getNumElements());
601+
if (substTupleTy && !origType.isTypeParameter()) {
602+
assert(origType.getNumTupleElements() == substTupleTy->getNumElements());
580603
for (auto i : indices(substTupleTy.getElementTypes())) {
581604
visit(origType.getTupleElementType(i),
582605
substTupleTy.getElementType(i));

lib/SILGen/SILGenLValue.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,8 +1092,8 @@ namespace {
10921092
ArgumentSource self = [&] {
10931093
if (!baseLV.isValid()) {
10941094
return ArgumentSource();
1095-
} else if (cast<FuncDecl>(setter.getDecl())->computeInterfaceSelfType()
1096-
->is<InOutType>()) {
1095+
} else if (computeSelfParam(cast<FuncDecl>(setter.getDecl()))
1096+
.getParameterFlags().isInOut()) {
10971097
return ArgumentSource(loc, std::move(baseLV));
10981098
} else {
10991099
return emitBaseValueForAccessor(SGF, loc, std::move(baseLV),

lib/SILGen/SILGenMaterializeForSet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ struct MaterializeForSetEmitter {
435435
}
436436

437437
CanType witnessSelfType =
438-
Witness->computeInterfaceSelfType()->getCanonicalType(
438+
computeSelfParam(Witness).getType()->getCanonicalType(
439439
GenericSig, *SGM.M.getSwiftModule());
440440
witnessSelfType = getSubstWitnessInterfaceType(witnessSelfType);
441441

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,21 +1068,23 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
10681068
initDecl->getAttrs().add(reqAttr);
10691069
}
10701070

1071-
Type selfType = initDecl->computeInterfaceSelfType();
1072-
Type selfInitType = initDecl->computeInterfaceSelfType(/*init=*/true);
1071+
auto selfParam = computeSelfParam(initDecl);
1072+
auto initSelfParam = computeSelfParam(initDecl, /*init=*/true);
10731073
Type interfaceType;
10741074
Type initializerType;
10751075
if (auto sig = target->getGenericSignatureOfContext()) {
10761076
// Evaluate the below, but in a generic environment (if Self is generic).
10771077
initDecl->setGenericEnvironment(target->getGenericEnvironmentOfContext());
1078-
interfaceType = GenericFunctionType::get(sig, selfType, innerType,
1078+
interfaceType = GenericFunctionType::get(sig, {selfParam}, innerType,
10791079
FunctionType::ExtInfo());
1080-
initializerType = GenericFunctionType::get(sig, selfInitType, innerType,
1080+
initializerType = GenericFunctionType::get(sig, {initSelfParam}, innerType,
10811081
FunctionType::ExtInfo());
10821082
} else {
10831083
// (Self) -> (Decoder) throws -> (Self)
1084-
interfaceType = FunctionType::get(selfType, innerType);
1085-
initializerType = FunctionType::get(selfInitType, innerType);
1084+
interfaceType = FunctionType::get({selfParam}, innerType,
1085+
FunctionType::ExtInfo());
1086+
initializerType = FunctionType::get({initSelfParam}, innerType,
1087+
FunctionType::ExtInfo());
10861088
}
10871089

10881090
initDecl->setInterfaceType(interfaceType);

lib/Sema/DerivedConformanceCodingKey.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -159,26 +159,25 @@ static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
159159
Type retInterfaceType =
160160
OptionalType::get(parentDC->getDeclaredInterfaceType());
161161
Type interfaceType = FunctionType::get(interfaceArgType, retInterfaceType);
162-
Type selfInterfaceType = initDecl->computeInterfaceSelfType();
163-
Type selfInitializerInterfaceType =
164-
initDecl->computeInterfaceSelfType(/*init*/ true);
162+
auto selfParam = computeSelfParam(initDecl);
163+
auto initSelfParam = computeSelfParam(initDecl, /*init*/ true);
165164

166165
Type allocIfaceType;
167166
Type initIfaceType;
168167
if (auto sig = parentDC->getGenericSignatureOfContext()) {
169168
initDecl->setGenericEnvironment(parentDC->getGenericEnvironmentOfContext());
170169

171-
allocIfaceType = GenericFunctionType::get(sig, selfInterfaceType,
170+
allocIfaceType = GenericFunctionType::get(sig, {selfParam},
172171
interfaceType,
173172
FunctionType::ExtInfo());
174-
initIfaceType = GenericFunctionType::get(sig, selfInitializerInterfaceType,
173+
initIfaceType = GenericFunctionType::get(sig, {initSelfParam},
175174
interfaceType,
176175
FunctionType::ExtInfo());
177176
} else {
178-
allocIfaceType = FunctionType::get(selfInterfaceType,
179-
interfaceType);
180-
initIfaceType = FunctionType::get(selfInitializerInterfaceType,
181-
interfaceType);
177+
allocIfaceType = FunctionType::get({selfParam},
178+
interfaceType, FunctionType::ExtInfo());
179+
initIfaceType = FunctionType::get({initSelfParam},
180+
interfaceType, FunctionType::ExtInfo());
182181
}
183182
initDecl->setInterfaceType(allocIfaceType);
184183
initDecl->setInitializerInterfaceType(initIfaceType);

0 commit comments

Comments
 (0)