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:
Doug Gregor
2013-10-09 17:27:58 +00:00
parent e6d578b1c6
commit a012f60633
35 changed files with 446 additions and 236 deletions

View File

@@ -320,9 +320,9 @@ bool ValueDecl::canBeAccessedByDynamicLookup() const {
(!isa<ClassDecl>(nominalDC) && !isa<ProtocolDecl>(nominalDC)))
return false;
// Dynamic lookup cannot find results within a generic context, because there
// is no sensible way to infer the generic arguments.
if (getDeclContext()->isGenericContext())
// Dynamic lookup cannot find results within a non-protocol generic context,
// because there is no sensible way to infer the generic arguments.
if (getDeclContext()->isGenericContext() && !isa<ProtocolDecl>(nominalDC))
return false;
// Dynamic lookup can find functions, variables, and subscripts.
@@ -398,16 +398,45 @@ void NominalTypeDecl::computeType() {
// Compute the declared type.
Type parentTy = getDeclContext()->getDeclaredTypeInContext();
ASTContext &ctx = getASTContext();
if (getGenericParams()) {
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
if (!DeclaredTy)
DeclaredTy = ProtocolType::get(proto, ctx);
} else if (getGenericParams()) {
DeclaredTy = UnboundGenericType::get(this, parentTy, ctx);
} else if (auto proto = dyn_cast<ProtocolDecl>(this)) {
DeclaredTy = new (ctx, AllocationArena::Permanent) ProtocolType(proto, ctx);
} else {
DeclaredTy = NominalType::get(this, parentTy, ctx);
}
// Set the type.
setType(MetaTypeType::get(DeclaredTy, ctx));
// A protocol has an implicit generic parameter list consisting of a single
// generic parameter, Self, that conforms to the protocol itself. This
// parameter is always implicitly bound.
//
// If this protocol has been deserialized, it already has generic parameters.
// Don't add them again.
if (!getGenericParams()) {
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
// The generic parameter 'Self'.
auto selfId = ctx.getIdentifier("Self");
auto selfDecl = new (ctx) GenericTypeParamDecl(proto, selfId,
proto->getLoc(), 0, 0);
IdentTypeRepr::Component protoRef(proto->getLoc(), proto->getName(), { });
protoRef.setValue(proto);
TypeLoc selfInherited[1] = {
TypeLoc(IdentTypeRepr::create(ctx, protoRef))
};
selfInherited[0].setType(DeclaredTy);
selfDecl->setInherited(ctx.AllocateCopy(selfInherited));
selfDecl->setImplicit();
// The generic parameter list itself.
GenericParams = GenericParamList::create(ctx, SourceLoc(),
GenericParam(selfDecl),
SourceLoc());
}
}
}
Type NominalTypeDecl::getDeclaredTypeInContext() {
@@ -439,7 +468,9 @@ Type NominalTypeDecl::getInterfaceType() {
parentType = typeOfParentContext->getAnyNominal()->getInterfaceType();
Type type;
if (auto params = getGenericParams()) {
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
type = ProtocolType::get(proto, getASTContext());
} else if (auto params = getGenericParams()) {
// If we have a generic type, bind the type to the archetypes
// in the type's definition.
SmallVector<Type, 4> genericArgs;
@@ -607,7 +638,8 @@ EnumElementDecl *EnumDecl::getElement(Identifier Name) const {
ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
SourceLoc NameLoc, Identifier Name,
MutableArrayRef<TypeLoc> Inherited)
: NominalTypeDecl(DeclKind::Protocol, DC, Name, NameLoc, Inherited, nullptr),
: NominalTypeDecl(DeclKind::Protocol, DC, Name, NameLoc, Inherited,
nullptr),
ProtocolLoc(ProtocolLoc)
{
ProtocolDeclBits.RequiresClassValid = false;
@@ -680,13 +712,8 @@ bool ProtocolDecl::requiresClassSlow() {
return false;
}
AssociatedTypeDecl *ProtocolDecl::getSelf() const {
for (auto member : getMembers()) {
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member))
if (assocType->isSelf())
return assocType;
}
llvm_unreachable("No 'Self' associated type?");
GenericTypeParamDecl *ProtocolDecl::getSelf() const {
return getGenericParams()->getParams()[0].getAsTypeParam();
}
void VarDecl::setComputedAccessors(ASTContext &Context, SourceLoc LBraceLoc,
@@ -844,23 +871,12 @@ Type FuncDecl::computeSelfType(GenericParamList **OuterGenericParams) const {
Type ContainerType = getExtensionType();
if (ContainerType.isNull()) return ContainerType;
// For a protocol, the type of 'self' is the associated type 'Self', not
// For a protocol, the type of 'self' is the parameter type 'Self', not
// the protocol itself.
if (auto Protocol = ContainerType->getAs<ProtocolType>()) {
AssociatedTypeDecl *Self = 0;
for (auto Member : Protocol->getDecl()->getMembers()) {
Self = dyn_cast<AssociatedTypeDecl>(Member);
if (!Self)
continue;
if (Self->isSelf())
break;
Self = nullptr;
}
assert(Self && "Missing 'Self' associated type in protocol");
ContainerType = Self->getDeclaredType();
auto Self = Protocol->getDecl()->getSelf();
assert(Self && "Missing 'Self' type in protocol");
ContainerType = Self->getArchetype();
}
if (UnboundGenericType *UGT = ContainerType->getAs<UnboundGenericType>()) {