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

View File

@@ -376,7 +376,8 @@ void decodeRequirement(NodePointer node,
llvm::SmallVectorImpl<BuiltRequirement> &requirements, llvm::SmallVectorImpl<BuiltRequirement> &requirements,
BuilderType &Builder) { BuilderType &Builder) {
for (auto &child : *node) { 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; continue;
if (child->getNumChildren() != 2) if (child->getNumChildren() != 2)
@@ -1180,10 +1181,75 @@ protected:
llvm::SmallVector<Field, 4> fields; llvm::SmallVector<Field, 4> fields;
llvm::SmallVector<BuiltSubstitution, 4> substitutions; llvm::SmallVector<BuiltSubstitution, 4> substitutions;
llvm::SmallVector<BuiltRequirement, 4> requirements; llvm::SmallVector<BuiltRequirement, 4> requirements;
llvm::SmallVector<BuiltType, 4> genericParams;
if (Node->getNumChildren() < 1) if (Node->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR0(Node, "no children"); 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); auto fieldsNode = Node->getChild(0);
if (fieldsNode->getKind() != NodeKind::SILBoxLayout) if (fieldsNode->getKind() != NodeKind::SILBoxLayout)
return MAKE_NODE_TYPE_ERROR0(fieldsNode, "expected layout"); return MAKE_NODE_TYPE_ERROR0(fieldsNode, "expected layout");
@@ -1203,60 +1269,8 @@ protected:
fields.emplace_back(type.getType(), isMutable); fields.emplace_back(type.getType(), isMutable);
} }
if (Node->getNumChildren() > 1) { if (pushedGenericParams) {
auto *substNode = Node->getChild(2); Builder.popGenericParams();
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;
}
} }
return Builder.createSILBoxTypeWithLayout(fields, substitutions, return Builder.createSILBoxTypeWithLayout(fields, substitutions,

View File

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

View File

@@ -31,6 +31,7 @@
#include "swift/AST/Type.h" #include "swift/AST/Type.h"
#include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/Types.h" #include "swift/AST/Types.h"
#include "swift/Basic/Defer.h"
#include "swift/Demangling/Demangler.h" #include "swift/Demangling/Demangler.h"
#include "swift/Demangling/ManglingMacros.h" #include "swift/Demangling/ManglingMacros.h"
#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringSwitch.h"
@@ -731,23 +732,28 @@ Type ASTBuilder::createMetatypeType(
return MetatypeType::get(instance, getMetatypeRepresentation(*repr)); 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, Type ASTBuilder::createGenericTypeParameterType(unsigned depth,
unsigned index) { unsigned index) {
// If we have a generic signature, find the parameter with the matching if (!ParameterPacks.empty()) {
// depth and index and return it, to get the correct value for the for (auto pair : ParameterPacks) {
// isParameterPack() bit. if (pair.first == depth && pair.second == index) {
if (GenericSig) { return GenericTypeParamType::get(/*isParameterPack*/ true,
for (auto paramTy : GenericSig.getGenericParams()) { depth, index, Ctx);
if (paramTy->getDepth() == depth && paramTy->getIndex() == index) {
return paramTy;
} }
} }
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, return GenericTypeParamType::get(/*isParameterPack*/ false,
depth, index, Ctx); depth, index, Ctx);
} }
@@ -1039,15 +1045,25 @@ LayoutConstraint ASTBuilder::getLayoutConstraintWithSizeAlign(
CanGenericSignature ASTBuilder::demangleGenericSignature( CanGenericSignature ASTBuilder::demangleGenericSignature(
NominalTypeDecl *nominalDecl, NominalTypeDecl *nominalDecl,
NodePointer node) { NodePointer node) {
llvm::SaveAndRestore<GenericSignature> savedSignature( auto baseGenericSig = nominalDecl->getGenericSignature();
GenericSig, 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; SmallVector<Requirement, 2> requirements;
decodeRequirement<BuiltType, BuiltRequirement, BuiltLayoutConstraint, decodeRequirement<BuiltType, BuiltRequirement, BuiltLayoutConstraint,
ASTBuilder>(node, requirements, *this); ASTBuilder>(node, requirements, *this);
return buildGenericSignature(Ctx, nominalDecl->getGenericSignature(),
{}, std::move(requirements)) return buildGenericSignature(Ctx, baseGenericSig, {}, std::move(requirements))
.getCanonicalSignature(); .getCanonicalSignature();
} }

View File

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