Skip to content

Commit 8405745

Browse files
committed
SIL: Fix SubstFunctionTypePatternVisitor handling of pack types
The included test case also covers the previous commit.
1 parent a00c058 commit 8405745

File tree

4 files changed

+225
-4
lines changed

4 files changed

+225
-4
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace swift {
3737
namespace Lowering {
3838
class FunctionParamGenerator;
3939
class TupleElementGenerator;
40+
class PackElementGenerator;
4041

4142
/// A pattern for the abstraction of a value.
4243
///
@@ -1450,6 +1451,15 @@ class AbstractionPattern {
14501451
llvm_unreachable("bad kind");
14511452
}
14521453

1454+
/// Perform a parallel visitation of the elements of a pack type,
1455+
/// preserving structure about where pack expansions appear in the
1456+
/// original type and how many elements of the substituted type they
1457+
/// expand to.
1458+
///
1459+
/// This pattern must be a pack pattern.
1460+
void forEachPackElement(CanPackType substPackType,
1461+
llvm::function_ref<void(PackElementGenerator &element)> fn) const;
1462+
14531463
/// Given that the value being abstracted is a move only type, return the
14541464
/// abstraction pattern with the move only bit removed.
14551465
AbstractionPattern removingMoveOnlyWrapper() const;

include/swift/SIL/AbstractionPatternGenerators.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,122 @@ class TupleElementGenerator {
335335
}
336336
};
337337

338+
/// A generator for traversing the formal elements of a pack type
339+
/// while properly respecting variadic generics.
340+
class PackElementGenerator {
341+
// The steady state of the generator.
342+
343+
/// The abstraction pattern of the entire pack type. Set once
344+
/// during construction.
345+
AbstractionPattern origPackType;
346+
347+
/// The substituted pack type. Set once during construction.
348+
CanPackType substPackType;
349+
350+
/// The number of orig elements to traverse. Set once during
351+
/// construction.
352+
unsigned numOrigElts;
353+
354+
/// The index of the current orig element.
355+
/// Incremented during advance().
356+
unsigned origEltIndex = 0;
357+
358+
/// The (start) index of the current subst elements.
359+
/// Incremented during advance().
360+
unsigned substEltIndex = 0;
361+
362+
/// The number of subst elements corresponding to the current
363+
/// orig element.
364+
unsigned numSubstEltsForOrigElt;
365+
366+
/// Whether the current orig element is a pack expansion.
367+
bool origEltIsExpansion;
368+
369+
/// The abstraction pattern of the current orig element.
370+
/// If it is a pack expansion, this is the expansion type, not the
371+
/// pattern type.
372+
AbstractionPattern origEltType = AbstractionPattern::getInvalid();
373+
374+
/// Load the informaton for the current orig element into the
375+
/// fields above for it.
376+
void loadElement() {
377+
origEltType = origPackType.getPackElementType(origEltIndex);
378+
origEltIsExpansion = origEltType.isPackExpansion();
379+
numSubstEltsForOrigElt =
380+
(origEltIsExpansion
381+
? origEltType.getNumPackExpandedComponents()
382+
: 1);
383+
}
384+
385+
public:
386+
PackElementGenerator(AbstractionPattern origTupleType,
387+
CanPackType substPackType);
388+
389+
/// Is the traversal finished? If so, none of the getters below
390+
/// are allowed to be called.
391+
bool isFinished() const {
392+
return origEltIndex == numOrigElts;
393+
}
394+
395+
/// Advance to the next orig element.
396+
void advance() {
397+
assert(!isFinished());
398+
origEltIndex++;
399+
substEltIndex += numSubstEltsForOrigElt;
400+
if (!isFinished()) loadElement();
401+
}
402+
403+
/// Return the index of the current orig element.
404+
unsigned getOrigIndex() const {
405+
assert(!isFinished());
406+
return origEltIndex;
407+
}
408+
409+
/// Return the index of the (first) subst element corresponding
410+
/// to the current orig element.
411+
unsigned getSubstIndex() const {
412+
assert(!isFinished());
413+
return substEltIndex;
414+
}
415+
416+
IntRange<unsigned> getSubstIndexRange() const {
417+
assert(!isFinished());
418+
return IntRange<unsigned>(substEltIndex,
419+
substEltIndex + numSubstEltsForOrigElt);
420+
}
421+
422+
/// Return the type of the current orig element.
423+
const AbstractionPattern &getOrigType() const {
424+
assert(!isFinished());
425+
return origEltType;
426+
}
427+
428+
/// Return whether the current orig element type is a pack expansion.
429+
bool isOrigPackExpansion() const {
430+
assert(!isFinished());
431+
return origEltIsExpansion;
432+
}
433+
434+
/// Return the substituted elements corresponding to the current
435+
/// orig element type. If the current orig element is not a
436+
/// pack expansion, this will have exactly one element.
437+
CanTypeArrayRef getSubstTypes() const {
438+
assert(!isFinished());
439+
return substPackType
440+
.getElementTypes().slice(substEltIndex,
441+
numSubstEltsForOrigElt);
442+
}
443+
444+
/// Call this to finalize the traversal and assert that it was done
445+
/// properly.
446+
void finish() {
447+
assert(isFinished() && "didn't finish the traversal");
448+
assert(substEltIndex == substPackType->getNumElements() &&
449+
"didn't exhaust subst elements; possible missing subs on "
450+
"orig pack type");
451+
}
452+
};
453+
338454
} // end namespace Lowering
339455
} // end namespace swift
340456

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,72 @@ bool AbstractionPattern::matchesPack(CanPackType substType) {
741741
llvm_unreachable("bad kind");
742742
}
743743

