Skip to content

Gather opaque type same-type requirements when scanning associated type infos from a binary #59972

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
Jul 9, 2022
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
7 changes: 5 additions & 2 deletions include/swift-c/StaticMirror/BinaryScan.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
/// SWIFTSTATICMIRROR_VERSION_MINOR should increase when there are API additions.
/// SWIFTSTATICMIRROR_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
#define SWIFTSTATICMIRROR_VERSION_MAJOR 0
#define SWIFTSTATICMIRROR_VERSION_MINOR 4 // Added opaque associated type's protocol requirements
#define SWIFTSTATICMIRROR_VERSION_MINOR 5 // Added opaque associated type's same-type requirements

SWIFTSTATICMIRROR_BEGIN_DECLS

Expand Down Expand Up @@ -116,7 +116,10 @@ SWIFTSTATICMIRROR_PUBLIC swift_static_mirror_string_ref_t
swift_static_mirror_type_alias_get_substituted_type_mangled_name(
swift_static_mirror_type_alias_t);
SWIFTSTATICMIRROR_PUBLIC swiftscan_string_set_t *
swift_static_mirror_type_alias_get_opaque_type_requirements(
swift_static_mirror_type_alias_get_opaque_type_protocol_requirements(
swift_static_mirror_type_alias_t);
SWIFTSTATICMIRROR_PUBLIC swift_static_mirror_type_alias_set_t *
swift_static_mirror_type_alias_get_opaque_type_same_type_requirements(
swift_static_mirror_type_alias_t);

// swift_static_mirror_associated_type_info query methods
Expand Down
12 changes: 12 additions & 0 deletions include/swift/ABI/GenericContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ class TargetGenericRequirementDescriptor {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Protocol);
}

/// Retreive the offset to the Type field
constexpr inline auto
getSameTypeNameOffset() const -> typename Runtime::StoredSize {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Type);
}

/// Retreive the offset to the Type field
constexpr inline auto
getParamOffset() const -> typename Runtime::StoredSize {
return offsetof(typename std::remove_reference<decltype(*this)>::type, Param);
}

