mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Make protocol methods generic over <Self>.
Pull the implicit 'Self' associated type out of the protocol and into
an implicitly-declared generic parameter list for the protocol. This
makes all of the methods of a protocol polymorphic, e.g., given
protocol P {
typealias Assoc
func getAssoc() -> Assoc
}
the type of P.getAssoc is:
<Self : P> (self : @inout P) -> () -> Self.Assoc
This directly expresses the notion that protocol methods are
polymorphic, even though 'Self' is always implicitly bound. It can be
used to simplify IRgen and some parts of the type checker, as well as
laying more of the groundwork for default definitions within
protocols as well as sundry other improvements to the generics
system.
There are a number of moving parts that needed to be updated in tandem
for this. In no particular order:
- Protocols always get an implicit generic parameter list, with a
single generic parameter 'Self' that conforms to the protocol itself.
- The 'Self' archetype type now knows which protocol it is
associated with (since we can no longer point it at the Self
associated type declaration).
- Protocol methods now get interface types (i.e., canonicalizable
dependent function types).
- The "all archetypes" list for a polymorphic function type does not
include the Self archetype nor its nested types, because they are
handled implicitly. This avoids the need to rework IRGen's handling
of archetypes for now.
- When (de-)serializing a XREF for a function type that has an
interface type, use the canonicalized interface type, which can be
meaningfully compared during deserialization (unlike the
PolymorphicFunctionType we'd otherwise be dealing with).
- Added a SIL-specific type attribute @sil_self, which extracts the
'Self' archetype of a protocol, because we can no longer refer to
the associated type "P.Self".
Swift SVN r9066
This commit is contained in:
@@ -707,6 +707,16 @@ static Optional<swift::Associativity> getActualAssociativity(uint8_t assoc) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the interface type for the given declaration.
|
||||
static Type getValueInterfaceType(ValueDecl *value) {
|
||||
if (auto func = dyn_cast<AbstractFunctionDecl>(value)) {
|
||||
if (auto interfaceTy = func->getInterfaceType())
|
||||
return interfaceTy;
|
||||
}
|
||||
|
||||
return value->getType();
|
||||
}
|
||||
|
||||
Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
std::function<void(Decl*)> DidRecord) {
|
||||
if (DID == 0)
|
||||
@@ -773,6 +783,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
case decls_block::GENERIC_TYPE_PARAM_DECL: {
|
||||
IdentifierID nameID;
|
||||
DeclID contextID;
|
||||
bool isImplicit;
|
||||
unsigned depth;
|
||||
unsigned index;
|
||||
TypeID superclassID;
|
||||
@@ -780,6 +791,7 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
|
||||
decls_block::GenericTypeParamDeclLayout::readRecord(scratch, nameID,
|
||||
contextID,
|
||||
isImplicit,
|
||||
depth,
|
||||
index,
|
||||
superclassID,
|
||||
@@ -797,6 +809,9 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
index);
|
||||
declOrOffset = genericParam;
|
||||
|
||||
if (isImplicit)
|
||||
genericParam->setImplicit();
|
||||
|
||||
genericParam->setSuperclass(getType(superclassID));
|
||||
genericParam->setArchetype(getType(archetypeID)->castTo<ArchetypeType>());
|
||||
|
||||
@@ -1172,19 +1187,35 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
auto proto = new (ctx) ProtocolDecl(DC, SourceLoc(), SourceLoc(),
|
||||
getIdentifier(nameID), { });
|
||||
declOrOffset = proto;
|
||||
proto->computeType();
|
||||
|
||||
if (DidRecord) {
|
||||
DidRecord(proto);
|
||||
DidRecord = nullptr;
|
||||
}
|
||||
|
||||
if (auto genericParams = maybeReadGenericParams(DC)) {
|
||||
proto->setGenericParams(genericParams);
|
||||
SmallVector<GenericTypeParamType *, 4> paramTypes;
|
||||
for (auto &genericParam : *proto->getGenericParams()) {
|
||||
genericParam.getAsTypeParam()->setDeclContext(proto);
|
||||
paramTypes.push_back(genericParam.getAsTypeParam()->getDeclaredType()
|
||||
->castTo<GenericTypeParamType>());
|
||||
}
|
||||
|
||||
// Read the generic requirements.
|
||||
SmallVector<Requirement, 4> requirements;
|
||||
readGenericRequirements(requirements);
|
||||
|
||||
proto->setGenericSignature(paramTypes, requirements);
|
||||
}
|
||||
|
||||
|
||||
if (isImplicit)
|
||||
proto->setImplicit();
|
||||
if (isClassProtocol)
|
||||
proto->getMutableAttrs().ClassProtocol = true;
|
||||
proto->setIsObjC(isObjC);
|
||||
proto->computeType();
|
||||
|
||||
// Deserialize the list of protocols.
|
||||
SmallVector<ProtocolDecl *, 4> protocols;
|
||||
@@ -1581,7 +1612,8 @@ Decl *ModuleFile::getDecl(DeclID DID, Optional<DeclContext *> ForcedContext,
|
||||
for (auto value : values) {
|
||||
if (!value->hasClangNode() && value->getModuleContext() != M)
|
||||
continue;
|
||||
if (expectedTy && value->getType()->getCanonicalType() != expectedTy)
|
||||
if (expectedTy &&
|
||||
getValueInterfaceType(value)->getCanonicalType() != expectedTy)
|
||||
continue;
|
||||
|
||||
if (!result || result == value) {
|
||||
@@ -1888,12 +1920,13 @@ Type ModuleFile::getType(TypeID TID) {
|
||||
IdentifierID nameID;
|
||||
bool isPrimary;
|
||||
TypeID parentOrIndex;
|
||||
DeclID assocTypeID;
|
||||
DeclID assocTypeOrProtoID;
|
||||
TypeID superclassID;
|
||||
ArrayRef<uint64_t> rawConformanceIDs;
|
||||
|
||||
decls_block::ArchetypeTypeLayout::readRecord(scratch, nameID, isPrimary,
|
||||
parentOrIndex, assocTypeID,
|
||||
parentOrIndex,
|
||||
assocTypeOrProtoID,
|
||||
superclassID,
|
||||
rawConformanceIDs);
|
||||
|
||||
@@ -1907,8 +1940,14 @@ Type ModuleFile::getType(TypeID TID) {
|
||||
else
|
||||
parent = getType(parentOrIndex)->castTo<ArchetypeType>();
|
||||
|
||||
AssociatedTypeDecl *assocType
|
||||
= cast_or_null<AssociatedTypeDecl>(getDecl(assocTypeID));
|
||||
ArchetypeType::AssocTypeOrProtocolType assocTypeOrProto;
|
||||
auto assocTypeOrProtoDecl = getDecl(assocTypeOrProtoID);
|
||||
if (auto assocType
|
||||
= dyn_cast_or_null<AssociatedTypeDecl>(assocTypeOrProtoDecl))
|
||||
assocTypeOrProto = assocType;
|
||||
else
|
||||
assocTypeOrProto = cast_or_null<ProtocolDecl>(assocTypeOrProtoDecl);
|
||||
|
||||
superclass = getType(superclassID);
|
||||
|
||||
for (DeclID protoID : rawConformanceIDs)
|
||||
@@ -1918,7 +1957,7 @@ Type ModuleFile::getType(TypeID TID) {
|
||||
if (typeOrOffset.isComplete())
|
||||
break;
|
||||
|
||||
auto archetype = ArchetypeType::getNew(ctx, parent, assocType,
|
||||
auto archetype = ArchetypeType::getNew(ctx, parent, assocTypeOrProto,
|
||||
getIdentifier(nameID), conformances,
|
||||
superclass, index);
|
||||
typeOrOffset = archetype;
|
||||
@@ -2106,6 +2145,7 @@ Type ModuleFile::getType(TypeID TID) {
|
||||
case DeclKind::Class:
|
||||
case DeclKind::Struct:
|
||||
case DeclKind::Enum:
|
||||
case DeclKind::Protocol:
|
||||
paramList = cast<NominalTypeDecl>(genericContext)->getGenericParams();
|
||||
break;
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user