744+
void AbstractionPattern::forEachPackElement(CanPackType substType,
745+
llvm::function_ref<void(PackElementGenerator &)> handleElement) const {
746+
PackElementGenerator elt(*this, substType);
747+
for (; !elt.isFinished(); elt.advance()) {
748+
handleElement(elt);
749+
}
750+
elt.finish();
751+
}
752+
753+
void AbstractionPattern::forEachExpandedPackElement(CanPackType substType,
754+
llvm::function_ref<void(AbstractionPattern origEltType,
755+
CanType substEltType)>
756+
handleElement) const {
757+
assert(matchesPack(substType));
758+
759+
auto substEltTypes = substPackType.getElementTypes();
760+
761+
// Handle opaque patterns by just iterating the substituted components.
762+
if (!isPack()) {
763+
for (auto i : indices(substEltTypes)) {
764+
handleElement(getPackElementType(i), substEltTypes[i]);
765+
}
766+
return;
767+
}
768+
769+
// For non-opaque patterns, we have to iterate the original components
770+
// in order to match things up properly, but we'll still end up calling
771+
// once per substituted element.
772+
size_t substEltIndex = 0;
773+
for (size_t origEltIndex : range(getNumPackElements())) {
774+
auto origEltType = getPackElementType(origEltIndex);
775+
if (!origEltType.isPackExpansion()) {
776+
handleElement(origEltType, substEltTypes[substEltIndex]);
777+
substEltIndex++;
778+
} else {
779+
auto origPatternType = origEltType.getPackExpansionPatternType();
780+
for (auto i : range(origEltType.getNumPackExpandedComponents())) {
781+
(void) i;
782+
auto substEltType = substEltTypes[substEltIndex];
783+
// When the substituted type is a pack expansion, pass down
784+
// the original element type so that it's *also* a pack expansion.
785+
// Clients expect to look through this structure in parallel on
786+
// both types. The count is misleading, but normal usage won't
787+
// access it, and there's nothing we could provide that *wouldn't*
788+
// be misleading in one way or another.
789+
handleElement(isa<PackExpansionType>(substEltType)
790+
? origEltType : origPatternType,
791+
substEltType);
792+
substEltIndex++;
793+
}
794+
}
795+
}
796+
assert(substEltIndex == substEltTypes.size());
797+
}
798+
799+
PackElementGenerator::PackElementGenerator(
800+
AbstractionPattern origPackType,
801+
CanPackType substPackType)
802+
: origPackType(origPackType), substPackType(substPackType) {
803+
assert(origPackType.isPack());
804+
assert(origPackType.matchesPack(substPackType));
805+
numOrigElts = origPackType.getNumPackElements();
806+
807+
if (!isFinished()) loadElement();
808+
}
809+
744810
AbstractionPattern
745811
AbstractionPattern::getPackExpansionComponentType(CanType substType) const {
746812
return getPackExpansionComponentType(isa<PackExpansionType>(substType));
@@ -2214,12 +2280,25 @@ class SubstFunctionTypePatternVisitor
22142280
}
22152281

22162282
CanType visitPackType(CanPackType pack, AbstractionPattern pattern) {
2283+
assert(pattern.isPack());
2284+
22172285
// Break down the pack.
22182286
SmallVector<CanType, 4> packElts;
2219-
for (auto i : range(pack->getNumElements())) {
2220-
packElts.push_back(visit(pack.getElementType(i),
2221-
pattern.getPackElementType(i)));
2222-
}
2287+
2288+
pattern.forEachPackElement(pack, [&](PackElementGenerator &elt) {
2289+
auto substEltTypes = elt.getSubstTypes();
2290+
CanType eltTy;
2291+
if (!elt.isOrigPackExpansion()) {
2292+
eltTy = visit(substEltTypes[0], elt.getOrigType());
2293+
} else {
2294+
CanType candidateSubstType;
2295+
if (!substEltTypes.empty())
2296+
candidateSubstType = substEltTypes[0];
2297+
eltTy = handlePackExpansion(elt.getOrigType(), candidateSubstType);
2298+
}
2299+
2300+
packElts.push_back(eltTy);
2301+
});
22232302

22242303
return CanPackType::get(TC.Context, packElts);
22252304
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-emit-silgen -enable-library-evolution -disable-availability-checking %s | %FileCheck %s
2+
3+
// rdar://problem/112474421
4+
5+
public struct G<each T> {
6+
public var property1: (repeat each T) -> ()
7+
public var property2: ((repeat each T)) -> ()
8+
public var property3: (G<repeat each T>) -> ()
9+
}
10+
11+
// We don't attempt to emit a keypath descriptor for property1 and property2,
12+
// and we shouldn't crash while emitting a keypath descriptor for property3.
13+
14+
// CHECK-NOT: sil_property #G.property1<each τ_0_0>
15+
// CHECK-NOT: sil_property #G.property2<each τ_0_0>
16+
// CHECK-LABEL: sil_property #G.property3<each τ_0_0>

0 commit comments

Comments
 (0)