Skip to content

Mangle associated types of opaque types like dependent member types. … #27014

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 2 commits into from
Sep 4, 2019
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
5 changes: 5 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,11 @@ Types
type ::= assoc-type-name 'Qz' // shortcut for 'Qyz'
type ::= assoc-type-list 'QY' GENERIC-PARAM-INDEX // associated type at depth
type ::= assoc-type-list 'QZ' // shortcut for 'QYz'
#if SWIFT_RUNTIME_VERSION >= 5.2
type ::= type assoc-type-name 'Qx' // associated type relative to base `type`
type ::= type assoc-type-list 'QX' // associated type relative to base `type`
#endif

protocol-list ::= protocol '_' protocol*
protocol-list ::= empty-list
Expand Down
16 changes: 16 additions & 0 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,22 @@ void ASTMangler::appendType(Type type, const ValueDecl *forDecl) {

case TypeKind::NestedArchetype: {
auto nestedType = cast<NestedArchetypeType>(tybase);

// Mangle associated types of opaque archetypes like dependent member
// types, so that they can be accurately demangled at runtime.
if (auto opaque =
dyn_cast<OpaqueTypeArchetypeType>(nestedType->getRoot())) {
if (tryMangleTypeSubstitution(nestedType))
return;

appendType(opaque);
bool isAssocTypeAtDepth = false;
appendAssocType(nestedType->getInterfaceType(), isAssocTypeAtDepth);
appendOperator(isAssocTypeAtDepth ? "QX" : "Qx");
addTypeSubstitution(nestedType);
return;
}

appendType(nestedType->getParent());
appendIdentifier(nestedType->getName().str());
appendOperator("Qa");
Expand Down
6 changes: 6 additions & 0 deletions lib/Basic/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ swift::getSwiftRuntimeCompatibilityVersionForTarget(const llvm::Triple &Triple){
if (Major == 10) {
if (Minor <= 14) {
return llvm::VersionTuple(5, 0);
} else if (Minor <= 15) {
return llvm::VersionTuple(5, 1);
} else {
return None;
}
Expand All @@ -361,13 +363,17 @@ swift::getSwiftRuntimeCompatibilityVersionForTarget(const llvm::Triple &Triple){
Triple.getiOSVersion(Major, Minor, Micro);
if (Major <= 12) {
return llvm::VersionTuple(5, 0);
} else if (Major <= 13) {
return llvm::VersionTuple(5, 1);
} else {
return None;
}
} else if (Triple.isWatchOS()) {
Triple.getWatchOSVersion(Major, Minor, Micro);
if (Major <= 5) {
return llvm::VersionTuple(5, 0);
} else if (Major <= 6) {
return llvm::VersionTuple(5, 1);
} else {
return None;
}
Expand Down
161 changes: 91 additions & 70 deletions lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1919,79 +1919,96 @@ NodePointer Demangler::demanglePrivateContextDescriptor() {

NodePointer Demangler::demangleArchetype() {
switch (nextChar()) {
case 'a': {
NodePointer Ident = popNode(Node::Kind::Identifier);
NodePointer ArcheTy = popTypeAndGetChild();
NodePointer AssocTy = createType(
createWithChildren(Node::Kind::AssociatedTypeRef, ArcheTy, Ident));
addSubstitution(AssocTy);
return AssocTy;
}
case 'O': {
auto definingContext = popContext();
return createWithChild(Node::Kind::OpaqueReturnTypeOf, definingContext);
}
case 'o': {
auto index = demangleIndex();
Vector<NodePointer> boundGenericArgs;
NodePointer retroactiveConformances;
if (!demangleBoundGenerics(boundGenericArgs, retroactiveConformances))
return nullptr;
auto Name = popNode();
auto opaque = createWithChildren(Node::Kind::OpaqueType, Name,
createNode(Node::Kind::Index, index));
auto boundGenerics = createNode(Node::Kind::TypeList);
for (unsigned i = boundGenericArgs.size(); i-- > 0;)
boundGenerics->addChild(boundGenericArgs[i], *this);
opaque->addChild(boundGenerics, *this);
if (retroactiveConformances)
opaque->addChild(retroactiveConformances, *this);

auto opaqueTy = createType(opaque);
addSubstitution(opaqueTy);
return opaqueTy;
}
case 'r': {
return createType(createNode(Node::Kind::OpaqueReturnType));
}
case 'y': {
NodePointer T = demangleAssociatedTypeSimple(demangleGenericParamIndex());
addSubstitution(T);
return T;
}
case 'z': {
NodePointer T = demangleAssociatedTypeSimple(
getDependentGenericParamType(0, 0));
addSubstitution(T);
return T;
}
case 'Y': {
NodePointer T = demangleAssociatedTypeCompound(
demangleGenericParamIndex());
addSubstitution(T);
return T;
}
case 'Z': {
NodePointer T = demangleAssociatedTypeCompound(
getDependentGenericParamType(0, 0));
addSubstitution(T);
return T;
}
default:
case 'a': {
NodePointer Ident = popNode(Node::Kind::Identifier);
NodePointer ArcheTy = popTypeAndGetChild();
NodePointer AssocTy = createType(
createWithChildren(Node::Kind::AssociatedTypeRef, ArcheTy, Ident));
addSubstitution(AssocTy);
return AssocTy;
}
case 'O': {
auto definingContext = popContext();
return createWithChild(Node::Kind::OpaqueReturnTypeOf, definingContext);
}
case 'o': {
auto index = demangleIndex();
Vector<NodePointer> boundGenericArgs;
NodePointer retroactiveConformances;
if (!demangleBoundGenerics(boundGenericArgs, retroactiveConformances))
return nullptr;
auto Name = popNode();
auto opaque = createWithChildren(Node::Kind::OpaqueType, Name,
createNode(Node::Kind::Index, index));
auto boundGenerics = createNode(Node::Kind::TypeList);
for (unsigned i = boundGenericArgs.size(); i-- > 0;)
boundGenerics->addChild(boundGenericArgs[i], *this);
opaque->addChild(boundGenerics, *this);
if (retroactiveConformances)
opaque->addChild(retroactiveConformances, *this);

auto opaqueTy = createType(opaque);
addSubstitution(opaqueTy);
return opaqueTy;
}
case 'r': {
return createType(createNode(Node::Kind::OpaqueReturnType));
}

case 'x': {
NodePointer T = demangleAssociatedTypeSimple(nullptr);
addSubstitution(T);
return T;
}

case 'X': {
NodePointer T = demangleAssociatedTypeCompound(nullptr);
addSubstitution(T);
return T;
}

case 'y': {
NodePointer T = demangleAssociatedTypeSimple(demangleGenericParamIndex());
addSubstitution(T);
return T;
}
case 'Y': {
NodePointer T = demangleAssociatedTypeCompound(
demangleGenericParamIndex());
addSubstitution(T);
return T;
}

case 'z': {
NodePointer T = demangleAssociatedTypeSimple(
getDependentGenericParamType(0, 0));
addSubstitution(T);
return T;
}
case 'Z': {
NodePointer T = demangleAssociatedTypeCompound(
getDependentGenericParamType(0, 0));
addSubstitution(T);
return T;
}
default:
return nullptr;
}
}

NodePointer Demangler::demangleAssociatedTypeSimple(
NodePointer GenericParamIdx) {
NodePointer GPI = createType(GenericParamIdx);
NodePointer Demangler::demangleAssociatedTypeSimple(NodePointer Base) {
NodePointer ATName = popAssocTypeName();
NodePointer BaseTy;
if (Base) {
BaseTy = createType(Base);
} else {
BaseTy = popNode(Node::Kind::Type);
}
return createType(createWithChildren(Node::Kind::DependentMemberType,
GPI, ATName));
BaseTy, ATName));
}

NodePointer Demangler::demangleAssociatedTypeCompound(
NodePointer GenericParamIdx) {
NodePointer Demangler::demangleAssociatedTypeCompound(NodePointer Base) {
Vector<NodePointer> AssocTyNames(*this, 4);
bool firstElem = false;
do {
Expand All @@ -2001,15 +2018,19 @@ NodePointer Demangler::demangleAssociatedTypeCompound(
return nullptr;
AssocTyNames.push_back(AssocTyName, *this);
} while (!firstElem);

NodePointer Base = GenericParamIdx;

NodePointer BaseTy;
if (Base)
BaseTy = createType(Base);
else
BaseTy = popNode(Node::Kind::Type);

while (NodePointer AssocTy = AssocTyNames.pop_back_val()) {
NodePointer depTy = createNode(Node::Kind::DependentMemberType);
depTy = addChild(depTy, createType(Base));
Base = addChild(depTy, AssocTy);
depTy = addChild(depTy, BaseTy);
BaseTy = createType(addChild(depTy, AssocTy));
}
return createType(Base);
return BaseTy;
}

NodePointer Demangler::popAssocTypeName() {
Expand Down
22 changes: 19 additions & 3 deletions lib/Demangling/Remangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,11 @@ std::pair<int, Node *> Remangler::mangleConstrainedType(Node *node) {
Chain.push_back(node->getChild(1), Factory);
node = getChildOfType(node->getFirstChild());
}
assert(node->getKind() == Node::Kind::DependentGenericParamType);

if (node->getKind() != Node::Kind::DependentGenericParamType) {
mangle(node);
node = nullptr;
}

const char *ListSeparator = (Chain.size() > 1 ? "_" : "");
for (unsigned i = 1, n = Chain.size(); i <= n; ++i) {
Expand Down Expand Up @@ -811,6 +815,7 @@ void Remangler::mangleDependentGenericConformanceRequirement(Node *node) {
if (ProtoOrClass->getFirstChild()->getKind() == Node::Kind::Protocol) {
manglePureProtocol(ProtoOrClass);
auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
switch (NumMembersAndParamIdx.first) {
case -1: Buffer << "RQ"; return; // substitution
case 0: Buffer << "R"; break;
Expand All @@ -822,6 +827,7 @@ void Remangler::mangleDependentGenericConformanceRequirement(Node *node) {
}
mangle(ProtoOrClass);
auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
switch (NumMembersAndParamIdx.first) {
case -1: Buffer << "RB"; return; // substitution
case 0: Buffer << "Rb"; break;
Expand Down Expand Up @@ -849,6 +855,7 @@ void Remangler::mangleDependentGenericParamType(Node *node) {
void Remangler::mangleDependentGenericSameTypeRequirement(Node *node) {
mangleChildNode(node, 1);
auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
switch (NumMembersAndParamIdx.first) {
case -1: Buffer << "RS"; return; // substitution
case 0: Buffer << "Rs"; break;
Expand All @@ -860,6 +867,7 @@ void Remangler::mangleDependentGenericSameTypeRequirement(Node *node) {

void Remangler::mangleDependentGenericLayoutRequirement(Node *node) {
auto NumMembersAndParamIdx = mangleConstrainedType(node->getChild(0));
assert(NumMembersAndParamIdx.first < 0 || NumMembersAndParamIdx.second);
switch (NumMembersAndParamIdx.first) {
case -1: Buffer << "RL"; break; // substitution
case 0: Buffer << "Rl"; break;
Expand Down Expand Up @@ -922,11 +930,19 @@ void Remangler::mangleDependentMemberType(Node *node) {
unreachable("wrong dependent member type");
case 1:
Buffer << 'Q';
mangleDependentGenericParamIndex(NumMembersAndParamIdx.second, "y", 'z');
if (auto dependentBase = NumMembersAndParamIdx.second) {
mangleDependentGenericParamIndex(dependentBase, "y", 'z');
} else {
Buffer << 'x';
}
break;
default:
Buffer << 'Q';
mangleDependentGenericParamIndex(NumMembersAndParamIdx.second, "Y", 'Z');
if (auto dependentBase = NumMembersAndParamIdx.second) {
mangleDependentGenericParamIndex(dependentBase, "Y", 'Z');
} else {
Buffer << 'X';
}
break;
}
}
Expand Down
21 changes: 15 additions & 6 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,9 +649,10 @@ getInitializerForComputedComponent(IRGenModule &IGM,
}

static llvm::Constant *
emitMetadataTypeRefForKeyPath(IRGenModule &IGM, CanType type) {
emitMetadataTypeRefForKeyPath(IRGenModule &IGM, CanType type,
CanGenericSignature sig) {
// Produce a mangled name for the type.
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata).first;
auto constant = IGM.getTypeRef(type, sig, MangledTypeRefRole::Metadata).first;

// Mask the bottom bit to tell the key path runtime this is a mangled name
// rather than a direct reference.
Expand Down Expand Up @@ -837,6 +838,10 @@ emitKeyPathComponent(IRGenModule &IGM,
SmallVector<llvm::Constant *, 4> externalSubArgs;
auto componentSig = externalDecl->getInnermostDeclContext()
->getGenericSignatureOfContext();

auto componentCanSig = componentSig
? componentSig->getCanonicalSignature()
: CanGenericSignature();
auto subs = component.getExternalSubstitutions();
if (!subs.empty()) {
enumerateGenericSignatureRequirements(
Expand All @@ -847,7 +852,7 @@ emitKeyPathComponent(IRGenModule &IGM,
if (!reqt.Protocol) {
// Type requirement.
externalSubArgs.push_back(
emitMetadataTypeRefForKeyPath(IGM, substType));
emitMetadataTypeRefForKeyPath(IGM, substType, componentCanSig));
} else {
// Protocol requirement.
auto conformance = subs.lookupConformance(
Expand Down Expand Up @@ -1182,9 +1187,11 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
getAddrOfGenericEnvironment(pattern->getGenericSignature()));
// Store type references for the root and leaf.
fields.addRelativeAddress(
emitMetadataTypeRefForKeyPath(*this, rootTy));
emitMetadataTypeRefForKeyPath(*this, rootTy,
pattern->getGenericSignature()));
fields.addRelativeAddress(
emitMetadataTypeRefForKeyPath(*this, valueTy));
emitMetadataTypeRefForKeyPath(*this, valueTy,
pattern->getGenericSignature()));

// Add a pointer to the ObjC KVC compatibility string, if there is one, or
// null otherwise.
Expand Down Expand Up @@ -1238,7 +1245,9 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
// For all but the last component, we pack in the type of the component.
if (i + 1 != pattern->getComponents().size()) {
fields.addRelativeAddress(
emitMetadataTypeRefForKeyPath(*this, component.getComponentType()));
emitMetadataTypeRefForKeyPath(*this,
component.getComponentType(),
pattern->getGenericSignature()));
}
baseTy = component.getComponentType();
}
Expand Down
7 changes: 5 additions & 2 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1683,11 +1683,14 @@ namespace {
}

void addUnderlyingTypeAndConformances() {
auto sig = O->getOpaqueInterfaceGenericSignature()
? O->getOpaqueInterfaceGenericSignature()->getCanonicalSignature()
: CanGenericSignature();
auto underlyingType = Type(O->getUnderlyingInterfaceType())
.subst(*O->getUnderlyingTypeSubstitutions())
->getCanonicalType(O->getOpaqueInterfaceGenericSignature());
->getCanonicalType(sig);

B.addRelativeAddress(IGM.getTypeRef(underlyingType,
B.addRelativeAddress(IGM.getTypeRef(underlyingType, sig,
MangledTypeRefRole::Metadata).first);

auto opaqueType = O->getDeclaredInterfaceType()
Expand Down
Loading