Skip to content

Commit f310e5d

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 4e7b4de commit f310e5d

File tree

7 files changed

+73
-55
lines changed

7 files changed

+73
-55
lines changed

lib/SILGen/SILGenExpr.cpp

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

51005117
emitSubExpr(E->getSubExpr());
5118+
assert(OpaqueLValues.count(E->getOpaqueValue()) == 0
5119+
&& "opened existential not removed?");
51015120
return;
51025121
}
51035122

@@ -5124,6 +5143,12 @@ RValue RValueEmitter::visitOpenExistentialExpr(OpenExistentialExpr *E,
51245143
return RValue(SGF, E, *result);
51255144
}
51265145

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

lib/SILGen/SILGenFunction.h

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

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

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

lib/SILGen/SILGenLValue.cpp

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2262,20 +2262,18 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
22622262
AccessKind accessKind,
22632263
LValueOptions options) {
22642264
// Handle an opaque lvalue that refers to an opened existential.
2265-
auto known = SGF.OpaqueValueExprs.find(e);
2266-
if (known != SGF.OpaqueValueExprs.end()) {
2267-
// Dig the open-existential expression out of the list.
2268-
OpenExistentialExpr *opened = known->second;
2269-
SGF.OpaqueValueExprs.erase(known);
2270-
2271-
// Do formal evaluation of the underlying existential lvalue.
2272-
auto lv = visitRec(opened->getExistentialValue(), accessKind, options);
2273-
lv = SGF.emitOpenExistentialLValue(
2274-
opened, std::move(lv),
2275-
CanArchetypeType(opened->getOpenedArchetype()),
2276-
e->getType()->getWithoutSpecifierType()->getCanonicalType(),
2277-
accessKind);
2278-
return lv;
2265+
auto known = SGF.OpaqueLValues.find(e);
2266+
if (known != SGF.OpaqueLValues.end()) {
2267+
// Dig the opened address out of the list.
2268+
SILValue opened = known->second.first;
2269+
CanType openedType = known->second.second;
2270+
SGF.OpaqueLValues.erase(known);
2271+
2272+
// Continue formal evaluation of the lvalue from this address.
2273+
return LValue::forAddress(ManagedValue::forLValue(opened),
2274+
None,
2275+
AbstractionPattern(openedType),
2276+
openedType);
22792277
}
22802278

22812279
assert(SGF.OpaqueValues.count(e) && "Didn't bind OpaqueValueExpr");
@@ -2567,29 +2565,12 @@ LValue SILGenLValue::visitTupleElementExpr(TupleElementExpr *e,
25672565
LValue SILGenLValue::visitOpenExistentialExpr(OpenExistentialExpr *e,
25682566
AccessKind accessKind,
25692567
LValueOptions options) {
2570-
// If the opaque value is not an lvalue, open the existential immediately.
2571-
if (!e->getOpaqueValue()->getType()->is<LValueType>()) {
2572-
return SGF.emitOpenExistentialExpr<LValue>(e,
2573-
[&](Expr *subExpr) -> LValue {
2574-
return visitRec(subExpr,
2575-
accessKind,
2576-
options);
2577-
});
2578-
}
2579-
2580-
// Record the fact that we're opening this existential. The actual
2581-
// opening operation will occur when we see the OpaqueValueExpr.
2582-
bool inserted = SGF.OpaqueValueExprs.insert({e->getOpaqueValue(), e}).second;
2583-
(void)inserted;
2584-
assert(inserted && "already have this opened existential?");
2585-
2586-
// Visit the subexpression.
2587-
LValue lv = visitRec(e->getSubExpr(), accessKind, options);
2588-
2589-
// Sanity check that we did see the OpaqueValueExpr.
2590-
assert(SGF.OpaqueValueExprs.count(e->getOpaqueValue()) == 0 &&
2591-
"opened existential not removed?");
2592-
return lv;
2568+
return SGF.emitOpenExistentialExpr<LValue>(e,
2569+
[&](Expr *subExpr) -> LValue {
2570+
return visitRec(subExpr,
2571+
accessKind,
2572+
options);
2573+
});
25932574
}
25942575

25952576
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 @_T010assignment15copyRightToLeftyAA1P_pz1p_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 & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,23 +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: [[X_VALUE:%.*]] = load [take] [[TEMPORARY_2]] : $*@opened("{{.*}}") InheritsMutatingMethod
208-
// CHECK-NEXT: destroy_value [[X_VALUE]] : $@opened("{{.*}}") InheritsMutatingMethod
209207
// CHECK-NEXT: dealloc_stack [[TEMPORARY_2]]
210-
// CHECK-NEXT: end_access [[X_ADDR]] : $*InheritsMutatingMethod
208+
// CHECK-NEXT: end_borrow [[X_PAYLOAD_RELOADED]]
211209
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[RESULT]] : $*Value
210+
// CHECK-NEXT: destroy_addr [[TEMPORARY]]
211+
// CHECK-NEXT: end_access [[X_ADDR]]
212212
// CHECK-NEXT: dealloc_stack [[TEMPORARY]] : $*@opened("{{.*}}") InheritsMutatingMethod
213213
// CHECK-NEXT: dealloc_stack [[RESULT_BOX]] : $*Value
214214
_ = x.mutatingCounter

test/SILGen/properties.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,11 +1190,11 @@ 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
11941193
// 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
11951194
// 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
11961195
// CHECK-NEXT: destroy_addr [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
1197-
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[UNINIT]] : $*Int
1196+
// CHECK-NEXT: assign [[RESULT_VALUE]] to [[UNINIT]]
1197+
// CHECK-NEXT: destroy_addr [[C_FIELD_BOX]]
11981198
// CHECK-NEXT: dealloc_stack [[C_FIELD_COPY]] : $*@opened("{{.*}}") NonmutatingProtocol
11991199
// CHECK-NEXT: dealloc_stack [[C_FIELD_BOX]] : $*NonmutatingProtocol
12001200
// 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
@@ -457,3 +457,15 @@ public func test(_ p: Proto) {
457457
// CHECK-LABEL: sil_witness_table hidden StructWithStoredClassProperty: PropertyWithGetter module protocols {
458458
// CHECK-NEXT: method #PropertyWithGetter.a!getter.1: {{.*}} : @_T09protocols29StructWithStoredClassPropertyVAA0fC6GetterA2aDP1aSivgTW
459459
// CHECK-NEXT: }
460+
461+
//
462+
// rdar://problem/37031037
463+
//
464+
465+
protocol MethodWithDefaultArgGenerator {}
466+
extension MethodWithDefaultArgGenerator {
467+
mutating func foo(_ x: Int = 0) {}
468+
}
469+
func invokeMethodWithDefaultArg(x: inout MethodWithDefaultArgGenerator) {
470+
x.foo()
471+
}

0 commit comments

Comments
 (0)