Skip to content

Commit 9accd0d

Browse files
authored
Merge pull request #74039 from slavapestov/pack-element-expr-capture-6.0
[6.0] Implement pack element reference captures
2 parents d4ee434 + 6809dc9 commit 9accd0d

17 files changed

+503
-110
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ template <> struct DenseMapInfo<swift::CapturedValue>;
4141
namespace swift {
4242
class ValueDecl;
4343
class FuncDecl;
44+
class Expr;
4445
class OpaqueValueExpr;
46+
class PackElementExpr;
4547
class VarDecl;
4648
class GenericEnvironment;
49+
class Type;
4750

4851
/// CapturedValue includes both the declaration being captured, along with flags
4952
/// that indicate how it is captured.
@@ -52,7 +55,7 @@ class CapturedValue {
5255

5356
public:
5457
using Storage =
55-
llvm::PointerIntPair<llvm::PointerUnion<ValueDecl*, OpaqueValueExpr*>, 2,
58+
llvm::PointerIntPair<llvm::PointerUnion<ValueDecl *, Expr *>, 2,
5659
unsigned>;
5760

5861
private:
@@ -78,15 +81,7 @@ class CapturedValue {
7881
CapturedValue(ValueDecl *Val, unsigned Flags, SourceLoc Loc)
7982
: Value(Val, Flags), Loc(Loc) {}
8083

81-
private:
82-
// This is only used in TypeLowering when forming Lowered Capture
83-
// Info. OpaqueValueExpr captured value should never show up in the AST
84-
// itself.
85-
//
86-
// NOTE: AbstractClosureExpr::getIsolationCrossing relies upon this and
87-
// asserts that it never sees one of these.
88-
explicit CapturedValue(OpaqueValueExpr *Val, unsigned Flags)
89-
: Value(Val, Flags), Loc(SourceLoc()) {}
84+
CapturedValue(Expr *Val, unsigned Flags);
9085

9186
public:
9287
static CapturedValue getDynamicSelfMetadata() {
@@ -97,36 +92,38 @@ class CapturedValue {
9792
bool isNoEscape() const { return Value.getInt() & IsNoEscape; }
9893

9994
bool isDynamicSelfMetadata() const { return !Value.getPointer(); }
100-
bool isOpaqueValue() const {
101-
return Value.getPointer().is<OpaqueValueExpr *>();
95+
96+
bool isExpr() const {
97+
return Value.getPointer().dyn_cast<Expr *>();
10298
}
10399

100+
bool isPackElement() const;
101+
bool isOpaqueValue() const;
102+
104103
/// Returns true if this captured value is a local capture.
105104
///
106105
/// NOTE: This implies that the value is not dynamic self metadata, since
107106
/// values with decls are the only values that are able to be local captures.
108107
bool isLocalCapture() const;
109108

110-
CapturedValue mergeFlags(CapturedValue cv) {
111-
assert(Value.getPointer() == cv.Value.getPointer() &&
112-
"merging flags on two different value decls");
113-
return CapturedValue(
114-
Storage(Value.getPointer(), getFlags() & cv.getFlags()),
115-
Loc);
109+
CapturedValue mergeFlags(unsigned flags) const {
110+
return CapturedValue(Storage(Value.getPointer(), getFlags() & flags), Loc);
116111
}
117112

118113
ValueDecl *getDecl() const {
119-
assert(Value.getPointer() && "dynamic Self metadata capture does not "
120-
"have a value");
121114
return Value.getPointer().dyn_cast<ValueDecl *>();
122115
}
123116

124-
OpaqueValueExpr *getOpaqueValue() const {
125-
assert(Value.getPointer() && "dynamic Self metadata capture does not "
126-
"have a value");
127-
return Value.getPointer().dyn_cast<OpaqueValueExpr *>();
117+
Expr *getExpr() const {
118+
return Value.getPointer().dyn_cast<Expr *>();
128119
}
129120

121+
OpaqueValueExpr *getOpaqueValue() const;
122+
123+
PackElementExpr *getPackElement() const;
124+
125+
Type getPackElementType() const;
126+
130127
SourceLoc getLoc() const { return Loc; }
131128

132129
unsigned getFlags() const { return Value.getInt(); }

include/swift/Sema/ConstraintSystem.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,6 +2229,10 @@ class ConstraintSystem {
22292229
/// from declared parameters/result and body.
22302230
llvm::MapVector<const ClosureExpr *, FunctionType *> ClosureTypes;
22312231

2232+
/// Maps closures and local functions to the pack expansion expressions they
2233+
/// capture.
2234+
llvm::MapVector<AnyFunctionRef, SmallVector<PackExpansionExpr *, 1>> CapturedExpansions;
2235+
22322236
/// Maps expressions for implied results (e.g implicit 'then' statements,
22332237
/// implicit 'return' statements in single expression body closures) to their
22342238
/// result kind.
@@ -3164,6 +3168,19 @@ class ConstraintSystem {
31643168
return nullptr;
31653169
}
31663170

3171+
SmallVector<PackExpansionExpr *, 1> getCapturedExpansions(AnyFunctionRef func) const {
3172+
auto result = CapturedExpansions.find(func);
3173+
if (result == CapturedExpansions.end())
3174+
return {};
3175+
3176+
return result->second;
3177+
}
3178+
3179+
void setCapturedExpansions(AnyFunctionRef func, SmallVector<PackExpansionExpr *, 1> exprs) {
3180+
assert(CapturedExpansions.count(func) == 0 && "Cannot reset captured expansions");
3181+
CapturedExpansions.insert({func, exprs});
3182+
}
3183+
31673184
TypeVariableType *getKeyPathValueType(const KeyPathExpr *keyPath) const {
31683185
auto result = getKeyPathValueTypeIfAvailable(keyPath);
31693186
assert(result);
@@ -6428,6 +6445,7 @@ class ConjunctionElementProducer : public BindingProducer<ConjunctionElement> {
64286445
///
64296446
/// This includes:
64306447
/// - Not yet resolved outer VarDecls (including closure parameters)
6448+
/// - Outer pack expansions that are not yet fully resolved
64316449
/// - Return statements with a contextual type that has not yet been resolved
64326450
///
64336451
/// This is required because isolated conjunctions, just like single-expression
@@ -6449,6 +6467,7 @@ class TypeVarRefCollector : public ASTWalker {
64496467

64506468
/// Infer the referenced type variables from a given decl.
64516469
void inferTypeVars(Decl *D);
6470+
void inferTypeVars(PackExpansionExpr *);
64526471

64536472
MacroWalking getMacroWalkingBehavior() const override {
64546473
return MacroWalking::Arguments;

lib/AST/CaptureInfo.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,36 @@
1313
#include "swift/AST/CaptureInfo.h"
1414
#include "swift/AST/ASTContext.h"
1515
#include "swift/AST/Decl.h"
16+
#include "swift/AST/Expr.h"
1617
#include "swift/AST/GenericEnvironment.h"
1718
#include "llvm/Support/raw_ostream.h"
1819

1920
using namespace swift;
2021

22+
CapturedValue::CapturedValue(Expr *Val, unsigned Flags)
23+
: Value(Val, Flags), Loc(SourceLoc()) {
24+
assert(isa<OpaqueValueExpr>(Val) || isa<PackElementExpr>(Val));
25+
}
26+
27+
bool CapturedValue::isPackElement() const {
28+
return isExpr() && isa<PackElementExpr>(getExpr());
29+
}
30+
bool CapturedValue::isOpaqueValue() const {
31+
return isExpr() && isa<OpaqueValueExpr>(getExpr());
32+
}
33+
34+
OpaqueValueExpr *CapturedValue::getOpaqueValue() const {
35+
return dyn_cast_or_null<OpaqueValueExpr>(getExpr());
36+
}
37+
38+
PackElementExpr *CapturedValue::getPackElement() const {
39+
return dyn_cast_or_null<PackElementExpr>(getExpr());
40+
}
41+
42+
Type CapturedValue::getPackElementType() const {
43+
return getPackElement()->getType();
44+
}
45+
2146
ArrayRef<CapturedValue>
2247
CaptureInfo::CaptureInfoStorage::getCaptures() const {
2348
return llvm::ArrayRef(this->getTrailingObjects<CapturedValue>(), NumCapturedValues);
@@ -153,7 +178,18 @@ void CaptureInfo::print(raw_ostream &OS) const {
153178

154179
interleave(getCaptures(),
155180
[&](const CapturedValue &capture) {
156-
OS << capture.getDecl()->getBaseName();
181+
if (capture.getDecl())
182+
OS << capture.getDecl()->getBaseName();
183+
else if (capture.isPackElement()) {
184+
OS << "[pack element] ";
185+
capture.getPackElement()->dump(OS);
186+
} else if (capture.isOpaqueValue()) {
187+
OS << "[opaque] ";
188+
capture.getOpaqueValue()->dump(OS);
189+
} else {
190+
OS << "[unknown] ";
191+
assert(false);
192+
}
157193

158194
if (capture.isDirect())
159195
OS << "<direct>";

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,33 +1970,39 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19701970
continue;
19711971
}
19721972

1973-
auto *varDecl = cast<VarDecl>(capture.getDecl());
1973+
auto options = SILParameterInfo::Options();
1974+
1975+
Type type;
1976+
VarDecl *varDecl = nullptr;
1977+
if (auto *expr = capture.getPackElement()) {
1978+
type = expr->getType();
1979+
} else {
1980+
varDecl = cast<VarDecl>(capture.getDecl());
1981+
type = varDecl->getTypeInContext();
1982+
1983+
// If we're capturing a parameter pack, wrap it in a tuple.
1984+
if (type->is<PackExpansionType>()) {
1985+
assert(!cast<ParamDecl>(varDecl)->supportsMutation() &&
1986+
"Cannot capture a pack as an lvalue");
1987+
1988+
SmallVector<TupleTypeElt, 1> elts;
1989+
elts.push_back(type);
1990+
type = TupleType::get(elts, TC.Context);
1991+
}
1992+
1993+
if (isolatedParam == varDecl) {
1994+
options |= SILParameterInfo::Isolated;
1995+
isolatedParam = nullptr;
1996+
}
1997+
}
19741998

1975-
auto type = varDecl->getTypeInContext();
19761999
assert(!type->hasLocalArchetype() ||
19772000
(genericSig && origGenericSig &&
19782001
!genericSig->isEqual(origGenericSig)));
19792002
type = mapTypeOutOfContext(type);
19802003

19812004
auto canType = type->getReducedType(
19822005
genericSig ? genericSig : origGenericSig);
1983-
1984-
auto options = SILParameterInfo::Options();
1985-
if (isolatedParam == varDecl) {
1986-
options |= SILParameterInfo::Isolated;
1987-
isolatedParam = nullptr;
1988-
}
1989-
1990-
// If we're capturing a parameter pack, wrap it in a tuple.
1991-
if (isa<PackExpansionType>(canType)) {
1992-
assert(!cast<ParamDecl>(varDecl)->supportsMutation() &&
1993-
"Cannot capture a pack as an lvalue");
1994-
1995-
SmallVector<TupleTypeElt, 1> elts;
1996-
elts.push_back(canType);
1997-
canType = CanTupleType(TupleType::get(elts, TC.Context));
1998-
}
1999-
20002006
auto &loweredTL =
20012007
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
20022008
expansion);
@@ -2018,6 +2024,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20182024
break;
20192025
}
20202026
case CaptureKind::Box: {
2027+
assert(varDecl);
2028+
20212029
// The type in the box is lowered in the minimal context.
20222030
auto minimalLoweredTy =
20232031
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
@@ -2035,6 +2043,8 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
20352043
break;
20362044
}
20372045
case CaptureKind::ImmutableBox: {
2046+
assert(varDecl);
2047+
20382048
// The type in the box is lowered in the minimal context.
20392049
auto minimalLoweredTy =
20402050
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,

lib/SIL/IR/TypeLowering.cpp

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,19 @@ static bool hasSingletonMetatype(CanType instanceType) {
118118

119119
CaptureKind TypeConverter::getDeclCaptureKind(CapturedValue capture,
120120
TypeExpansionContext expansion) {
121+
if (auto *expr = capture.getPackElement()) {
122+
auto contextTy = expr->getType();
123+
auto &lowering = getTypeLowering(
124+
contextTy, TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
125+
expansion.getResilienceExpansion()));
126+
127+
assert(!contextTy->isNoncopyable() && "Not implemented");
128+
if (!lowering.isAddressOnly())
129+
return CaptureKind::Constant;
130+
131+
return CaptureKind::Immutable;
132+
}
133+
121134
auto decl = capture.getDecl();
122135
auto *var = cast<VarDecl>(decl);
123136
assert(var->hasStorage() &&
@@ -4219,7 +4232,10 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
42194232

42204233
// Recursively collect transitive captures from captured local functions.
42214234
llvm::DenseSet<AnyFunctionRef> visitedFunctions;
4222-
llvm::MapVector<ValueDecl*,CapturedValue> captures;
4235+
4236+
// FIXME: CapturedValue should just be a hash key
4237+
llvm::MapVector<VarDecl *, CapturedValue> varCaptures;
4238+
llvm::MapVector<PackElementExpr *, CapturedValue> packElementCaptures;
42234239

42244240
// If there is a capture of 'self' with dynamic 'Self' type, it goes last so
42254241
// that IRGen can pass dynamic 'Self' metadata.
@@ -4236,9 +4252,29 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
42364252
std::function<void (AnyFunctionRef)> collectFunctionCaptures;
42374253
std::function<void (SILDeclRef)> collectConstantCaptures;
42384254

4255+
auto recordCapture = [&](CapturedValue capture) {
4256+
if (auto *expr = capture.getPackElement()) {
4257+
auto existing = packElementCaptures.find(expr);
4258+
if (existing != packElementCaptures.end()) {
4259+
existing->second = existing->second.mergeFlags(capture.getFlags());
4260+
} else {
4261+
packElementCaptures.insert(std::pair<PackElementExpr *, CapturedValue>(
4262+
expr, capture));
4263+
}
4264+
} else {
4265+
VarDecl *value = cast<VarDecl>(capture.getDecl());
4266+
auto existing = varCaptures.find(value);
4267+
if (existing != varCaptures.end()) {
4268+
existing->second = existing->second.mergeFlags(capture.getFlags());
4269+
} else {
4270+
varCaptures.insert(std::pair<VarDecl *, CapturedValue>(
4271+
value, capture));
4272+
}
4273+
}
4274+
};
4275+
42394276
collectCaptures = [&](CaptureInfo captureInfo, DeclContext *dc) {
42404277
assert(captureInfo.hasBeenComputed());
4241-
42424278
if (captureInfo.hasGenericParamCaptures())
42434279
capturesGenericParams = true;
42444280
if (captureInfo.hasDynamicSelfCapture())
@@ -4253,9 +4289,15 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
42534289
genericEnv.insert(env);
42544290
}
42554291

4256-
SmallVector<CapturedValue, 4> localCaptures;
4257-
captureInfo.getLocalCaptures(localCaptures);
4258-
for (auto capture : localCaptures) {
4292+
for (auto capture : captureInfo.getCaptures()) {
4293+
if (capture.isPackElement()) {
4294+
recordCapture(capture);
4295+
continue;
4296+
}
4297+
4298+
if (!capture.isLocalCapture())
4299+
continue;
4300+
42594301
// If the capture is of another local function, grab its transitive
42604302
// captures instead.
42614303
if (auto capturedFn = getAnyFunctionRefFromCapture(capture)) {
@@ -4367,7 +4409,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
43674409
// If we've already captured the same value already, just merge
43684410
// flags.
43694411
if (selfCapture && selfCapture->getDecl() == capture.getDecl()) {
4370-
selfCapture = selfCapture->mergeFlags(capture);
4412+
selfCapture = selfCapture->mergeFlags(capture.getFlags());
43714413
continue;
43724414

43734415
// Otherwise, record the canonical self capture. It will appear
@@ -4387,13 +4429,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
43874429
}
43884430

43894431
// Collect non-function captures.
4390-
ValueDecl *value = capture.getDecl();
4391-
auto existing = captures.find(value);
4392-
if (existing != captures.end()) {
4393-
existing->second = existing->second.mergeFlags(capture);
4394-
} else {
4395-
captures.insert(std::pair<ValueDecl *, CapturedValue>(value, capture));
4396-
}
4432+
recordCapture(capture);
43974433
}
43984434
};
43994435

@@ -4450,7 +4486,10 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
44504486
collectConstantCaptures(fn);
44514487

44524488
SmallVector<CapturedValue, 4> resultingCaptures;
4453-
for (auto capturePair : captures) {
4489+
for (auto capturePair : varCaptures) {
4490+
resultingCaptures.push_back(capturePair.second);
4491+
}
4492+
for (auto capturePair : packElementCaptures) {
44544493
resultingCaptures.push_back(capturePair.second);
44554494
}
44564495

@@ -4469,7 +4508,7 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
44694508
resultingCaptures.push_back(*selfCapture);
44704509
}
44714510

4472-
// Cache the uniqued set of transitive captures.
4511+
// Cache the result.
44734512
CaptureInfo info(Context, resultingCaptures,
44744513
capturesDynamicSelf, capturesOpaqueValue,
44754514
capturesGenericParams, genericEnv.getArrayRef());

0 commit comments

Comments
 (0)