Skip to content

Commit a27abcc

Browse files
committed
SE-0492: Metatypes and existential metatypes
1 parent 09fec7d commit a27abcc

File tree

10 files changed

+142
-2
lines changed

10 files changed

+142
-2
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,10 @@ extension Instruction {
462462
}
463463
case let gvi as GlobalValueInst:
464464
return context.canMakeStaticObjectReadOnly(objectType: gvi.type)
465+
case let mti as MetatypeInst:
466+
return true
467+
case let mti as InitExistentialMetatypeInst:
468+
return true
465469
case is StructInst,
466470
is TupleInst,
467471
is EnumInst,

include/swift/SIL/SILBuilder.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,6 +2149,11 @@ class SILBuilder {
21492149
createInitExistentialMetatype(SILLocation Loc, SILValue metatype,
21502150
SILType existentialType,
21512151
ArrayRef<ProtocolConformanceRef> conformances) {
2152+
if (isInsertingIntoGlobal()) {
2153+
return insert(InitExistentialMetatypeInst::create(
2154+
getSILDebugLocation(Loc), existentialType, metatype, conformances,
2155+
getModule()));
2156+
}
21522157
return insert(InitExistentialMetatypeInst::create(
21532158
getSILDebugLocation(Loc), existentialType, metatype, conformances,
21542159
&getFunction()));
@@ -2283,6 +2288,10 @@ class SILBuilder {
22832288
}
22842289

22852290
MetatypeInst *createMetatype(SILLocation Loc, SILType Metatype) {
2291+
if (isInsertingIntoGlobal()) {
2292+
return insert(MetatypeInst::create(getSILDebugLocation(Loc), Metatype,
2293+
getModule()));
2294+
}
22862295
return insert(MetatypeInst::create(getSILDebugLocation(Loc), Metatype,
22872296
&getFunction()));
22882297
}

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7431,6 +7431,9 @@ class MetatypeInst final
74317431
ArrayRef<SILValue> TypeDependentOperands)
74327432
: NullaryInstructionWithTypeDependentOperandsBase(DebugLoc,
74337433
TypeDependentOperands, Metatype) {}
7434+
7435+
static MetatypeInst *create(SILDebugLocation DebugLoc, SILType Metatype,
7436+
SILModule &Mod);
74347437

74357438
static MetatypeInst *create(SILDebugLocation DebugLoc, SILType Metatype,
74367439
SILFunction *F);
@@ -8108,6 +8111,11 @@ class InitExistentialMetatypeInst final
81088111
ArrayRef<SILValue> TypeDependentOperands,
81098112
ArrayRef<ProtocolConformanceRef> conformances);
81108113

