mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #76572 from kubamracek/embedded-class-bound-existentials
[embedded] Introduce class-bound existentials into Embedded Swift
This commit is contained in:
@@ -89,9 +89,23 @@ inline bool isEmbedded(CanType t) {
|
|||||||
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded);
|
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Metadata is not generated and not allowed to be referenced in Embedded Swift,
|
||||||
|
// expect for classes (both generic and non-generic), dynamic self, and
|
||||||
|
// class-bound existentials.
|
||||||
inline bool isMetadataAllowedInEmbedded(CanType t) {
|
inline bool isMetadataAllowedInEmbedded(CanType t) {
|
||||||
return isa<ClassType>(t) || isa<BoundGenericClassType>(t) ||
|
if (isa<ClassType>(t) || isa<BoundGenericClassType>(t) ||
|
||||||
isa<DynamicSelfType>(t);
|
isa<DynamicSelfType>(t)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (auto existentialTy = dyn_cast<ExistentialType>(t)) {
|
||||||
|
if (existentialTy->requiresClass())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (auto archeTy = dyn_cast<ArchetypeType>(t)) {
|
||||||
|
if (archeTy->requiresClass())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isEmbedded(Decl *d) {
|
inline bool isEmbedded(Decl *d) {
|
||||||
@@ -1062,7 +1076,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LinkEntity forProtocolWitnessTable(const RootProtocolConformance *C) {
|
static LinkEntity forProtocolWitnessTable(const RootProtocolConformance *C) {
|
||||||
assert(!isEmbedded(C));
|
if (isEmbedded(C)) {
|
||||||
|
assert(C->getProtocol()->requiresClass());
|
||||||
|
}
|
||||||
|
|
||||||
LinkEntity entity;
|
LinkEntity entity;
|
||||||
entity.setForProtocolConformance(Kind::ProtocolWitnessTable, C);
|
entity.setForProtocolConformance(Kind::ProtocolWitnessTable, C);
|
||||||
return entity;
|
return entity;
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ enum class RuntimeEffect : unsigned {
|
|||||||
/// Witness methods, boxing, unboxing, initializing, etc.
|
/// Witness methods, boxing, unboxing, initializing, etc.
|
||||||
Existential = 0x80,
|
Existential = 0x80,
|
||||||
|
|
||||||
|
/// Class-bound only existential
|
||||||
|
ExistentialClassBound = 0x200,
|
||||||
|
|
||||||
/// Not modelled currently.
|
/// Not modelled currently.
|
||||||
Concurrency = 0x0,
|
Concurrency = 0x0,
|
||||||
|
|
||||||
|
|||||||
@@ -1142,8 +1142,9 @@ void IRGenModule::emitGlobalLists() {
|
|||||||
// Eagerly emit functions that are externally visible. Functions that are
|
// Eagerly emit functions that are externally visible. Functions that are
|
||||||
// dynamic replacements must also be eagerly emitted.
|
// dynamic replacements must also be eagerly emitted.
|
||||||
static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
|
static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
|
||||||
// Embedded Swift only emits specialized function, so don't emit generic
|
// Embedded Swift only emits specialized function (except when they are
|
||||||
// functions, even if they're externally visible.
|
// protocol witness methods). So don't emit generic functions, even if they're
|
||||||
|
// externally visible.
|
||||||
if (f.getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
|
if (f.getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
|
||||||
f.getLoweredFunctionType()->getSubstGenericSignature()) {
|
f.getLoweredFunctionType()->getSubstGenericSignature()) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1332,7 +1333,7 @@ void IRGenerator::emitLazyDefinitions() {
|
|||||||
assert(LazyFieldDescriptors.empty());
|
assert(LazyFieldDescriptors.empty());
|
||||||
// LazyFunctionDefinitions are allowed, but they must not be generic
|
// LazyFunctionDefinitions are allowed, but they must not be generic
|
||||||
for (SILFunction *f : LazyFunctionDefinitions) {
|
for (SILFunction *f : LazyFunctionDefinitions) {
|
||||||
assert(!f->isGeneric());
|
assert(hasValidSignatureForEmbedded(f));
|
||||||
}
|
}
|
||||||
assert(LazyWitnessTables.empty());
|
assert(LazyWitnessTables.empty());
|
||||||
assert(LazyCanonicalSpecializedMetadataAccessors.empty());
|
assert(LazyCanonicalSpecializedMetadataAccessors.empty());
|
||||||
@@ -1482,7 +1483,7 @@ void IRGenerator::addLazyFunction(SILFunction *f) {
|
|||||||
|
|
||||||
// Embedded Swift doesn't expect any generic functions to be referenced.
|
// Embedded Swift doesn't expect any generic functions to be referenced.
|
||||||
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
|
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
assert(!f->isGeneric());
|
assert(hasValidSignatureForEmbedded(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!FinishedEmittingLazyDefinitions);
|
assert(!FinishedEmittingLazyDefinitions);
|
||||||
@@ -3472,6 +3473,24 @@ llvm::CallBase *swift::irgen::emitCXXConstructorCall(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For a SILFunction to be legal in Embedded Swift, it must be either
|
||||||
|
// - non-generic
|
||||||
|
// - generic with parameters thar are either
|
||||||
|
// - fully specialized (concrete)
|
||||||
|
// - a class-bound archetype (class-bound existential)
|
||||||
|
bool swift::irgen::hasValidSignatureForEmbedded(SILFunction *f) {
|
||||||
|
auto s = f->getLoweredFunctionType()->getInvocationGenericSignature();
|
||||||
|
for (auto genParam : s.getGenericParams()) {
|
||||||
|
auto mappedParam = f->getGenericEnvironment()->mapTypeIntoContext(genParam);
|
||||||
|
if (auto archeTy = dyn_cast<ArchetypeType>(mappedParam)) {
|
||||||
|
if (archeTy->requiresClass())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
StackProtectorMode IRGenModule::shouldEmitStackProtector(SILFunction *f) {
|
StackProtectorMode IRGenModule::shouldEmitStackProtector(SILFunction *f) {
|
||||||
const SILOptions &opts = IRGen.SIL.getOptions();
|
const SILOptions &opts = IRGen.SIL.getOptions();
|
||||||
return (opts.EnableStackProtection && f->needsStackProtection()) ?
|
return (opts.EnableStackProtection && f->needsStackProtection()) ?
|
||||||
@@ -4351,6 +4370,9 @@ static bool conformanceIsVisibleViaMetadata(
|
|||||||
|
|
||||||
|
|
||||||
void IRGenModule::addProtocolConformance(ConformanceDescription &&record) {
|
void IRGenModule::addProtocolConformance(ConformanceDescription &&record) {
|
||||||
|
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
emitProtocolConformance(record);
|
emitProtocolConformance(record);
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ namespace irgen {
|
|||||||
llvm::FunctionType *ctorFnType,
|
llvm::FunctionType *ctorFnType,
|
||||||
llvm::Constant *ctorAddress,
|
llvm::Constant *ctorAddress,
|
||||||
llvm::ArrayRef<llvm::Value *> args);
|
llvm::ArrayRef<llvm::Value *> args);
|
||||||
|
|
||||||
|
bool hasValidSignatureForEmbedded(SILFunction *f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1791,11 +1791,6 @@ static void forEachProtocolWitnessTable(
|
|||||||
assert(protocols.size() == witnessConformances.size() &&
|
assert(protocols.size() == witnessConformances.size() &&
|
||||||
"mismatched protocol conformances");
|
"mismatched protocol conformances");
|
||||||
|
|
||||||
// Don't emit witness tables in embedded Swift.
|
|
||||||
if (srcType->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = protocols.size(); i < e; ++i) {
|
for (unsigned i = 0, e = protocols.size(); i < e; ++i) {
|
||||||
assert(protocols[i] == witnessConformances[i].getRequirement());
|
assert(protocols[i] == witnessConformances[i].getRequirement());
|
||||||
auto table = emitWitnessTableRef(IGF, srcType, srcMetadataCache,
|
auto table = emitWitnessTableRef(IGF, srcType, srcMetadataCache,
|
||||||
|
|||||||
@@ -1516,6 +1516,13 @@ public:
|
|||||||
/// Add reference to the protocol conformance descriptor that generated
|
/// Add reference to the protocol conformance descriptor that generated
|
||||||
/// this table.
|
/// this table.
|
||||||
void addProtocolConformanceDescriptor() {
|
void addProtocolConformanceDescriptor() {
|
||||||
|
// In Embedded Swift, there are no protocol conformance descriptors. Emit
|
||||||
|
// a null pointer instead to keep the same layout as regular Swift.
|
||||||
|
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
|
Table.addNullPointer(IGM.Int8PtrTy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto descriptor =
|
auto descriptor =
|
||||||
IGM.getAddrOfProtocolConformanceDescriptor(&Conformance);
|
IGM.getAddrOfProtocolConformanceDescriptor(&Conformance);
|
||||||
if (isRelative)
|
if (isRelative)
|
||||||
@@ -2564,6 +2571,8 @@ static void addWTableTypeMetadata(IRGenModule &IGM,
|
|||||||
|
|
||||||
void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
|
void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
|
||||||
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
|
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
|
// In Embedded Swift, only class-bound wtables are allowed.
|
||||||
|
if (!wt->getConformance()->getProtocol()->requiresClass())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3564,9 +3573,13 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
|
|||||||
CanType srcType,
|
CanType srcType,
|
||||||
llvm::Value **srcMetadataCache,
|
llvm::Value **srcMetadataCache,
|
||||||
ProtocolConformanceRef conformance) {
|
ProtocolConformanceRef conformance) {
|
||||||
assert(!srcType->getASTContext().LangOpts.hasFeature(Feature::Embedded));
|
|
||||||
|
|
||||||
auto proto = conformance.getRequirement();
|
auto proto = conformance.getRequirement();
|
||||||
|
|
||||||
|
// In Embedded Swift, only class-bound wtables are allowed.
|
||||||
|
if (srcType->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
|
assert(proto->requiresClass());
|
||||||
|
}
|
||||||
|
|
||||||
assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto)
|
assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto)
|
||||||
&& "protocol does not have witness tables?!");
|
&& "protocol does not have witness tables?!");
|
||||||
|
|
||||||
|
|||||||
@@ -1407,7 +1407,10 @@ bool IRGenerator::canEmitWitnessTableLazily(SILWitnessTable *wt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRGenerator::addLazyWitnessTable(const ProtocolConformance *Conf) {
|
void IRGenerator::addLazyWitnessTable(const ProtocolConformance *Conf) {
|
||||||
assert(!SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded));
|
// In Embedded Swift, only class-bound wtables are allowed.
|
||||||
|
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
|
assert(Conf->getProtocol()->requiresClass());
|
||||||
|
}
|
||||||
|
|
||||||
if (auto *wt = SIL.lookUpWitnessTable(Conf)) {
|
if (auto *wt = SIL.lookUpWitnessTable(Conf)) {
|
||||||
// Add it to the queue if it hasn't already been put there.
|
// Add it to the queue if it hasn't already been put there.
|
||||||
|
|||||||
@@ -2478,10 +2478,6 @@ void IRGenModule::emitSILFunction(SILFunction *f) {
|
|||||||
if (f->isExternalDeclaration())
|
if (f->isExternalDeclaration())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Context.LangOpts.hasFeature(Feature::Embedded) &&
|
|
||||||
f->getLoweredFunctionType()->isPolymorphic())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Do not emit bodies of public_external or package_external functions.
|
// Do not emit bodies of public_external or package_external functions.
|
||||||
if (hasPublicOrPackageVisibility(f->getLinkage(),
|
if (hasPublicOrPackageVisibility(f->getLinkage(),
|
||||||
f->getASTContext().SILOpts.EnableSerializePackage) &&
|
f->getASTContext().SILOpts.EnableSerializePackage) &&
|
||||||
|
|||||||
@@ -671,9 +671,13 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
|
|||||||
RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
||||||
|
|
||||||
case SILInstructionKind::InitExistentialRefInst:
|
case SILInstructionKind::InitExistentialRefInst:
|
||||||
|
impactType = inst->getOperand(0)->getType();
|
||||||
|
return RuntimeEffect::MetaData | RuntimeEffect::ExistentialClassBound;
|
||||||
|
|
||||||
case SILInstructionKind::InitExistentialMetatypeInst:
|
case SILInstructionKind::InitExistentialMetatypeInst:
|
||||||
impactType = inst->getOperand(0)->getType();
|
impactType = inst->getOperand(0)->getType();
|
||||||
return RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
return RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
||||||
|
|
||||||
case SILInstructionKind::ObjCToThickMetatypeInst:
|
case SILInstructionKind::ObjCToThickMetatypeInst:
|
||||||
impactType = inst->getOperand(0)->getType();
|
impactType = inst->getOperand(0)->getType();
|
||||||
return RuntimeEffect::MetaData;
|
return RuntimeEffect::MetaData;
|
||||||
@@ -693,14 +697,8 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
|
|||||||
return RuntimeEffect::Existential;
|
return RuntimeEffect::Existential;
|
||||||
|
|
||||||
case SILInstructionKind::OpenExistentialRefInst: {
|
case SILInstructionKind::OpenExistentialRefInst: {
|
||||||
SILType opType = cast<OpenExistentialRefInst>(inst)->getOperand()->getType();
|
impactType = inst->getOperand(0)->getType();
|
||||||
impactType = opType;
|
return RuntimeEffect::MetaData | RuntimeEffect::ExistentialClassBound;
|
||||||
if (opType.getASTType()->isObjCExistentialType()) {
|
|
||||||
return RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
|
||||||
}
|
|
||||||
return RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
|
||||||
// TODO: should be Existential
|
|
||||||
//return RuntimeEffect::Existential;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case SILInstructionKind::UnconditionalCheckedCastInst:
|
case SILInstructionKind::UnconditionalCheckedCastInst:
|
||||||
@@ -962,9 +960,16 @@ RuntimeEffect swift::getRuntimeEffect(SILInstruction *inst, SILType &impactType)
|
|||||||
case SILFunctionTypeRepresentation::Block:
|
case SILFunctionTypeRepresentation::Block:
|
||||||
rt |= RuntimeEffect::ObjectiveC | RuntimeEffect::MetaData;
|
rt |= RuntimeEffect::ObjectiveC | RuntimeEffect::MetaData;
|
||||||
break;
|
break;
|
||||||
case SILFunctionTypeRepresentation::WitnessMethod:
|
case SILFunctionTypeRepresentation::WitnessMethod: {
|
||||||
|
auto conformance =
|
||||||
|
as.getOrigCalleeType()->getWitnessMethodConformanceOrInvalid();
|
||||||
|
if (conformance.getRequirement()->requiresClass()) {
|
||||||
|
rt |= RuntimeEffect::MetaData | RuntimeEffect::ExistentialClassBound;
|
||||||
|
} else {
|
||||||
rt |= RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
rt |= RuntimeEffect::MetaData | RuntimeEffect::Existential;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SILFunctionTypeRepresentation::CFunctionPointer:
|
case SILFunctionTypeRepresentation::CFunctionPointer:
|
||||||
case SILFunctionTypeRepresentation::CXXMethod:
|
case SILFunctionTypeRepresentation::CXXMethod:
|
||||||
case SILFunctionTypeRepresentation::Thin:
|
case SILFunctionTypeRepresentation::Thin:
|
||||||
|
|||||||
@@ -534,7 +534,8 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
|
|||||||
LocWithParent loc(inst->getLoc().getSourceLoc(), parentLoc);
|
LocWithParent loc(inst->getLoc().getSourceLoc(), parentLoc);
|
||||||
|
|
||||||
if (perfConstr == PerformanceConstraints::NoExistentials &&
|
if (perfConstr == PerformanceConstraints::NoExistentials &&
|
||||||
(impact & RuntimeEffect::Existential)) {
|
((impact & RuntimeEffect::Existential) ||
|
||||||
|
(impact & RuntimeEffect::ExistentialClassBound))) {
|
||||||
PrettyStackTracePerformanceDiagnostics stackTrace("existential", inst);
|
PrettyStackTracePerformanceDiagnostics stackTrace("existential", inst);
|
||||||
if (impactType) {
|
if (impactType) {
|
||||||
diagnose(loc, diag::perf_diag_existential_type, impactType.getASTType());
|
diagnose(loc, diag::perf_diag_existential_type, impactType.getASTType());
|
||||||
@@ -556,6 +557,8 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (module.getOptions().EmbeddedSwift) {
|
if (module.getOptions().EmbeddedSwift) {
|
||||||
|
// Explicitly don't detect RuntimeEffect::ExistentialClassBound - those are
|
||||||
|
// allowed in Embedded Swift.
|
||||||
if (impact & RuntimeEffect::Existential) {
|
if (impact & RuntimeEffect::Existential) {
|
||||||
PrettyStackTracePerformanceDiagnostics stackTrace("existential", inst);
|
PrettyStackTracePerformanceDiagnostics stackTrace("existential", inst);
|
||||||
if (impactType) {
|
if (impactType) {
|
||||||
|
|||||||
@@ -457,7 +457,13 @@ void addFunctionPasses(SILPassPipelinePlan &P,
|
|||||||
P.addMem2Reg();
|
P.addMem2Reg();
|
||||||
|
|
||||||
// Run the existential specializer Pass.
|
// Run the existential specializer Pass.
|
||||||
|
if (!P.getOptions().EmbeddedSwift) {
|
||||||
|
// MandatoryPerformanceOptimizations already took care of all specializations
|
||||||
|
// in embedded Swift mode, running the existential specializer might introduce
|
||||||
|
// more generic calls from non-generic functions, which breaks the assumptions
|
||||||
|
// of embedded Swift.
|
||||||
P.addExistentialSpecializer();
|
P.addExistentialSpecializer();
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup, which is important if the inliner has restarted the pass pipeline.
|
// Cleanup, which is important if the inliner has restarted the pass pipeline.
|
||||||
P.addPerformanceConstantPropagation();
|
P.addPerformanceConstantPropagation();
|
||||||
|
|||||||
43
test/embedded/existential-class-bound1.swift
Normal file
43
test/embedded/existential-class-bound1.swift
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s
|
||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo -O) | %FileCheck %s
|
||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo -Osize) | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: OS=macosx || OS=linux-gnu
|
||||||
|
|
||||||
|
protocol ClassBound: AnyObject {
|
||||||
|
func foo()
|
||||||
|
func bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass {}
|
||||||
|
extension MyClass: ClassBound {
|
||||||
|
func foo() { print("MyClass.foo()") }
|
||||||
|
func bar() { print("MyClass.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyOtherClass {}
|
||||||
|
extension MyOtherClass: ClassBound {
|
||||||
|
func foo() { print("MyOtherClass.foo()") }
|
||||||
|
func bar() { print("MyOtherClass.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
func test(existential: any ClassBound) {
|
||||||
|
existential.foo()
|
||||||
|
existential.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
test(existential: MyClass())
|
||||||
|
// CHECK: MyClass.foo()
|
||||||
|
// CHECK: MyClass.bar()
|
||||||
|
test(existential: MyOtherClass())
|
||||||
|
// CHECK: MyOtherClass.foo()
|
||||||
|
// CHECK: MyOtherClass.bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
50
test/embedded/existential-class-bound2.swift
Normal file
50
test/embedded/existential-class-bound2.swift
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: OS=macosx || OS=linux-gnu
|
||||||
|
|
||||||
|
protocol ClassBound: AnyObject {
|
||||||
|
func foo()
|
||||||
|
func bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ClassBound {
|
||||||
|
func extensionMethod() {
|
||||||
|
self.foo()
|
||||||
|
self.bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass {}
|
||||||
|
extension MyClass: ClassBound {
|
||||||
|
func foo() { print("MyClass.foo()") }
|
||||||
|
func bar() { print("MyClass.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyOtherClass {}
|
||||||
|
extension MyOtherClass: ClassBound {
|
||||||
|
func foo() { print("MyOtherClass.foo()") }
|
||||||
|
func bar() { print("MyOtherClass.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
var array: [any ClassBound] = []
|
||||||
|
array.append(MyClass())
|
||||||
|
array.append(MyOtherClass())
|
||||||
|
|
||||||
|
for e in array {
|
||||||
|
e.extensionMethod()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: MyClass.foo()
|
||||||
|
// CHECK: MyClass.bar()
|
||||||
|
|
||||||
|
// CHECK: MyOtherClass.foo()
|
||||||
|
// CHECK: MyOtherClass.bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
44
test/embedded/existential-class-bound3.swift
Normal file
44
test/embedded/existential-class-bound3.swift
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: OS=macosx || OS=linux-gnu
|
||||||
|
|
||||||
|
protocol ClassBound: AnyObject {
|
||||||
|
func foo()
|
||||||
|
func bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass {}
|
||||||
|
extension MyClass: ClassBound {
|
||||||
|
func foo() { print("MyClass.foo()") }
|
||||||
|
func bar() { print("MyClass.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyOtherClass {}
|
||||||
|
extension MyOtherClass: ClassBound {
|
||||||
|
func foo() { print("MyOtherClass.foo()") }
|
||||||
|
func bar() { print("MyOtherClass.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
var array: [any ClassBound] = []
|
||||||
|
array.append(MyClass())
|
||||||
|
array.append(MyOtherClass())
|
||||||
|
|
||||||
|
for e in array {
|
||||||
|
e.foo()
|
||||||
|
e.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: MyClass.foo()
|
||||||
|
// CHECK: MyClass.bar()
|
||||||
|
|
||||||
|
// CHECK: MyOtherClass.foo()
|
||||||
|
// CHECK: MyOtherClass.bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
44
test/embedded/existential-class-bound4.swift
Normal file
44
test/embedded/existential-class-bound4.swift
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// RUN: %target-run-simple-swift(-enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: executable_test
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: OS=macosx || OS=linux-gnu
|
||||||
|
|
||||||
|
// Generic classes don't work yet.
|
||||||
|
// XFAIL: *
|
||||||
|
|
||||||
|
protocol ClassBound: AnyObject {
|
||||||
|
func foo()
|
||||||
|
func bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyGenericClass<T> {
|
||||||
|
var typ: String
|
||||||
|
init(typ: String) { self.typ = typ }
|
||||||
|
}
|
||||||
|
extension MyGenericClass: ClassBound {
|
||||||
|
func foo() { print("MyGenericClass<\(typ)>.foo()") }
|
||||||
|
func bar() { print("MyGenericClass<\(typ)>.bar()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
var array: [any ClassBound] = []
|
||||||
|
array.append(MyGenericClass<Int>(typ: "Int"))
|
||||||
|
array.append(MyGenericClass<String>(typ: "String"))
|
||||||
|
|
||||||
|
for e in array {
|
||||||
|
e.foo()
|
||||||
|
e.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: MyGenericClass<Int>.foo()
|
||||||
|
// CHECK: MyGenericClass<Int>.bar()
|
||||||
|
|
||||||
|
// CHECK: MyGenericClass<String>.foo()
|
||||||
|
// CHECK: MyGenericClass<String>.bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
35
test/embedded/existential-class-bound5.swift
Normal file
35
test/embedded/existential-class-bound5.swift
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// RUN: %target-swift-emit-ir -parse-as-library -module-name main -verify %s -enable-experimental-feature Embedded -wmo
|
||||||
|
|
||||||
|
// REQUIRES: swift_in_compiler
|
||||||
|
// REQUIRES: optimized_stdlib
|
||||||
|
// REQUIRES: OS=macosx || OS=linux-gnu
|
||||||
|
|
||||||
|
protocol ClassBound: AnyObject {
|
||||||
|
func foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol NotClassBound {
|
||||||
|
func foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyClass {}
|
||||||
|
extension MyClass: ClassBound, NotClassBound {
|
||||||
|
func foo() { print("MyClass.foo()") }
|
||||||
|
}
|
||||||
|
|
||||||
|
func test(existential: any ClassBound) {
|
||||||
|
existential.foo() // ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func test(existential: any NotClassBound) {
|
||||||
|
existential.foo() // expected-error {{cannot use a value of protocol type in embedded Swift}}
|
||||||
|
// expected-note@+3 {{called from here}}
|
||||||
|
}
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct Main {
|
||||||
|
static func main() {
|
||||||
|
test(existential: MyClass() as (any ClassBound)) // ok
|
||||||
|
test(existential: MyClass() as (any NotClassBound)) // expected-error {{cannot use a value of protocol type 'any NotClassBound' in embedded Swift}}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user