Skip to content

ASTDemangler: Fix round-tripping of SILBoxTypeWithLayout #68700

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
merged 2 commits into from
Sep 22, 2023
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
24 changes: 18 additions & 6 deletions include/swift/AST/ASTDemangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -71,7 +75,7 @@ class ASTBuilder {
/// - advancePackExpansion()
/// - createExpandedPackElement()
/// - endPackExpansion()
llvm::SmallVector<Type> ActivePackExpansions;
llvm::SmallVector<Type, 2> ActivePackExpansions;

public:
using BuiltType = swift::Type;
Expand All @@ -84,7 +88,12 @@ class ASTBuilder {
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();
Expand Down Expand Up @@ -165,6 +174,9 @@ class ASTBuilder {
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);
Expand Down
106 changes: 60 additions & 46 deletions include/swift/Demangling/TypeDecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -1180,28 +1181,12 @@ class TypeDecoder {
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");

auto fieldsNode = Node->getChild(0);
if (fieldsNode->getKind() != NodeKind::SILBoxLayout)
return MAKE_NODE_TYPE_ERROR0(fieldsNode, "expected layout");
for (auto *fieldNode : *fieldsNode) {
bool isMutable;
switch (fieldNode->getKind()) {
case NodeKind::SILBoxMutableField: isMutable = true; break;
case NodeKind::SILBoxImmutableField: isMutable = false; break;
default:
return MAKE_NODE_TYPE_ERROR0(fieldNode, "unhandled field type");
}
if (fieldNode->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR0(fieldNode, "no children");
auto type = decodeMangledType(fieldNode->getChild(0), depth + 1);
if (type.isError())
return type;
fields.emplace_back(type.getType(), isMutable);
}
bool pushedGenericParams = false;

if (Node->getNumChildren() > 1) {
auto *substNode = Node->getChild(2);
Expand All @@ -1218,47 +1203,76 @@ class TypeDecoder {
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;

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;
auto paramTy = Builder.createGenericTypeParameterType(
paramDepth, index);
substitutions.emplace_back(paramTy, substTy.getType());
++index;
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");
for (auto *fieldNode : *fieldsNode) {
bool isMutable;
switch (fieldNode->getKind()) {
case NodeKind::SILBoxMutableField: isMutable = true; break;
case NodeKind::SILBoxImmutableField: isMutable = false; break;
default:
return MAKE_NODE_TYPE_ERROR0(fieldNode, "unhandled field type");
}
if (fieldNode->getNumChildren() < 1)
return MAKE_NODE_TYPE_ERROR0(fieldNode, "no children");
auto type = decodeMangledType(fieldNode->getChild(0), depth + 1);
if (type.isError())
return type;
fields.emplace_back(type.getType(), isMutable);
}

if (pushedGenericParams) {
Builder.popGenericParams();
}

return Builder.createSILBoxTypeWithLayout(fields, substitutions,
requirements);
}
Expand Down
4 changes: 4 additions & 0 deletions include/swift/RemoteInspection/TypeRefBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -910,8 +910,12 @@ class TypeRefBuilder {
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);
}

Expand Down
48 changes: 32 additions & 16 deletions lib/AST/ASTDemangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
}

Expand Down
47 changes: 15 additions & 32 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,37 +770,6 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
return ErrorType::get(ctx);
}

// Build ParameterizedProtocolType if the protocol has a primary associated
// type and we're in a supported context.
if (resolution.getOptions().isConstraintImplicitExistential() &&
!ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {

if (!genericArgs.empty()) {

SmallVector<Type, 2> argTys;
for (auto *genericArg : genericArgs) {
Type argTy = resolution.resolveType(genericArg);
if (!argTy || argTy->hasError())
return ErrorType::get(ctx);

argTys.push_back(argTy);
}

auto parameterized =
ParameterizedProtocolType::get(ctx, protoType, argTys);
diags.diagnose(loc, diag::existential_requires_any, parameterized,
ExistentialType::get(parameterized),
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
} else {
diags.diagnose(loc, diag::existential_requires_any,
protoDecl->getDeclaredInterfaceType(),
protoDecl->getDeclaredExistentialType(),
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
}

return ErrorType::get(ctx);
}

// Disallow opaque types anywhere in the structure of the generic arguments
// to a parameterized existential type.
if (options.is(TypeResolverContext::ExistentialConstraint))
Expand All @@ -809,6 +778,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
TypeResolverContext::ProtocolGenericArgument);
auto genericResolution = resolution.withOptions(argOptions);

// Resolve the generic arguments.
SmallVector<Type, 2> argTys;
for (auto *genericArg : genericArgs) {
Type argTy = genericResolution.resolveType(genericArg, silContext);
Expand All @@ -818,7 +788,20 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
argTys.push_back(argTy);
}

return ParameterizedProtocolType::get(ctx, protoType, argTys);
auto parameterized =
ParameterizedProtocolType::get(ctx, protoType, argTys);

// Build ParameterizedProtocolType if the protocol has primary associated
// types and we're in a supported context.
if (resolution.getOptions().isConstraintImplicitExistential() &&
!ctx.LangOpts.hasFeature(Feature::ImplicitSome)) {
diags.diagnose(loc, diag::existential_requires_any, parameterized,
ExistentialType::get(parameterized),
/*isAlias=*/isa<TypeAliasType>(type.getPointer()));
return ErrorType::get(ctx);
}

return parameterized;
}

// We must either have an unbound generic type, or a generic type alias.
Expand Down
3 changes: 3 additions & 0 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1869,6 +1869,9 @@ class DecodedMetadataBuilder {
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.
Expand Down
14 changes: 12 additions & 2 deletions test/DebugInfo/variadic-generics-closure.swift
Original file line number Diff line number Diff line change
@@ -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()) }
}