Skip to content

Commit 48d60a4

Browse files
authored
Merge pull request #9852 from rjmccall/open-existential-metatype-lvalue
Fix the emission of open-existential-metatype l-values
2 parents ab101eb + bb5fe80 commit 48d60a4

File tree

6 files changed

+93
-44
lines changed

6 files changed

+93
-44
lines changed

lib/SILGen/LValue.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +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
110+
OpenNonOpaqueExistentialKind, // opened class or metatype existential
111111
// Translation LValue kinds (a subtype of logical)
112112
OrigToSubstKind, // generic type substitution
113113
SubstToOrigKind, // generic type substitution

lib/SILGen/SILGenExpr.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4011,10 +4011,14 @@ void SILGenFunction::emitOpenExistentialExprImpl(
40114011
// Create a writeback scope for the access to the existential lvalue.
40124012
writebackScope.emplace(*this);
40134013

4014+
Type formalRValueType =
4015+
E->getOpaqueValue()->getType()->getLValueOrInOutObjectType();
4016+
40144017
accessKind = E->getExistentialValue()->getLValueAccessKind();
40154018
auto lv = emitLValue(E->getExistentialValue(), accessKind);
40164019
lv = emitOpenExistentialLValue(E, std::move(lv),
40174020
CanArchetypeType(E->getOpenedArchetype()),
4021+
formalRValueType->getCanonicalType(),
40184022
accessKind);
40194023
auto addr = emitAddressOfLValue(E, std::move(lv), accessKind);
40204024
state = {addr, false, false};

lib/SILGen/SILGenFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
13041304
LValue emitOpenExistentialLValue(SILLocation loc,
13051305
LValue &&existentialLV,
13061306
CanArchetypeType openedArchetype,
1307+
CanType formalRValueType,
13071308
AccessKind accessKind);
13081309

13091310
RValue emitLoadOfLValue(SILLocation loc, LValue &&src, SGFContext C,

lib/SILGen/SILGenLValue.cpp

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -627,16 +627,15 @@ namespace {
627627
/// A physical path component which projects out an opened archetype
628628
/// from an existential.
629629
class OpenOpaqueExistentialComponent : public PhysicalPathComponent {
630-
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
631-
return {
632-
AbstractionPattern::getOpaque(), type,
633-
SILType::getPrimitiveObjectType(type)
634-
};
630+
CanArchetypeType getOpenedArchetype() const {
631+
return cast<ArchetypeType>(getSubstFormalType());
635632
}
636633
public:
637-
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype)
638-
: PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
639-
OpenOpaqueExistentialKind) {}
634+
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype,
635+
LValueTypeData typeData)
636+
: PhysicalPathComponent(typeData, OpenOpaqueExistentialKind) {
637+
assert(getOpenedArchetype() == openedArchetype);
638+
}
640639

641640
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
642641
AccessKind accessKind) && override {
@@ -665,8 +664,7 @@ namespace {
665664
llvm_unreachable("Bad existential representation for address-only type");
666665
}
667666

668-
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
669-
addr);
667+
SGF.setArchetypeOpeningSite(getOpenedArchetype(), addr);
670668
return ManagedValue::forLValue(addr);
671669
}
672670

@@ -675,21 +673,17 @@ namespace {
675673
}
676674
};
677675

678-
/// A local path component for the payload of a class existential.
676+
/// A local path component for the payload of a class or metatype existential.
679677
///
680678
/// TODO: Could be physical if we had a way to project out the
681679
/// payload.
682-
class OpenClassExistentialComponent : public LogicalPathComponent {
683-
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
684-
return {
685-
AbstractionPattern::getOpaque(), type,
686-
SILType::getPrimitiveObjectType(type)
687-
};
688-
}
680+
class OpenNonOpaqueExistentialComponent : public LogicalPathComponent {
681+
CanArchetypeType OpenedArchetype;
689682
public:
690-
OpenClassExistentialComponent(CanArchetypeType openedArchetype)
691-
: LogicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
692-
OpenClassExistentialKind) {}
683+
OpenNonOpaqueExistentialComponent(CanArchetypeType openedArchetype,
684+
LValueTypeData typeData)
685+
: LogicalPathComponent(typeData, OpenNonOpaqueExistentialKind),
686+
OpenedArchetype(openedArchetype) {}
693687