8114+
static InitExistentialMetatypeInst *
8115+
create(SILDebugLocation DebugLoc, SILType existentialMetatypeType,
8116+
SILValue metatype, ArrayRef<ProtocolConformanceRef> conformances,
8117+
SILModule &mod);
8118+
81118119
static InitExistentialMetatypeInst *
81128120
create(SILDebugLocation DebugLoc, SILType existentialMetatypeType,
81138121
SILValue metatype, ArrayRef<ProtocolConformanceRef> conformances,

lib/IRGen/GenConstant.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Explosion.h"
2121
#include "GenConstant.h"
2222
#include "GenEnum.h"
23+
#include "GenExistential.h"
2324
#include "GenIntegerLiteral.h"
2425
#include "GenStruct.h"
2526
#include "GenTuple.h"
@@ -31,6 +32,7 @@
3132
#include "swift/IRGen/Linking.h"
3233
#include "swift/Basic/Assertions.h"
3334
#include "swift/Basic/Range.h"
35+
#include "swift/SIL/SILInstruction.h"
3436
#include "swift/SIL/SILModule.h"
3537
#include "llvm/Analysis/ConstantFolding.h"
3638
#include "llvm/Support/BLAKE3.h"
@@ -407,6 +409,24 @@ Explosion irgen::emitConstantValue(IRGenModule &IGM, SILValue operand,
407409
assert(ti.isFixedSize(expansion));
408410
Address addr = IGM.getAddrOfSILGlobalVariable(var, ti, NotForDefinition);
409411
return addr.getAddress();
412+
} else if (auto *mti = dyn_cast<MetatypeInst>(operand)) {
413+
auto metaTy = mti->getType().castTo<MetatypeType>();
414+
auto type = metaTy.getInstanceType();
415+
return IGM.getAddrOfTypeMetadata(type);
416+
} else if (auto *iemi = dyn_cast<InitExistentialMetatypeInst>(operand)) {
417+
auto *mti = cast<MetatypeInst>(iemi->getOperand().getDefiningInstruction());
418+
419+
auto metaTy = mti->getType().castTo<MetatypeType>();
420+
auto type = metaTy.getInstanceType();
421+
Explosion metatype = IGM.getAddrOfTypeMetadata(type);
422+
423+
//Explosion metatype = getLoweredExplosion(iemi->getOperand());
424+
Explosion result;
425+
emitExistentialMetatypeContainer(IGM, result, iemi->getType(),
426+
metatype.claimNext(),
427+
iemi->getOperand()->getType(),
428+
iemi->getConformances());
429+
return result;
410430
} else if (auto *atp = dyn_cast<AddressToPointerInst>(operand)) {
411431
auto *val = emitConstantValue(IGM, atp->getOperand()).claimNextConstant();
412432
return val;

lib/IRGen/GenExistential.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,41 @@ void irgen::emitExistentialMetatypeContainer(IRGenFunction &IGF,
20332033
});
20342034
}
20352035

2036+
/// Emit an existential metatype container from a metatype value
2037+
/// as an explosion.
2038+
void irgen::emitExistentialMetatypeContainer(IRGenModule &IGM,
2039+
Explosion &out, SILType outType,
2040+
llvm::Value *metatype, SILType metatypeType,
2041+
ArrayRef<ProtocolConformanceRef> conformances) {
2042+
assert(outType.is<ExistentialMetatypeType>());
2043+
auto &destTI = IGM.getTypeInfo(outType).as<ExistentialMetatypeTypeInfo>();
2044+
out.add(metatype);
2045+
2046+
auto srcType = metatypeType.castTo<MetatypeType>().getInstanceType();
2047+
auto destType = outType.castTo<ExistentialMetatypeType>().getInstanceType();
2048+
while (auto destMetatypeType = dyn_cast<ExistentialMetatypeType>(destType)) {
2049+
destType = destMetatypeType.getInstanceType();
2050+
srcType = cast<AnyMetatypeType>(srcType).getInstanceType();
2051+
}
2052+
2053+
// Emit the witness table pointers as constants.
2054+
for (auto protocol : destTI.getStoredProtocols()) {
2055+
// Find the corresponding conformance
2056+
ProtocolConformanceRef conformance;
2057+
for (auto conf : conformances) {
2058+
if (conf.getProtocol() == protocol) {
2059+
conformance = conf;
2060+
break;
2061+
}
2062+
}
2063+
assert(conformance.isConcrete() && "missing conformance");
2064+
2065+
// Emit witness table constant
2066+
auto table = IGM.getAddrOfWitnessTable(conformance.getConcrete());
2067+
out.add(table);
2068+
}
2069+
}
2070+
20362071
void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address buffer,
20372072
SILType type, Explosion &out) {
20382073
assert(type.isExistentialType());

lib/IRGen/GenExistential.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace irgen {
3434
class Address;
3535
class Explosion;
3636
class IRGenFunction;
37+
class IRGenModule;
3738

3839
/// Emit the metadata and witness table initialization for an allocated
3940
/// opaque existential container.
@@ -52,6 +53,15 @@ namespace irgen {
5253
llvm::Value *metatype,
5354
SILType metatypeType,
5455
ArrayRef<ProtocolConformanceRef> conformances);
56+
57+
/// Emit an existential metatype container from a metatype value
58+
/// as an explosion.
59+
void emitExistentialMetatypeContainer(IRGenModule &IGM,
60+
Explosion &out,
61+
SILType outType,
62+
llvm::Value *metatype,
63+
SILType metatypeType,
64+
ArrayRef<ProtocolConformanceRef> conformances);
5565

5666

5767
/// Emit a class existential container from a class instance value

lib/SIL/IR/SILInstructions.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,6 +2327,17 @@ InitExistentialMetatypeInst::InitExistentialMetatypeInst(
23272327
getTrailingObjects<ProtocolConformanceRef>());
23282328
}
23292329

2330+
InitExistentialMetatypeInst *InitExistentialMetatypeInst::create(
2331+
SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype,
2332+
ArrayRef<ProtocolConformanceRef> conformances, SILModule &M) {
2333+
unsigned size = totalSizeToAlloc<swift::Operand, ProtocolConformanceRef>(
2334+
1, conformances.size());
2335+
void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst));
2336+
return ::new (buffer) InitExistentialMetatypeInst(
2337+
Loc, existentialMetatypeType, metatype,
2338+
{}, conformances);
2339+
}
2340+
23302341
InitExistentialMetatypeInst *InitExistentialMetatypeInst::create(
23312342
SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype,
23322343
ArrayRef<ProtocolConformanceRef> conformances, SILFunction *F) {
@@ -2737,6 +2748,13 @@ CheckedCastBranchInst *CheckedCastBranchInst::create(
27372748
Target2Count, forwardingOwnershipKind, preservesOwnership);
27382749
}
27392750

