Skip to content

Commit c7ffdac

Browse files
committed
Fix the emission of open-existential-metatype l-values.
rdar://32288618
1 parent 107b220 commit c7ffdac

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
@@ -4020,10 +4020,14 @@ void SILGenFunction::emitOpenExistentialExprImpl(
40204020
// Create a writeback scope for the access to the existential lvalue.
40214021
writebackScope.emplace(*this);
40224022

4023+
Type formalRValueType =
4024+
E->getOpaqueValue()->getType()->getLValueOrInOutObjectType();
4025+
40234026
accessKind = E->getExistentialValue()->getLValueAccessKind();
40244027
auto lv = emitLValue(E->getExistentialValue(), accessKind);
40254028
lv = emitOpenExistentialLValue(E, std::move(lv),
40264029
CanArchetypeType(E->getOpenedArchetype()),
4030+
formalRValueType->getCanonicalType(),
40274031
accessKind);
40284032
auto addr = emitAddressOfLValue(E, std::move(lv), accessKind);
40294033
state = {addr, false, false};

lib/SILGen/SILGenFunction.h

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

13101311
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
@@ -631,16 +631,15 @@ namespace {
631631
/// A physical path component which projects out an opened archetype
632632
/// from an existential.
633633
class OpenOpaqueExistentialComponent : public PhysicalPathComponent {
634-
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
635-
return {
636-
AbstractionPattern::getOpaque(), type,
637-
SILType::getPrimitiveObjectType(type)
638-
};
634+
CanArchetypeType getOpenedArchetype() const {
635+
return cast<ArchetypeType>(getSubstFormalType());
639636
}
640637
public:
641-
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype)
642-
: PhysicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
643-
OpenOpaqueExistentialKind) {}
638+
OpenOpaqueExistentialComponent(CanArchetypeType openedArchetype,
639+
LValueTypeData typeData)
640+
: PhysicalPathComponent(typeData, OpenOpaqueExistentialKind) {
641+
assert(getOpenedArchetype() == openedArchetype);
642+
}
644643

645644
ManagedValue offset(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
646645
AccessKind accessKind) && override {
@@ -669,8 +668,7 @@ namespace {
669668
llvm_unreachable("Bad existential representation for address-only type");
670669
}
671670

672-
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
673-
addr);
671+
SGF.setArchetypeOpeningSite(getOpenedArchetype(), addr);
674672
return ManagedValue::forLValue(addr);
675673
}
676674

@@ -679,21 +677,17 @@ namespace {
679677
}
680678
};
681679

682-
/// A local path component for the payload of a class existential.
680+
/// A local path component for the payload of a class or metatype existential.
683681
///
684682
/// TODO: Could be physical if we had a way to project out the
685683
/// payload.
686-
class OpenClassExistentialComponent : public LogicalPathComponent {
687-
static LValueTypeData getOpenedArchetypeTypeData(CanArchetypeType type) {
688-
return {
689-
AbstractionPattern::getOpaque(), type,
690-
SILType::getPrimitiveObjectType(type)
691-
};
692-
}
684+
class OpenNonOpaqueExistentialComponent : public LogicalPathComponent {
685+
CanArchetypeType OpenedArchetype;
693686
public:
694-
OpenClassExistentialComponent(CanArchetypeType openedArchetype)
695-
: LogicalPathComponent(getOpenedArchetypeTypeData(openedArchetype),
696-
OpenClassExistentialKind) {}
687+
OpenNonOpaqueExistentialComponent(CanArchetypeType openedArchetype,
688+
LValueTypeData typeData)
689+
: LogicalPathComponent(typeData, OpenNonOpaqueExistentialKind),
690+
OpenedArchetype(openedArchetype) {}
697691

698692
AccessKind getBaseAccessKind(SILGenFunction &SGF,
699693
AccessKind kind) const override {
@@ -716,15 +710,23 @@ namespace {
716710
auto result = SGF.emitLoad(loc, base.getValue(), TL,
717711
SGFContext(), IsNotTake);
718712

719-
assert(refType.isExistentialType() &&
713+
assert(refType.isAnyExistentialType() &&
720714
"base for open existential component must be an existential");
721-
assert(refType.getPreferredExistentialRepresentation(SGF.SGM.M)
722-
== ExistentialRepresentation::Class);
723-
auto ref = SGF.B.createOpenExistentialRef(
724-
loc, result, getTypeOfRValue());
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+
}
725728

726-
SGF.setArchetypeOpeningSite(cast<ArchetypeType>(getSubstFormalType()),
727-
ref.getValue());
729+
SGF.setArchetypeOpeningSite(OpenedArchetype, ref.getValue());
728730

729731
return RValue(SGF, loc, getSubstFormalType(), ref);
730732
}
@@ -734,15 +736,24 @@ namespace {
734736
auto payload = std::move(value).forwardAsSingleValue(SGF, loc);
735737

736738
SmallVector<ProtocolConformanceRef, 2> conformances;
737-
for (auto proto : cast<ArchetypeType>(getSubstFormalType())->getConformsTo())
739+
for (auto proto : OpenedArchetype->getConformsTo())
738740
conformances.push_back(ProtocolConformanceRef(proto));
739741

740-
auto ref = SGF.B.createInitExistentialRef(
741-
loc,
742-
base.getType().getObjectType(),
743-
getSubstFormalType(),
744-
payload,
745-
SGF.getASTContext().AllocateCopy(conformances));
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+
}
746757

747758
auto &TL = SGF.getTypeLowering(base.getType());
748759
SGF.emitSemanticStore(loc, ref,
@@ -752,13 +763,13 @@ namespace {
752763
std::unique_ptr<LogicalPathComponent>
753764
clone(SILGenFunction &SGF, SILLocation loc) const override {
754765
LogicalPathComponent *clone =
755-
new OpenClassExistentialComponent(
756-
cast<ArchetypeType>(getSubstFormalType()));
766+
new OpenNonOpaqueExistentialComponent(OpenedArchetype, getTypeData());
757767
return std::unique_ptr<LogicalPathComponent>(clone);
758768
}
759769

760770
void print(raw_ostream &OS) const override {
761-
OS << "OpenClassExistentialComponent(...)\n";
771+
OS << "OpenNonOpaqueExistentialComponent(" << OpenedArchetype
772+
<< ", ...)\n";
762773
}
763774
};
764775

@@ -2076,6 +2087,7 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
20762087
lv = SGF.emitOpenExistentialLValue(
20772088
opened, std::move(lv),
20782089
CanArchetypeType(opened->getOpenedArchetype()),
2090+
e->getType()->getLValueOrInOutObjectType()->getCanonicalType(),
20792091
accessKind);
20802092
return lv;
20812093
}
@@ -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)