694688
AccessKind getBaseAccessKind(SILGenFunction &SGF,
695689
AccessKind kind) const override {
@@ -712,15 +706,23 @@ namespace {
712706
auto result = SGF.emitLoad(loc, base.getValue(), TL,
713707
SGFContext(), IsNotTake);
714708

715-
assert(refType.isExistentialType() &&
709+
assert(refType.isAnyExistentialType() &&
716710
"base for open existential component must be an existential");
717-
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
718-
== ExistentialRepresentation::Class);
719-
auto ref = SGF.B.createOpenExistentialRef(
720-
loc, result, getTypeOfRValue());
711+
ManagedValue ref;
712+
if (refType.is<ExistentialMetatypeType>()) {
713+
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
714+
== ExistentialRepresentation::Metatype);
715+
ref = ManagedValue::forUnmanaged(
716+
SGF.B.createOpenExistentialMetatype(loc,
717+
result.getUnmanagedValue(),
718+
getTypeOfRValue()));
719+
} else {
720+
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
721+
== ExistentialRepresentation::Class);
722+
ref = SGF.B.createOpenExistentialRef(loc, result, getTypeOfRValue());
723+
}
721724

722-
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
723-
ref.getValue());
725+
SGF.setArchetypeOpeningSite(OpenedArchetype, ref.getValue());
724726

