ASTDemangler: Fix round-tripping of SILBoxTypeWithLayout

The more awkward setup with pushGenericParams()/popGenericParams()
is required so that when demangling requirements and field types
we get the correct pack-ness for each type parameter. The pack-ness
is encoded as part of the generic signature, and not as part of
the type parameter mangling itself.

Fixes the ASTDemangler issue from rdar://problem/115459973.
This commit is contained in:
Slava Pestov
2023-09-21 13:52:40 -04:00
parent 04c5374cef
commit 57b702be07
6 changed files with 138 additions and 79 deletions

View File

@@ -59,10 +59,14 @@ class ASTBuilder {
/// Created lazily.
DeclContext *NotionalDC = nullptr;
/// The generic signature for interpreting type parameters. This is used
/// because the mangling for a type parameter doesn't record whether it
/// is a pack or not, so we have to find it here.
GenericSignature GenericSig;
/// The depth and index of each parameter pack in the current generic
/// signature. We need this because the mangling for a type parameter
/// doesn't record whether it is a pack or not; we find the correct
/// depth and index in this array, and use its pack-ness.
llvm::SmallVector<std::pair<unsigned, unsigned>, 2> ParameterPacks;
/// For saving and restoring generic parameters.
llvm::SmallVector<decltype(ParameterPacks), 2> ParameterPackStack;
/// This builder doesn't perform "on the fly" substitutions, so we preserve
/// all pack expansions. We still need an active expansion stack though,
@@ -71,7 +75,7 @@ class ASTBuilder {
/// - advancePackExpansion()
/// - createExpandedPackElement()
/// - endPackExpansion()
llvm::SmallVector<Type> ActivePackExpansions;
llvm::SmallVector<Type, 2> ActivePackExpansions;
public:
using BuiltType = swift::Type;
@@ -84,7 +88,12 @@ public:
static constexpr bool needsToPrecomputeParentGenericContextShapes = false;
explicit ASTBuilder(ASTContext &ctx, GenericSignature genericSig)
: Ctx(ctx), GenericSig(genericSig) {}
: Ctx(ctx) {
for (auto *paramTy : genericSig.getGenericParams()) {
if (paramTy->isParameterPack())
ParameterPacks.emplace_back(paramTy->getDepth(), paramTy->getIndex());
}
}
ASTContext &getASTContext() { return Ctx; }
DeclContext *getNotionalDC();
@@ -165,6 +174,9 @@ public:
Type instance,
llvm::Optional<Demangle::ImplMetatypeRepresentation> repr = llvm::None);
void pushGenericParams(ArrayRef<std::pair<unsigned, unsigned>> parameterPacks);
void popGenericParams();
Type createGenericTypeParameterType(unsigned depth, unsigned index);
Type createDependentMemberType(StringRef member, Type base);

View File

@@ -376,7 +376,8 @@ void decodeRequirement(NodePointer node,
llvm::SmallVectorImpl<BuiltRequirement> &requirements,
BuilderType &Builder) {
for (auto &child : *node) {
if (child->getKind() == Demangle::Node::Kind::DependentGenericParamCount)
if (child->getKind() == Demangle::Node::Kind::DependentGenericParamCount ||
child->getKind() == Demangle::Node::Kind::DependentGenericParamPackMarker)
continue;
if (child->getNumChildren() != 2)
@@ -1180,10 +1181,75 @@ protected:
llvm::SmallVector<Field, 4> fields;
llvm::SmallVector<BuiltSubstitution, 4> substitutions;
llvm::SmallVector<BuiltRequirement, 4> requirements;
llvm::SmallVector<BuiltType, 4> genericParams;
if (Node->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR0(Node, "no children");
bool pushedGenericParams = false;
if (Node->getNumChildren() > 1) {
auto *substNode = Node->getChild(2);
if (substNode->getKind() != NodeKind::TypeList)
return MAKE_NODE_TYPE_ERROR0(substNode, "expected type list");
auto *dependentGenericSignatureNode = Node->getChild(1);
if (dependentGenericSignatureNode->getKind() !=
NodeKind::DependentGenericSignature)
return MAKE_NODE_TYPE_ERROR0(dependentGenericSignatureNode,
"expected dependent generic signature");
if (dependentGenericSignatureNode->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR(
dependentGenericSignatureNode,
"fewer children (%zu) than required (1)",
dependentGenericSignatureNode->getNumChildren());
// The number of generic parameters at each depth are in a mini
// state machine and come first.
llvm::SmallVector<unsigned, 4> genericParamsAtDepth;
for (auto *reqNode : *dependentGenericSignatureNode)
if (reqNode->getKind() == NodeKind::DependentGenericParamCount)
if (reqNode->hasIndex())
genericParamsAtDepth.push_back(reqNode->getIndex());
llvm::SmallVector<std::pair<unsigned, unsigned>> parameterPacks;
for (auto &child : *dependentGenericSignatureNode) {
if (child->getKind() == Demangle::Node::Kind::DependentGenericParamPackMarker) {
auto *marker = child->getChild(0)->getChild(0);
parameterPacks.emplace_back(marker->getChild(0)->getIndex(),
marker->getChild(1)->getIndex());
}
}
Builder.pushGenericParams(parameterPacks);
pushedGenericParams = true;
// Decode generic parameter types.
for (unsigned d = 0; d < genericParamsAtDepth.size(); ++d) {
for (unsigned i = 0; i < genericParamsAtDepth[d]; ++i) {
auto paramTy = Builder.createGenericTypeParameterType(d, i);
genericParams.push_back(paramTy);
}
}
// Decode requirements.
decodeRequirement<BuiltType, BuiltRequirement, BuiltLayoutConstraint,
BuilderType>(dependentGenericSignatureNode,
requirements,
Builder);
// Decode substitutions.
for (unsigned i = 0, e = substNode->getNumChildren(); i < e; ++i) {
auto *subst = substNode->getChild(i);
auto substTy = decodeMangledType(subst, depth + 1,
/*forRequirement=*/false);
if (substTy.isError())
return substTy;
substitutions.emplace_back(genericParams[i], substTy.getType());
}
}
// Decode field types.
auto fieldsNode = Node->getChild(0);
if (fieldsNode->getKind() != NodeKind::SILBoxLayout)
return MAKE_NODE_TYPE_ERROR0(fieldsNode, "expected layout");
@@ -1203,60 +1269,8 @@ protected:
fields.emplace_back(type.getType(), isMutable);
}
if (Node->getNumChildren() > 1) {
auto *substNode = Node->getChild(2);
if (substNode->getKind() != NodeKind::TypeList)
return MAKE_NODE_TYPE_ERROR0(substNode, "expected type list");
auto *dependentGenericSignatureNode = Node->getChild(1);
if (dependentGenericSignatureNode->getKind() !=
NodeKind::DependentGenericSignature)
return MAKE_NODE_TYPE_ERROR0(dependentGenericSignatureNode,
"expected dependent generic signature");
if (dependentGenericSignatureNode->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR(
dependentGenericSignatureNode,
"fewer children (%zu) than required (1)",
dependentGenericSignatureNode->getNumChildren());
decodeRequirement<BuiltType, BuiltRequirement, BuiltLayoutConstraint,
BuilderType>(dependentGenericSignatureNode,
requirements,
Builder /*,
[&](NodePointer Node) -> BuiltType {
return decodeMangledType(Node, depth + 1).getType();
},
[&](LayoutConstraintKind Kind) -> BuiltLayoutConstraint {
return {}; // Not implemented!
},
[&](LayoutConstraintKind Kind, unsigned SizeInBits,
unsigned Alignment) -> BuiltLayoutConstraint {
return {}; // Not Implemented!
}*/);
// The number of generic parameters at each depth are in a mini
// state machine and come first.
llvm::SmallVector<unsigned, 4> genericParamsAtDepth;
for (auto *reqNode : *dependentGenericSignatureNode)
if (reqNode->getKind() == NodeKind::DependentGenericParamCount)
if (reqNode->hasIndex())
genericParamsAtDepth.push_back(reqNode->getIndex());
unsigned paramDepth = 0;
unsigned index = 0;
for (auto *subst : *substNode) {
if (paramDepth >= genericParamsAtDepth.size())
return MAKE_NODE_TYPE_ERROR0(
dependentGenericSignatureNode,
"more substitutions than generic params");
while (index >= genericParamsAtDepth[paramDepth])
++paramDepth, index = 0;
auto substTy = decodeMangledType(subst, depth + 1,
/*forRequirement=*/false);
if (substTy.isError())
return substTy;
auto paramTy = Builder.createGenericTypeParameterType(
paramDepth, index);
substitutions.emplace_back(paramTy, substTy.getType());
++index;
}
if (pushedGenericParams) {
Builder.popGenericParams();
}
return Builder.createSILBoxTypeWithLayout(fields, substitutions,

View File

@@ -910,8 +910,12 @@ public:
return MetatypeTypeRef::create(*this, instance, WasAbstract);
}
void pushGenericParams(llvm::ArrayRef<std::pair<unsigned, unsigned>> parameterPacks) {}
void popGenericParams() {}
const GenericTypeParameterTypeRef *
createGenericTypeParameterType(unsigned depth, unsigned index) {
// FIXME: variadic generics
return GenericTypeParameterTypeRef::create(*this, depth, index);
}

View File

@@ -31,6 +31,7 @@
#include "swift/AST/Type.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Defer.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Demangling/ManglingMacros.h"
#include "llvm/ADT/StringSwitch.h"
@@ -731,23 +732,28 @@ Type ASTBuilder::createMetatypeType(
return MetatypeType::get(instance, getMetatypeRepresentation(*repr));
}
void ASTBuilder::pushGenericParams(ArrayRef<std::pair<unsigned, unsigned>> parameterPacks) {
ParameterPackStack.push_back(ParameterPacks);
ParameterPacks.clear();
ParameterPacks.append(parameterPacks.begin(), parameterPacks.end());
}
void ASTBuilder::popGenericParams() {
ParameterPacks = ParameterPackStack.back();
ParameterPackStack.pop_back();
}
Type ASTBuilder::createGenericTypeParameterType(unsigned depth,
unsigned index) {
// If we have a generic signature, find the parameter with the matching
// depth and index and return it, to get the correct value for the
// isParameterPack() bit.
if (GenericSig) {
for (auto paramTy : GenericSig.getGenericParams()) {
if (paramTy->getDepth() == depth && paramTy->getIndex() == index) {
return paramTy;
if (!ParameterPacks.empty()) {
for (auto pair : ParameterPacks) {
if (pair.first == depth && pair.second == index) {
return GenericTypeParamType::get(/*isParameterPack*/ true,
depth, index, Ctx);
}
}
return Type();
}
// Otherwise, just assume we're not working with variadic generics.
// FIXME: Should we always require a generic signature in this case?
return GenericTypeParamType::get(/*isParameterPack*/ false,
depth, index, Ctx);
}
@@ -1039,15 +1045,25 @@ LayoutConstraint ASTBuilder::getLayoutConstraintWithSizeAlign(
CanGenericSignature ASTBuilder::demangleGenericSignature(
NominalTypeDecl *nominalDecl,
NodePointer node) {
llvm::SaveAndRestore<GenericSignature> savedSignature(
GenericSig, nominalDecl->getGenericSignature());
auto baseGenericSig = nominalDecl->getGenericSignature();
// The generic signature is for a constrained extension of nominalDecl, so
// we introduce the parameter packs from the nominal's generic signature.
ParameterPackStack.push_back(ParameterPacks);
ParameterPacks.clear();
for (auto *paramTy : baseGenericSig.getGenericParams()) {
if (paramTy->isParameterPack())
ParameterPacks.emplace_back(paramTy->getDepth(), paramTy->getIndex());
}
SWIFT_DEFER { popGenericParams(); };
// Constrained extensions mangle the subset of requirements not satisfied
// by the nominal's generic signature.
SmallVector<Requirement, 2> requirements;
decodeRequirement<BuiltType, BuiltRequirement, BuiltLayoutConstraint,
ASTBuilder>(node, requirements, *this);
return buildGenericSignature(Ctx, nominalDecl->getGenericSignature(),
{}, std::move(requirements))
return buildGenericSignature(Ctx, baseGenericSig, {}, std::move(requirements))
.getCanonicalSignature();
}

View File

@@ -1869,6 +1869,9 @@ public:
return BuiltType();
}
void pushGenericParams(llvm::ArrayRef<std::pair<unsigned, unsigned>> parameterPacks) {}
void popGenericParams() {}
BuiltType
createGenericTypeParameterType(unsigned depth, unsigned index) const {
// Use the callback, when provided.

View File

@@ -1,4 +1,14 @@
// RUN: %target-swift-frontend -emit-ir %s -g | %FileCheck %s
// RUN: %target-swift-frontend -emit-ir %s -g -module-name closure | %FileCheck %s
// CHECK: !{{[0-9]+}} = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxxQp_QSiIgp_D", {{.*}})
// CHECK-DAG: !{{[0-9]+}} = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxxQp_QSiIgp_D", {{.*}})
public func f<each Input>(builder: (repeat each Input) -> ()) {}
public protocol P {
func f() -> Self
}
// CHECK-DAG: !{{[0-9]+}} = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxxQp_tz_xxQp_QP_Rvz7closure1PRzlXXD", {{.*}})
public func foo<each T: P>(t: repeat each T) -> () -> () {
var x = (repeat each t)
return { x = (repeat (each x).f()) }
}