Skip to content

[runtime] Handle same-type constraints when resolving generic params #25984

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, 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
11 changes: 6 additions & 5 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,12 @@ struct TargetContextDescriptor {
? genericContext->getGenericContextHeader().NumParams
: 0;
}

#ifndef NDEBUG
LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
"only for use in the debugger");
#endif

private:
TargetContextDescriptor(const TargetContextDescriptor &) = delete;
TargetContextDescriptor(TargetContextDescriptor &&) = delete;
Expand Down Expand Up @@ -3649,11 +3655,6 @@ class TargetTypeContextDescriptor
return cd->getKind() >= ContextDescriptorKind::Type_First
&& cd->getKind() <= ContextDescriptorKind::Type_Last;
}

#ifndef NDEBUG
LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
"Only meant for use in the debugger");
#endif
};

using TypeContextDescriptor = TargetTypeContextDescriptor<InProcess>;
Expand Down
25 changes: 19 additions & 6 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3945,20 +3945,33 @@ void Metadata::dump() const {
printf("TargetMetadata.\n");
printf("Kind: %s.\n", getStringForMetadataKind(getKind()).data());
printf("Value Witnesses: %p.\n", getValueWitnesses());
printf("Class Object: %p.\n", getClassObject());
printf("Type Context Description: %p.\n", getTypeContextDescriptor());

auto *contextDescriptor = getTypeContextDescriptor();
printf("Name: %s.\n", contextDescriptor->Name.get());
printf("Type Context Description: %p.\n", contextDescriptor);
printf("Generic Args: %p.\n", getGenericArgs());

#if SWIFT_OBJC_INTEROP
if (auto *classObject = getClassObject()) {
printf("ObjC Name: %s.\n", class_getName(
reinterpret_cast<Class>(const_cast<ClassMetadata *>(classObject))));
printf("Class Object: %p.\n", classObject);
}
#endif
}

