mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user