725727
return RValue(SGF, loc, getSubstFormalType(), ref);
726728
}
@@ -730,15 +732,24 @@ namespace {
730732
auto payload = std::move(value).forwardAsSingleValue(SGF, loc);
731733

732734
SmallVector<ProtocolConformanceRef, 2> conformances;
733-
for (auto proto : cast<ArchetypeType>(getSubstFormalType())->getConformsTo())
735+
for (auto proto : OpenedArchetype->getConformsTo())
734736
conformances.push_back(ProtocolConformanceRef(proto));
735737

736-
auto ref = SGF.B.createInitExistentialRef(
737-
loc,
738-
base.getType().getObjectType(),
739-
getSubstFormalType(),
740-
payload,
741-
SGF.getASTContext().AllocateCopy(conformances));
738+
SILValue ref;
739+
if (base.getType().is<ExistentialMetatypeType>()) {
740+
ref = SGF.B.createInitExistentialMetatype(
741+
loc,
742+
payload,
743+
base.getType().getObjectType(),
744+
SGF.getASTContext().AllocateCopy(conformances));
745+
} else {
746+
ref = SGF.B.createInitExistentialRef(
747+
loc,
748+
base.getType().getObjectType(),
749+
getSubstFormalType(),
750+
payload,
751+
SGF.getASTContext().AllocateCopy(conformances));
752+
}
742753

743754
auto &TL = SGF.getTypeLowering(base.getType());
744755
SGF.emitSemanticStore(loc, ref,
@@ -748,13 +759,13 @@ namespace {
748759
std::unique_ptr<LogicalPathComponent>
749760
clone(SILGenFunction &SGF, SILLocation loc) const override {
750761
LogicalPathComponent *clone =
751-
new OpenClassExistentialComponent(
752-
cast<ArchetypeType>(getSubstFormalType()));
762+
new OpenNonOpaqueExistentialComponent(OpenedArchetype, getTypeData());
753763
return std::unique_ptr<LogicalPathComponent>(clone);
754764
}
755765

756766
void print(raw_ostream &OS) const override {
757-
OS << "OpenClassExistentialComponent(...)\n";
767+
OS << "OpenNonOpaqueExistentialComponent(" << OpenedArchetype
768+
<< ", ...)\n";
758769
}
759770
};
760771

@@ -2072,6 +2083,7 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
20722083
lv = SGF.emitOpenExistentialLValue(
20732084
opened, std::move(lv),
20742085
CanArchetypeType(opened->getOpenedArchetype()),
2086+
e->getType()->getLValueOrInOutObjectType()->getCanonicalType(),
20752087
accessKind);
20762088
return lv;
20772089
}
@@ -2977,23 +2989,30 @@ LValue
29772989
SILGenFunction::emitOpenExistentialLValue(SILLocation loc,
29782990
LValue &&lv,
29792991
CanArchetypeType openedArchetype,
2992+
CanType formalRValueType,
29802993
AccessKind accessKind) {
2994+
assert(!formalRValueType->isLValueType());
2995+
LValueTypeData typeData = {
2996+
AbstractionPattern::getOpaque(), formalRValueType,
2997+
getLoweredType(formalRValueType).getObjectType()
2998+
};
2999+
29813000
// Open up the existential.
29823001
auto rep = lv.getTypeOfRValue()
29833002
.getPreferredExistentialRepresentation(SGM.M);
29843003
switch (rep) {
29853004
case ExistentialRepresentation::Opaque:
29863005
case ExistentialRepresentation::Boxed: {
2987-
lv.add<OpenOpaqueExistentialComponent>(openedArchetype);
3006+
lv.add<OpenOpaqueExistentialComponent>(openedArchetype, typeData);
29883007
break;
29893008
}
3009+
case ExistentialRepresentation::Metatype:
29903010
case ExistentialRepresentation::Class: {
2991-
lv.add<OpenClassExistentialComponent>(openedArchetype);
3011+
lv.add<OpenNonOpaqueExistentialComponent>(openedArchetype, typeData);
29923012
break;
29933013
}
2994-
default:
2995-
llvm_unreachable("Cannot perform lvalue access of "
2996-
"non-opaque, non-class existential");
3014+
case ExistentialRepresentation::None:
3015+
llvm_unreachable("cannot open non-existential");
29973016
}
29983017

29993018
return std::move(lv);

test/SILGen/existential_metatypes.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
// RUN: %target-swift-frontend -emit-silgen -parse-stdlib %s | %FileCheck %s
22

3+
struct Value {}
4+
35
protocol P {
46
init()
57
static func staticMethod() -> Self
8+
static var value: Value { get }
69
}
710

811
struct S: P {
912
init() {}
1013
static func staticMethod() -> S { return S() }
14+
static var value: Value { return Value() }
1115
}
1216

1317
// CHECK-LABEL: sil hidden @_T021existential_metatypes0A8MetatypeyAA1P_pF
@@ -51,3 +55,18 @@ func existentialMetatypeUpcast1(_ x: PP.Type) -> P.Type {
5155
func existentialMetatypeUpcast2(_ x: (P & Q).Type) -> P.Type {
5256
return x
5357
}
58+
59+
// rdar://32288618
60+
// CHECK-LABEL: sil hidden @_T021existential_metatypes0A19MetatypeVarPropertyAA5ValueVyF : $@convention(thin) () -> Value
61+
func existentialMetatypeVarProperty() -> Value {
62+
// CHECK: [[BOX:%.*]] = alloc_box ${ var @thick P.Type }
63+
// CHECK: [[ADDR:%.*]] = project_box [[BOX]] : ${ var @thick P.Type }, 0
64+
// CHECK: [[T0:%.*]] = metatype $@thick S.Type
65+
// CHECK: [[T1:%.*]] = init_existential_metatype [[T0]]
66+
// CHECK: store [[T1]] to [trivial] [[ADDR]] :
67+
// CHECK: [[T0:%.*]] = begin_access [read] [unknown] [[ADDR]] :
68+
// CHECK: [[T1:%.*]] = load [trivial] [[T0]]
69+
// CHECK: open_existential_metatype [[T1]] :
70+
var type: P.Type = S.self
71+
return type.value
72+
}

test/SILOptimizer/devirt_protocol_method_invocations.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ public func testExMetatype() -> Int {
192192
return type.size
193193
}
194194

195+
// rdar://32288618
196+
public func testExMetatypeVar() -> Int {
197+
var type: StaticP.Type = HasStatic<Int>.self
198+
return type.size
199+
}
200+
195201
// IRGen used to crash on the testPropagationOfConcreteTypeIntoExistential method.
196202
// rdar://26286278
197203

0 commit comments

Comments
 (0)