Skip to content

Commit 4aa2878

Browse files
slavapestovrjmccall
authored andcommitted
SILGen: Introduce OpenClassExistentialComponent
This is an LValue component whose value is the class reference inside of a class existential. Unlike OpenOpaqueExistentialComponent, this is a logical component, with a "writeback" consisting of wrapping the new class reference in a class existential having the same conformances as the original. This is slightly awkward, but adding "by-address" operations on class existentials, and projecting the payload out is a big change and might not make sense for other reasons.
1 parent 78eecc4 commit 4aa2878

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
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+
OpenClassExistentialKind, // opened class existential
110111
// Translation LValue kinds (a subtype of logical)
111112
OrigToSubstKind, // generic type substitution
112113
SubstToOrigKind, // generic type substitution

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,10 @@ 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+
AccessKind accessKind);
13051309

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

lib/SILGen/SILGenLValue.cpp

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ namespace {
583583
public:
584584
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype)
585585
: PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
586-
OpenedExistentialKind) {}
586+
OpenOpaqueExistentialKind) {}
587587

588588
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
589589
AccessKind accessKind) && override {
@@ -606,6 +606,89 @@ namespace {
606606
}
607607
};
608608

609+
/// A local path component for the payload of a class existential.
610+
///
611+
/// TODO: Could be physical if we had a way to project out the
612+
/// payload.
613+
class OpenClassExistentialComponent : public LogicalPathComponent {
614+
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
615+
return {
616+
AbstractionPattern::getOpaque(), type,
617+
SILType::getPrimitiveObjectType(type)
618+
};
619+
}
620+
public:
621+
OpenClassExistentialComponent(CanArchetypeType openedArchetype)
622+
: LogicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
623+
OpenClassExistentialKind) {}
624+
625+
AccessKind getBaseAccessKind(SILGenFunction &SGF,
626+
AccessKind kind) const override {
627+
// Always use the same access kind for the base.
628+
return kind;
629+
}
630+
631+
void diagnoseWritebackConflict(LogicalPathComponent *RHS,
632+
SILLocation loc1, SILLocation loc2,
633+
SILGenFunction &SGF) override {
634+
// no useful writeback diagnostics at this point
635+
}
636+
637+
RValue get(SILGenFunction &SGF, SILLocation loc,
638+
ManagedValue base, SGFContext c) && override {
639+
auto refType = base.getType().getObjectType();
640+
auto &TL = SGF.getTypeLowering(refType);
641+
642+
// Load the original value.
643+
auto result = SGF.emitLoad(loc, base.getValue(), TL,
644+
SGFContext(), IsNotTake);
645+
646+
assert(refType.isExistentialType() &&
647+
"base for open existential component must be an existential");
648+
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
649+
== ExistentialRepresentation::Class);
650+
auto ref = SGF.B.createOpenExistentialRef(
651+
loc, result, getTypeOfRValue());
652+
653+
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
654+
ref.getValue());
655+
656+
return RValue(SGF, loc, getSubstFormalType(), ref);
657+
}
658+
659+
void set(SILGenFunction &SGF, SILLocation loc,
660+
RValue &&value, ManagedValue base) && override {
661+
auto payload = std::move(value).forwardAsSingleValue(SGF, loc);
662+
663+
SmallVector<ProtocolConformanceRef, 2> conformances;
664+
for (auto proto : cast<ArchetypeType>(getSubstFormalType())->getConformsTo())
665+
conformances.push_back(ProtocolConformanceRef(proto));
666+
667+
auto ref = SGF.B.createInitExistentialRef(
668+
loc,
669+
base.getType().getObjectType(),
670+
getSubstFormalType(),
671+
payload,
672+
SGF.getASTContext().AllocateCopy(conformances));
673+
674+
auto &TL = SGF.getTypeLowering(base.getType());
675+
SGF.emitSemanticStore(loc, ref,
676+
base.getValue(), TL, IsNotInitialization);
677+
}
678+
679+
std::unique_ptr<LogicalPathComponent>
680+
clone(SILGenFunction &SGF, SILLocation loc) const override {
681+
LogicalPathComponent *clone =
682+
new OpenClassExistentialComponent(
683+
cast<ArchetypeType>(getSubstFormalType()));
684+
return std::unique_ptr<LogicalPathComponent>(clone);
685+
}
686+
687+
void print(raw_ostream &OS) const override {
688+
OS << "OpenClassExistentialComponent(...)\n";
689+
}
690+
};
691+
609692
/// A physical path component which returns a literal address.
610693
class ValueComponent : public PhysicalPathComponent {
611694
ManagedValue Value;
@@ -2815,6 +2898,31 @@ ManagedValue SILGenFunction::emitAddressOfLValue(SILLocation loc,
28152898
return ManagedValue::forLValue(addr.getValue());
28162899
}
28172900

2901+
LValue
2902+
SILGenFunction::emitOpenExistentialLValue(SILLocation loc,
2903+
LValue &&lv,
2904+
CanArchetypeType openedArchetype,
2905+
AccessKind accessKind) {
2906+
// Open up the existential.
2907+
auto rep = lv.getTypeOfRValue()
2908+
.getPreferredExistentialRepresentation(SGM.M);
2909+
switch (rep) {
2910+
case ExistentialRepresentation::Opaque: {
2911+
lv.add<OpenOpaqueExistentialComponent>(openedArchetype);
2912+
break;
2913+
}
2914+
case ExistentialRepresentation::Class: {
2915+
lv.add<OpenClassExistentialComponent>(openedArchetype);
2916+
break;
2917+
}
2918+
default:
2919+
llvm_unreachable("Cannot perform lvalue access of "
2920+
"non-opaque, non-class existential");
2921+
}
2922+
2923+
return std::move(lv);
2924+
}
2925+
28182926
void SILGenFunction::emitAssignToLValue(SILLocation loc, RValue &&src,
28192927
LValue &&dest) {
28202928
FormalEvaluationScope scope(*this);

0 commit comments

Comments
 (0)