2751+
MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty,
2752+
SILModule &Mod) {
2753+
auto Size = totalSizeToAlloc<swift::Operand>(1);
2754+
auto Buffer = Mod.allocateInst(Size, alignof(MetatypeInst));
2755+
return ::new (Buffer) MetatypeInst(Loc, Ty, {});
2756+
}
2757+
27402758
MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty,
27412759
SILFunction *F) {
27422760
SILModule &Mod = F->getModule();

lib/Sema/LegalConstExprVerifier.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
#include "TypeChecker.h"
2121
#include "swift/AST/ASTContext.h"
2222
#include "swift/AST/ASTWalker.h"
23+
#include "swift/AST/Expr.h"
2324
#include "swift/AST/ParameterList.h"
2425
#include "swift/AST/SemanticAttrs.h"
26+
#include "swift/AST/Type.h"
2527
#include "swift/Basic/Assertions.h"
2628
using namespace swift;
2729

@@ -261,6 +263,25 @@ checkSupportedWithSectionAttribute(const Expr *expr,
261263
expressionsToCheck.push_back(identityExpr->getSubExpr());
262264
continue;
263265
}
266+
267+
// Upcasts of metatypes to existential metatypes (e.g. Any.Type)
268+
if (const ErasureExpr *erasureExpr = dyn_cast<ErasureExpr>(expr)) {
269+
if (const DotSelfExpr *dotSelfExpr = dyn_cast<DotSelfExpr>(erasureExpr->getSubExpr())) {
270+
if (const TypeExpr *typeExpr = dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
271+
auto baseType = typeExpr->getType();
272+
if (baseType && baseType->is<MetatypeType>()) {
273+
auto instanceType = baseType->getMetatypeInstanceType();
274+
if (auto nominal = instanceType->getNominalOrBoundGenericNominal()) {
275+
// Allow non-generic, non-resilient types
276+
if (!nominal->isGeneric() && !nominal->isResilient()) {
277+
continue;
278+
}
279+
}
280+
}
281+
}
282+
}
283+
return std::make_pair(expr, TypeExpression);
284+
}
264285

265286
// Function calls and constructors are not allowed
266287
if (isa<ApplyExpr>(expr))

test/ConstValues/SectionIR.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,14 @@ func bar(x: Int) -> String { return "test" }
2828
@section("mysection") let funcRef1 = foo // ok
2929
@section("mysection") let funcRef2 = bar // ok
3030

31-
// metatypes - TODO
32-
//@section("mysection") let metatype1 = Int.self
31+
struct S: Hashable, Sendable {}
32+
33+
// metatypes
34+
@section("mysection") let metatype1 = Int.self
35+
@section("mysection") let metatype2: Any.Type = Int.self
36+
@section("mysection") let metatype3: Any.Type = S.self
37+
@section("mysection") let metatype4: any (Hashable & Sendable).Type = Int.self
38+
@section("mysection") let metatype5: any (Hashable & Sendable).Type = S.self
3339

3440
// tuples
3541
@section("mysection") let tuple1 = (1, 2, 3, 2.718, true) // ok
@@ -56,6 +62,12 @@ func bar(x: Int) -> String { return "test" }
5662
// CHECK: @"$s9SectionIR12boolLiteral2Sbvp" = {{.*}}constant %TSb zeroinitializer, section "mysection"
5763
// CHECK: @"$s9SectionIR8funcRef1Siycvp" = {{.*}}constant %swift.function { ptr @"$s9SectionIR3fooSiyF", ptr null }, section "mysection"
5864
// CHECK: @"$s9SectionIR8funcRef2ySSSicvp" = {{.*}}constant %swift.function { ptr @"$s9SectionIR3bar1xSSSi_tF", ptr null }, section "mysection"
65+
66+
// CHECK: @"$s9SectionIR9metatype2ypXpvp" = {{.*}}constant ptr @"$sSiN", section "mysection"
67+
// CHECK: @"$s9SectionIR9metatype3ypXpvp" = {{.*}}constant ptr getelementptr inbounds (<{ ptr, ptr, i64, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), section "mysection"
68+
// CHECK: @"$s9SectionIR9metatype4SH_s8SendablepXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr @"$sSiN", ptr @"$sSiSHsWP" }>, section "mysection"
69+
// CHECK: @"$s9SectionIR9metatype5SH_s8SendablepXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, i64, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVSHAAWP" }>, section "mysection"
70+
5971
// CHECK: @"$s9SectionIR6tuple1Si_S2iSdSbtvp" = {{.*}}constant <{ %TSi, %TSi, %TSi, %TSd, %TSb }> <{ %TSi <{ i64 1 }>, %TSi <{ i64 2 }>, %TSi <{ i64 3 }>, %TSd <{ double 2.718000e+00 }>, %TSb <{ i1 true }> }>, section "mysection"
6072
// CHECK: @"$s9SectionIR6tuple2Si_SfSbtvp" = {{.*}}constant <{ %TSi, %TSf, %TSb }> <{ %TSi <{ i64 42 }>, %TSf <{ float 0x40091EB860000000 }>, %TSb zeroinitializer }>, section "mysection"
6173
// CHECK: @"$s9SectionIR6tuple3Siyc_SSSictvp" = {{.*}}constant <{ %swift.function, %swift.function }> <{ %swift.function { ptr @"$s9SectionIR3fooSiyF", ptr null }, %swift.function { ptr @"$s9SectionIR3bar1xSSSi_tF", ptr null } }>, section "mysection"

test/ConstValues/SectionSyntactic.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ enum E { case a }
7070

7171
// metatypes
7272
@section("mysection") let metatype1 = Int.self // ok
73+
@section("mysection") let metatype2: Any.Type = Int.self // ok
74+
@section("mysection") let metatype3: any (Hashable).Type = Int.self // ok
75+
@section("mysection") let metatype4: any (Hashable & Sendable).Type = Int.self // ok
7376

7477
// invalid metatype references
7578
@section("mysection") let invalidMetatype1 = Int.self.self

0 commit comments

Comments
 (0)