Skip to content

Commit 9a42ce1

Browse files
committed
SILGen: Open existential lvalues on entry into an OpenExistentialExpr again.
4b25945 changed codegen for lvalue OpenExistentialExprs so that the existential was not opened until the OpaqueValue's lvalue was evaluated, but this is incorrect—we need to open the dynamic type of the existential immediately since it can be used arbitrarily within the subexpression. This caused a regression when evaluating default argument generators on protocol extension methods (rdar://problem/37031037), and would become a bigger problem when we generalize the ability to open existentials.
1 parent d1d0763 commit 9a42ce1

File tree

7 files changed

+73
-54
lines changed

7 files changed

+73
-54
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5091,15 +5091,34 @@ RValue RValueEmitter::emitForceValue(ForceValueExpr *loc, Expr *E,
50915091
void SILGenFunction::emitOpenExistentialExprImpl(
50925092
OpenExistentialExpr *E,
50935093
llvm::function_ref<void(Expr *)> emitSubExpr) {
5094-
Optional<FormalEvaluationScope> writebackScope;
5095-
50965094
// Emit the existential value.
50975095
if (E->getExistentialValue()->getType()->is<LValueType>()) {
5098-
bool inserted = OpaqueValueExprs.insert({E->getOpaqueValue(), E}).second;
5096+
// Open the existential container right away. We need the dynamic type
5097+
// to be opened in order to evaluate the subexpression.
5098+
AccessKind accessKind;
5099+
if (E->hasLValueAccessKind())
5100+
accessKind = E->getLValueAccessKind();
5101+
else
5102+
accessKind = E->getExistentialValue()->getLValueAccessKind();
5103+
auto lv = emitLValue(E->getExistentialValue(), accessKind);
5104+
auto formalOpenedType = E->getOpaqueValue()->getType()
5105+
->getWithoutSpecifierType()
5106+
->getCanonicalType();
5107+
lv = emitOpenExistentialLValue(E, std::move(lv),
5108+
CanArchetypeType(E->getOpenedArchetype()),
5109+
formalOpenedType,
5110+
accessKind);
5111+
5112+
auto addr = emitAddressOfLValue(E, std::move(lv), accessKind);
5113+
bool inserted = OpaqueLValues.insert({E->getOpaqueValue(),
5114+
{addr.getValue(), formalOpenedType}})
5115+
.second;
50995116
(void)inserted;
51005117
assert(inserted && "already have this opened existential?");
51015118

51025119
emitSubExpr(E->getSubExpr());
5120+
assert(OpaqueLValues.count(E->getOpaqueValue()) == 0
5121+
&& "opened existential not removed?");
51035122
return;
51045123
}
51055124

@@ -5126,6 +5145,12 @@ RValue RValueEmitter::visitOpenExistentialExpr(OpenExistentialExpr *E,
51265145
return RValue(SGF, E, *result);
51275146
}
51285147

5148+
Optional<FormalEvaluationScope> scope;
5149+
// Begin an evaluation scope for an lvalue existential opened into an
5150+
// rvalue expression.
5151+
if (E->getExistentialValue()->getType()->is<LValueType>())
5152+
scope.emplace(SGF);
5153+
51295154
return SGF.emitOpenExistentialExpr<RValue>(E,
51305155
[&](Expr *subExpr) -> RValue {
51315156
return visit(subExpr, C);

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,10 +1417,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14171417
llvm::SmallDenseMap<OpaqueValueExpr *, OpaqueValueState>
14181418
OpaqueValues;
14191419

1420-
/// A mapping from opaque value expressions to the open-existential
1421-
/// expression that determines them, used while lowering lvalues.
1422-
llvm::SmallDenseMap<OpaqueValueExpr *, OpenExistentialExpr *>
1423-
OpaqueValueExprs;
1420+
/// A mapping from opaque value lvalue expressions to the address of the
1421+
/// opened value in memory.
1422+
llvm::SmallDenseMap<OpaqueValueExpr *, std::pair<SILValue, CanType>>
1423+
OpaqueLValues;
14241424

14251425
/// RAII object that introduces a temporary binding for an opaque value.
14261426
///

lib/SILGen/SILGenLValue.cpp

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,20 +2208,18 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
22082208
AccessKind accessKind,
22092209
LValueOptions options) {
22102210
// Handle an opaque lvalue that refers to an opened existential.
2211-
auto known = SGF.OpaqueValueExprs.find(e);
2212-
if (known != SGF.OpaqueValueExprs.end()) {
2213-
// Dig the open-existential expression out of the list.
2214-
OpenExistentialExpr *opened = known->second;
2215-
SGF.OpaqueValueExprs.erase(known);
2216-
2217-
// Do formal evaluation of the underlying existential lvalue.
2218-
auto lv = visitRec(opened->getExistentialValue(), accessKind, options);
2219-
lv = SGF.emitOpenExistentialLValue(
2220-
opened, std::move(lv),
2221-
CanArchetypeType(opened->getOpenedArchetype()),
2222-
e->getType()->getWithoutSpecifierType()->getCanonicalType(),
2223-
accessKind);
2224-
return lv;
2211+
auto known = SGF.OpaqueLValues.find(e);
2212+
if (known != SGF.OpaqueLValues.end()) {
2213+
// Dig the opened address out of the list.
2214+
SILValue opened = known->second.first;
2215+
CanType openedType = known->second.second;
2216+
SGF.OpaqueLValues.erase(known);
2217+
2218+
// Continue formal evaluation of the lvalue from this address.
2219+
return LValue::forAddress(ManagedValue::forLValue(opened),
2220+
None,
2221+
AbstractionPattern(openedType),
2222+
openedType);
22252223
}
22262224

22272225
assert(SGF.OpaqueValues.count(e) && "Didn't bind OpaqueValueExpr");
@@ -2513,29 +2511,12 @@ LValue SILGenLValue::visitTupleElementExpr(TupleElementExpr *e,
25132511
LValue SILGenLValue::visitOpenExistentialExpr(OpenExistentialExpr *e,
25142512
AccessKind accessKind,
25152513
LValueOptions options) {
2516-
// If the opaque value is not an lvalue, open the existential immediately.
2517-
if (!e->getOpaqueValue()->getType()->is<LValueType>()) {
2518-
return SGF.emitOpenExistentialExpr<LValue>(e,
2519-
[&](Expr *subExpr) -> LValue {
2520-
return visitRec(subExpr,
2521-
accessKind,
2522-
options);
2523-
});
2524-
}
2525-
2526-
// Record the fact that we're opening this existential. The actual
2527-
// opening operation will occur when we see the OpaqueValueExpr.
2528-
bool inserted = SGF.OpaqueValueExprs.insert({e->getOpaqueValue(), e}).second;
2529-
(void)inserted;
2530-
assert(inserted && "already have this opened existential?");
2531-
2532-
// Visit the subexpression.
2533-
LValue lv = visitRec(e->getSubExpr(), accessKind, options);
2534-
2535-
// Sanity check that we did see the OpaqueValueExpr.
2536-
assert(SGF.OpaqueValueExprs.count(e->getOpaqueValue()) == 0 &&
2537-
"opened existential not removed?");
2538-
return lv;
2514+
return SGF.emitOpenExistentialExpr<LValue>(e,
2515+
[&](Expr *subExpr) -> LValue {
2516+
return visitRec(subExpr,
2517+
accessKind,
2518+
options);
2519+
});
25392520
}
25402521

25412522
static LValueTypeData

test/SILGen/assignment.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ protocol P {
4343
// CHECK-LABEL: sil hidden @$S10assignment15copyRightToLeft1pyAA1P_pz_tF : $@convention(thin) (@inout P) -> () {
4444
func copyRightToLeft(p: inout P) {
4545
// CHECK: bb0(%0 : @trivial $*P):
46+
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*P
47+
// CHECK: [[WRITE_OPEN:%.*]] = open_existential_addr mutable_access [[WRITE]]
4648
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] %0 : $*P
4749
// CHECK: [[READ_OPEN:%.*]] = open_existential_addr immutable_access [[READ]]
4850
// CHECK: end_access [[READ]] : $*P
49-
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*P
50-
// CHECK: [[WRITE_OPEN:%.*]] = open_existential_addr mutable_access [[WRITE]]
5151
// CHECK: end_access [[WRITE]] : $*P
5252
p.left = p.right
5353
}

test/SILGen/class_bound_protocols.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,22 +192,23 @@ func takesInheritsMutatingMethod(x: inout InheritsMutatingMethod,
192192
// CHECK-NEXT: [[X_PAYLOAD:%.*]] = open_existential_ref [[X_VALUE]] : $InheritsMutatingMethod to $@opened("{{.*}}") InheritsMutatingMethod
193193
// CHECK-NEXT: [[TEMPORARY:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
194194
// CHECK-NEXT: store [[X_PAYLOAD]] to [init] [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
195-
// CHECK-NEXT: [[X_PAYLOAD_RELOADED:%.*]] = load [take] [[TEMPORARY]]
195+
// CHECK-NEXT: [[X_PAYLOAD_RELOADED:%.*]] = load_borrow [[TEMPORARY]]
196196
//
197197
// ** *NOTE* This extra copy is here since RValue invariants enforce that all
198198
// ** loadable objects are actually loaded. So we form the RValue and
199199
// ** load... only to then need to store the value back in a stack location to
200200
// ** pass to an in_guaranteed method. PredictableMemOpts is able to handle this
201201
// ** type of temporary codegen successfully.
202202
// CHECK-NEXT: [[TEMPORARY_2:%.*]] = alloc_stack $@opened("{{.*}}") InheritsMutatingMethod
203-
// CHECK-NEXT: store [[X_PAYLOAD_RELOADED:%.*]] to [init] [[TEMPORARY_2]]
203+
// CHECK-NEXT: store_borrow [[X_PAYLOAD_RELOADED:%.*]] to [[TEMPORARY_2]]
204204
//
205205
// CHECK-NEXT: [[METHOD:%.*]] = witness_method $@opened("{{.*}}") InheritsMutatingMethod, #HasMutatingMethod.mutatingCounter!getter.1 : <Self where Self : HasMutatingMethod> (Self) -> () -> Value, [[X_PAYLOAD]] : $@opened("{{.*}}") InheritsMutatingMethod : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@in_guaranteed τ_0_0) -> Value
206206
// CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[METHOD]]<@opened("{{.*}}") InheritsMutatingMethod>([[TEMPORARY_2]]) : $@convention(witness_method: HasMutatingMethod) <τ_0_0 where τ_0_0 : HasMutatingMethod> (@in_guaranteed τ_0_0) -> Value
207-
// CHECK-NEXT: destroy_addr [[TEMPORARY_2]] : $*@opened("{{.*}}") InheritsMutatingMethod
208207
// CHECK-NEXT: dealloc_stack [[TEMPORARY_2]]
209-
// CHECK-NEXT: end_access [[X_ADDR]] : $*InheritsMutatingMethod
208+
// CHECK-NEXT: end_borrow [[X_PAYLOAD_RELOADED]]
210209
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[RESULT]] : $*Value
210+
// CHECK-NEXT: destroy_addr [[TEMPORARY]]
211+
// CHECK-NEXT: end_access [[X_ADDR]]
211212
// CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
212213
// CHECK-NEXT: dealloc_stack [[RESULT_BOX]] : $*Value
213214
_ = x.mutatingCounter

test/SILGen/properties.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,12 +1190,12 @@ protocol NonmutatingProtocol {
11901190
// CHECK-NEXT: [[C_FIELD_PAYLOAD:%.*]] = open_existential_addr immutable_access [[C_FIELD_BOX]] : $*NonmutatingProtocol to $*@opened("{{.*}}") NonmutatingProtocol
11911191
// CHECK-NEXT: [[C_FIELD_COPY:%.*]] = alloc_stack $@opened("{{.*}}") NonmutatingProtocol
11921192
// CHECK-NEXT: copy_addr [[C_FIELD_PAYLOAD]] to [initialization] [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
1193-
// CHECK-NEXT: destroy_addr [[C_FIELD_BOX]] : $*NonmutatingProtocol
1194-
// CHECK-NEXT: destroy_value [[C]] : $ReferenceType
11951193
// CHECK-NEXT: [[GETTER:%.*]] = witness_method $@opened("{{.*}}") NonmutatingProtocol, #NonmutatingProtocol.x!getter.1 : <Self where Self : NonmutatingProtocol> (Self) -> () -> Int, [[C_FIELD_PAYLOAD]] : $*@opened("{{.*}}") NonmutatingProtocol : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int
11961194
// CHECK-NEXT: [[RESULT_VALUE:%.*]] = apply [[GETTER]]<@opened("{{.*}}") NonmutatingProtocol>([[C_FIELD_COPY]]) : $@convention(witness_method: NonmutatingProtocol) <τ_0_0 where τ_0_0 : NonmutatingProtocol> (@in_guaranteed τ_0_0) -> Int
11971195
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[UNINIT]] : $*Int
11981196
// CHECK-NEXT: destroy_addr [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
1197+
// CHECK-NEXT: destroy_addr [[C_FIELD_BOX]] : $*NonmutatingProtocol
1198+
// CHECK-NEXT: destroy_value [[C]] : $ReferenceType
11991199
// CHECK-NEXT: dealloc_stack [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
12001200
// CHECK-NEXT: dealloc_stack [[C_FIELD_BOX]] : $*NonmutatingProtocol
12011201
// CHECK-NEXT: dealloc_stack [[RESULT]] : $*Int

test/SILGen/protocols.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ func use_subscript_rvalue_get(_ i : Int) -> Int {
2626
// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*SubscriptableGet to $*[[OPENED:@opened(.*) SubscriptableGet]]
2727
// CHECK: [[ALLOCSTACK:%[0-9]+]] = alloc_stack $[[OPENED]]
2828
// CHECK: copy_addr [[PROJ]] to [initialization] [[ALLOCSTACK]] : $*[[OPENED]]
29-
// CHECK-NEXT: end_access [[READ]] : $*SubscriptableGet
3029
// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #SubscriptableGet.subscript!getter.1
3130
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[METH]]<[[OPENED]]>(%0, [[ALLOCSTACK]])
3231
// CHECK-NEXT: destroy_addr [[ALLOCSTACK]]
32+
// CHECK-NEXT: end_access [[READ]] : $*SubscriptableGet
3333
// CHECK-NEXT: dealloc_stack [[ALLOCSTACK]] : $*[[OPENED]]
3434
// CHECK-NEXT: return [[RESULT]]
3535

@@ -133,9 +133,9 @@ func use_property_rvalue_get() -> Int {
133133
// CHECK: [[PROJ:%[0-9]+]] = open_existential_addr immutable_access [[READ]] : $*PropertyWithGetter to $*[[OPENED:@opened(.*) PropertyWithGetter]]
134134
// CHECK: [[COPY:%.*]] = alloc_stack $[[OPENED]]
135135
// CHECK-NEXT: copy_addr [[PROJ]] to [initialization] [[COPY]] : $*[[OPENED]]
136-
// CHECK-NEXT: end_access [[READ]] : $*PropertyWithGetter
137136
// CHECK-NEXT: [[METH:%[0-9]+]] = witness_method $[[OPENED]], #PropertyWithGetter.a!getter.1
138137
// CHECK-NEXT: apply [[METH]]<[[OPENED]]>([[COPY]])
138+
// CHECK: end_access [[READ]] : $*PropertyWithGetter
139139

140140
func use_property_lvalue_get() -> Int {
141141
return propertyGetSet.b
@@ -458,3 +458,15 @@ public func test(_ p: Proto) {
458458
// CHECK-LABEL: sil_witness_table hidden StructWithStoredClassProperty: PropertyWithGetter module protocols {
459459
// CHECK-NEXT: method #PropertyWithGetter.a!getter.1: {{.*}} : @$S9protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSivgTW
460460
// CHECK-NEXT: }
461+
462+
//
463+
// rdar://problem/37031037
464+
//
465+
466+
protocol MethodWithDefaultArgGenerator {}
467+
extension MethodWithDefaultArgGenerator {
468+
mutating func foo(_ x: Int = 0) {}
469+
}
470+
func invokeMethodWithDefaultArg(x: inout MethodWithDefaultArgGenerator) {
471+
x.foo()
472+
}

0 commit comments

Comments
 (0)