Skip to content

5.9 [RemoteMirror] Fix handling of generic and zero-sized cases in MPEs #65525

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
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
20 changes: 7 additions & 13 deletions include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2959,19 +2959,13 @@ class MetadataReader {
// Only consider generic contexts of type class, enum or struct.
// There are other context types that can be generic, but they should
// not affect the generic shape.
if (current->getKind() == ContextDescriptorKind::Class ||
current->getKind() == ContextDescriptorKind::Enum ||
current->getKind() == ContextDescriptorKind::Struct) {
if (genericContext) {
auto contextHeader = genericContext->getGenericContextHeader();
paramsPerLevel.emplace_back(contextHeader.NumParams -
runningCount);
runningCount += paramsPerLevel.back();
} else {
// If there is no generic context, this is a non-generic type
// which has 0 generic parameters.
paramsPerLevel.emplace_back(0);
}
if (genericContext &&
(current->getKind() == ContextDescriptorKind::Class ||
current->getKind() == ContextDescriptorKind::Enum ||
current->getKind() == ContextDescriptorKind::Struct)) {
auto contextHeader = genericContext->getGenericContextHeader();
paramsPerLevel.emplace_back(contextHeader.NumParams - runningCount);
runningCount += paramsPerLevel.back();
}
};
countLevels(descriptor, runningCount);
Expand Down
4 changes: 4 additions & 0 deletions include/swift/RemoteInspection/TypeRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ class alignas(8) TypeRef {
const TypeRef *subst(TypeRefBuilder &Builder,
const GenericArgumentMap &Subs) const;

const TypeRef *subst(TypeRefBuilder &Builder,
const GenericArgumentMap &Subs,
bool &DidSubstitute) const;

llvm::Optional<GenericArgumentMap> getSubstMap() const;

virtual ~TypeRef() = default;
Expand Down
179 changes: 109 additions & 70 deletions include/swift/RemoteInspection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,21 +288,18 @@ struct FieldTypeInfo {
int Value;
const TypeRef *TR;
bool Indirect;
bool Generic;

FieldTypeInfo() : Name(""), Value(0), TR(nullptr), Indirect(false) {}
FieldTypeInfo(const std::string &Name, int Value, const TypeRef *TR, bool Indirect)
: Name(Name), Value(Value), TR(TR), Indirect(Indirect) {}
FieldTypeInfo() : Name(""), Value(0), TR(nullptr), Indirect(false), Generic(false) {}
FieldTypeInfo(const std::string &Name, int Value, const TypeRef *TR, bool Indirect, bool Generic)
: Name(Name), Value(Value), TR(TR), Indirect(Indirect), Generic(Generic) {}

static FieldTypeInfo forEmptyCase(std::string Name, int Value) {
return FieldTypeInfo(Name, Value, nullptr, false);
}

static FieldTypeInfo forIndirectCase(std::string Name, int Value, const TypeRef *TR) {
return FieldTypeInfo(Name, Value, TR, true);
return FieldTypeInfo(Name, Value, nullptr, false, false);
}

static FieldTypeInfo forField(std::string Name, int Value, const TypeRef *TR) {
return FieldTypeInfo(Name, Value, TR, false);
return FieldTypeInfo(Name, Value, TR, false, false);
}
};

Expand Down Expand Up @@ -567,65 +564,66 @@ class TypeRefBuilder {
return nullptr;
}

const BoundGenericTypeRef *createBoundGenericTypeReconstructingParent(
const NodePointer node, const TypeRefDecl &decl, size_t shapeIndex,
const llvm::ArrayRef<const TypeRef *> &args, size_t argsIndex) {
if (!node || !node->hasChildren())
return nullptr;

auto maybeGenericParamsPerLevel = decl.genericParamsPerLevel;
if (!maybeGenericParamsPerLevel)
return nullptr;

auto genericParamsPerLevel = *maybeGenericParamsPerLevel;

auto kind = node->getKind();
// Kinds who have a "BoundGeneric..." variant.
if (kind != Node::Kind::Class && kind != Node::Kind::Structure &&
kind != Node::Kind::Enum)
return nullptr;
auto mangling = Demangle::mangleNode(node);
if (!mangling.isSuccess())
return nullptr;

if (shapeIndex >= genericParamsPerLevel.size())
return nullptr;

auto numGenericArgs = genericParamsPerLevel[shapeIndex];

auto startOffsetFromEnd = argsIndex + numGenericArgs;
auto endOffsetFromEnd = argsIndex;
if (startOffsetFromEnd > args.size() || endOffsetFromEnd > args.size())
return nullptr;

std::vector<const TypeRef *> genericParams(
args.end() - startOffsetFromEnd, args.end() - endOffsetFromEnd);

const BoundGenericTypeRef *parent = nullptr;
if (node->hasChildren()) {
// Skip over nodes that are not of type class, enum or struct
auto parentNode = node->getFirstChild();
while (parentNode->getKind() != Node::Kind::Class &&
parentNode->getKind() != Node::Kind::Structure &&
parentNode->getKind() != Node::Kind::Enum) {
if (parentNode->hasChildren()) {
parentNode = parentNode->getFirstChild();
} else {
parentNode = nullptr;
break;
}
// Construct a bound generic type ref along with the parent type info
// The parent list contains every parent type with at least 1 generic
// type parameter.
const BoundGenericTypeRef *reconstructParentsOfBoundGenericType(
const NodePointer startNode,
const std::vector<size_t> &genericParamsPerLevel,
const llvm::ArrayRef<const TypeRef *> &args)
{
// Collect the first N parents that potentially have generic args
// (Ignore the last genericParamPerLevel, which
// applies to the startNode itself.)
std::vector<NodePointer> nodes;
NodePointer node = startNode;
while (nodes.size() < genericParamsPerLevel.size() - 1) {
if (!node || !node->hasChildren()) {
return nullptr;
}
if (parentNode) {
if (shapeIndex > 0)
parent = createBoundGenericTypeReconstructingParent(
parentNode, decl, --shapeIndex, args, argsIndex + numGenericArgs);
else
return nullptr;
node = node->getFirstChild();
switch (node->getKind()) {
case Node::Kind::Class:
case Node::Kind::Structure:
case Node::Kind::Enum:
nodes.push_back(node);
break;
default:
break;
}
}
assert(nodes.size() == genericParamsPerLevel.size() - 1);

// We're now going to build the type tree from the
// outermost parent in, which matches the order of
// the generic parameter list and genericParamsPerLevel.
std::reverse(nodes.begin(), nodes.end());

// Walk the list of parent types together with
// the generic argument list...
const BoundGenericTypeRef *typeref = nullptr;
auto argBegin = args.begin();
for (size_t i = 0; i < nodes.size(); i++) {
// Get the mangling for this node
auto mangling = Demangle::mangleNode(nodes[i]);
if (!mangling.isSuccess()) {
return nullptr;
}

return BoundGenericTypeRef::create(*this, mangling.result(), genericParams,
parent);
// Use the next N params for this node
auto numGenericArgs = genericParamsPerLevel[i];
// Skip nodes that don't have any actual type params.
if (numGenericArgs == 0) {
continue;
}
auto argEnd = argBegin + numGenericArgs;
std::vector<const TypeRef *> params(argBegin, argEnd);
argBegin = argEnd;

// Extend the typeref list towards the innermost type
typeref = BoundGenericTypeRef::create(*this, mangling.result(), params, typeref);
}
return typeref;
}

const BoundGenericTypeRef *
Expand All @@ -634,17 +632,58 @@ class TypeRefBuilder {
if (!builtTypeDecl)
return nullptr;

if (!builtTypeDecl->genericParamsPerLevel)
// If there aren't generic params on the parent types, we just emit
// a single BG typeref with all the generic args
auto maybeGenericParamsPerLevel = builtTypeDecl->genericParamsPerLevel;
if (!maybeGenericParamsPerLevel) {
return BoundGenericTypeRef::create(*this, builtTypeDecl->mangledName, args, nullptr);
}


// Otherwise, work from a full demangle tree to produce a
// typeref that includes information about parent generic args
auto node = Dem.demangleType(builtTypeDecl->mangledName);
if (!node || !node->hasChildren() || node->getKind() != Node::Kind::Type)
if (!node || !node->hasChildren() || node->getKind() != Node::Kind::Type) {
return nullptr;
}
auto startNode = node->getFirstChild();
auto mangling = Demangle::mangleNode(startNode);
if (!mangling.isSuccess()) {
return nullptr;
}

// Sanity: Verify that the generic params per level add
// up exactly to the number of args we were provided, and
// that we don't have a rediculous number of either one
auto genericParamsPerLevel = *maybeGenericParamsPerLevel;
if (genericParamsPerLevel.size() > 1000 || args.size() > 1000) {
return nullptr;
}
size_t totalParams = 0;
for (size_t i = 0; i < genericParamsPerLevel.size(); i++) {
if (genericParamsPerLevel[i] > args.size()) {
return nullptr;
}
totalParams += genericParamsPerLevel[i];
}
if (totalParams != args.size()) {
return nullptr;
}

auto type = node->getFirstChild();
return createBoundGenericTypeReconstructingParent(
type, *builtTypeDecl, builtTypeDecl->genericParamsPerLevel->size() - 1, args, 0);
// Reconstruct all parents that have non-zero generic params
auto parents = reconstructParentsOfBoundGenericType(startNode, genericParamsPerLevel, args);

// Collect the final set of generic params for the
// innermost type. Note: This will sometimes be empty:
// consider `Foo<Int, String>.Bar.Baz<Double>.Quux`
// which has 2 parents in the parent list
// (`Foo<Int,String>`, `Baz<Double>`), and the
// startNode is `Quux` with no params.
auto numGenericArgs = genericParamsPerLevel[genericParamsPerLevel.size() - 1];
auto argBegin = args.end() - numGenericArgs;
std::vector<const TypeRef *> params(argBegin, args.end());

// Build and return the top typeref
return BoundGenericTypeRef::create(*this, mangling.result(), params, parents);
}

const BoundGenericTypeRef *
Expand Down
Loading