Skip to content

Commit dc477a0

Browse files
authored
Merge pull request #64167 from rjmccall/variadic-results
Implement the caller side of return types containing variadic packs
2 parents 75c1b6e + 81f11c1 commit dc477a0

17 files changed

+771
-97
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,10 +277,18 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
277277
/// Map a generic parameter type to a contextual type.
278278
Type mapTypeIntoContext(GenericTypeParamType *type) const;
279279

280-
/// Map a type containing parameter packs to a contextual type
281-
/// in the opened element generic context.
280+
/// Map an interface type containing parameter packs to a contextual
281+
/// type in the opened element generic context.
282282
Type mapPackTypeIntoElementContext(Type type) const;
283283

284+
/// Map a contextual type containing parameter packs to a contextual
285+
/// type in the opened element generic context.
286+
Type mapContextualPackTypeIntoElementContext(Type type) const;
287+
288+
/// Map a contextual type containing parameter packs to a contextual
289+
/// type in the opened element generic context.
290+
CanType mapContextualPackTypeIntoElementContext(CanType type) const;
291+
284292
/// Map a type containing pack element type parameters to a contextual
285293
/// type in the pack generic context.
286294
Type mapElementTypeIntoPackContext(Type type) const;

include/swift/AST/Types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6829,6 +6829,7 @@ class PackType final : public TypeBase, public llvm::FoldingSetNode,
68296829
};
68306830
BEGIN_CAN_TYPE_WRAPPER(PackType, Type)
68316831
static CanPackType get(const ASTContext &ctx, ArrayRef<CanType> elements);
6832+
static CanPackType get(const ASTContext &ctx, CanTupleEltTypeArrayRef elts);
68326833

