Skip to content

Commit f4741aa

Browse files
committed
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 366f238 commit f4741aa

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
@@ -1284,6 +1284,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
12841284
ManagedValue emitAddressOfLValue(SILLocation loc, LValue &&src,
12851285
AccessKind accessKind,
12861286
TSanKind tsanKind = TSanKind::None);
1287+
LValue emitOpenExistentialLValue(SILLocation loc,
1288+
LValue &&existentialLV,
1289+
CanArchetypeType openedArchetype,
1290+
AccessKind accessKind);
12871291

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

lib/SILGen/SILGenLValue.cpp

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ namespace {
579579
public:
580580
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype)
581581
: PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
582-
OpenedExistentialKind) {}
582+
OpenOpaqueExistentialKind) {}
583583

584584
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
585585
AccessKind accessKind) && override {
@@ -604,6 +604,89 @@ namespace {
604604
}
605605
};
606606

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

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

0 commit comments

Comments
 (0)