Skip to content

Runtime demangler support for pack expansions #67124

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
20 changes: 17 additions & 3 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,20 @@ class ASTBuilder {
/// is a pack or not, so we have to find it here.
GenericSignature GenericSig;

/// This builder doesn't perform "on the fly" substitutions, so we preserve
/// all pack expansions. We still need an active expansion stack though,
/// for the dummy implementation of these methods:
/// - beginPackExpansion()
/// - advancePackExpansion()
/// - createExpandedPackElement()
/// - endPackExpansion()
llvm::SmallVector<Type> ActivePackExpansions;

public:
using BuiltType = swift::Type;
using BuiltTypeDecl = swift::GenericTypeDecl *; // nominal or type alias
using BuiltProtocolDecl = swift::ProtocolDecl *;
using BuiltGenericSignature = swift::GenericSignature;
using BuiltGenericTypeParam = swift::GenericTypeParamType *;
using BuiltRequirement = swift::Requirement;
using BuiltSubstitutionMap = swift::SubstitutionMap;

Expand Down Expand Up @@ -110,13 +118,19 @@ class ASTBuilder {
Type createBoundGenericType(GenericTypeDecl *decl, ArrayRef<Type> args,
Type parent);

Type createTupleType(ArrayRef<Type> eltTypes, StringRef labels);
Type createTupleType(ArrayRef<Type> eltTypes, ArrayRef<StringRef> labels);

Type createPackType(ArrayRef<Type> eltTypes);

Type createSILPackType(ArrayRef<Type> eltTypes, bool isElementAddress);

Type createPackExpansionType(Type patternType, Type countType);
size_t beginPackExpansion(Type countType);

void advancePackExpansion(size_t index);

Type createExpandedPackElement(Type patternType);

void endPackExpansion();

Type createFunctionType(
ArrayRef<Demangle::FunctionParam<Type>> params,
Expand Down
186 changes: 116 additions & 70 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,6 @@ class TypeDecoder {
using BuiltSubstitution = typename BuilderType::BuiltSubstitution;
using BuiltRequirement = typename BuilderType::BuiltRequirement;
using BuiltLayoutConstraint = typename BuilderType::BuiltLayoutConstraint;
using BuiltGenericTypeParam = typename BuilderType::BuiltGenericTypeParam;
using BuiltGenericSignature = typename BuilderType::BuiltGenericSignature;
using BuiltSubstitutionMap = typename BuilderType::BuiltSubstitutionMap;
using NodeKind = Demangle::Node::Kind;
Expand Down Expand Up @@ -886,10 +885,11 @@ class TypeDecoder {

bool hasParamFlags = false;
llvm::SmallVector<FunctionParam<BuiltType>, 8> parameters;
if (!decodeMangledFunctionInputType(Node->getChild(firstChildIdx),
depth + 1, parameters, hasParamFlags))
return MAKE_NODE_TYPE_ERROR0(Node->getChild(firstChildIdx),
"failed to decode function type");
auto optError = decodeMangledFunctionInputType(Node->getChild(firstChildIdx),
depth + 1, parameters, hasParamFlags);
if (optError)
return *optError;

flags =
flags.withNumParameters(parameters.size())
.withParameterFlags(hasParamFlags)
Expand Down Expand Up @@ -1022,7 +1022,8 @@ class TypeDecoder {

case NodeKind::Tuple: {
llvm::SmallVector<BuiltType, 8> elements;
std::string labels;
llvm::SmallVector<StringRef, 8> labels;

for (auto &element : *Node) {
if (element->getKind() != NodeKind::TupleElement)
return MAKE_NODE_TYPE_ERROR0(Node, "unexpected kind");
Expand All @@ -1033,31 +1034,32 @@ class TypeDecoder {
return MAKE_NODE_TYPE_ERROR0(element->getChild(typeChildIndex),
"no children");
}
if (element->getChild(typeChildIndex)->getKind() == NodeKind::TupleElementName) {
// Add spaces to terminate all the previous labels if this
// is the first we've seen.
if (labels.empty()) labels.append(elements.size(), ' ');

// Add the label and its terminator.
labels += element->getChild(typeChildIndex)->getText();
labels += ' ';
StringRef label;
if (element->getChild(typeChildIndex)->getKind() == NodeKind::TupleElementName) {
label = element->getChild(typeChildIndex)->getText();
typeChildIndex++;

// Otherwise, add a space if a previous element had a label.
} else if (!labels.empty()) {
labels += ' ';
}

// Decode the element type.
auto elementType =
decodeMangledType(element->getChild(typeChildIndex), depth + 1,
/*forRequirement=*/false);
if (elementType.isError())
return elementType;

elements.push_back(elementType.getType());
auto optError = decodeTypeSequenceElement(
element->getChild(typeChildIndex), depth + 1,
[&](BuiltType type) {
elements.push_back(type);
labels.push_back(label);
});
if (optError)
return *optError;
}
return Builder.createTupleType(elements, std::move(labels));

// Unwrap one-element tuples.
//
// FIXME: The behavior of one-element labeled tuples is inconsistent throughout
// the different re-implementations of type substitution and pack expansion.
// if (elements.size() == 1)
// return elements[0];

return Builder.createTupleType(elements, labels);
}
case NodeKind::TupleElement:
if (Node->getNumChildren() < 1)
Expand All @@ -1082,12 +1084,13 @@ class TypeDecoder {

for (auto &element : *Node) {
// Decode the element type.
auto elementType =
decodeMangledType(element, depth + 1, /*forRequirement=*/false);
if (elementType.isError())
return elementType;

elements.push_back(elementType.getType());
auto optError = decodeTypeSequenceElement(
element, depth + 1,
[&](BuiltType elementType) {
elements.push_back(elementType);
});
if (optError)
return *optError;
}

switch (Node->getKind()) {
Expand All @@ -1103,16 +1106,8 @@ class TypeDecoder {
}

case NodeKind::PackExpansion: {
if (Node->getNumChildren() < 2)
return MAKE_NODE_TYPE_ERROR(Node,
"fewer children (%zu) than required (2)",
Node->getNumChildren());

auto patternType = decodeMangledType(Node->getChild(0), depth + 1);
auto countType = decodeMangledType(Node->getChild(1), depth + 1);

return Builder.createPackExpansionType(patternType.getType(),
countType.getType());
return MAKE_NODE_TYPE_ERROR0(Node,
"pack expansion type in unsupported position");
}

case NodeKind::DependentGenericType: {
Expand Down Expand Up @@ -1264,9 +1259,9 @@ return {}; // Not Implemented!
/*forRequirement=*/false);
if (substTy.isError())
return substTy;
substitutions.emplace_back(
Builder.createGenericTypeParameterType(paramDepth, index),
substTy.getType());
auto paramTy = Builder.createGenericTypeParameterType(
paramDepth, index);
substitutions.emplace_back(paramTy, substTy.getType());
++index;
}
}
Expand Down Expand Up @@ -1369,6 +1364,58 @@ return {}; // Not Implemented!
}

private:
template<typename Fn>
llvm::Optional<TypeLookupError>
decodeTypeSequenceElement(Demangle::NodePointer node, unsigned depth,
Fn resultCallback) {
if (node->getKind() == NodeKind::Type)
node = node->getChild(0);

if (node->getKind() == NodeKind::PackExpansion) {
if (node->getNumChildren() < 2)
return MAKE_NODE_TYPE_ERROR(node,
"fewer children (%zu) than required (2)",
node->getNumChildren());

auto patternType = node->getChild(0);

// Decode the shape pack first, to form a metadata pack.
auto countType = decodeMangledType(node->getChild(1), depth);
if (countType.isError())
return *countType.getError();

// Push the pack expansion on the active expansion stack inside the
// builder concept.
size_t numElements = Builder.beginPackExpansion(countType.getType());

for (size_t i = 0; i < numElements; ++i) {
// Advance the lane index inside the builder concept.
Builder.advancePackExpansion(i);

// Decode the pattern type, taking the ith element of each pack
// referenced therein.
auto expandedElementType = decodeMangledType(patternType, depth);
if (expandedElementType.isError())
return *expandedElementType.getError();

resultCallback(Builder.createExpandedPackElement(
expandedElementType.getType()));
}

// Pop the active expansion stack inside the builder concept.
Builder.endPackExpansion();
} else {
auto elementType =
decodeMangledType(node, depth, /*forRequirement=*/false);
if (elementType.isError())
return *elementType.getError();

resultCallback(elementType.getType());
}

return llvm::None;
}

template <typename T>
bool decodeImplFunctionPart(Demangle::NodePointer node, unsigned depth,
llvm::SmallVectorImpl<T> &results) {
Expand Down Expand Up @@ -1532,12 +1579,12 @@ return {}; // Not Implemented!
return Builder.createProtocolDecl(node);
}

bool decodeMangledFunctionInputType(
llvm::Optional<TypeLookupError> decodeMangledFunctionInputType(
Demangle::NodePointer node, unsigned depth,
llvm::SmallVectorImpl<FunctionParam<BuiltType>> &params,
bool &hasParamFlags) {
if (depth > TypeDecoder::MaxDepth)
return false;
return llvm::None;

// Look through a couple of sugar nodes.
if (node->getKind() == NodeKind::Type ||
Expand All @@ -1548,7 +1595,7 @@ return {}; // Not Implemented!

auto decodeParamTypeAndFlags =
[&](Demangle::NodePointer typeNode,
FunctionParam<BuiltType> &param) -> bool {
FunctionParam<BuiltType> &param) -> llvm::Optional<TypeLookupError> {
Demangle::NodePointer node = typeNode;

bool recurse = true;
Expand Down Expand Up @@ -1597,17 +1644,15 @@ return {}; // Not Implemented!
}
}

auto paramType = decodeMangledType(node, depth + 1,
/*forRequirement=*/false);
if (paramType.isError())
return false;

param.setType(paramType.getType());
return true;
return decodeTypeSequenceElement(node, depth + 1,
[&](BuiltType paramType) {
param.setType(paramType);
params.push_back(param);
});
};

auto decodeParam =
[&](NodePointer paramNode) -> llvm::Optional<FunctionParam<BuiltType>> {
[&](NodePointer paramNode) -> llvm::Optional<TypeLookupError> {
if (paramNode->getKind() != NodeKind::TupleElement)
return llvm::None;

Expand All @@ -1623,40 +1668,41 @@ return {}; // Not Implemented!
hasParamFlags = true;
break;

case NodeKind::Type:
if (!decodeParamTypeAndFlags(child->getFirstChild(), param))
return llvm::None;
case NodeKind::Type: {
auto optError = decodeParamTypeAndFlags(
child->getFirstChild(), param);
if (optError)
return optError;
break;
}

default:
return llvm::None;
return TYPE_LOOKUP_ERROR_FMT("unknown node");
}
}

return param;
return llvm::None;
};

// Expand a single level of tuple.
if (node->getKind() == NodeKind::Tuple) {
// Decode all the elements as separate arguments.
for (const auto &elt : *node) {
auto param = decodeParam(elt);
if (!param)
return false;

params.push_back(std::move(*param));
auto optError = decodeParam(elt);
if (optError)
return *optError;
}

return true;
return llvm::None;
}

// Otherwise, handle the type as a single argument.
FunctionParam<BuiltType> param;
if (!decodeParamTypeAndFlags(node, param))
return false;
auto optError = decodeParamTypeAndFlags(node, param);
if (optError)
return *optError;

params.push_back(std::move(param));
return true;
return llvm::None;
}
};

Expand Down
20 changes: 16 additions & 4 deletions include/swift/Remote/MetadataReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ class MetadataReader {
using BuiltRequirement = typename BuilderType::BuiltRequirement;
using BuiltSubstitution = typename BuilderType::BuiltSubstitution;
using BuiltSubstitutionMap = typename BuilderType::BuiltSubstitutionMap;
using BuiltGenericTypeParam = typename BuilderType::BuiltGenericTypeParam;
using BuiltGenericSignature = typename BuilderType::BuiltGenericSignature;
using StoredPointer = typename Runtime::StoredPointer;
using StoredSignedPointer = typename Runtime::StoredSignedPointer;
Expand Down Expand Up @@ -871,13 +870,26 @@ class MetadataReader {
}

// Read the labels string.
std::string labels;
std::string labelStr;
if (tupleMeta->Labels &&
!Reader->readString(RemoteAddress(tupleMeta->Labels), labels))
!Reader->readString(RemoteAddress(tupleMeta->Labels), labelStr))
return BuiltType();

std::vector<llvm::StringRef> labels;
std::string::size_type end, start = 0;
while (true) {
end = labelStr.find(' ', start);
if (end == std::string::npos)
break;
labels.push_back(llvm::StringRef(labelStr.data() + start, end - start));
start = end + 1;
}
// Pad the vector with empty labels.
for (unsigned i = labels.size(); i < elementTypes.size(); ++i)
labels.push_back(StringRef());

auto BuiltTuple =
Builder.createTupleType(elementTypes, std::move(labels));
Builder.createTupleType(elementTypes, labels);
TypeCache[MetadataAddress] = BuiltTuple;
return BuiltTuple;
}
Expand Down
Loading