/// Retrieve the right-hand type for a SameType or BaseClass requirement.
llvm::StringRef getMangledTypeName() const {
assert(getKind() == GenericRequirementKind::SameType ||
Expand Down
118 changes: 91 additions & 27 deletions include/swift/Reflection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,12 +312,17 @@ struct ConformanceCollectionResult {
std::vector<std::string> Errors;
};

struct AssociatedType {
struct TypeAliasInfo {
std::string TypeAliasName;
std::string SubstitutedTypeMangledName;
std::string SubstitutedTypeFullyQualifiedName;
std::string SubstitutedTypeDiagnosticPrintName;
};

struct AssociatedType {
TypeAliasInfo SubstitutionInfo;
std::vector<std::string> OpaqueTypeProtocolConformanceRequirements;
std::vector<TypeAliasInfo> OpaqueTypeSameTypeRequirements;
};

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

// If the substituted type is an opaque type, also gather info
// about which protocols it is required to conform to
std::vector<std::string> OpaqueTypeConformanceRequirements;
gatherConformanceRequirementsIfOpaque<ObjCInteropKind, PointerSize>(
substitutedDemangleTree, OpaqueTypeConformanceRequirements);
// about which protocols it is required to conform to and the corresponding
// same-type requirements
std::vector<std::string> opaqueTypeConformanceRequirements;
std::vector<TypeAliasInfo> sameTypeRequirements;
gatherOpaqueTypeRequirements<ObjCInteropKind, PointerSize>(
substitutedDemangleTree, opaqueTypeConformanceRequirements,
sameTypeRequirements);

auto substitutedTypeName = nodeToString(substitutedDemangleTree);
std::stringstream OS;
dumpTypeRef(substitutedTypeRef, OS);
associatedTypes.emplace_back(
AssociatedType{typealiasTypeName, mangledSubstitutedTypeName,
substitutedTypeName, OS.str(),
OpaqueTypeConformanceRequirements});
associatedTypes.emplace_back(AssociatedType{
TypeAliasInfo{typealiasTypeName, mangledSubstitutedTypeName,
substitutedTypeName, OS.str()},
opaqueTypeConformanceRequirements, sameTypeRequirements});
}
result.AssociatedTypeInfos.emplace_back(AssociatedTypeInfo{
mangledTypeName, typeName, protocolName, associatedTypes});
Expand All @@ -1193,9 +1201,10 @@ class TypeRefBuilder {

template <template <typename Runtime> class ObjCInteropKind,
unsigned PointerSize>
void gatherConformanceRequirementsIfOpaque(
void gatherOpaqueTypeRequirements(
Demangle::Node *substitutedTypeDemangleTree,
std::vector<std::string> &OpaqueTypeConformanceRequirements) {
std::vector<std::string> &opaqueTypeConformanceRequirements,
std::vector<TypeAliasInfo> &sameTypeRequirements) {
// With unresolved opaque symbolic references, the demangle tree we
// extract the opaque type descriptor's address from is of the form:
// kind=Type
Expand All @@ -1209,9 +1218,10 @@ class TypeRefBuilder {
auto opaqueTypeChildDemangleTree = childDemangleTree->getFirstChild();
if (opaqueTypeChildDemangleTree->getKind() ==
Node::Kind::OpaqueTypeDescriptorSymbolicReference) {
OpaqueTypeConformanceRequirements =
collectOpaqueTypeConformanceNames<ObjCInteropKind, PointerSize>(
opaqueTypeChildDemangleTree->getIndex());
extractOpaqueTypeProtocolRequirements<ObjCInteropKind, PointerSize>(
opaqueTypeChildDemangleTree->getIndex(),
opaqueTypeConformanceRequirements,
sameTypeRequirements);
}
}
}
Expand Down Expand Up @@ -1628,41 +1638,71 @@ class TypeRefBuilder {
stream << "- " << info.FullyQualifiedName << " : "
<< info.ProtocolFullyQualifiedName << "\n";
for (const auto &typeAlias : info.AssociatedTypes) {
stream << "typealias " << typeAlias.TypeAliasName << " = "
<< typeAlias.SubstitutedTypeFullyQualifiedName << "\n";
stream << typeAlias.SubstitutedTypeDiagnosticPrintName;
stream << "typealias " << typeAlias.SubstitutionInfo.TypeAliasName << " = "
<< typeAlias.SubstitutionInfo.SubstitutedTypeFullyQualifiedName << "\n";
stream << typeAlias.SubstitutionInfo.SubstitutedTypeDiagnosticPrintName;
if (!typeAlias.OpaqueTypeProtocolConformanceRequirements.empty()) {
stream << "opaque type conformance requirements: \n";
stream << "-------------------------\n";
stream << "conformance requirements: \n";
for (const auto &protocolName :
typeAlias.OpaqueTypeProtocolConformanceRequirements) {
stream << protocolName << "\n";
}
}
if (!typeAlias.OpaqueTypeSameTypeRequirements.empty()) {
stream << "-----------------------\n";
stream << "same-type requirements: \n";
for (const auto &sameTypeRequirementInfo :
typeAlias.OpaqueTypeSameTypeRequirements) {
stream << sameTypeRequirementInfo.TypeAliasName << " = "
<< sameTypeRequirementInfo.SubstitutedTypeMangledName << " ("
<< sameTypeRequirementInfo.SubstitutedTypeFullyQualifiedName
<< ")\n";
}
}
}
stream << "\n";
}
}

template <template <typename Runtime> class ObjCInteropKind,
unsigned PointerSize>
std::vector<std::string>
collectOpaqueTypeConformanceNames(uintptr_t opaqueTypeDescriptorAddress) {
std::vector<std::string> result;
void extractOpaqueTypeProtocolRequirements(
uintptr_t opaqueTypeDescriptorAddress,
std::vector<std::string> &protocolRequirements,
std::vector<TypeAliasInfo> &sameTypeRequirements) {
auto opaqueTypeDescriptorBytes = OpaqueByteReader(
remote::RemoteAddress(opaqueTypeDescriptorAddress),
sizeof(ExternalOpaqueTypeDescriptor<ObjCInteropKind, PointerSize>));
if (!opaqueTypeDescriptorBytes.get()) {
return result;
return;
}
const ExternalOpaqueTypeDescriptor<ObjCInteropKind, PointerSize>
*opaqueTypeDescriptor =
(const ExternalOpaqueTypeDescriptor<ObjCInteropKind, PointerSize> *)
opaqueTypeDescriptorBytes.get();

if (!opaqueTypeDescriptor) {
return result;
return;
}

// Given that at a given offset from the opaque type descriptor base there
// is an offset to a TypeRef string, read it.
auto readRequirementTypeRefAddress =
[&](uintptr_t offsetFromOpaqueDescBase,
uintptr_t requirementAddress) -> uint32_t {
std::string typeRefString = "";
auto fieldOffsetOffset = requirementAddress + offsetFromOpaqueDescBase -
(uintptr_t)opaqueTypeDescriptor;
auto fieldOffsetAddress = opaqueTypeDescriptorAddress + fieldOffsetOffset;
auto fieldOffsetBytes = OpaqueByteReader(
remote::RemoteAddress(fieldOffsetAddress), sizeof(uint32_t));
auto fieldOffset = (const int32_t *)fieldOffsetBytes.get();
auto fieldAddress = detail::applyRelativeOffset(
(const char *)fieldOffsetAddress, *fieldOffset);
return fieldAddress;
};

for (const auto &req : opaqueTypeDescriptor->getGenericRequirements()) {
if (req.getKind() == GenericRequirementKind::Protocol) {
// Compute the address of the protocol descriptor offset as:
Expand All @@ -1688,10 +1728,32 @@ class TypeRefBuilder {
auto conformanceRequirementProtocolName =
nameReader.readFullyQualifiedProtocolName(
protocolDescriptorAddress);
result.push_back(*conformanceRequirementProtocolName);
protocolRequirements.push_back(*conformanceRequirementProtocolName);
}
if (req.getKind() == GenericRequirementKind::SameType) {
// Read Param Name
auto paramAddress = readRequirementTypeRefAddress(req.getParamOffset(),
(uintptr_t)(&req));
std::string demangledParamName =
nodeToString(demangleTypeRef(readTypeRef(paramAddress)));

// Read the substituted Type Name
auto typeAddress = readRequirementTypeRefAddress(
req.getSameTypeNameOffset(), (uintptr_t)(&req));
auto typeTypeRef = readTypeRef(typeAddress);
std::string demangledTypeName =
nodeToString(demangleTypeRef(typeTypeRef));
std::string mangledTypeName;
auto typeMangling = Demangle::mangleNode(demangleTypeRef(typeTypeRef));
if (!typeMangling.isSuccess())
mangledTypeName = "";
else
mangledTypeName = typeMangling.result();
sameTypeRequirements.push_back(TypeAliasInfo{
demangledParamName, mangledTypeName, demangledTypeName, ""});
}
}
return result;
return;
}

///
Expand Down Expand Up @@ -1759,8 +1821,10 @@ class TypeRefBuilder {
(const char *)contextDescriptorFieldAddress,
*contextDescriptorOffset);

// Instead of a type descriptor this may just be a reference to an external, check that first
if (auto symbol = OpaqueDynamicSymbolResolver(remote::RemoteAddress(contextTypeDescriptorAddress))) {
// Instead of a type descriptor this may just be a reference to an
// external, check that first
if (auto symbol = OpaqueDynamicSymbolResolver(
remote::RemoteAddress(contextTypeDescriptorAddress))) {
if (!symbol->isResolved()) {
Demangle::Context Ctx;
auto demangledRoot =
Expand Down
3 changes: 2 additions & 1 deletion include/swift/StaticMirror/BinaryScanImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ struct swift_static_mirror_type_alias_s {
swift_static_mirror_string_ref_t type_alias_name;
swift_static_mirror_string_ref_t substituted_type_name;
swift_static_mirror_string_ref_t substituted_type_mangled_name;
swift_static_mirror_string_set_t *opaque_requirements_set;
swift_static_mirror_string_set_t *opaque_protocol_requirements_set;
swift_static_mirror_type_alias_set_t *opaque_same_type_requirements_set;
};

struct swift_static_mirror_associated_type_info_s {
Expand Down
28 changes: 19 additions & 9 deletions test/Reflection/opaque_associated_type_requirements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,40 @@
// RUN: %target-swift-reflection-dump -binary-filename %t/AssociatedTypeRequirements | %FileCheck %s

// CHECK: ASSOCIATED TYPES:
// CHECK-NEXT: =============
// CHECK-NEXT: - AssociatedTypeRequirements.Foo : AssociatedTypeRequirements.myProto
// CHECK: - AssociatedTypeRequirements.Foo : AssociatedTypeRequirements.myProto
// CHECK-NEXT: typealias PerformReturn = opaque type symbolic reference
// CHECK-NEXT: opaque type symbolic reference
// CHECK-NEXT: (struct AssociatedTypeRequirements.Bar)
// CHECK-NEXT: (bound_generic_struct AssociatedTypeRequirements.Bar

// CHECK: opaque type conformance requirements:
// CHECK: conformance requirements:
// CHECK-NEXT: AssociatedTypeRequirements.protoA
// CHECK-NEXT: AssociatedTypeRequirements.protoB
// CHECK-NEXT: testModB.testModBProtocol

// CHECK: same-type requirements:
// CHECK-NEXT: A.AssociatedTypeRequirements.protoB.K = Sf (Swift.Float)
// CHECK-NEXT: A.AssociatedTypeRequirements.protoA.T = 8testModB0aB7BStructV (testModB.testModBStruct)

import testModB

public protocol myProto {
associatedtype PerformReturn
func perform() -> PerformReturn
}
public protocol protoA {}
public protocol protoB {}
public protocol protoA<T> {
associatedtype T
}
public protocol protoB<K> {
associatedtype K
}

public struct Bar : protoA, protoB, testModBProtocol {}
public struct Bar<M, N> : protoA, protoB, testModBProtocol {
public typealias T = M
public typealias K = N
}

public struct Foo : myProto {
public func perform() -> some protoA & protoB & testModBProtocol { return baz() }
public func perform() -> some protoA<testModBStruct> & protoB<Float> & testModBProtocol { return baz() }
}

private func baz() -> some protoA & protoB & testModBProtocol { return Bar() }
private func baz() -> some protoA<testModBStruct> & protoB<Float> & testModBProtocol { return Bar<testModBStruct, Float>() }
51 changes: 43 additions & 8 deletions tools/libStaticMirror/libStaticMirror.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,18 +176,48 @@ convertAssociatedTypeQueryResult(
swift_static_mirror_type_alias_s *typeAliasDetails =
new swift_static_mirror_type_alias_s;
typeAliasDetails->type_alias_name = swift::c_string_utils::create_clone(
typeAliasInfo.TypeAliasName.c_str());
typeAliasInfo.SubstitutionInfo.TypeAliasName.c_str());
typeAliasDetails->substituted_type_name =
swift::c_string_utils::create_clone(
typeAliasInfo.SubstitutedTypeFullyQualifiedName.c_str());
typeAliasInfo.SubstitutionInfo.SubstitutedTypeFullyQualifiedName.c_str());
typeAliasDetails->substituted_type_mangled_name =
swift::c_string_utils::create_clone(
typeAliasInfo.SubstitutedTypeMangledName.c_str());
info->type_alias_set->type_aliases[typealiasIndex] = typeAliasDetails;
typealiasIndex += 1;
typeAliasDetails->opaque_requirements_set =
typeAliasInfo.SubstitutionInfo.SubstitutedTypeMangledName.c_str());

// Opaque type's protocol conformance requirements
typeAliasDetails->opaque_protocol_requirements_set =
swift::c_string_utils::create_set(
typeAliasInfo.OpaqueTypeProtocolConformanceRequirements);

// Opaque type's same-type requirements
typeAliasDetails->opaque_same_type_requirements_set =
new swift_static_mirror_type_alias_set_t;
typeAliasDetails->opaque_same_type_requirements_set->count =
typeAliasInfo.OpaqueTypeSameTypeRequirements.size();
typeAliasDetails->opaque_same_type_requirements_set->type_aliases =
new swift_static_mirror_type_alias_t
[typeAliasInfo.OpaqueTypeSameTypeRequirements.size()];
int sameTypeReqIndex = 0;
for (const auto &sameTypeReq :
typeAliasInfo.OpaqueTypeSameTypeRequirements) {
swift_static_mirror_type_alias_s *sameTypeReqDetails =
new swift_static_mirror_type_alias_s;
sameTypeReqDetails->type_alias_name =
swift::c_string_utils::create_clone(
sameTypeReq.TypeAliasName.c_str());
sameTypeReqDetails->substituted_type_mangled_name =
swift::c_string_utils::create_clone(
sameTypeReq.SubstitutedTypeMangledName.c_str());
sameTypeReqDetails->substituted_type_name =
swift::c_string_utils::create_clone(
sameTypeReq.SubstitutedTypeFullyQualifiedName.c_str());
typeAliasDetails->opaque_same_type_requirements_set
->type_aliases[sameTypeReqIndex] = sameTypeReqDetails;
sameTypeReqIndex += 1;
}

info->type_alias_set->type_aliases[typealiasIndex] = typeAliasDetails;
typealiasIndex += 1;
}
result->associated_type_infos[associatedTypeInfoIndex] = info;
associatedTypeInfoIndex += 1;
Expand Down Expand Up @@ -282,9 +312,14 @@ swift_static_mirror_type_alias_get_substituted_type_mangled_name(
return type_alias->substituted_type_mangled_name;
}
swiftscan_string_set_t *
swift_static_mirror_type_alias_get_opaque_type_requirements(
swift_static_mirror_type_alias_get_opaque_type_protocol_requirements(
swift_static_mirror_type_alias_t type_alias) {
return type_alias->opaque_protocol_requirements_set;
}
swift_static_mirror_type_alias_set_t *
swift_static_mirror_type_alias_get_opaque_type_same_type_requirements(
swift_static_mirror_type_alias_t type_alias) {
return type_alias->opaque_requirements_set;
return type_alias->opaque_same_type_requirements_set;
}

// swift_static_mirror_associated_type_info query methods
Expand Down
3 changes: 2 additions & 1 deletion tools/libStaticMirror/libStaticMirror.exports
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ swift_static_mirror_conformance_info_get_mangled_type_name
swift_static_mirror_type_alias_get_type_alias_name
swift_static_mirror_type_alias_get_substituted_type_name
swift_static_mirror_type_alias_get_substituted_type_mangled_name
swift_static_mirror_type_alias_get_opaque_type_requirements
swift_static_mirror_type_alias_get_opaque_type_protocol_requirements
swift_static_mirror_type_alias_get_opaque_type_same_type_requirements
swift_static_mirror_associated_type_info_get_mangled_type_name
swift_static_mirror_associated_type_info_get_type_alias_set
swift_static_mirror_associated_type_info_set_create
Expand Down