Skip to content

[NFC] Refactor self type computation to return a Param #11126

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 1 commit into from
Jul 24, 2017
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
15 changes: 0 additions & 15 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5045,21 +5045,6 @@ class AbstractFunctionDecl : public ValueDecl, public GenericContext {
return getParameterLists()[i];
}

/// \brief If this is a method in a type or extension thereof, compute
/// and return the type to be used for the 'self' argument of the interface
/// type, or an empty Type() if no 'self' argument should exist. This can
/// only be used after name binding has resolved types.
///
/// \param isInitializingCtor Specifies whether we're computing the 'self'
/// type of an initializing constructor, which accepts an instance 'self'
/// rather than a metatype 'self'.
///
/// \param wantDynamicSelf Specifies whether the 'self' type should be
/// wrapped in a DynamicSelfType, which is the case for the 'self' parameter
/// type inside a class method returning 'Self'.
Type computeInterfaceSelfType(bool isInitializingCtor=false,
bool wantDynamicSelf=false);

/// \brief This method returns the implicit 'self' decl.
///
/// Note that some functions don't have an implicit 'self' decl, for example,
Expand Down
16 changes: 16 additions & 0 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -4807,6 +4807,22 @@ ParameterTypeFlags::fromParameterType(Type paramTy, bool isVariadic) {
bool inOut = paramTy->is<InOutType>();
return {isVariadic, autoclosure, escaping, inOut};
}

/// \brief If this is a method in a type or extension thereof, compute
/// and return a parameter to be used for the 'self' argument. The type of
/// the parameter is the empty Type() if no 'self' argument should exist. This
/// can only be used after name binding has resolved types.
///
/// \param isInitializingCtor Specifies whether we're computing the 'self'
/// type of an initializing constructor, which accepts an instance 'self'
/// rather than a metatype 'self'.
///
/// \param wantDynamicSelf Specifies whether the 'self' type should be
/// wrapped in a DynamicSelfType, which is the case for the 'self' parameter
/// type inside a class method returning 'Self'.
AnyFunctionType::Param computeSelfParam(AbstractFunctionDecl *AFD,
bool isInitializingCtor=false,
bool wantDynamicSelf=false);

#define TYPE(id, parent)
#define SUGARED_TYPE(id, parent) \
Expand Down
55 changes: 55 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2775,6 +2775,61 @@ Type AnyFunctionType::Param::getType() const {
return Ty;
}

AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
bool isInitializingCtor,
bool wantDynamicSelf) {
auto *dc = AFD->getDeclContext();
auto &Ctx = dc->getASTContext();

// Determine the type of the container.
auto containerTy = dc->getDeclaredInterfaceType();
if (!containerTy || containerTy->hasError())
return AnyFunctionType::Param(ErrorType::get(Ctx), Identifier(),
ParameterTypeFlags());

// Determine the type of 'self' inside the container.
auto selfTy = dc->getSelfInterfaceType();
if (!selfTy || selfTy->hasError())
return AnyFunctionType::Param(ErrorType::get(Ctx), Identifier(),
ParameterTypeFlags());

bool isStatic = false;
bool isMutating = false;

if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
isStatic = FD->isStatic();
isMutating = FD->isMutating();

if (wantDynamicSelf && FD->hasDynamicSelf())
selfTy = DynamicSelfType::get(selfTy, Ctx);
} else if (isa<ConstructorDecl>(AFD)) {
if (isInitializingCtor) {
// initializing constructors of value types always have an implicitly
// inout self.
isMutating = true;
} else {
// allocating constructors have metatype 'self'.
isStatic = true;
}
} else if (isa<DestructorDecl>(AFD)) {
// destructors of value types always have an implicitly inout self.
isMutating = true;
}

// 'static' functions have 'self' of type metatype<T>.
if (isStatic)
return AnyFunctionType::Param(MetatypeType::get(selfTy, Ctx), Identifier(),
ParameterTypeFlags());

// Reference types have 'self' of type T.
if (containerTy->hasReferenceSemantics())
return AnyFunctionType::Param(selfTy, Identifier(),
ParameterTypeFlags());

return AnyFunctionType::Param(selfTy, Identifier(),
ParameterTypeFlags().withInOut(isMutating));
}