68336834
CanType getElementType(unsigned elementNo) const {
68346835
return CanType(getPointer()->getElementType(elementNo));
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//===- IndexedViewRange.h - Iterators for indexed projections ---*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines IndexedViewRange, a template class which makes it
14+
// easy to define a range for a "collection" that is normally just vended
15+
// with an indexed accessor.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_BASIC_INDEXEDVIEWRANGE_H
20+
#define SWIFT_BASIC_INDEXEDVIEWRANGE_H
21+
22+
#include <iterator>
23+
#include <memory>
24+
#include "llvm/ADT/iterator_range.h"
25+
26+
namespace swift {
27+
28+
/// An iterator over a range of values provided by an indexed accessor
29+
/// on a base type.
30+
template <class BaseType, class ProjectedType,
31+
ProjectedType (&Project)(BaseType, size_t)>
32+
class IndexedViewIterator {
33+
public:
34+
using value_type = ProjectedType;
35+
using reference = ProjectedType;
36+
using pointer = void;
37+
using difference_type = ptrdiff_t;
38+
using iterator_category = std::random_access_iterator_tag;
39+
private:
40+
BaseType Base;
41+
size_t Index;
42+
public:
43+
IndexedViewIterator(BaseType base, size_t index)
44+
: Base(base), Index(index) {}
45+
public:
46+
ProjectedType operator*() const { return Project(Base, Index); }
47+
ProjectedType operator->() const { return Project(Base, Index); }
48+
IndexedViewIterator &operator++() { Index++; return *this; }
49+
IndexedViewIterator operator++(int) { return iterator(Base, Index++); }
50+
IndexedViewIterator &operator--() { Index--; return *this; }
51+
IndexedViewIterator operator--(int) { return iterator(Base, Index--); }
52+
bool operator==(IndexedViewIterator rhs) const { return Index == rhs.Index; }
53+
bool operator!=(IndexedViewIterator rhs) const { return Index != rhs.Index; }
54+
55+
IndexedViewIterator &operator+=(difference_type i) {
56+
Index += i;
57+
return *this;
58+
}
59+
IndexedViewIterator operator+(difference_type i) const {
60+
return IndexedViewIterator(Base, Index + i);
61+
}
62+
friend IndexedViewIterator operator+(difference_type i,
63+
IndexedViewIterator rhs) {
64+
return IndexedViewIterator(rhs.Base, rhs.Index + i);
65+
}
66+
IndexedViewIterator &operator-=(difference_type i) {
67+
Index -= i;
68+
return *this;
69+
}
70+
IndexedViewIterator operator-(difference_type i) const {
71+
return IndexedViewIterator(Base, Index - i);
72+
}
73+
difference_type operator-(IndexedViewIterator rhs) const {
74+
return Index - rhs.Index;
75+
}
76+
ProjectedType operator[](difference_type i) const {
77+
return Project(Base, Index + i);
78+
}
79+
bool operator<(IndexedViewIterator rhs) const {
80+
return Index < rhs.Index;
81+
}
82+
bool operator<=(IndexedViewIterator rhs) const {
83+
return Index <= rhs.Index;
84+
}
85+
bool operator>(IndexedViewIterator rhs) const {
86+
return Index > rhs.Index;
87+
}
88+
bool operator>=(IndexedViewIterator rhs) const {
89+
return Index >= rhs.Index;
90+
}
91+
};
92+
93+
template <class BaseType, class ProjectedType,
94+
ProjectedType (&Project)(BaseType, size_t)>
95+
using IndexedViewRange =
96+
llvm::iterator_range<IndexedViewIterator<BaseType, ProjectedType, Project>>;
97+
98+
} // end namespace swift
99+
100+
#endif // SWIFT_BASIC_INDEXEDVIEWRANGE_H

include/swift/SIL/AbstractionPattern.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef SWIFT_SIL_ABSTRACTIONPATTERN_H
1919
#define SWIFT_SIL_ABSTRACTIONPATTERN_H
2020

21+
#include "swift/Basic/IndexedViewRange.h"
2122
#include "swift/AST/Decl.h"
2223
#include "swift/AST/Types.h"
2324

@@ -1332,6 +1333,17 @@ class AbstractionPattern {
13321333
llvm_unreachable("bad kind");
13331334
}
13341335

1336+
static AbstractionPattern
1337+
projectTupleElementType(const AbstractionPattern *base, size_t index) {
1338+
return base->getTupleElementType(index);
1339+
}
1340+
1341+
IndexedViewRange<const AbstractionPattern *, AbstractionPattern,
1342+
projectTupleElementType> getTupleElementTypes() const {
1343+
assert(isTuple());
1344+
return { { this, 0 }, { this, getNumTupleElements() } };
1345+
}
1346+
13351347
/// Is the given pack type a valid substitution of this abstraction
13361348
/// pattern?
13371349
bool matchesPack(CanPackType substType);
@@ -1472,6 +1484,8 @@ class AbstractionPattern {
14721484
void forEachPackExpandedComponent(
14731485
llvm::function_ref<void(AbstractionPattern pattern)> fn) const;
14741486

1487+
SmallVector<AbstractionPattern, 4> getPackExpandedComponents() const;
1488+
14751489
/// If this pattern refers to a foreign ObjC method that was imported as
14761490
/// async, return the bridged-back-to-ObjC completion handler type.
14771491
CanType getObjCMethodAsyncCompletionHandlerForeignType(

lib/AST/ASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3303,6 +3303,12 @@ CanPackType CanPackType::get(const ASTContext &C, ArrayRef<CanType> elements) {
33033303
return CanPackType(PackType::get(C, ncElements));
33043304
}
33053305

3306+
CanPackType CanPackType::get(const ASTContext &C,
3307+
CanTupleEltTypeArrayRef elements) {
3308+
SmallVector<Type, 8> ncElements(elements.begin(), elements.end());
3309+
return CanPackType(PackType::get(C, ncElements));
3310+
}
3311+
33063312
PackType *PackType::get(const ASTContext &C, ArrayRef<Type> elements) {
33073313
RecursiveTypeProperties properties;
33083314
bool isCanonical = true;

lib/AST/GenericEnvironment.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,29 @@ Type GenericEnvironment::mapTypeIntoContext(GenericTypeParamType *type) const {
583583
return result;
584584
}
585585

586+
Type
587+
GenericEnvironment::mapContextualPackTypeIntoElementContext(Type type) const {
588+
if (!type->hasArchetype()) return type;
589+
590+
// FIXME: this is potentially wrong if there are multiple
591+
// openings in play at once, because we really shouldn't touch
592+
// other element archetypes.
593+
return mapPackTypeIntoElementContext(type->mapTypeOutOfContext());
594+
}
595+
596+
CanType
597+
GenericEnvironment::mapContextualPackTypeIntoElementContext(CanType type) const {
598+
if (!type->hasArchetype()) return type;
599+
600+
// FIXME: this is potentially wrong if there are multiple
601+
// openings in play at once, because we really shouldn't touch
602+
// other element archetypes.
603+
// FIXME: if we do this properly, there's no way for this rewrite
604+
// to produce a non-canonical type.
605+
return mapPackTypeIntoElementContext(type->mapTypeOutOfContext())
606+
->getCanonicalType();
607+
}
608+
586609
Type
587610
GenericEnvironment::mapPackTypeIntoElementContext(Type type) const {
588611
assert(getKind() == Kind::OpenedElement);

lib/AST/ParameterPack.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,6 @@ bool SILPackType::containsPackExpansionType() const {
478478
CanPackType
479479
CanTupleType::getInducedPackTypeImpl(CanTupleType tuple, unsigned start, unsigned count) {
480480
assert(start + count <= tuple->getNumElements() && "range out of range");
481-
482481
auto &ctx = tuple->getASTContext();
483-
if (count == 0) return CanPackType::get(ctx, {});
484-
485-
SmallVector<CanType, 4> eltTypes;
486-
eltTypes.reserve(count);
487-
for (unsigned i = start, e = start + count; i != e; ++i)
488-
eltTypes.push_back(tuple.getElementType(i));
489-
return CanPackType::get(ctx, eltTypes);
482+
return CanPackType::get(ctx, tuple.getElementTypes().slice(start, count));
490483
}

lib/IRGen/GenPack.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,7 @@ static llvm::Value *emitPackExpansionElementMetadata(
336336
// Replace pack archetypes with element archetypes in the pattern type.
337337
auto instantiatedPatternTy =
338338
context.environment
339-
->mapPackTypeIntoElementContext(patternTy->mapTypeOutOfContext())
340-
->getCanonicalType();
339+
->mapContextualPackTypeIntoElementContext(patternTy);
341340

342341
// Emit the element metadata.
343342
auto element = IGF.emitTypeMetadataRef(instantiatedPatternTy, request)
@@ -513,9 +512,7 @@ static llvm::Value *emitPackExpansionElementWitnessTable(
513512

514513
// Replace pack archetypes with element archetypes in the pattern type.
515514
auto instantiatedPatternTy =
516-
context.environment
517-
->mapPackTypeIntoElementContext(patternTy->mapTypeOutOfContext())
518-
->getCanonicalType();
515+
context.environment->mapContextualPackTypeIntoElementContext(patternTy);
519516
auto instantiatedConformance =
520517
context.environment->getGenericSignature()->lookupConformance(
521518
instantiatedPatternTy, conformance.getRequirement());

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,15 @@ AbstractionPattern AbstractionPattern::getPackExpansionCountType() const {
588588
llvm_unreachable("bad kind");
589589
}
590590

591+
SmallVector<AbstractionPattern, 4>
592+
AbstractionPattern::getPackExpandedComponents() const {
593+
SmallVector<AbstractionPattern, 4> result;
594+
forEachPackExpandedComponent([&](AbstractionPattern pattern) {
595+
result.push_back(pattern);
596+
});
597+
return result;
598+
}
599+
591600
void AbstractionPattern::forEachPackExpandedComponent(
592601
llvm::function_ref<void (AbstractionPattern)> fn) const {
593602
assert(isPackExpansion());

lib/SILGen/Initialization.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,31 @@ class Initialization {
122122
llvm_unreachable("Must implement if canPerformPackExpansionInitialization"
123123
"returns true");
124124
}
125+
126+
/// Given that this supports pack expansion initialization, can it
127+
/// perform *in place* pack expansion initialization by producing
128+
/// a pack element of the given type?
129+
///
130+
/// The dominance relationship gets a little screwed up here; only
131+
/// return true if it's okay for the address to be written into a
132+
/// pack and then initialized later.
133+
virtual bool
134+
canPerformInPlacePackInitialization(GenericEnvironment *env,
135+
SILType eltAddrTy) const {
136+
return false;
137+
}
138+
139+
/// Given that this supports in-place pack expansion initialization,
140+
/// return the address of the storage.
141+
///
142+
/// For convenience, the same element type that was accepted before
143+
/// is passed again.
144+
virtual SILValue getAddressForInPlacePackInitialization(SILGenFunction &SGF,
145+
SILLocation loc,
146+
SILType eltAddrTy) {
147+
llvm_unreachable("Must implement if canPerformInPlacePackInitialization"
148+
"returns true");
149+
}
125150

126151
/// Return true if we can get the addresses of elements with the
127152
/// 'splitIntoTupleElements' method. Subclasses can override this to
@@ -365,6 +390,13 @@ class InPlacePackExpansionInitialization : public Initialization {
365390
SILValue indexWithinComponent,
366391
llvm::function_ref<void(Initialization *into)> fn) override;
367392

393+
bool canPerformInPlacePackInitialization(GenericEnvironment *env,
394+
SILType eltAddrTy) const override;
395+
396+
SILValue getAddressForInPlacePackInitialization(SILGenFunction &SGF,
397+
SILLocation loc,
398+
SILType eltAddrTy) override;
399+
368400
virtual CanPackExpansionType getLoweredExpansionType() const = 0;
369401
virtual CleanupHandle enterPartialDestroyCleanup(SILGenFunction &SGF,
370402
SILValue indexWithinComponent) = 0;

0 commit comments

Comments
 (0)