diff --git a/SwiftCompilerSources/Sources/AST/Conformance.swift b/SwiftCompilerSources/Sources/AST/Conformance.swift index f67c942924c3d..7574ce34d631e 100644 --- a/SwiftCompilerSources/Sources/AST/Conformance.swift +++ b/SwiftCompilerSources/Sources/AST/Conformance.swift @@ -87,6 +87,23 @@ public struct Conformance: CustomStringConvertible, Hashable, NoReflectionChildr assert(isConcrete) return bridged.getAssociatedConformance(assocType.bridged, proto.bridged).conformance } + + // This is a less precise definition of "resilient conformance" because it's + // only used for SIL optimizations -- where it's okay to think a conformance + // is resilient even if IRGen will decide it's not (see + // IRGenModule::isResilientConformance). + public func isResilientConformance(currentModule: ModuleDecl) -> Bool { + let conformanceModule = self.protocol.parentModule + let protocolModule = self.protocol.parentModule + + // If the protocol and the conformance are both in the current module, + // they're not resilient. + if conformanceModule == currentModule && protocolModule == currentModule { + return false + } + + return true + } } public struct ConformanceArray : RandomAccessCollection, CustomReflectable { diff --git a/SwiftCompilerSources/Sources/AST/Declarations.swift b/SwiftCompilerSources/Sources/AST/Declarations.swift index 35ba159eea2c3..13f4b3c4bd3d1 100644 --- a/SwiftCompilerSources/Sources/AST/Declarations.swift +++ b/SwiftCompilerSources/Sources/AST/Declarations.swift @@ -135,6 +135,7 @@ final public class ClassDecl: NominalTypeDecl { final public class ProtocolDecl: NominalTypeDecl { public var requiresClass: Bool { bridged.ProtocolDecl_requiresClass() } public var isMarkerProtocol: Bool { bridged.ProtocolDecl_isMarkerProtocol() } + public var isInvertible: Bool { bridged.ProtocolDecl_isInvertible() } } final public class BuiltinTupleDecl: NominalTypeDecl {} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index 053b71c9535db..bdfef5487f9cd 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -503,6 +503,27 @@ extension Instruction { } case let gvi as GlobalValueInst: return context.canMakeStaticObjectReadOnly(objectType: gvi.type) + + // Metatypes (and upcasts of them to existentials) can be used as static initializers for SE-0492, as long as they + // do not require an accessor to reference the metadata (i.e. are not generic, not resilient and not a class). + // See also irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable. + case let mti as MetatypeInst: + let silType = mti.type.loweredInstanceTypeOfMetatype(in: parentFunction) + let instanceType = mti.type.canonicalType.instanceTypeOfMetatype + if !mti.type.isGenericAtAnyLevel, + !instanceType.isClass, + let nominal = instanceType.nominal, + !nominal.isGenericAtAnyLevel, + silType.isFixedABI(in: mti.parentFunction) { + return true + } + return false + case let iemi as InitExistentialMetatypeInst: + let isAnyConformanceResilient = iemi.conformances.contains { + !$0.protocol.isInvertible && $0.isResilientConformance(currentModule: context.currentModuleContext) + } + return !iemi.type.isGenericAtAnyLevel && !isAnyConformanceResilient + case is StructInst, is TupleInst, is EnumInst, diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index 3255c41cd310a..0b835e7c69701 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -944,6 +944,10 @@ class OpenExistentialBoxValueInst : SingleValueInstruction, UnaryInstruction {} final public class InitExistentialMetatypeInst : SingleValueInstruction, UnaryInstruction { public var metatype: Value { operand.value } + + public var conformances: ConformanceArray { + ConformanceArray(bridged: bridged.InitExistentialMetatypeInst_getConformances()) + } } final public diff --git a/SwiftCompilerSources/Sources/SIL/Type.swift b/SwiftCompilerSources/Sources/SIL/Type.swift index 26bd2b9c144ab..1cc4bc2b74736 100644 --- a/SwiftCompilerSources/Sources/SIL/Type.swift +++ b/SwiftCompilerSources/Sources/SIL/Type.swift @@ -103,6 +103,10 @@ public struct Type : TypeProperties, CustomStringConvertible, NoReflectionChildr bridged.isAddressableForDeps(function.bridged) } + public func isFixedABI(in function: Function) -> Bool { + bridged.isFixedABI(function.bridged) + } + /// If this is a raw layout type, returns the substituted like-type. public var rawLayoutSubstitutedLikeType: AST.`Type`? { .init(bridgedOrNil: bridged.getRawLayoutSubstitutedLikeType()) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index d4f17ace66efe..1606ccfa44389 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -350,6 +350,7 @@ struct BridgedDeclObj { BRIDGED_INLINE bool Class_isForeign() const; BRIDGED_INLINE bool ProtocolDecl_requiresClass() const; BRIDGED_INLINE bool ProtocolDecl_isMarkerProtocol() const; + BRIDGED_INLINE bool ProtocolDecl_isInvertible() const; BRIDGED_INLINE bool AbstractFunction_isOverridden() const; BRIDGED_INLINE bool Constructor_isInheritable() const; BRIDGED_INLINE bool Destructor_isIsolated() const; diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 128b1c444dd15..c08787810b021 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -268,6 +268,10 @@ bool BridgedDeclObj::ProtocolDecl_isMarkerProtocol() const { return getAs()->isMarkerProtocol(); } +bool BridgedDeclObj::ProtocolDecl_isInvertible() const { + return getAs()->getInvertibleProtocolKind() != std::nullopt; +} + bool BridgedDeclObj::AbstractFunction_isOverridden() const { return getAs()->isOverridden(); } diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index e2b729ab23902..bd204426a3544 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -291,6 +291,7 @@ struct BridgedType { BRIDGED_INLINE bool isExactSuperclassOf(BridgedType t) const; BRIDGED_INLINE bool isMarkedAsImmortal() const; BRIDGED_INLINE bool isAddressableForDeps(BridgedFunction f) const; + BRIDGED_INLINE bool isFixedABI(BridgedFunction f) const; BRIDGED_INLINE SWIFT_IMPORT_UNSAFE BridgedASTType getRawLayoutSubstitutedLikeType() const; BRIDGED_INLINE SWIFT_IMPORT_UNSAFE BridgedASTType getRawLayoutSubstitutedCountType() const; BRIDGED_INLINE bool mayHaveCustomDeinit(BridgedFunction f) const; @@ -810,6 +811,7 @@ struct BridgedInstruction { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialRefInst_getFormalConcreteType() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialAddrInst_getConformances() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialAddrInst_getFormalConcreteType() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialMetatypeInst_getConformances() const; BRIDGED_INLINE bool OpenExistentialAddr_isImmutable() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar GlobalAccessInst_getGlobal() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar AllocGlobalInst_getGlobal() const; diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index 36b256bdd1ddf..aeb59300dc4a2 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -402,6 +402,10 @@ bool BridgedType::isAddressableForDeps(BridgedFunction f) const { return unbridged().isAddressableForDeps(*f.getFunction()); } +bool BridgedType::isFixedABI(BridgedFunction f) const { + return unbridged().isFixedABI(*f.getFunction()); +} + BridgedASTType BridgedType::getRawLayoutSubstitutedLikeType() const { return {unbridged().getRawLayoutSubstitutedLikeType().getPointer()}; } @@ -1296,6 +1300,10 @@ BridgedCanType BridgedInstruction::InitExistentialAddrInst_getFormalConcreteType return getAs()->getFormalConcreteType(); } +BridgedConformanceArray BridgedInstruction::InitExistentialMetatypeInst_getConformances() const { + return {getAs()->getConformances()}; +} + bool BridgedInstruction::OpenExistentialAddr_isImmutable() const { switch (getAs()->getAccessKind()) { case swift::OpenedExistentialAccess::Immutable: return true; diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index dde860ce12daa..ee5a3ccd1376f 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -2155,6 +2155,11 @@ class SILBuilder { createInitExistentialMetatype(SILLocation Loc, SILValue metatype, SILType existentialType, ArrayRef conformances) { + if (isInsertingIntoGlobal()) { + return insert(InitExistentialMetatypeInst::create( + getSILDebugLocation(Loc), existentialType, metatype, conformances, + getModule())); + } return insert(InitExistentialMetatypeInst::create( getSILDebugLocation(Loc), existentialType, metatype, conformances, &getFunction())); @@ -2289,6 +2294,10 @@ class SILBuilder { } MetatypeInst *createMetatype(SILLocation Loc, SILType Metatype) { + if (isInsertingIntoGlobal()) { + return insert(MetatypeInst::create(getSILDebugLocation(Loc), Metatype, + getModule())); + } return insert(MetatypeInst::create(getSILDebugLocation(Loc), Metatype, &getFunction())); } diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index a24c08d0e3fd9..84c017c5990af 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -7509,6 +7509,9 @@ class MetatypeInst final ArrayRef TypeDependentOperands) : NullaryInstructionWithTypeDependentOperandsBase(DebugLoc, TypeDependentOperands, Metatype) {} + + static MetatypeInst *create(SILDebugLocation DebugLoc, SILType Metatype, + SILModule &Mod); static MetatypeInst *create(SILDebugLocation DebugLoc, SILType Metatype, SILFunction *F); @@ -8186,6 +8189,11 @@ class InitExistentialMetatypeInst final ArrayRef TypeDependentOperands, ArrayRef conformances); + static InitExistentialMetatypeInst * + create(SILDebugLocation DebugLoc, SILType existentialMetatypeType, + SILValue metatype, ArrayRef conformances, + SILModule &mod); + static InitExistentialMetatypeInst * create(SILDebugLocation DebugLoc, SILType existentialMetatypeType, SILValue metatype, ArrayRef conformances, diff --git a/lib/IRGen/GenConstant.cpp b/lib/IRGen/GenConstant.cpp index 7271525557751..859e0e999d1e4 100644 --- a/lib/IRGen/GenConstant.cpp +++ b/lib/IRGen/GenConstant.cpp @@ -20,9 +20,11 @@ #include "Explosion.h" #include "GenConstant.h" #include "GenEnum.h" +#include "GenExistential.h" #include "GenIntegerLiteral.h" #include "GenStruct.h" #include "GenTuple.h" +#include "MetadataRequest.h" #include "TypeInfo.h" #include "StructLayout.h" #include "Callee.h" @@ -31,9 +33,11 @@ #include "swift/IRGen/Linking.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Range.h" +#include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILModule.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Support/BLAKE3.h" +#include "llvm/Support/ErrorHandling.h" using namespace swift; using namespace irgen; @@ -414,6 +418,26 @@ Explosion irgen::emitConstantValue(IRGenModule &IGM, SILValue operand, assert(ti.isFixedSize(expansion)); Address addr = IGM.getAddrOfSILGlobalVariable(var, ti, NotForDefinition); return addr.getAddress(); + } else if (auto *mti = dyn_cast(operand)) { + auto metaTy = mti->getType().castTo(); + auto type = metaTy.getInstanceType(); + ASSERT(isCanonicalCompleteTypeMetadataStaticallyAddressable(IGM, type)); + return IGM.getAddrOfTypeMetadata(type); + } else if (auto *iemi = dyn_cast(operand)) { + auto *mti = + dyn_cast(iemi->getOperand().getDefiningInstruction()); + ASSERT(mti != nullptr && "couldn't constant fold initializer expression"); + + auto metaTy = mti->getType().castTo(); + auto type = metaTy.getInstanceType(); + ASSERT(isCanonicalCompleteTypeMetadataStaticallyAddressable(IGM, type)); + llvm::Constant *metadata = IGM.getAddrOfTypeMetadata(type); + + Explosion result; + emitExistentialMetatypeContainer(IGM, result, iemi->getType(), metadata, + iemi->getOperand()->getType(), + iemi->getConformances()); + return result; } else if (auto *atp = dyn_cast(operand)) { auto *val = emitConstantValue(IGM, atp->getOperand()).claimNextConstant(); return val; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 1a6921606165b..55d04086ac6a9 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -25,11 +25,13 @@ #include "swift/AST/ModuleDependencies.h" #include "swift/AST/NameLookup.h" #include "swift/AST/Pattern.h" +#include "swift/AST/PrettyStackTrace.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/TypeMemberVisitor.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Mangler.h" +#include "swift/Basic/PrettyStackTrace.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/IRGen/Linking.h" @@ -2931,6 +2933,9 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var, llvm::Constant *IRGenModule::getGlobalInitValue(SILGlobalVariable *var, llvm::Type *storageType, Alignment alignment) { + PrettyStackTraceStringAction trace( + "constant-folding init value for SIL global", var->getName()); + if (var->isInitializedObject()) { StructLayout *layout = StaticObjectLayouts[var].layout.get(); ObjectInst *oi = cast(var->getStaticInitializerValue()); @@ -2962,7 +2967,12 @@ llvm::Constant *IRGenModule::getGlobalInitValue(SILGlobalVariable *var, if (SILInstruction *initInst = var->getStaticInitializerValue()) { Explosion initExp = emitConstantValue(*this, cast(initInst)); - return getConstantValue(std::move(initExp), /*paddingBytes=*/ 0); + llvm::Constant *initVal = getConstantValue(std::move(initExp), /*paddingBytes=*/ 0); + llvm::errs() << "getGlobalInitValue:\n"; + var->dump(); + initVal->dump(); + llvm::errs() << "\n"; + return initVal; } return nullptr; } diff --git a/lib/IRGen/GenExistential.cpp b/lib/IRGen/GenExistential.cpp index 89e017d922d96..3f6b9c1dd04d8 100644 --- a/lib/IRGen/GenExistential.cpp +++ b/lib/IRGen/GenExistential.cpp @@ -2033,6 +2033,40 @@ void irgen::emitExistentialMetatypeContainer(IRGenFunction &IGF, }); } +/// Emit an existential metatype container from a metatype value as an +/// explosion of llvm::Constant values (suitable for static initialization). +void irgen::emitExistentialMetatypeContainer( + IRGenModule &IGM, Explosion &out, SILType outType, llvm::Constant *metatype, + SILType metatypeType, ArrayRef conformances) { + assert(outType.is()); + auto &destTI = IGM.getTypeInfo(outType).as(); + out.add(metatype); + + auto srcType = metatypeType.castTo().getInstanceType(); + auto destType = outType.castTo().getInstanceType(); + while (auto destMetatypeType = dyn_cast(destType)) { + destType = destMetatypeType.getInstanceType(); + srcType = cast(srcType).getInstanceType(); + } + + // Emit the witness table pointers as constants. + for (auto protocol : destTI.getStoredProtocols()) { + // Find the corresponding conformance + ProtocolConformanceRef conformance; + for (auto conf : conformances) { + if (conf.getProtocol() == protocol) { + conformance = conf; + break; + } + } + assert(conformance.isConcrete() && "missing conformance"); + + // Emit witness table constant + auto table = IGM.getAddrOfWitnessTable(conformance.getConcrete()); + out.add(table); + } +} + void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address buffer, SILType type, Explosion &out) { assert(type.isExistentialType()); diff --git a/lib/IRGen/GenExistential.h b/lib/IRGen/GenExistential.h index 32af225a38545..4159c37d61e3d 100644 --- a/lib/IRGen/GenExistential.h +++ b/lib/IRGen/GenExistential.h @@ -34,6 +34,7 @@ namespace irgen { class Address; class Explosion; class IRGenFunction; + class IRGenModule; /// Emit the metadata and witness table initialization for an allocated /// opaque existential container. @@ -44,16 +45,20 @@ namespace irgen { SILType loweredSrcType, ArrayRef conformances); - /// Emit an existential metatype container from a metatype value - /// as an explosion. - void emitExistentialMetatypeContainer(IRGenFunction &IGF, - Explosion &out, - SILType outType, - llvm::Value *metatype, - SILType metatypeType, - ArrayRef conformances); - - + /// Emit an existential metatype container from a metatype value as an + /// explosion. + void emitExistentialMetatypeContainer( + IRGenFunction &IGF, Explosion &out, SILType outType, + llvm::Value *metatype, SILType metatypeType, + ArrayRef conformances); + + /// Emit an existential metatype container from a metatype value as an + /// explosion of llvm::Constant values (suitable for static initialization). + void emitExistentialMetatypeContainer( + IRGenModule &IGM, Explosion &out, SILType outType, + llvm::Constant *metatype, SILType metatypeType, + ArrayRef conformances); + /// Emit a class existential container from a class instance value /// as an explosion. void emitClassExistentialContainer(IRGenFunction &IGF, diff --git a/lib/SIL/IR/SILInstructions.cpp b/lib/SIL/IR/SILInstructions.cpp index f6abf477dbcfb..eac25389be153 100644 --- a/lib/SIL/IR/SILInstructions.cpp +++ b/lib/SIL/IR/SILInstructions.cpp @@ -2328,6 +2328,17 @@ InitExistentialMetatypeInst::InitExistentialMetatypeInst( getTrailingObjects()); } +InitExistentialMetatypeInst *InitExistentialMetatypeInst::create( + SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype, + ArrayRef conformances, SILModule &M) { + unsigned size = totalSizeToAlloc( + 1, conformances.size()); + void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst)); + return ::new (buffer) InitExistentialMetatypeInst( + Loc, existentialMetatypeType, metatype, + {}, conformances); +} + InitExistentialMetatypeInst *InitExistentialMetatypeInst::create( SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype, ArrayRef conformances, SILFunction *F) { @@ -2738,6 +2749,13 @@ CheckedCastBranchInst *CheckedCastBranchInst::create( Target2Count, forwardingOwnershipKind, preservesOwnership); } +MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty, + SILModule &Mod) { + auto Size = totalSizeToAlloc(1); + auto Buffer = Mod.allocateInst(Size, alignof(MetatypeInst)); + return ::new (Buffer) MetatypeInst(Loc, Ty, {}); +} + MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty, SILFunction *F) { SILModule &Mod = F->getModule(); diff --git a/lib/Sema/LegalConstExprVerifier.cpp b/lib/Sema/LegalConstExprVerifier.cpp index 62f3c611def0c..359bd87436bf6 100644 --- a/lib/Sema/LegalConstExprVerifier.cpp +++ b/lib/Sema/LegalConstExprVerifier.cpp @@ -22,6 +22,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/ParameterList.h" #include "swift/AST/SemanticAttrs.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/Basic/Assertions.h" using namespace swift; @@ -328,7 +329,9 @@ checkSupportedWithSectionAttribute(const Expr *expr, auto instanceType = baseType->getMetatypeInstanceType(); if (auto nominal = instanceType->getNominalOrBoundGenericNominal()) { // Allow non-generic, non-resilient types - if (!nominal->hasGenericParamList() && !nominal->isResilient()) { + if (!nominal->hasGenericParamList() && + !nominal->getDeclContext()->isGenericContext() && + !nominal->isResilient()) { continue; } } @@ -344,6 +347,56 @@ checkSupportedWithSectionAttribute(const Expr *expr, continue; } + // Upcasts of metatypes to existential metatypes (e.g. Any.Type) + if (const ErasureExpr *erasureExpr = dyn_cast(expr)) { + // Only allow concrete conformances when the protocol, type and + // conformance are all from the current module (except for + // Copyable+Escapable so that we can upcast to Any.Type) + bool allConformanceAreOkay = true; + for (auto conformance : erasureExpr->getConformances()) { + auto concreteConformance = conformance.getConcrete(); + if (!concreteConformance) { + allConformanceAreOkay = false; + break; + } + if (conformance.getProtocol()->getInvertibleProtocolKind()) { + continue; + } + auto conformanceModule = + concreteConformance->getDeclContext()->getParentModule(); + if (conformanceModule != declContext->getParentModule() || + conformanceModule != conformance.getProtocol()->getParentModule()) { + allConformanceAreOkay = false; + break; + } + } + + if (!allConformanceAreOkay) { + return std::make_pair(expr, TypeExpression); + } + + if (const DotSelfExpr *dotSelfExpr = + dyn_cast(erasureExpr->getSubExpr())) { + if (const TypeExpr *typeExpr = + dyn_cast(dotSelfExpr->getSubExpr())) { + auto baseType = typeExpr->getType(); + if (baseType && baseType->is()) { + auto instanceType = baseType->getMetatypeInstanceType(); + if (auto nominal = + instanceType->getNominalOrBoundGenericNominal()) { + // Allow non-generic, non-resilient types + if (!nominal->hasGenericParamList() && + !nominal->getDeclContext()->isGenericContext() && + !nominal->isResilient()) { + continue; + } + } + } + } + } + return std::make_pair(expr, TypeExpression); + } + // Function calls and constructors are not allowed if (isa(expr)) return std::make_pair(expr, Default); diff --git a/test/ConstValues/SectionIR.swift b/test/ConstValues/SectionIR.swift index a981b2de77806..98aaaa26107e3 100644 --- a/test/ConstValues/SectionIR.swift +++ b/test/ConstValues/SectionIR.swift @@ -39,8 +39,16 @@ struct W { @section("mysection") static let closure7: @convention(c) (Int) -> Int = { x in x * 2 } } -// metatypes - TODO -//@section("mysection") let metatype1 = Int.self +protocol P1 { } +protocol P2 { } +struct S: Hashable, Sendable, P1, P2 {} + +// metatypes +@section("mysection") let metatype1 = Int.self +@section("mysection") let metatype2: Any.Type = Int.self +@section("mysection") let metatype3: Any.Type = S.self +@section("mysection") let metatype4: any (P1).Type = S.self +@section("mysection") let metatype5: any (P1 & P2).Type = S.self // tuples @section("mysection") let tuple1 = (1, 2, 3, 2.718, true) // ok @@ -76,6 +84,11 @@ struct W { // CHECK: @"$s9SectionIR8closure6yS2iXCvp" = {{.*}}constant ptr @"$s9SectionIR8closure6yS2iXCvpfiS2icfU_To{{(.ptrauth)?}}", section "mysection" // CHECK: @"$s9SectionIR1WV8closure7yS2iXCvpZ" = {{.*}}constant ptr @"$s9SectionIR1WV8closure7yS2iXCvpZfiS2icfU_To{{(.ptrauth)?}}", section "mysection" +// CHECK: @"$s9SectionIR9metatype2ypXpvp" = {{.*}}constant ptr @"$sSiN", section "mysection" +// CHECK: @"$s9SectionIR9metatype3ypXpvp" = {{.*}}constant ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), section "mysection" +// CHECK: @"$s9SectionIR9metatype4AA2P1_pXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVAA2P1AAWP" }>, section "mysection" +// CHECK: @"$s9SectionIR9metatype5AA2P1_AA2P2pXpvp" = {{.*}}constant <{ ptr, ptr, ptr }> <{ ptr getelementptr inbounds (<{ ptr, ptr, {{i64|i32}}, ptr }>, ptr @"$s9SectionIR1SVMf", i32 0, i32 2), ptr @"$s9SectionIR1SVAA2P1AAWP", ptr @"$s9SectionIR1SVAA2P2AAWP" }>, section "mysection" + // CHECK: @"$s9SectionIR6tuple1Si_S2iSdSbtvp" = {{.*}}constant <{ %TSi, %TSi, %TSi, {{.*}} }> <{ %TSi <{ {{i64|i32}} 1 }>, %TSi <{ {{i64|i32}} 2 }>, %TSi <{ {{i64|i32}} 3 }>, {{.*}} }>, section "mysection" // CHECK: @"$s9SectionIR6tuple2Si_SfSbtvp" = {{.*}}constant <{ %TSi, %TSf, %TSb }> <{ %TSi <{ {{i64|i32}} 42 }>, %TSf <{ float 0x40091EB860000000 }>, %TSb zeroinitializer }>, section "mysection" // CHECK: @"$s9SectionIR6tuple3Siyc_SSSictvp" = {{.*}}constant <{ %swift.function, %swift.function }> <{ %swift.function { ptr @"$s9SectionIR3fooSiyF{{.*}}", ptr null }, %swift.function { ptr @"$s9SectionIR3bar1xSSSi_tF{{.*}}", ptr null } }>, section "mysection" diff --git a/test/ConstValues/SectionSyntactic.swift b/test/ConstValues/SectionSyntactic.swift index ce2165a25cc36..de4a2f43c13df 100644 --- a/test/ConstValues/SectionSyntactic.swift +++ b/test/ConstValues/SectionSyntactic.swift @@ -118,9 +118,16 @@ var capturedMutableVar = TestClass() struct S { } enum E { case a } +protocol P1 { } +protocol P2 { } +extension S: P1, P2 { } // metatypes @section("mysection") let metatype1 = Int.self // ok +@section("mysection") let metatype2: Any.Type = Int.self // ok +@section("mysection") let metatype3: Any.Type = S.self // ok +@section("mysection") let metatype4: any (P1).Type = S.self // ok +@section("mysection") let metatype5: any (P1 & P2).Type = S.self // ok // invalid metatype references @section("mysection") let invalidMetatype1 = Int.self.self @@ -131,6 +138,14 @@ enum E { case a } // expected-error@-1{{type expressions not supported in a constant expression}} @section("mysection") let invalidMetatype4 = Mirror.self // resilient // expected-error@-1{{type expressions not supported in a constant expression}} +@section("mysection") let invalidMetatype5: any (Hashable).Type = Int.self +// expected-error@-1{{type expressions not supported in a constant expression}} +@section("mysection") let invalidMetatype6: any (Hashable & Sendable).Type = Int.self +// expected-error@-1{{type expressions not supported in a constant expression}} +@section("mysection") let invalidMetatype7: any (Sendable).Type = S.self +// expected-error@-1{{type expressions not supported in a constant expression}} +@section("mysection") let invalidMetatype8: any (P1 & Sendable).Type = S.self +// expected-error@-1{{type expressions not supported in a constant expression}} // tuples @section("mysection") let tuple1 = (1, 2, 3, 2.718, true) // ok diff --git a/test/SILOptimizer/static_init_metatypes.swift b/test/SILOptimizer/static_init_metatypes.swift new file mode 100644 index 0000000000000..c13b18d145ee1 --- /dev/null +++ b/test/SILOptimizer/static_init_metatypes.swift @@ -0,0 +1,111 @@ +// RUN: %target-swift-frontend %s -parse-as-library -module-name=test -emit-sil | %FileCheck --check-prefix=SIL %s +// RUN: %target-swift-frontend %s -parse-as-library -O -module-name=test -emit-sil | %FileCheck --check-prefix=SIL %s + +// RUN: %target-swift-frontend %s -parse-as-library -module-name=test -emit-ir | %FileCheck --check-prefix=IR %s +// RUN: %target-swift-frontend %s -parse-as-library -O -module-name=test -emit-ir | %FileCheck --check-prefix=IR %s + +// RUN: %target-run-simple-swift(-parse-as-library) +// RUN: %target-run-simple-swift(-parse-as-library -O) + +// REQUIRES: executable_test + +// TODO: Resolve link-time error (unresolved external symbol $sSiN) to Windows +// XFAIL: OS=windows-msvc + +public protocol MyProtocol {} +public protocol MyProtocol2 {} + +public struct S: Hashable, Sendable, MyProtocol, MyProtocol2 {} +extension Int: MyProtocol, MyProtocol2 {} + +public let metatype1 = Int.self +// SIL: sil_global [let] @$s4test9metatype1Simvp : $@thin Int.Type = { +// SIL-NEXT: %initval = metatype $@thin Int.Type +// SIL-NEXT: } +public let metatype2 = S.self +// SIL: sil_global [let] @$s4test9metatype2AA1SVmvp : $@thin S.Type = { +// SIL-NEXT: %initval = metatype $@thin S.Type +// SIL-NEXT: } +public let metatype3: Any.Type = Int.self +// SIL: sil_global [let] @$s4test9metatype3ypXpvp : $@thick any Any.Type = { +// SIL-NEXT: %0 = metatype $@thick Int.Type // user: %1 +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any Any.Type +// SIL-NEXT: } +public let metatype4: Any.Type = S.self +// SIL: sil_global [let] @$s4test9metatype4ypXpvp : $@thick any Any.Type = { +// SIL-NEXT: %0 = metatype $@thick S.Type // user: %1 +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any Any.Type +// SIL-NEXT: } +public let metatype5: any MyProtocol.Type = Int.self +// SIL: sil_global [let] @$s4test9metatype5AA10MyProtocol_pXpvp : $@thick any MyProtocol.Type = { +// SIL-NEXT: %0 = metatype $@thick Int.Type // user: %1 +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any MyProtocol.Type +// SIL-NEXT: } +public let metatype6: any MyProtocol.Type = S.self +// SIL: sil_global [let] @$s4test9metatype6AA10MyProtocol_pXpvp : $@thick any MyProtocol.Type = { +// SIL-NEXT: %0 = metatype $@thick S.Type // user: %1 +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any MyProtocol.Type +// SIL-NEXT: } +public let metatype7: any (MyProtocol & MyProtocol2).Type = Int.self +// SIL: sil_global [let] @$s4test9metatype7AA10MyProtocol_AA0C9Protocol2pXpvp : $@thick any (MyProtocol & MyProtocol2).Type = { +// SIL-NEXT: %0 = metatype $@thick Int.Type // user: %1 +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any (MyProtocol & MyProtocol2).Type +// SIL-NEXT: } +public let metatype8: any (MyProtocol & MyProtocol2).Type = S.self +// SIL: sil_global [let] @$s4test9metatype8AA10MyProtocol_AA0C9Protocol2pXpvp : $@thick any (MyProtocol & MyProtocol2).Type = { +// SIL-NEXT: %0 = metatype $@thick S.Type // user: %1 +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any (MyProtocol & MyProtocol2).Type +// SIL-NEXT: } +public let metatype9: any Hashable.Type = Int.self +// SIL: sil_global [let] @$s4test9metatype9SH_pXpvp : $@thick any Hashable.Type +// SIL-EMPTY: +public let metatype10: any Hashable.Type = S.self +// SIL: sil_global [let] @$s4test10metatype10SH_pXpvp : $@thick any Hashable.Type +// SIL-EMPTY: +public let metatype11: any (Hashable & Sendable).Type = Int.self +// SIL: sil_global [let] @$s4test10metatype11SH_s8SendablepXpvp : $@thick any (Hashable & Sendable).Type +// SIL-EMPTY: +public let metatype12: any (Hashable & Sendable).Type = S.self +// SIL: sil_global [let] @$s4test10metatype12SH_s8SendablepXpvp : $@thick any (Hashable & Sendable).Type +// SIL-EMPTY: +public let metatype13: any (Hashable & MyProtocol).Type = Int.self +// SIL: sil_global [let] @$s4test10metatype13SH_AA10MyProtocolpXpvp : $@thick any (Hashable & MyProtocol).Type +// SIL-EMPTY: +public let metatype14: any (Hashable & MyProtocol).Type = S.self +// SIL: sil_global [let] @$s4test10metatype14SH_AA10MyProtocolpXpvp : $@thick any (Hashable & MyProtocol).Type +// SIL-EMPTY: +public let metatype15: Any.Type = Array.self +// SIL: sil_global [let] @$s4test10metatype15ypXpvp : $@thick any Any.Type +// SIL-EMPTY: +public let metatype16: any (Hashable & Sendable).Type = Array.self +// SIL: sil_global [let] @$s4test10metatype16SH_s8SendablepXpvp : $@thick any (Hashable & Sendable).Type +// SIL-EMPTY: +public let metatype17: Any.Type = (Bool.random() ? Array.self : Array.self).self +// SIL: sil_global [let] @$s4test10metatype17ypXpvp : $@thick any Any.Type +// SIL-EMPTY: +public let metatype18: Any.Type = Mirror.self // resilient +// SIL: sil_global [let] @$s4test10metatype18ypXpvp : $@thick any Any.Type +// SIL-EMPTY: +public var metatype19: Any.Type = (any MyProtocol).self +// SIL: sil_global @$s4test10metatype19ypXpvp : $@thick any Any.Type +// SIL-EMPTY: +public var metatype20: [Any.Type] = [(any MyProtocol).self] +// SIL: sil_global @$s4test10metatype20SayypXpGvp : $Array +// SIL-EMPTY: +public var metatype21: [Any.Type] = [Int.self] +// SIL: sil_global @$s4test10metatype21SayypXpGvp : $Array +// SIL-EMPTY: +public var metatype22: [Any.Type] = [S.self] +// SIL: sil_global @$s4test10metatype22SayypXpGvp : $Array +// SIL-EMPTY: + +// Only to detect link-time missing symbols +@main +struct Main { static func main() { } } + +// IR: @"$s4test9metatype3ypXpvp" = {{.*}}constant ptr @"$sSiN" +// IR: @"$s4test9metatype4ypXpvp" = {{.*}}constant ptr getelementptr inbounds{{.*}} ({{.*}}, ptr @"$s4test1SVMf", {{.*}}) +// IR: @"$s4test9metatype5AA10MyProtocol_pXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr @"$sSiN", ptr @"$sSi4test10MyProtocolAAWP" }> +// IR: @"$s4test9metatype6AA10MyProtocol_pXpvp" = {{.*}}constant <{ ptr, ptr }> <{ ptr getelementptr inbounds{{.*}} ({{.*}}, ptr @"$s4test1SVMf", {{.*}}), ptr @"$s4test1SVAA10MyProtocolAAWP" }> +// IR: @"$s4test9metatype7AA10MyProtocol_AA0C9Protocol2pXpvp" = {{.*}}constant <{ ptr, ptr, ptr }> <{ ptr @"$sSiN", ptr @"$sSi4test10MyProtocolAAWP", ptr @"$sSi4test11MyProtocol2AAWP" }> +// IR: @"$s4test9metatype8AA10MyProtocol_AA0C9Protocol2pXpvp" = {{.*}}constant <{ ptr, ptr, ptr }> <{ ptr getelementptr inbounds{{.*}} ({{.*}}, ptr @"$s4test1SVMf", {{.*}}), ptr @"$s4test1SVAA10MyProtocolAAWP", ptr @"$s4test1SVAA11MyProtocol2AAWP" }> diff --git a/test/SILOptimizer/static_init_metatypes2.swift b/test/SILOptimizer/static_init_metatypes2.swift new file mode 100644 index 0000000000000..a9f657971dcb8 --- /dev/null +++ b/test/SILOptimizer/static_init_metatypes2.swift @@ -0,0 +1,38 @@ +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-frontend -parse-as-library -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -O +// XXX: %target-swift-frontend -parse-as-library -I %t %t/Main.swift -O -emit-sil | %FileCheck %s --check-prefix SIL +// RUN: %target-swift-frontend -parse-as-library -I %t %t/Main.swift -O -emit-ir | %FileCheck %s --check-prefix IR + +// BEGIN MyModule.swift + +public class MyClass {} +public struct MyStruct {} + +// BEGIN Main.swift + +import MyModule + +public let classMetatype: Any.Type = MyClass.self +public let classMetatypeArray: [Any.Type] = [classMetatype] + +public let structMetatype: Any.Type = MyStruct.self +public let structMetatypeArray: [Any.Type] = [structMetatype] + +// SIL: sil_global [let] @$s4Main13classMetatypeypXpvp : $@thick any Any.Type +// SIL-EMPTY: +// SIL: sil_global [let] @$s4Main18classMetatypeArraySayypXpGvp : $Array +// SIL-EMPTY: +// SIL: sil_global [let] @$s4Main14structMetatypeypXpvp : $@thick any Any.Type = { +// SIL-NEXT: %0 = metatype $@thick MyStruct.Type +// SIL-NEXT: %initval = init_existential_metatype %0, $@thick any Any.Type +// SIL-NEXT: } +// SIL: sil_global [let] @$s4Main19structMetatypeArraySayypXpGvp : $Array +// SIL-EMPTY: + +// IR: @"$s4Main13classMetatypeypXpvp" = {{.*}}global { ptr } zeroinitializer +// IR: @"$s4Main18classMetatypeArraySayypXpGvp" = {{.*}}global %TSa zeroinitializer +// IR: @"$s8MyModule0A6StructVN" = {{.*}}global %swift.type +// IR: @"$s4Main14structMetatypeypXpvp" = {{.*}}constant ptr @"$s8MyModule0A6StructVN" +// IR: @"$s4Main19structMetatypeArraySayypXpGvp" = {{.*}}global %TSa zeroinitializer diff --git a/test/SILOptimizer/static_init_metatypes3.swift b/test/SILOptimizer/static_init_metatypes3.swift new file mode 100644 index 0000000000000..14bd63844ac5f --- /dev/null +++ b/test/SILOptimizer/static_init_metatypes3.swift @@ -0,0 +1,25 @@ +// RUN: %empty-directory(%t) +// RUN: %{python} %utils/split_file.py -o %t %s + +// RUN: %target-swift-frontend -parse-as-library -emit-module -o %t/MyModule.swiftmodule %t/MyModule.swift -O +// RUN: %target-swift-frontend -parse-as-library -I %t %t/Main.swift -O -emit-ir | %FileCheck %s + +// BEGIN MyModule.swift + +public struct NonResilientTypeContainingAResilientType { + var m: Mirror? = nil +} + +// BEGIN Main.swift + +import MyModule + +public protocol MyProtocol {} + +public struct MyStruct: MyProtocol { + public var x: NonResilientTypeContainingAResilientType? = nil +} + +public let glob: [any MyProtocol.Type] = [MyStruct.self] + +// CHECK: @"$s4Main4globSayAA10MyProtocol_pXpGvp" = {{.*}}global %TSa zeroinitializer diff --git a/utils/build-presets.ini b/utils/build-presets.ini index 040cbccaacee9..f61371c43cc2c 100644 --- a/utils/build-presets.ini +++ b/utils/build-presets.ini @@ -946,6 +946,7 @@ mixin-preset= buildbot_linux_base skip-test-swiftdocc +verbose-build [preset: buildbot_linux,release_foundation_tests] mixin-preset=buildbot_linux