template <>
LLVM_ATTRIBUTE_USED
void TypeContextDescriptor::dump() const {
void ContextDescriptor::dump() const {
printf("TargetTypeContextDescriptor.\n");
printf("Flags: 0x%x.\n", this->Flags.getIntValue());
printf("Parent: %p.\n", this->Parent.get());
printf("Name: %s.\n", Name.get());
printf("Access function: %p.\n", static_cast<void *>(getAccessFunction()));
printf("Fields: %p.\n", Fields.get());
if (auto *typeDescriptor = dyn_cast<TypeContextDescriptor>(this)) {
printf("Name: %s.\n", typeDescriptor->Name.get());
printf("Fields: %p.\n", typeDescriptor->Fields.get());
printf("Access function: %p.\n",
static_cast<void *>(typeDescriptor->getAccessFunction()));
}
}

template<>
Expand Down
61 changes: 42 additions & 19 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,17 @@ _findContextDescriptor(Demangle::NodePointer node,
Demangle::Demangler &Dem);

/// Find the context descriptor for the type extended by the given extension.
///
/// If \p maybeExtension isn't actually an extension context, returns nullptr.
static const ContextDescriptor *
_findExtendedTypeContextDescriptor(const ExtensionContextDescriptor *extension,
_findExtendedTypeContextDescriptor(const ContextDescriptor *maybeExtension,
Demangler &demangler,
Demangle::NodePointer *demangledNode
= nullptr) {
auto extension = dyn_cast<ExtensionContextDescriptor>(maybeExtension);
if (!extension)
return nullptr;

Demangle::NodePointer localNode;
Demangle::NodePointer &node = demangledNode ? *demangledNode : localNode;

Expand Down Expand Up @@ -844,28 +850,26 @@ bool swift::_gatherGenericParameterCounts(
DemanglerForRuntimeTypeResolution<> demangler;
demangler.providePreallocatedMemory(BorrowFrom);

if (auto extension = dyn_cast<ExtensionContextDescriptor>(descriptor)) {
// If we have an nominal type extension descriptor, extract the extended type
if (auto extension = _findExtendedTypeContextDescriptor(descriptor,
demangler)) {
// If we have a nominal type extension descriptor, extract the extended type
// and use that. If the extension is not nominal, then we can use the
// extension's own signature.
if (auto extendedType =
_findExtendedTypeContextDescriptor(extension, demangler)) {
descriptor = extendedType;
}
descriptor = extension;
}

// Once we hit a non-generic descriptor, we're done.
if (!descriptor->isGeneric()) return false;

// Recurse to record the parent context's generic parameters.
if (auto parent = descriptor->Parent.get())
(void)_gatherGenericParameterCounts(parent, genericParamCounts, demangler);
auto parent = descriptor->Parent.get();
(void)_gatherGenericParameterCounts(parent, genericParamCounts, demangler);

// Record a new level of generic parameters if the count exceeds the
// previous count.
auto myCount =
descriptor->getGenericContext()->getGenericContextHeader().NumParams;
if (genericParamCounts.empty() || myCount > genericParamCounts.back()) {
unsigned parentCount = parent->getNumGenericParams();
unsigned myCount = descriptor->getNumGenericParams();
if (myCount > parentCount) {
genericParamCounts.push_back(myCount);
return true;
}
Expand Down Expand Up @@ -1658,32 +1662,50 @@ static void installGetClassHook() {
#endif

unsigned SubstGenericParametersFromMetadata::
buildDescriptorPath(const ContextDescriptor *context) const {
buildDescriptorPath(const ContextDescriptor *context,
Demangler &borrowFrom) const {
assert(sourceIsMetadata);

// Terminating condition: we don't have a context.
if (!context)
return 0;

DemanglerForRuntimeTypeResolution<> demangler;
demangler.providePreallocatedMemory(borrowFrom);

if (auto extension = _findExtendedTypeContextDescriptor(context, demangler)) {
// If we have a nominal type extension descriptor, extract the extended type
// and use that. If the extension is not nominal, then we can use the
// extension's own signature.
context = extension;
}

// Add the parent's contribution to the descriptor path.
unsigned numKeyGenericParamsInParent =
buildDescriptorPath(context->Parent.get());
const ContextDescriptor *parent = context->Parent.get();
unsigned numKeyGenericParamsInParent = buildDescriptorPath(parent, demangler);

// If this context is non-generic, we're done.
if (!context->isGeneric())
return numKeyGenericParamsInParent;

// Count the number of key generic params at this level.
auto allGenericParams = baseContext->getGenericContext()->getGenericParams();
unsigned parentCount = parent->getNumGenericParams();
unsigned localCount = context->getNumGenericParams();
auto localGenericParams = allGenericParams.slice(parentCount,
localCount - parentCount);

unsigned numKeyGenericParamsHere = 0;
bool hasNonKeyGenericParams = false;
auto localGenericParams = getLocalGenericParams(context);
for (const auto &genericParam : localGenericParams) {
if (genericParam.hasKeyArgument())
++numKeyGenericParamsHere;
else
hasNonKeyGenericParams = true;
}

// Form the path element if there are any generic parameters to be found.
if (numKeyGenericParamsHere != 0)
// Form the path element if there are any new generic parameters.
if (localCount > parentCount)
descriptorPath.push_back(PathElement{localGenericParams,
context->getNumGenericParams(),
numKeyGenericParamsInParent,
Expand Down Expand Up @@ -1738,7 +1760,8 @@ void SubstGenericParametersFromMetadata::setup() const {
return;

if (sourceIsMetadata && baseContext) {
numKeyGenericParameters = buildDescriptorPath(baseContext);
DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler;
numKeyGenericParameters = buildDescriptorPath(baseContext, demangler);
return;
}

Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ class TypeInfo {
///
/// \returns a pair containing the number of key generic parameters in
/// the path up to this point.
unsigned buildDescriptorPath(const ContextDescriptor *context) const;
unsigned buildDescriptorPath(const ContextDescriptor *context,
Demangler &demangler) const;

/// Builds a path from the generic environment.
unsigned buildEnvironmentPath(
Expand Down
19 changes: 12 additions & 7 deletions test/IRGen/nested_generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ protocol HasAssoc {
associatedtype Assoc
}

class SeparateGenericSuperclass<T> {}

enum Container<T : TagProtocol> {
class _Superclass {}
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO9_SubclassCMn" =
Expand All @@ -127,27 +129,30 @@ enum Container<T : TagProtocol> {
// CHECK-CONSTANTS-SAME: @"symbolic _____yx_G 15nested_generics9ContainerO11_SuperclassC"
class _Subclass2<U: Collection>: _Superclass where T == U.Element {}


// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO10_Subclass3CMn" =
// FIXME: That "qd__" still causes problems: it's (depth: 1, index: 0), but
// the runtime doesn't count the parameters at depth 0 correctly.
// CHECK-CONSTANTS-SAME: @"symbolic _____y______qd__G 15nested_generics9ContainerO18_GenericSuperclassC AA5OuterO"
class _GenericSuperclass<U> {}
class _Subclass3<U>: _GenericSuperclass<U> where T == Outer {}

class MoreNesting {
// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO11MoreNestingC9_SubclassCMn" =
// CHECK-CONSTANTS-SAME: @"symbolic _____y______G 15nested_generics9ContainerO11_SuperclassC AA5OuterO"
class _Subclass<U>: _Superclass where T == Outer {}
}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO24_SeparateGenericSubclassCMn" =
// CHECK-CONSTANTS-SAME: @"symbolic _____yxSgG 15nested_generics25SeparateGenericSuperclassC"
class _SeparateGenericSubclass: SeparateGenericSuperclass<T?> {}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO6FieldsVMF" =
// CHECK-CONSTANTS-SAME: @"symbolic _____ 15nested_generics5OuterO"
// FIXME: This still causes problems: it's (depth: 1, index: 0), but
// the runtime doesn't count the parameters at depth 0 correctly.
// CHECK-CONSTANTS-SAME: @"symbolic qd__"
struct Fields<U> where T == Outer {
var x: T
var y: U
}

// CHECK-CONSTANTS-LABEL: @"$s15nested_generics9ContainerO5CasesOMF" =
// FIXME: This still causes problems: it's (depth: 1, index: 0), but
// the runtime doesn't count the parameters at depth 0 correctly.
// CHECK-CONSTANTS-SAME: @"symbolic qd__"
enum Cases<U> where T == Outer {
case a(T)
Expand Down
Loading