Skip to content

Commit fc7d9ec

Browse files
authored
Merge pull request #9864 from rjmccall/existential-lvalue-fixes
Various existential l-value fixes
2 parents 2d85fb3 + c7ffdac commit fc7d9ec

File tree

6 files changed

+269
-27
lines changed

6 files changed

+269
-27
lines changed

lib/SILGen/LValue.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class PathComponent {
9797
TupleElementKind, // tuple_element_addr
9898
StructElementKind, // struct_element_addr
9999
OptionalObjectKind, // optional projection
100-
OpenedExistentialKind, // opened opaque existential
100+
OpenOpaqueExistentialKind, // opened opaque existential
101101
AddressorKind, // var/subscript addressor
102102
ValueKind, // random base pointer as an lvalue
103103
KeyPathApplicationKind, // applying a key path
@@ -107,6 +107,7 @@ class PathComponent {
107107
OwnershipKind, // weak pointer remapping
108108
AutoreleasingWritebackKind, // autorelease pointer on set
109109
WritebackPseudoKind, // a fake component to customize writeback
110+
OpenNonOpaqueExistentialKind, // opened class or metatype existential
110111
// Translation LValue kinds (a subtype of logical)
111112
OrigToSubstKind, // generic type substitution
112113
SubstToOrigKind, // generic type substitution

lib/SILGen/SILGenExpr.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,29 +4010,37 @@ void SILGenFunction::emitOpenExistentialExprImpl(
40104010
llvm::function_ref<void(Expr *)> emitSubExpr) {
40114011
Optional<FormalEvaluationScope> writebackScope;
40124012

4013+
Type opaqueValueType = E->getOpaqueValue()->getType()->getRValueType();
4014+
40134015
// Emit the existential value.
4014-
ManagedValue existentialValue;
4016+
SILGenFunction::OpaqueValueState state;
4017+
40154018
AccessKind accessKind;
40164019
if (E->getExistentialValue()->getType()->is<LValueType>()) {
40174020
// Create a writeback scope for the access to the existential lvalue.
40184021
writebackScope.emplace(*this);
40194022

4023+
Type formalRValueType =
4024+
E->getOpaqueValue()->getType()->getLValueOrInOutObjectType();
4025+
40204026
accessKind = E->getExistentialValue()->getLValueAccessKind();
4021-
existentialValue = emitAddressOfLValue(
4022-
E->getExistentialValue(),
4023-
emitLValue(E->getExistentialValue(), accessKind),
4024-
accessKind);
4027+
auto lv = emitLValue(E->getExistentialValue(), accessKind);
4028+
lv = emitOpenExistentialLValue(E, std::move(lv),
4029+
CanArchetypeType(E->getOpenedArchetype()),
4030+
formalRValueType->getCanonicalType(),
4031+
accessKind);
4032+
auto addr = emitAddressOfLValue(E, std::move(lv), accessKind);
4033+
state = {addr, false, false};
40254034
} else {
40264035
accessKind = AccessKind::Read;
4027-
existentialValue = emitRValueAsSingleValue(
4028-
E->getExistentialValue(),
4029-
SGFContext::AllowGuaranteedPlusZero);
4030-
}
4036+
auto existentialValue = emitRValueAsSingleValue(
4037+
E->getExistentialValue(),
4038+
SGFContext::AllowGuaranteedPlusZero);
40314039

4032-
Type opaqueValueType = E->getOpaqueValue()->getType()->getRValueType();
4033-
SILGenFunction::OpaqueValueState state = emitOpenExistential(
4040+
state = emitOpenExistential(
40344041
E, existentialValue, E->getOpenedArchetype(),
40354042
getLoweredType(opaqueValueType), accessKind);
4043+
}
40364044

40374045
// Register the opaque value for the projected existential.
40384046
SILGenFunction::OpaqueValueRAII opaqueValueRAII(

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
975975
/// \param openedArchetype The opened existential archetype.
976976
/// \param loweredOpenedType The lowered type of the projection, which in
977977
/// practice will be the openedArchetype, possibly wrapped in a metatype.
978-
SILGenFunction::OpaqueValueState
978+
OpaqueValueState
979979
emitOpenExistential(SILLocation loc,
980980
ManagedValue existentialValue,
981981
ArchetypeType *openedArchetype,
@@ -1302,6 +1302,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
13021302
ManagedValue emitAddressOfLValue(SILLocation loc, LValue &&src,
13031303
AccessKind accessKind,
13041304
TSanKind tsanKind = TSanKind::None);
1305+
LValue emitOpenExistentialLValue(SILLocation loc,
1306+
LValue &&existentialLV,
1307+
CanArchetypeType openedArchetype,
1308+
CanType formalRValueType,
1309+
AccessKind accessKind);
13051310

13061311
RValue emitLoadOfLValue(SILLocation loc, LValue &&src, SGFContext C,
13071312
bool isGuaranteedValid = false);

lib/SILGen/SILGenLValue.cpp

Lines changed: 217 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,63 @@ ManagedValue LogicalPathComponent::getMaterialized(SILGenFunction &SGF,
227227
SILLocation loc,
228228
ManagedValue base,
229229
AccessKind kind) && {
230+
if (getTypeOfRValue().getSwiftRValueType()->hasOpenedExistential()) {
231+
if (kind == AccessKind::Read) {
232+
// Emit a 'get' into the temporary.
233+
RValue value =
234+
std::move(*this).get(SGF, loc, base, SGFContext());
235+
236+
// Create a temporary.
237+
std::unique_ptr<TemporaryInitialization> temporaryInit =
238+
SGF.emitFormalAccessTemporary(loc,
239+
SGF.getTypeLowering(getTypeOfRValue()));
240+
241+
std::move(value).forwardInto(SGF, loc, temporaryInit.get());
242+
243+
return temporaryInit->getManagedAddress();
244+
}
245+
246+
assert(SGF.InWritebackScope &&
247+
"materializing l-value for modification without writeback scope");
248+
249+
// Clone anything else about the component that we might need in the
250+
// writeback.
251+
auto clonedComponent = clone(SGF, loc);
252+
253+
SILValue mv;
254+
{
255+
FormalEvaluationScope Scope(SGF);
256+
257+
// Otherwise, we need to emit a get and set. Borrow the base for
258+
// the getter.
259+
ManagedValue getterBase =
260+
base ? base.formalAccessBorrow(SGF, loc) : ManagedValue();
261+
262+
// Emit a 'get' into a temporary and then pop the borrow of base.
263+
RValue value =
264+
std::move(*this).get(SGF, loc, getterBase, SGFContext());
265+
266+
mv = std::move(value).forwardAsSingleValue(SGF, loc);
267+
}
268+
269+
auto &TL = SGF.getTypeLowering(getTypeOfRValue());
270+
271+
// Create a temporary.
272+
std::unique_ptr<TemporaryInitialization> temporaryInit =
273+
SGF.emitFormalAccessTemporary(loc, TL);
274+
275+
SGF.emitSemanticStore(loc, mv, temporaryInit->getAddress(),
276+
TL, IsInitialization);
277+
temporaryInit->finishInitialization(SGF);
278+
279+
auto temporary = temporaryInit->getManagedAddress();
280+
281+
// Push a writeback for the temporary.
282+
pushWriteback(SGF, loc, std::move(clonedComponent), base,
283+
MaterializedLValue(temporary));
284+
return temporary.unmanagedBorrow();
285+
}
286+
230287
// If this is just for a read, emit a load into a temporary memory
231288
// location.
232289
if (kind == AccessKind::Read) {
@@ -574,30 +631,44 @@ namespace {
574631
/// A physical path component which projects out an opened archetype
575632
/// from an existential.
576633
class OpenOpaqueExistentialComponent : public PhysicalPathComponent {
577-
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
578-
return {
579-
AbstractionPattern::getOpaque(), type,
580-
SILType::getPrimitiveObjectType(type)
581-
};
634+
CanArchetypeType getOpenedArchetype() const {
635+
return cast<ArchetypeType>(getSubstFormalType());
582636
}
583637
public:
584-
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype)
585-
: PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
586-
OpenedExistentialKind) {}
638+
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype,
639+
LValueTypeData typeData)
640+
: PhysicalPathComponent(typeData, OpenOpaqueExistentialKind) {
641+
assert(getOpenedArchetype() == openedArchetype);
642+
}
587643

588644
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
589645
AccessKind accessKind) && override {
590646
assert(base.getType().isExistentialType() &&
591647
"base for open existential component must be an existential");
592648
assert(base.getType().isAddress() &&
593649
"base value of open-existential component was not an address?");
650+
SILValue addr;
594651

595-
SILValue addr = SGF.B.createOpenExistentialAddr(
652+
auto rep = base.getType().getPreferredExistentialRepresentation(SGF.SGM.M);
653+
switch (rep) {
654+
case ExistentialRepresentation::Opaque:
655+
addr = SGF.B.createOpenExistentialAddr(
596656
loc, base.getValue(), getTypeOfRValue().getAddressType(),
597657
getOpenedExistentialAccessFor(accessKind));
658+
break;
659+
case ExistentialRepresentation::Boxed: {
660+
auto &TL = SGF.getTypeLowering(base.getType());
661+
auto error = SGF.emitLoad(loc, base.getValue(), TL,
662+
SGFContext(), IsNotTake);
663+
addr = SGF.B.createOpenExistentialBox(
664+
loc, error.getValue(), getTypeOfRValue().getAddressType());
665+
break;
666+
}
667+
default:
668+
llvm_unreachable("Bad existential representation for address-only type");
669+
}
598670

599-
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
600-
addr);
671+
SGF.setArchetypeOpeningSite(getOpenedArchetype(), addr);
601672
return ManagedValue::forLValue(addr);
602673
}
603674

@@ -606,6 +677,102 @@ namespace {
606677
}
607678
};
608679

680+
/// A local path component for the payload of a class or metatype existential.
681+
///
682+
/// TODO: Could be physical if we had a way to project out the
683+
/// payload.
684+
class OpenNonOpaqueExistentialComponent : public LogicalPathComponent {
685+
CanArchetypeType OpenedArchetype;
686+
public:
687+
OpenNonOpaqueExistentialComponent(CanArchetypeType openedArchetype,
688+
LValueTypeData typeData)
689+
: LogicalPathComponent(typeData, OpenNonOpaqueExistentialKind),
690+
OpenedArchetype(openedArchetype) {}
691+
692+
AccessKind getBaseAccessKind(SILGenFunction &SGF,
693+
AccessKind kind) const override {
694+
// Always use the same access kind for the base.
695+
return kind;
696+
}
697+
698+
void diagnoseWritebackConflict(LogicalPathComponent *RHS,
699+
SILLocation loc1, SILLocation loc2,
700+
SILGenFunction &SGF) override {
701+
// no useful writeback diagnostics at this point
702+
}
703+
704+
RValue get(SILGenFunction &SGF, SILLocation loc,
705+
ManagedValue base, SGFContext c) && override {
706+
auto refType = base.getType().getObjectType();
707+
auto &TL = SGF.getTypeLowering(refType);
708+
709+
// Load the original value.
710+
auto result = SGF.emitLoad(loc, base.getValue(), TL,
711+
SGFContext(), IsNotTake);
712+
713+
assert(refType.isAnyExistentialType() &&
714+
"base for open existential component must be an existential");
715+
ManagedValue ref;
716+
if (refType.is<ExistentialMetatypeType>()) {
717+
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
718+
== ExistentialRepresentation::Metatype);
719+
ref = ManagedValue::forUnmanaged(
720+
SGF.B.createOpenExistentialMetatype(loc,
721+
result.getUnmanagedValue(),
722+
getTypeOfRValue()));
723+
} else {
724+
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
725+
== ExistentialRepresentation::Class);
726+
ref = SGF.B.createOpenExistentialRef(loc, result, getTypeOfRValue());
727+
}
728+
729+
SGF.setArchetypeOpeningSite(OpenedArchetype, ref.getValue());
730+
731+
return RValue(SGF, loc, getSubstFormalType(), ref);
732+
}
733+
734+
void set(SILGenFunction &SGF, SILLocation loc,
735+
RValue &&value, ManagedValue base) && override {
736+
auto payload = std::move(value).forwardAsSingleValue(SGF, loc);
737+
738+
SmallVector<ProtocolConformanceRef, 2> conformances;
739+
for (auto proto : OpenedArchetype->getConformsTo())
740+
conformances.push_back(ProtocolConformanceRef(proto));
741+
742+
SILValue ref;
743+
if (base.getType().is<ExistentialMetatypeType>()) {
744+
ref = SGF.B.createInitExistentialMetatype(
745+
loc,
746+
payload,
747+
base.getType().getObjectType(),
748+
SGF.getASTContext().AllocateCopy(conformances));
749+
} else {
750+
ref = SGF.B.createInitExistentialRef(
751+
loc,
752+
base.getType().getObjectType(),
753+
getSubstFormalType(),
754+
payload,
755+
SGF.getASTContext().AllocateCopy(conformances));
756+
}
757+
758+
auto &TL = SGF.getTypeLowering(base.getType());
759+
SGF.emitSemanticStore(loc, ref,
760+
base.getValue(), TL, IsNotInitialization);
761+
}
762+
763+
std::unique_ptr<LogicalPathComponent>
764+
clone(SILGenFunction &SGF, SILLocation loc) const override {
765+
LogicalPathComponent *clone =
766+
new OpenNonOpaqueExistentialComponent(OpenedArchetype, getTypeData());
767+
return std::unique_ptr<LogicalPathComponent>(clone);
768+
}
769+
770+
void print(raw_ostream &OS) const override {
771+
OS << "OpenNonOpaqueExistentialComponent(" << OpenedArchetype
772+
<< ", ...)\n";
773+
}
774+
};
775+
609776
/// A physical path component which returns a literal address.
610777
class ValueComponent : public PhysicalPathComponent {
611778
ManagedValue Value;
@@ -1916,9 +2083,12 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
19162083
openedExistentials.erase(known);
19172084

19182085
// Do formal evaluation of the underlying existential lvalue.
1919-
LValue lv = visitRec(opened->getExistentialValue(), accessKind);
1920-
lv.add<OpenOpaqueExistentialComponent>(
1921-
cast<ArchetypeType>(opened->getOpenedArchetype()->getCanonicalType()));
2086+
auto lv = visitRec(opened->getExistentialValue(), accessKind);
2087+
lv = SGF.emitOpenExistentialLValue(
2088+
opened, std::move(lv),
2089+
CanArchetypeType(opened->getOpenedArchetype()),
2090+
e->getType()->getLValueOrInOutObjectType()->getCanonicalType(),
2091+
accessKind);
19222092
return lv;
19232093
}
19242094

@@ -2815,6 +2985,39 @@ ManagedValue SILGenFunction::emitAddressOfLValue(SILLocation loc,
28152985
return ManagedValue::forLValue(addr.getValue());
28162986
}
28172987

2988+
LValue
2989+
SILGenFunction::emitOpenExistentialLValue(SILLocation loc,
2990+
LValue &&lv,
2991+
CanArchetypeType openedArchetype,
2992+
CanType formalRValueType,
2993+
AccessKind accessKind) {
2994+
assert(!formalRValueType->isLValueType());
2995+
LValueTypeData typeData = {
2996+
AbstractionPattern::getOpaque(), formalRValueType,
2997+
getLoweredType(formalRValueType).getObjectType()
2998+
};
2999+
3000+
// Open up the existential.
3001+
auto rep = lv.getTypeOfRValue()
3002+
.getPreferredExistentialRepresentation(SGM.M);
3003+
switch (rep) {
3004+
case ExistentialRepresentation::Opaque:
3005+
case ExistentialRepresentation::Boxed: {
3006+
lv.add<OpenOpaqueExistentialComponent>(openedArchetype, typeData);
3007+
break;
3008+
}
3009+
case ExistentialRepresentation::Metatype:
3010+
case ExistentialRepresentation::Class: {
3011+
lv.add<OpenNonOpaqueExistentialComponent>(openedArchetype, typeData);
3012+
break;
3013+
}
3014+
case ExistentialRepresentation::None:
3015+
llvm_unreachable("cannot open non-existential");
3016+
}
3017+
3018+
return std::move(lv);
3019+
}
3020+
28183021
void SILGenFunction::emitAssignToLValue(SILLocation loc, RValue &&src,
28193022
LValue &&dest) {
28203023
FormalEvaluationScope scope(*this);

0 commit comments

Comments
 (0)