Skip to content

Preliminary SILGen and IRGen support for nested generic types #3064

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 5 commits into from
Jun 23, 2016
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
1 change: 1 addition & 0 deletions include/swift/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class Mangler {
void mangleClosureEntity(const AbstractClosureExpr *closure,
unsigned uncurryingLevel);
void mangleNominalType(const NominalTypeDecl *decl);
void mangleBoundGenericType(Type type);
void mangleProtocolDecl(const ProtocolDecl *protocol);
void mangleType(Type type, unsigned uncurryingLevel);
void mangleDirectness(bool isIndirect);
Expand Down
67 changes: 46 additions & 21 deletions lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,32 +940,17 @@ void Mangler::mangleType(Type type, unsigned uncurryLevel) {
Buffer << '_';
return;

case TypeKind::UnboundGeneric: {
// We normally reject unbound types in IR-generation, but there
// are several occasions in which we'd like to mangle them in the
// abstract.
auto decl = cast<UnboundGenericType>(tybase)->getDecl();
mangleNominalType(cast<NominalTypeDecl>(decl));
return;
}

case TypeKind::UnboundGeneric:
case TypeKind::Class:
case TypeKind::Enum:
case TypeKind::Struct: {
return mangleNominalType(cast<NominalType>(tybase)->getDecl());
}

case TypeKind::Struct:
case TypeKind::BoundGenericClass:
case TypeKind::BoundGenericEnum:
case TypeKind::BoundGenericStruct: {
// type ::= 'G' <type> <type>+ '_'
auto *boundType = cast<BoundGenericType>(tybase);
Buffer << 'G';
mangleNominalType(boundType->getDecl());
for (auto arg : boundType->getGenericArgs()) {
mangleType(arg, /*uncurry*/ 0);
}
Buffer << '_';
if (type->isSpecialized())
mangleBoundGenericType(type);
else
mangleNominalType(tybase->getAnyNominal());
return;
}

Expand Down Expand Up @@ -1332,6 +1317,46 @@ void Mangler::mangleNominalType(const NominalTypeDecl *decl) {
addSubstitution(key);
}

static void
collectBoundGenericArgs(Type type,
SmallVectorImpl<SmallVector<Type, 2>> &genericArgs) {
if (auto *unboundType = type->getAs<UnboundGenericType>()) {
if (auto parent = unboundType->getParent())
collectBoundGenericArgs(parent, genericArgs);
genericArgs.push_back({});
} else if (auto *nominalType = type->getAs<NominalType>()) {
if (auto parent = nominalType->getParent())
collectBoundGenericArgs(parent, genericArgs);
genericArgs.push_back({});
} else {
auto *boundType = type->castTo<BoundGenericType>();
if (auto parent = boundType->getParent())
collectBoundGenericArgs(parent, genericArgs);

SmallVector<Type, 2> args;
for (auto arg : boundType->getGenericArgs())
args.push_back(arg);
genericArgs.push_back(args);
}
}

void Mangler::mangleBoundGenericType(Type type) {
// type ::= 'G' <type> (<type>+ '_')+
Buffer << 'G';
auto *nominal = type->getAnyNominal();
mangleNominalType(nominal);

SmallVector<SmallVector<Type, 2>, 2> genericArgs;
collectBoundGenericArgs(type, genericArgs);
assert(!genericArgs.empty());

for (auto args : genericArgs) {
for (auto arg : args)
mangleType(arg, /*uncurry*/ 0);
Buffer << '_';
}
}

void Mangler::mangleProtocolDecl(const ProtocolDecl *protocol) {
Buffer << 'P';
mangleContextOf(protocol);
Expand Down
107 changes: 72 additions & 35 deletions lib/Basic/Demangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,73 @@ class Demangler {
return nullptr;
}

NodePointer demangleBoundGenericArgs(NodePointer nominalType) {
// Generic arguments for the outermost type come first.
NodePointer parentOrModule = nominalType->getChild(0);
if (parentOrModule->getKind() != Node::Kind::Module) {
parentOrModule = demangleBoundGenericArgs(parentOrModule);

// Rebuild this type with the new parent type, which may have
// had its generic arguments applied.
NodePointer result = NodeFactory::create(nominalType->getKind());
result->addChild(parentOrModule);
result->addChild(nominalType->getChild(1));

nominalType = result;
}

NodePointer args = NodeFactory::create(Node::Kind::TypeList);
while (!Mangled.nextIf('_')) {
NodePointer type = demangleType();
if (!type)
return nullptr;
args->addChild(type);
if (Mangled.isEmpty())
return nullptr;
}

// If there were no arguments at this level there is nothing left
// to do.
if (args->getNumChildren() == 0)
return nominalType;

// Otherwise, build a bound generic type node from the unbound
// type and arguments.
NodePointer unboundType = NodeFactory::create(Node::Kind::Type);
unboundType->addChild(nominalType);

Node::Kind kind;
switch (nominalType->getKind()) { // look through Type node
case Node::Kind::Class:
kind = Node::Kind::BoundGenericClass;
break;
case Node::Kind::Structure:
kind = Node::Kind::BoundGenericStructure;
break;
case Node::Kind::Enum:
kind = Node::Kind::BoundGenericEnum;
break;
default:
return nullptr;
}
NodePointer result = NodeFactory::create(kind);
result->addChild(unboundType);
result->addChild(args);
return result;
}

NodePointer demangleBoundGenericType() {
// bound-generic-type ::= 'G' nominal-type (args+ '_')+
//
// Each level of nominal type nesting has its own list of arguments.

NodePointer nominalType = demangleNominalType();
if (!nominalType)
return nullptr;

return demangleBoundGenericArgs(nominalType);
}

NodePointer demangleContext() {
// context ::= module
// context ::= entity
Expand Down Expand Up @@ -1191,6 +1258,8 @@ class Demangler {
return demangleSubstitutionIndex();
if (Mangled.nextIf('s'))
return NodeFactory::create(Node::Kind::Module, STDLIB_NAME);
if (Mangled.nextIf('G'))
return demangleBoundGenericType();
if (isStartOfEntity(Mangled.peek()))
return demangleEntity();
return demangleModule();
Expand Down Expand Up @@ -1872,37 +1941,7 @@ class Demangler {
return demangleFunctionType(Node::Kind::UncurriedFunctionType);
}
if (c == 'G') {
NodePointer unboundType = demangleType();
if (!unboundType)
return nullptr;
NodePointer type_list = NodeFactory::create(Node::Kind::TypeList);
while (!Mangled.nextIf('_')) {
NodePointer type = demangleType();
if (!type)
return nullptr;
type_list->addChild(type);
if (Mangled.isEmpty())
return nullptr;
}
Node::Kind bound_type_kind;
switch (unboundType->getChild(0)->getKind()) { // look through Type node
case Node::Kind::Class:
bound_type_kind = Node::Kind::BoundGenericClass;
break;
case Node::Kind::Structure:
bound_type_kind = Node::Kind::BoundGenericStructure;
break;
case Node::Kind::Enum:
bound_type_kind = Node::Kind::BoundGenericEnum;
break;
default:
return nullptr;
}
NodePointer type_application =
NodeFactory::create(bound_type_kind);
type_application->addChild(unboundType);
type_application->addChild(type_list);
return type_application;
return demangleBoundGenericType();
}
if (c == 'X') {
if (Mangled.nextIf('b')) {
Expand Down Expand Up @@ -2049,10 +2088,8 @@ class Demangler {

return nullptr;
}
if (isStartOfNominalType(c)) {
NodePointer nominal_type = demangleDeclarationName(nominalTypeMarkerToNodeKind(c));
return nominal_type;
}
if (isStartOfNominalType(c))
return demangleDeclarationName(nominalTypeMarkerToNodeKind(c));
return nullptr;
}

Expand Down
Loading