void UnboundGenericType::Profile(llvm::FoldingSetNodeID &ID,
GenericTypeDecl *TheDecl, Type Parent) {
ID.AddPointer(TheDecl);
Expand Down
55 changes: 0 additions & 55 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4412,61 +4412,6 @@ SourceRange SubscriptDecl::getSourceRange() const {
return { getSubscriptLoc(), ElementTy.getSourceRange().End };
}

Type AbstractFunctionDecl::computeInterfaceSelfType(bool isInitializingCtor,
bool wantDynamicSelf) {
auto *dc = getDeclContext();
auto &Ctx = dc->getASTContext();

// Determine the type of the container.
auto containerTy = dc->getDeclaredInterfaceType();
if (!containerTy || containerTy->hasError())
return ErrorType::get(Ctx);

// Determine the type of 'self' inside the container.
auto selfTy = dc->getSelfInterfaceType();
if (!selfTy || selfTy->hasError())
return ErrorType::get(Ctx);

bool isStatic = false;
bool isMutating = false;

if (auto *FD = dyn_cast<FuncDecl>(this)) {
isStatic = FD->isStatic();
isMutating = FD->isMutating();

if (wantDynamicSelf && FD->hasDynamicSelf())
selfTy = DynamicSelfType::get(selfTy, Ctx);
} else if (isa<ConstructorDecl>(this)) {
if (isInitializingCtor) {
// initializing constructors of value types always have an implicitly
// inout self.
isMutating = true;
} else {
// allocating constructors have metatype 'self'.
isStatic = true;
}
} else if (isa<DestructorDecl>(this)) {
// destructors of value types always have an implicitly inout self.
isMutating = true;
}

// 'static' functions have 'self' of type metatype<T>.
if (isStatic)
return MetatypeType::get(selfTy, Ctx);

// Reference types have 'self' of type T.
if (containerTy->hasReferenceSemantics())
return selfTy;

// Mutating methods are always passed inout so we can receive the side
// effect.
if (isMutating)
return InOutType::get(selfTy);

// Nonmutating methods on structs and enums pass the receiver by value.
return selfTy;
}

DeclName AbstractFunctionDecl::getEffectiveFullName() const {
if (getFullName())
return getFullName();
Expand Down
87 changes: 55 additions & 32 deletions lib/SIL/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,48 +511,76 @@ enum class ConventionsKind : uint8_t {
void visitTopLevelParams(AbstractionPattern origType,
CanAnyFunctionType::CanParamArrayRef params,
AnyFunctionType::ExtInfo extInfo) {
// If we don't have 'self', we don't need to do anything special.
if (!extInfo.hasSelfParam() && !Foreign.Self.isImportAsMember()) {
// Add any leading foreign parameters.
maybeAddForeignParameters();

if (params.empty()) {
visit(origType, M.getASTContext().TheEmptyTupleType);
} else {
CanType ty = AnyFunctionType::composeInput(M.getASTContext(), params,
/*canonicalVararg*/true)
->getCanonicalType();
visit(origType, ty);
}
return;
}

// Okay, handle 'self'.

unsigned numEltTypes = params.size();
assert(numEltTypes > 0);
unsigned numNonSelfParams = numEltTypes - 1;

// We have to declare this out here so that the lambda scope lasts for
// the duration of the loop below.
auto handleForeignSelf = [&] {
visit(origType.getTupleElementType(numNonSelfParams),
params[numNonSelfParams].getType());
};

// If we have a foreign-self, install handleSelf as the handler.
if (Foreign.Self.isInstance()) {
assert(numEltTypes > 0);
// This is safe because function_ref just stores a pointer to the
// existing lambda object.
HandleForeignSelf = handleForeignSelf;
}

// Now we can add any leading foreign parameters.
// Add any leading foreign parameters.
maybeAddForeignParameters();

// If we have no parameters, even 'self' parameters, bail unless we need
// to substitute.
if (params.empty()) {
if (origType.isTypeParameter())
visit(origType, M.getASTContext().TheEmptyTupleType);
return;
}

assert(numEltTypes > 0);

// If we don't have 'self', we don't need to do anything special.
if (!extInfo.hasSelfParam() && !Foreign.Self.isImportAsMember()) {
CanType ty = AnyFunctionType::composeInput(M.getASTContext(), params,
/*canonicalVararg*/true)
->getCanonicalType();
CanTupleType tty = dyn_cast<TupleType>(ty);
if (!tty || (origType.isTypeParameter() && !tty->hasInOutElement())) {
visit(origType, ty);
return;
}

// If the abstraction pattern is opaque, and the tuple type is
// materializable -- if it doesn't contain an l-value type -- then it's
// a valid target for substitution and we should not expand it.
for (auto i : indices(tty.getElementTypes())) {
visit(origType.getTupleElementType(i), tty.getElementType(i));
}
return;
}

// Okay, handle 'self'.

// Process all the non-self parameters.
for (unsigned i = 0; i != numNonSelfParams; ++i) {
visit(origType.getTupleElementType(i), params[i].getType());
CanType ty = params[i].getType();
CanTupleType tty = dyn_cast<TupleType>(ty);
AbstractionPattern eltPattern = origType.getTupleElementType(i);
if (!tty || (eltPattern.isTypeParameter() && !tty->hasInOutElement())) {
visit(eltPattern, ty);
continue;
}

assert(eltPattern.isTuple());
// If the abstraction pattern is opaque, and the tuple type is
// materializable -- if it doesn't contain an l-value type -- then it's
// a valid target for substitution and we should not expand it.
for (unsigned j = 0; j < eltPattern.getNumTupleElements(); ++j) {
visit(eltPattern.getTupleElementType(j), tty.getElementType(j));
}
}

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

void visit(AbstractionPattern origType, CanType substType) {
// Expand tuples. But if the abstraction pattern is opaque, and
// the tuple type is materializable -- if it doesn't contain an
// l-value type -- then it's a valid target for substitution and
// we should not expand it.
// Expand tuples.
CanTupleType substTupleTy = dyn_cast<TupleType>(substType);
if (substTupleTy &&
(!origType.isTypeParameter() || substTupleTy->hasInOutElement())) {
assert(origType.isTypeParameter() ||
origType.getNumTupleElements() == substTupleTy->getNumElements());
if (substTupleTy && !origType.isTypeParameter()) {
assert(origType.getNumTupleElements() == substTupleTy->getNumElements());
for (auto i : indices(substTupleTy.getElementTypes())) {
visit(origType.getTupleElementType(i),
substTupleTy.getElementType(i));
Expand Down
4 changes: 2 additions & 2 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1092,8 +1092,8 @@ namespace {
ArgumentSource self = [&] {
if (!baseLV.isValid()) {
return ArgumentSource();
} else if (cast<FuncDecl>(setter.getDecl())->computeInterfaceSelfType()
->is<InOutType>()) {
} else if (computeSelfParam(cast<FuncDecl>(setter.getDecl()))
.getParameterFlags().isInOut()) {
return ArgumentSource(loc, std::move(baseLV));
} else {
return emitBaseValueForAccessor(SGF, loc, std::move(baseLV),
Expand Down
2 changes: 1 addition & 1 deletion lib/SILGen/SILGenMaterializeForSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ struct MaterializeForSetEmitter {
}

CanType witnessSelfType =
Witness->computeInterfaceSelfType()->getCanonicalType(
computeSelfParam(Witness).getType()->getCanonicalType(
GenericSig, *SGM.M.getSwiftModule());
witnessSelfType = getSubstWitnessInterfaceType(witnessSelfType);

Expand Down
14 changes: 8 additions & 6 deletions lib/Sema/DerivedConformanceCodable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,21 +1068,23 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
initDecl->getAttrs().add(reqAttr);
}

Type selfType = initDecl->computeInterfaceSelfType();
Type selfInitType = initDecl->computeInterfaceSelfType(/*init=*/true);
auto selfParam = computeSelfParam(initDecl);
auto initSelfParam = computeSelfParam(initDecl, /*init=*/true);
Type interfaceType;
Type initializerType;
if (auto sig = target->getGenericSignatureOfContext()) {
// Evaluate the below, but in a generic environment (if Self is generic).
initDecl->setGenericEnvironment(target->getGenericEnvironmentOfContext());
interfaceType = GenericFunctionType::get(sig, selfType, innerType,
interfaceType = GenericFunctionType::get(sig, {selfParam}, innerType,
FunctionType::ExtInfo());
initializerType = GenericFunctionType::get(sig, selfInitType, innerType,
initializerType = GenericFunctionType::get(sig, {initSelfParam}, innerType,
FunctionType::ExtInfo());
} else {
// (Self) -> (Decoder) throws -> (Self)
interfaceType = FunctionType::get(selfType, innerType);
initializerType = FunctionType::get(selfInitType, innerType);
interfaceType = FunctionType::get({selfParam}, innerType,
FunctionType::ExtInfo());
initializerType = FunctionType::get({initSelfParam}, innerType,
FunctionType::ExtInfo());
}

initDecl->setInterfaceType(interfaceType);
Expand Down
17 changes: 8 additions & 9 deletions lib/Sema/DerivedConformanceCodingKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,26 +159,25 @@ static ValueDecl *deriveInitDecl(TypeChecker &tc, Decl *parentDecl,
Type retInterfaceType =
OptionalType::get(parentDC->getDeclaredInterfaceType());
Type interfaceType = FunctionType::get(interfaceArgType, retInterfaceType);
Type selfInterfaceType = initDecl->computeInterfaceSelfType();
Type selfInitializerInterfaceType =
initDecl->computeInterfaceSelfType(/*init*/ true);
auto selfParam = computeSelfParam(initDecl);
auto initSelfParam = computeSelfParam(initDecl, /*init*/ true);

Type allocIfaceType;
Type initIfaceType;
if (auto sig = parentDC->getGenericSignatureOfContext()) {
initDecl->setGenericEnvironment(parentDC->getGenericEnvironmentOfContext());

allocIfaceType = GenericFunctionType::get(sig, selfInterfaceType,
allocIfaceType = GenericFunctionType::get(sig, {selfParam},
interfaceType,
FunctionType::ExtInfo());
initIfaceType = GenericFunctionType::get(sig, selfInitializerInterfaceType,
initIfaceType = GenericFunctionType::get(sig, {initSelfParam},
interfaceType,
FunctionType::ExtInfo());
} else {
allocIfaceType = FunctionType::get(selfInterfaceType,
interfaceType);
initIfaceType = FunctionType::get(selfInitializerInterfaceType,
interfaceType);
allocIfaceType = FunctionType::get({selfParam},
interfaceType, FunctionType::ExtInfo());
initIfaceType = FunctionType::get({initSelfParam},
interfaceType, FunctionType::ExtInfo());
}
initDecl->setInterfaceType(allocIfaceType);
initDecl->setInitializerInterfaceType(initIfaceType);
Expand Down
Loading