Skip to content

Commit e9a11c0

Browse files
committed
SILGen: Update for PackElementExpr captures
Fixes #68941. Fixes #69282. Fixes #72153. Fixes rdar://110711746. Fixes rdar://119212867. Fixes rdar://124202697.
1 parent a6a10a7 commit e9a11c0

File tree

8 files changed

+208
-9
lines changed

8 files changed

+208
-9
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,14 @@ RValueEmitter::visitPackExpansionExpr(PackExpansionExpr *E,
16671667

16681668
RValue
16691669
RValueEmitter::visitPackElementExpr(PackElementExpr *E, SGFContext C) {
1670+
// If this is a captured pack element reference, just emit the parameter value
1671+
// that was passed to the closure.
1672+
auto found = SGF.OpaqueValues.find(E);
1673+
if (found != SGF.OpaqueValues.end())
1674+
return RValue(SGF, E, SGF.manageOpaqueValue(found->second, E, C));
1675+
1676+
// Otherwise, we're going to project the address of an element from the pack
1677+
// itself.
16701678
FormalEvaluationScope scope(SGF);
16711679

16721680
LValue lv = SGF.emitLValue(E, SGFAccessKind::OwnedObjectRead);
@@ -5972,9 +5980,9 @@ RValue RValueEmitter::visitMakeTemporarilyEscapableExpr(
59725980
}
59735981

59745982
RValue RValueEmitter::visitOpaqueValueExpr(OpaqueValueExpr *E, SGFContext C) {
5975-
assert(SGF.OpaqueValues.count(E) && "Didn't bind OpaqueValueExpr");
5976-
auto value = SGF.OpaqueValues[E];
5977-
return RValue(SGF, E, SGF.manageOpaqueValue(value, E, C));
5983+
auto found = SGF.OpaqueValues.find(E);
5984+
assert(found != SGF.OpaqueValues.end());
5985+
return RValue(SGF, E, SGF.manageOpaqueValue(found->second, E, C));
59785986
}
59795987

59805988
RValue RValueEmitter::visitPropertyWrapperValuePlaceholderExpr(

lib/SILGen/SILGenFunction.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,10 +569,9 @@ void SILGenFunction::emitCaptures(SILLocation loc,
569569
continue;
570570
}
571571

572-
if (capture.isOpaqueValue()) {
573-
OpaqueValueExpr *opaqueValue = capture.getOpaqueValue();
572+
if (capture.isOpaqueValue() || capture.isPackElement()) {
574573
capturedArgs.push_back(
575-
emitRValueAsSingleValue(opaqueValue).ensurePlusOne(*this, loc));
574+
emitRValueAsSingleValue(capture.getExpr()).ensurePlusOne(*this, loc));
576575
continue;
577576
}
578577

lib/SILGen/SILGenFunction.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,9 +2185,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
21852185
emitOpenExistentialExprImpl(e, emitSubExpr);
21862186
}
21872187

2188-
/// Mapping from active opaque value expressions to their values.
2189-
llvm::SmallDenseMap<OpaqueValueExpr *, ManagedValue>
2190-
OpaqueValues;
2188+
/// Mapping from OpaqueValueExpr/PackElementExpr to their values.
2189+
llvm::SmallDenseMap<Expr *, ManagedValue> OpaqueValues;
21912190

21922191
/// A mapping from opaque value expressions to the open-existential
21932192
/// expression that determines them, used while lowering lvalues.

lib/SILGen/SILGenProlog.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,49 @@ static void emitCaptureArguments(SILGenFunction &SGF,
10521052
GenericSignature origGenericSig,
10531053
CapturedValue capture,
10541054
uint16_t ArgNo) {
1055+
if (auto *expr = capture.getPackElement()) {
1056+
SILLocation Loc(expr);
1057+
Loc.markAsPrologue();
1058+
1059+
auto interfaceType = expr->getType()->mapTypeOutOfContext();
1060+
1061+
auto type = SGF.F.mapTypeIntoContext(interfaceType);
1062+
auto &lowering = SGF.getTypeLowering(type);
1063+
SILType ty = lowering.getLoweredType();
1064+
1065+
SILValue arg;
1066+
1067+
auto expansion = SGF.getTypeExpansionContext();
1068+
auto captureKind = SGF.SGM.Types.getDeclCaptureKind(capture, expansion);
1069+
switch (captureKind) {
1070+
case CaptureKind::Constant:
1071+
case CaptureKind::StorageAddress:
1072+
case CaptureKind::Immutable: {
1073+
auto argIndex = SGF.F.begin()->getNumArguments();
1074+
// Non-escaping stored decls are captured as the address of the value.
1075+
auto param = SGF.F.getConventions().getParamInfoForSILArg(argIndex);
1076+
if (SGF.F.getConventions().isSILIndirect(param))
1077+
ty = ty.getAddressType();
1078+
1079+
auto *fArg = SGF.F.begin()->createFunctionArgument(ty, nullptr);
1080+
fArg->setClosureCapture(true);
1081+
1082+
arg = fArg;
1083+
break;
1084+
}
1085+
1086+
case CaptureKind::ImmutableBox:
1087+
case CaptureKind::Box:
1088+
llvm_unreachable("should be impossible");
1089+
}
1090+
1091+
ManagedValue mv = ManagedValue::forBorrowedRValue(arg);
1092+
auto inserted = SGF.OpaqueValues.insert(std::make_pair(expr, mv));
1093+
assert(inserted.second);
1094+
(void) inserted;
1095+
1096+
return;
1097+
}
10551098

10561099
auto *VD = cast<VarDecl>(capture.getDecl());
10571100

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -disable-concrete-type-metadata-mangled-name-accessors)
2+
// RUN: %target-run-simple-swift
3+
4+
// REQUIRES: executable_test
5+
6+
import StdlibUnittest
7+
8+
var captures = TestSuite("VariadicGenericCaptures")
9+
10+
func f1<T>(_ fn: @autoclosure () -> T) {
11+
_ = fn()
12+
}
13+
14+
func f2<T>(_ fn: @autoclosure @escaping () -> T) {
15+
_ = fn()
16+
}
17+
18+
func f3<T>(_ fn: () -> T) {
19+
_ = fn()
20+
}
21+
22+
func f4<T>(_ fn: @escaping () -> T) {
23+
_ = fn()
24+
}
25+
26+
func f5<T: AnyObject>(_ fn: @autoclosure () -> T) {
27+
_ = fn()
28+
}
29+
30+
func f6<T: AnyObject>(_ fn: @autoclosure @escaping () -> T) {
31+
_ = fn()
32+
}
33+
34+
func f7<T: AnyObject>(_ fn: () -> T) {
35+
_ = fn()
36+
}
37+
38+
func f8<T: AnyObject>(_ fn: @escaping () -> T) {
39+
_ = fn()
40+
}
41+
42+
func g1<each T>(_ t: repeat each T) {
43+
repeat f1(each t)
44+
repeat f2(each t)
45+
repeat f3 { each t }
46+
repeat f4 { each t }
47+
repeat _ = ({ each t }())
48+
repeat _ = ({ (each t, each t) }())
49+
}
50+
51+
func g2<each T: AnyObject>(_ t: repeat each T) {
52+
repeat f5(each t)
53+
repeat f6(each t)
54+
repeat f7 { each t }
55+
repeat f8 { each t }
56+
repeat _ = ({ (each t, each t) }())
57+
}
58+
59+
class C {
60+
var x = LifetimeTracked(0)
61+
}
62+
63+
class D: C {}
64+
65+
class E: D {}
66+
67+
captures.test("Test") {
68+
g1(C(), D(), E())
69+
g2(C(), D(), E())
70+
}
71+
72+
runAllTests()
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-emit-silgen -parse-as-library %s | %FileCheck %s
2+
3+
func callee(_ fn: () -> Any) {}
4+
5+
func caller<each T>(_ t: repeat each T) {
6+
repeat callee { each t }
7+
}
8+
9+
// CHECK-LABEL: sil hidden [ossa] @$s26pack_element_expr_captures6calleryyxxQpRvzlF : $@convention(thin) <each T> (@pack_guaranteed Pack{repeat each T}) -> () {
10+
// CHECK: [[FN:%.*]] = function_ref @$s26pack_element_expr_captures6calleryyxxQpRvzlFypyXEfU_ : $@convention(thin) <each τ_0_0><τ_1_0> (@in_guaranteed τ_1_0) -> @out Any
11+
// CHECK: [[ELT_ADDR:%.*]] = pack_element_get {{.*}} of %0 : $*Pack{repeat each T} as $*@pack_element("{{.*}}") each T
12+
// CHECK: [[ELT_COPY:%.*]] = alloc_stack $@pack_element("{{.*}}") each T
13+
// CHECK: copy_addr [[ELT_ADDR]] to [init] [[ELT_COPY]] : $*@pack_element("{{.*}}") each T
14+
// CHECK: [[CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[FN]]<Pack{repeat each T}, @pack_element("{{.*}}") each T>([[ELT_COPY]])
15+
// CHECK: [[CONVERTED:%.*]] = convert_escape_to_noescape [not_guaranteed] %15 : $@callee_guaranteed () -> @out Any to $@noescape @callee_guaranteed () -> @out Any
16+
// CHECK: [[CALLEE:%.*]] = function_ref @$s26pack_element_expr_captures6calleeyyypyXEF : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Any) -> ()
17+
// CHECK: apply [[CALLEE]]([[CONVERTED]]) : $@convention(thin) (@guaranteed @noescape @callee_guaranteed () -> @out Any) -> ()
18+
19+
// CHECK-LABEL: sil private [ossa] @$s26pack_element_expr_captures6calleryyxxQpRvzlFypyXEfU_ : $@convention(thin) <each T><τ_1_0> (@in_guaranteed τ_1_0) -> @out Any {
20+
// CHECK: bb0(%0 : $*Any, %1 : @closureCapture $*τ_1_0):
21+
// CHECK: [[ADDR:%.*]] = init_existential_addr %0 : $*Any, $τ_1_0
22+
// CHECK: copy_addr %1 to [init] [[ADDR]] : $*τ_1_0
23+
// CHECK: return
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
2+
3+
public struct S<each T> {
4+
public var value: (repeat each T)
5+
6+
public init(_ value: repeat each T) {
7+
self.value = (repeat each value)
8+
let getters: (repeat () -> each T) = (repeat { each self.value })
9+
}
10+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking
2+
3+
protocol P {
4+
func evaluate(_ item: Int) -> Bool
5+
}
6+
7+
struct G<each F: P>: P {
8+
init(filters: repeat each F) {
9+
self.filters = (repeat each filters)
10+
}
11+
12+
var filters: (repeat each F)
13+
14+
func evaluate(_ item: Int) -> Bool {
15+
var result = true
16+
17+
(repeat result.and((each filters).evaluate(item)))
18+
19+
return result
20+
}
21+
}
22+
23+
private extension Bool {
24+
mutating func and(_ other: @autoclosure () -> Bool) {
25+
self = self && other()
26+
}
27+
}
28+
29+
struct S1: P {
30+
func evaluate(_ item: Int) -> Bool {
31+
print("S1", item)
32+
return false
33+
}
34+
}
35+
struct S2: P {
36+
func evaluate(_ item: Int) -> Bool {
37+
print("S2", item)
38+
return false
39+
}
40+
}
41+
42+
do {
43+
let filter = G(filters: S1(), S2())
44+
print(filter.evaluate(5))
45+
}

0 commit comments

Comments
 (0)