Skip to content

Commit b3cb845

Browse files
committed
Runtime: support metadata packs in _buildDemanglingForNominalType()
This adds a bunch of new code but once I finish refactoring the other demangling stuff, I should be able to remove - gatherWrittenGenericArgs() - _gatherGenericParameters() - SubstGenericParametersFromWrittenArgs
1 parent aced44a commit b3cb845

File tree

3 files changed

+215
-24
lines changed

3 files changed

+215
-24
lines changed

stdlib/public/runtime/Demangle.cpp

Lines changed: 211 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,215 @@ _buildDemanglerForBuiltinType(const Metadata *type, Demangle::Demangler &Dem) {
247247
return nullptr;
248248
}
249249

250+
// Build a demangled type tree for a type pack.
251+
static Demangle::NodePointer
252+
_buildDemanglingForMetadataPack(MetadataPackPointer pack, size_t count,
253+
Demangle::Demangler &Dem) {
254+
using namespace Demangle;
255+
256+
auto node = Dem.createNode(Node::Kind::Pack);
257+
258+
for (size_t i = 0; i < count; ++i) {
259+
auto elt = _swift_buildDemanglingForMetadata(pack.getElements()[i], Dem);
260+
if (elt == nullptr)
261+
return nullptr;
262+
263+
node->addChild(elt, Dem);
264+
}
265+
266+
return node;
267+
}
268+
269+
/// Demangle the given type name to a generic parameter reference, which
270+
/// will be returned as (depth, index).
271+
static llvm::Optional<std::pair<unsigned, unsigned>>
272+
demangleToGenericParamRef(StringRef typeName) {
273+
StackAllocatedDemangler<1024> demangler;
274+
NodePointer node = demangler.demangleType(typeName);
275+
if (!node)
276+
return None;
277+
278+
// Find the flat index that the right-hand side refers to.
279+
if (node->getKind() == Demangle::Node::Kind::Type)
280+
node = node->getChild(0);
281+
if (node->getKind() != Demangle::Node::Kind::DependentGenericParamType)
282+
return None;
283+
284+
return std::pair<unsigned, unsigned>(node->getChild(0)->getIndex(),
285+
node->getChild(1)->getIndex());
286+
}
287+
288+
/// Build an array of demangling trees for each generic argument of the given
289+
/// type metadata.
290+
///
291+
/// Note:
292+
/// - The input array has an entry for those generic parameter descriptors which
293+
/// are key arguments only.
294+
/// - The output array has an entry for each generic parameter descriptor,
295+
/// whether or not it is a key argument.
296+
///
297+
/// The generic parameters which are not key arguments were made non-canonical
298+
/// by constraining them to a concrete type or another generic parameter.
299+
///
300+
/// We figure out their type by looking at the same-type requirements of the
301+
/// generic context. We demangle their type from the requirement, using the
302+
/// generic arguments area as the substitution map; this gives us the metadata
303+
/// for their argument. Then we convert the metadata to a mangling.
304+
///
305+
/// The output array is flat; the generic parameters of each depth are
306+
/// concatenated together.
307+
static bool _buildDemanglingForGenericArgs(
308+
const Metadata *type,
309+
const TypeContextDescriptor *description,
310+
llvm::SmallVectorImpl<NodePointer> &demangledGenerics,
311+
Demangle::Demangler &Dem) {
312+
auto generics = description->getGenericContext();
313+
if (!generics)
314+
return true;
315+
316+
auto genericArgs = description->getGenericArguments(type);
317+
318+
auto packHeader = generics->getGenericPackShapeHeader();
319+
auto packDescriptors = generics->getGenericPackShapeDescriptors();
320+
321+
unsigned packIndex = 0;
322+
unsigned argIndex = packHeader.NumShapeClasses;
323+
324+
bool missingWrittenArguments = false;
325+
326+
for (auto param : generics->getGenericParams()) {
327+
switch (param.getKind()) {
328+
case GenericParamKind::Type:
329+
// The type should have a key argument unless it's been same-typed to
330+
// another type.
331+
if (param.hasKeyArgument()) {
332+
auto genericArg = reinterpret_cast<const Metadata *>(genericArgs[argIndex]);
333+
334+
auto genericArgDemangling =
335+
_swift_buildDemanglingForMetadata(genericArg, Dem);
336+
if (!genericArgDemangling)
337+
return false;
338+
demangledGenerics.push_back(genericArgDemangling);
339+
340+
++argIndex;
341+
} else {
342+
// Leave a gap for us to fill in by looking at same-type requirements.
343+
demangledGenerics.push_back(nullptr);
344+
missingWrittenArguments = true;
345+
}
346+
347+
break;
348+
349+
case GenericParamKind::TypePack:
350+
if (param.hasKeyArgument()) {
351+
auto packDescriptor = packDescriptors[packIndex];
352+
assert(packDescriptor.Kind == GenericPackKind::Metadata);
353+
assert(packDescriptor.ShapeClass < packHeader.NumShapeClasses);
354+
assert(packDescriptor.Index == argIndex);
355+
356+
MetadataPackPointer pack(genericArgs[argIndex]);
357+
size_t count = reinterpret_cast<size_t>(genericArgs[packDescriptor.ShapeClass]);
358+
359+
auto genericArgDemangling = _buildDemanglingForMetadataPack(pack, count, Dem);
360+
if (genericArgDemangling == nullptr)
361+
return false;
362+
363+
demangledGenerics.push_back(genericArgDemangling);
364+
365+
++packIndex;
366+
++argIndex;
367+
} else {
368+
// Leave a gap for us to fill in by looking at same-type requirements.
369+
demangledGenerics.push_back(nullptr);
370+
missingWrittenArguments = true;
371+
}
372+
373+
break;
374+
375+
default:
376+
// We don't know about this kind of parameter.
377+
return false;
378+
}
379+
}
380+
381+
// If there is no follow-up work to do, we're done.
382+
if (!missingWrittenArguments)
383+
return true;
384+
385+
// We have generic arguments that would be written, but have been
386+
// canonicalized away. Use same-type requirements to reconstitute them.
387+
SubstGenericParametersFromMetadata substitutions(
388+
description, reinterpret_cast<const void * const *>(genericArgs));
389+
390+
// Retrieve the mapping information needed for depth/index -> flat index.
391+
llvm::SmallVector<unsigned, 8> genericParamCounts;
392+
(void)_gatherGenericParameterCounts(description, genericParamCounts, Dem);
393+
394+
// Walk through the generic requirements to evaluate same-type
395+
// constraints that are needed to fill in missing generic arguments.
396+
for (const auto &req : generics->getGenericRequirements()) {
397+
// We only care about same-type constraints.
398+
if (req.Flags.getKind() != GenericRequirementKind::SameType)
399+
continue;
400+
401+
auto lhsParam = demangleToGenericParamRef(req.getParam());
402+
if (!lhsParam)
403+
continue;
404+
405+
assert(!req.Flags.isPackRequirement() &&
406+
"Pack requirements not supported here yet");
407+
408+
// If we don't yet have an argument for this parameter, it's a
409+
// same-type-to-concrete constraint.
410+
auto lhsFlatIndex =
411+
_depthIndexToFlatIndex(lhsParam->first, lhsParam->second,
412+
genericParamCounts);
413+
if (!lhsFlatIndex || *lhsFlatIndex >= demangledGenerics.size())
414+
return false;
415+
416+
if (!demangledGenerics[*lhsFlatIndex]) {
417+
// Substitute into the right-hand side.
418+
auto *genericArg =
419+
swift_getTypeByMangledName(MetadataState::Abstract,
420+
req.getMangledTypeName(),
421+
reinterpret_cast<const void * const *>(genericArgs),
422+
[&substitutions](unsigned depth, unsigned index) {
423+
return substitutions.getMetadata(depth, index);
424+
},
425+
[&substitutions](const Metadata *type, unsigned index) {
426+
return substitutions.getWitnessTable(type, index);
427+
}).getType().getMetadata();
428+
if (!genericArg)
429+
return false;
430+
431+
demangledGenerics[*lhsFlatIndex] =
432+
_swift_buildDemanglingForMetadata(genericArg, Dem);
433+
434+
continue;
435+
}
436+
437+
// If we do have an argument for this parameter, it might be that
438+
// the right-hand side is itself a generic parameter, which means
439+
// we have a same-type constraint A == B where A is already filled in.
440+
auto rhsParam = demangleToGenericParamRef(req.getMangledTypeName());
441+
if (!rhsParam)
442+
return false;
443+
444+
auto rhsFlatIndex =
445+
_depthIndexToFlatIndex(rhsParam->first, rhsParam->second,
446+
genericParamCounts);
447+
if (!rhsFlatIndex || *rhsFlatIndex >= demangledGenerics.size())
448+
return false;
449+
450+
if (demangledGenerics[*rhsFlatIndex] || !demangledGenerics[*lhsFlatIndex])
451+
return false;
452+
453+
demangledGenerics[*rhsFlatIndex] = demangledGenerics[*lhsFlatIndex];
454+
}
455+
456+
return true;
457+
}
458+
250459
/// Build a demangled type tree for a nominal type.
251460
static Demangle::NodePointer
252461
_buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
@@ -293,30 +502,9 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
293502

