Skip to content

Commit 8716fd0

Browse files
committed
Gather opaque type same-type requirements when scanning associated type infos from a binary
1 parent 8f6d22c commit 8716fd0

File tree

4 files changed

+125
-39
lines changed

4 files changed

+125
-39
lines changed

include/swift/ABI/GenericContext.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,18 @@ class TargetGenericRequirementDescriptor {
157157
return offsetof(typename std::remove_reference<decltype(*this)>::type, Protocol);
158158
}
159159

160+
/// Retreive the offset to the Type field
161+
constexpr inline auto
162+
getSameTypeNameOffset() const -> typename Runtime::StoredSize {
163+
return offsetof(typename std::remove_reference<decltype(*this)>::type, Type);
164+
}
165+
166+
/// Retreive the offset to the Type field
167+
constexpr inline auto
168+
getParamOffset() const -> typename Runtime::StoredSize {
169+
return offsetof(typename std::remove_reference<decltype(*this)>::type, Param);
170+
}
171+
160172
/// Retrieve the right-hand type for a SameType or BaseClass requirement.
161173
llvm::StringRef getMangledTypeName() const {
162174
assert(getKind() == GenericRequirementKind::SameType ||

include/swift/Reflection/TypeRefBuilder.h

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -312,12 +312,17 @@ struct ConformanceCollectionResult {
312312
std::vector<std::string> Errors;
313313
};
314314

315-
struct AssociatedType {
315+
struct TypeAliasInfo {
316316
std::string TypeAliasName;
317317
std::string SubstitutedTypeMangledName;
318318
std::string SubstitutedTypeFullyQualifiedName;
319319
std::string SubstitutedTypeDiagnosticPrintName;
320+
};
321+
322+
struct AssociatedType {
323+
TypeAliasInfo SubstitutionInfo;
320324
std::vector<std::string> OpaqueTypeProtocolConformanceRequirements;
325+
std::vector<TypeAliasInfo> OpaqueTypeSameTypeRequirements;
321326
};
322327

323328
/// Info about all of a given type's associated types, as read out from an Image
@@ -1170,18 +1175,21 @@ class TypeRefBuilder {
11701175
/* useOpaqueTypeSymbolicReferences */ true);
11711176

11721177
// If the substituted type is an opaque type, also gather info
1173-
// about which protocols it is required to conform to
1174-
std::vector<std::string> OpaqueTypeConformanceRequirements;
1175-
gatherConformanceRequirementsIfOpaque<ObjCInteropKind, PointerSize>(
1176-
substitutedDemangleTree, OpaqueTypeConformanceRequirements);
1178+
// about which protocols it is required to conform to and the corresponding
1179+
// same-type requirements
1180+
std::vector<std::string> opaqueTypeConformanceRequirements;
1181+
std::vector<TypeAliasInfo> sameTypeRequirements;
1182+
gatherOpaqueTypeRequirements<ObjCInteropKind, PointerSize>(
1183+
substitutedDemangleTree, opaqueTypeConformanceRequirements,
1184+
sameTypeRequirements);
11771185

11781186
auto substitutedTypeName = nodeToString(substitutedDemangleTree);
11791187
std::stringstream OS;
11801188
dumpTypeRef(substitutedTypeRef, OS);
1181-
associatedTypes.emplace_back(
1182-
AssociatedType{typealiasTypeName, mangledSubstitutedTypeName,
1183-
substitutedTypeName, OS.str(),
1184-
OpaqueTypeConformanceRequirements});
1189+
associatedTypes.emplace_back(AssociatedType{
1190+
TypeAliasInfo{typealiasTypeName, mangledSubstitutedTypeName,
1191+
substitutedTypeName, OS.str()},
1192+
opaqueTypeConformanceRequirements, sameTypeRequirements});
11851193
}
11861194
result.AssociatedTypeInfos.emplace_back(AssociatedTypeInfo{
11871195
mangledTypeName, typeName, protocolName, associatedTypes});
@@ -1193,9 +1201,10 @@ class TypeRefBuilder {
11931201

11941202
template <template <typename Runtime> class ObjCInteropKind,
11951203
unsigned PointerSize>
1196-
void gatherConformanceRequirementsIfOpaque(
1204+
void gatherOpaqueTypeRequirements(
11971205
Demangle::Node *substitutedTypeDemangleTree,
1198-
std::vector<std::string> &OpaqueTypeConformanceRequirements) {
1206+
std::vector<std::string> &opaqueTypeConformanceRequirements,
1207+
std::vector<TypeAliasInfo> &sameTypeRequirements) {
11991208
// With unresolved opaque symbolic references, the demangle tree we
12001209
// extract the opaque type descriptor's address from is of the form:
12011210
// kind=Type
@@ -1209,9 +1218,10 @@ class TypeRefBuilder {
12091218
auto opaqueTypeChildDemangleTree = childDemangleTree->getFirstChild();
12101219
if (opaqueTypeChildDemangleTree->getKind() ==
12111220
Node::Kind::OpaqueTypeDescriptorSymbolicReference) {
1212-
OpaqueTypeConformanceRequirements =
1213-
collectOpaqueTypeConformanceNames<ObjCInteropKind, PointerSize>(
1214-
opaqueTypeChildDemangleTree->getIndex());
1221+
extractOpaqueTypeProtocolRequirements<ObjCInteropKind, PointerSize>(
1222+
opaqueTypeChildDemangleTree->getIndex(),
1223+
opaqueTypeConformanceRequirements,
1224+
sameTypeRequirements);
12151225
}
12161226
}
12171227
}
@@ -1628,41 +1638,71 @@ class TypeRefBuilder {
16281638
stream << "- " << info.FullyQualifiedName << " : "
16291639
<< info.ProtocolFullyQualifiedName << "\n";
16301640
for (const auto &typeAlias : info.AssociatedTypes) {
1631-
stream << "typealias " << typeAlias.TypeAliasName << " = "
1632-
<< typeAlias.SubstitutedTypeFullyQualifiedName << "\n";
1633-
stream << typeAlias.SubstitutedTypeDiagnosticPrintName;
1641+
stream << "typealias " << typeAlias.SubstitutionInfo.TypeAliasName << " = "
1642+
<< typeAlias.SubstitutionInfo.SubstitutedTypeFullyQualifiedName << "\n";
1643+
stream << typeAlias.SubstitutionInfo.SubstitutedTypeDiagnosticPrintName;
16341644
if (!typeAlias.OpaqueTypeProtocolConformanceRequirements.empty()) {
1635-
stream << "opaque type conformance requirements: \n";
1645+
stream << "-------------------------\n";
1646+
stream << "conformance requirements: \n";
16361647
for (const auto &protocolName :
16371648
typeAlias.OpaqueTypeProtocolConformanceRequirements) {
16381649
stream << protocolName << "\n";
16391650
}
16401651
}
1652+
if (!typeAlias.OpaqueTypeSameTypeRequirements.empty()) {
1653+
stream << "-----------------------\n";
1654+
stream << "same-type requirements: \n";
1655+
for (const auto &sameTypeRequirementInfo :
1656+
typeAlias.OpaqueTypeSameTypeRequirements) {
1657+
stream << sameTypeRequirementInfo.TypeAliasName << " = "
1658+
<< sameTypeRequirementInfo.SubstitutedTypeMangledName << " ("
1659+
<< sameTypeRequirementInfo.SubstitutedTypeFullyQualifiedName
1660+
<< ")\n";
1661+
}
1662+
}
16411663
}
16421664
stream << "\n";
16431665
}
16441666
}
16451667

16461668
template <template <typename Runtime> class ObjCInteropKind,
16471669
unsigned PointerSize>
1648-
std::vector<std::string>
1649-
collectOpaqueTypeConformanceNames(uintptr_t opaqueTypeDescriptorAddress) {
1650-
std::vector<std::string> result;
1670+
void extractOpaqueTypeProtocolRequirements(
1671+
uintptr_t opaqueTypeDescriptorAddress,
1672+
std::vector<std::string> &protocolRequirements,
1673+
std::vector<TypeAliasInfo> &sameTypeRequirements) {
16511674
auto opaqueTypeDescriptorBytes = OpaqueByteReader(
16521675
remote::RemoteAddress(opaqueTypeDescriptorAddress),
16531676
sizeof(ExternalOpaqueTypeDescriptor<ObjCInteropKind, PointerSize>));
16541677
if (!opaqueTypeDescriptorBytes.get()) {
1655-
return result;
1678+
return;
16561679
}
16571680
const ExternalOpaqueTypeDescriptor<ObjCInteropKind, PointerSize>
16581681
*opaqueTypeDescriptor =
16591682
(const ExternalOpaqueTypeDescriptor<ObjCInteropKind, PointerSize> *)
16601683
opaqueTypeDescriptorBytes.get();
16611684

16621685
if (!opaqueTypeDescriptor) {
1663-
return result;
1686+
return;
16641687
}
16651688

1689+
// Given that at a given offset from the opaque type descriptor base there
1690+
// is an offset to a TypeRef string, read it.
1691+
auto readRequirementTypeRefAddress =
1692+
[&](uintptr_t offsetFromOpaqueDescBase,
1693+
uintptr_t requirementAddress) -> uint32_t {
1694+
std::string typeRefString = "";
1695+
auto fieldOffsetOffset = requirementAddress + offsetFromOpaqueDescBase -
1696+
(uintptr_t)opaqueTypeDescriptor;
1697+
auto fieldOffsetAddress = opaqueTypeDescriptorAddress + fieldOffsetOffset;
1698+
auto fieldOffsetBytes = OpaqueByteReader(
1699+
remote::RemoteAddress(fieldOffsetAddress), sizeof(uint32_t));
1700+
auto fieldOffset = (const int32_t *)fieldOffsetBytes.get();
1701+
auto fieldAddress = detail::applyRelativeOffset(
1702+
(const char *)fieldOffsetAddress, *fieldOffset);
1703+
return fieldAddress;
1704+
};
1705+
16661706
for (const auto &req : opaqueTypeDescriptor->getGenericRequirements()) {
16671707
if (req.getKind() == GenericRequirementKind::Protocol) {
16681708
// Compute the address of the protocol descriptor offset as:
@@ -1688,10 +1728,32 @@ class TypeRefBuilder {
16881728
auto conformanceRequirementProtocolName =
16891729
nameReader.readFullyQualifiedProtocolName(
16901730
protocolDescriptorAddress);
1691-
result.push_back(*conformanceRequirementProtocolName);
1731+
protocolRequirements.push_back(*conformanceRequirementProtocolName);
1732+
}
1733+
if (req.getKind() == GenericRequirementKind::SameType) {
1734+
// Read Param Name
1735+
auto paramAddress = readRequirementTypeRefAddress(req.getParamOffset(),
1736+
(uintptr_t)(&req));
1737+
std::string demangledParamName =
1738+
nodeToString(demangleTypeRef(readTypeRef(paramAddress)));
1739+
1740+
// Read the substituted Type Name
1741+
auto typeAddress = readRequirementTypeRefAddress(
1742+
req.getSameTypeNameOffset(), (uintptr_t)(&req));
1743+
auto typeTypeRef = readTypeRef(typeAddress);
1744+
std::string demangledTypeName =
1745+
nodeToString(demangleTypeRef(typeTypeRef));
1746+
std::string mangledTypeName;
1747+
auto typeMangling = Demangle::mangleNode(demangleTypeRef(typeTypeRef));
1748+
if (!typeMangling.isSuccess())
1749+
mangledTypeName = "";
1750+
else
1751+
mangledTypeName = typeMangling.result();
1752+
sameTypeRequirements.push_back(TypeAliasInfo{
1753+
demangledParamName, mangledTypeName, demangledTypeName, ""});
16921754
}
16931755
}
1694-
return result;
1756+
return;
16951757
}
16961758

16971759
///
@@ -1759,8 +1821,10 @@ class TypeRefBuilder {
17591821
(const char *)contextDescriptorFieldAddress,
17601822
*contextDescriptorOffset);
17611823

1762-
// Instead of a type descriptor this may just be a reference to an external, check that first
1763-
if (auto symbol = OpaqueDynamicSymbolResolver(remote::RemoteAddress(contextTypeDescriptorAddress))) {
1824+
// Instead of a type descriptor this may just be a reference to an
1825+
// external, check that first
1826+
if (auto symbol = OpaqueDynamicSymbolResolver(
1827+
remote::RemoteAddress(contextTypeDescriptorAddress))) {
17641828
if (!symbol->isResolved()) {
17651829
Demangle::Context Ctx;
17661830
auto demangledRoot =

test/Reflection/opaque_associated_type_requirements.swift

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,40 @@
1010
// RUN: %target-swift-reflection-dump -binary-filename %t/AssociatedTypeRequirements | %FileCheck %s
1111

1212
// CHECK: ASSOCIATED TYPES:
13-
// CHECK-NEXT: =============
14-
// CHECK-NEXT: - AssociatedTypeRequirements.Foo : AssociatedTypeRequirements.myProto
13+
// CHECK: - AssociatedTypeRequirements.Foo : AssociatedTypeRequirements.myProto
1514
// CHECK-NEXT: typealias PerformReturn = opaque type symbolic reference
1615
// CHECK-NEXT: opaque type symbolic reference
17-
// CHECK-NEXT: (struct AssociatedTypeRequirements.Bar)
16+
// CHECK-NEXT: (bound_generic_struct AssociatedTypeRequirements.Bar
1817

19-
// CHECK: opaque type conformance requirements:
18+
// CHECK: conformance requirements:
2019
// CHECK-NEXT: AssociatedTypeRequirements.protoA
2120
// CHECK-NEXT: AssociatedTypeRequirements.protoB
2221
// CHECK-NEXT: testModB.testModBProtocol
2322

23+
// CHECK: same-type requirements:
24+
// CHECK-NEXT: A.AssociatedTypeRequirements.protoB.K = Sf (Swift.Float)
25+
// CHECK-NEXT: A.AssociatedTypeRequirements.protoA.T = 8testModB0aB7BStructV (testModB.testModBStruct)
26+
2427
import testModB
2528

2629
public protocol myProto {
2730
associatedtype PerformReturn
2831
func perform() -> PerformReturn
2932
}
30-
public protocol protoA {}
31-
public protocol protoB {}
33+
public protocol protoA<T> {
34+
associatedtype T
35+
}
36+
public protocol protoB<K> {
37+
associatedtype K
38+
}
3239

33-
public struct Bar : protoA, protoB, testModBProtocol {}
40+
public struct Bar<M, N> : protoA, protoB, testModBProtocol {
41+
public typealias T = M
42+
public typealias K = N
43+
}
3444

3545
public struct Foo : myProto {
36-
public func perform() -> some protoA & protoB & testModBProtocol { return baz() }
46+
public func perform() -> some protoA<testModBStruct> & protoB<Float> & testModBProtocol { return baz() }
3747
}
3848

39-
private func baz() -> some protoA & protoB & testModBProtocol { return Bar() }
49+
private func baz() -> some protoA<testModBStruct> & protoB<Float> & testModBProtocol { return Bar<testModBStruct, Float>() }

tools/libStaticMirror/libStaticMirror.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,13 @@ convertAssociatedTypeQueryResult(
176176
swift_static_mirror_type_alias_s *typeAliasDetails =
177177
new swift_static_mirror_type_alias_s;
178178
typeAliasDetails->type_alias_name = swift::c_string_utils::create_clone(
179-
typeAliasInfo.TypeAliasName.c_str());
179+
typeAliasInfo.SubstitutionInfo.TypeAliasName.c_str());
180180
typeAliasDetails->substituted_type_name =
181181
swift::c_string_utils::create_clone(
182-
typeAliasInfo.SubstitutedTypeFullyQualifiedName.c_str());
182+
typeAliasInfo.SubstitutionInfo.SubstitutedTypeFullyQualifiedName.c_str());
183183
typeAliasDetails->substituted_type_mangled_name =
184184
swift::c_string_utils::create_clone(
185-
typeAliasInfo.SubstitutedTypeMangledName.c_str());
185+
typeAliasInfo.SubstitutionInfo.SubstitutedTypeMangledName.c_str());
186186
info->type_alias_set->type_aliases[typealiasIndex] = typeAliasDetails;
187187
typealiasIndex += 1;
188188
typeAliasDetails->opaque_requirements_set =

0 commit comments

Comments
 (0)