294503
// Gather the complete set of generic arguments that must be written to
295504
// form this type.
296-
llvm::SmallVector<const Metadata *, 8> allGenericArgs;
297-
gatherWrittenGenericArgs(type, description, allGenericArgs, Dem);
298-
299-
// Demangle the generic arguments.
300505
llvm::SmallVector<NodePointer, 8> demangledGenerics;
301-
for (auto genericArg : allGenericArgs) {
302-
// When there is no generic argument, put in a placeholder.
303-
if (!genericArg) {
304-
auto placeholder = Dem.createNode(Node::Kind::Tuple);
305-
auto emptyList = Dem.createNode(Node::Kind::TypeList);
306-
placeholder->addChild(emptyList, Dem);
307-
auto type = Dem.createNode(Node::Kind::Type);
308-
type->addChild(placeholder, Dem);
309-
demangledGenerics.push_back(type);
310-
continue;
311-
}
312-
313-
// Demangle this argument.
314-
auto genericArgDemangling =
315-
_swift_buildDemanglingForMetadata(genericArg, Dem);
316-
if (!genericArgDemangling)
317-
return nullptr;
318-
demangledGenerics.push_back(genericArgDemangling);
319-
}
506+
if (!_buildDemanglingForGenericArgs(type, description, demangledGenerics, Dem))
507+
return nullptr;
320508

321509
return _buildDemanglingForContext(description, demangledGenerics, Dem);
322510
}

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,6 +2754,9 @@ void swift::gatherWrittenGenericArgs(
27542754
if (!lhsParam)
27552755
continue;
27562756

2757+
assert(!req.Flags.isPackRequirement() &&
2758+
"Pack requirements not supported here yet");
2759+
27572760
// If we don't yet have an argument for this parameter, it's a
27582761
// same-type-to-concrete constraint.
27592762
auto lhsFlatIndex =

stdlib/public/runtime/Private.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ class TypeInfo {
535535
void *allocateMetadata(size_t size, size_t align);
536536

537537
/// Gather the set of generic arguments that would be written in the
538-
/// source, as a f
538+
/// source.
539539
///
540540
/// This function computes generic arguments even when they are not
541541
/// directly represented in the metadata, e.g., generic parameters that

0 commit comments

Comments
 (0)