diff --git a/SwiftCompilerSources/Sources/AST/Declarations.swift b/SwiftCompilerSources/Sources/AST/Declarations.swift index 463c07e94cf7a..35ba159eea2c3 100644 --- a/SwiftCompilerSources/Sources/AST/Declarations.swift +++ b/SwiftCompilerSources/Sources/AST/Declarations.swift @@ -182,10 +182,12 @@ final public class ParamDecl: VarDecl { final public class SubscriptDecl: AbstractStorageDecl, GenericContext {} public class AbstractFunctionDecl: ValueDecl, GenericContext { - public var isOverridden: Bool { bridged.AbstractFunction_isOverridden() } + final public var isOverridden: Bool { bridged.AbstractFunction_isOverridden() } } -final public class ConstructorDecl: AbstractFunctionDecl {} +final public class ConstructorDecl: AbstractFunctionDecl { + public var isInheritable: Bool { bridged.Constructor_isInheritable() } +} final public class DestructorDecl: AbstractFunctionDecl { final public var isIsolated: Bool { bridged.Destructor_isIsolated() } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift index 23b5c9a1e857d..6b01f416e8612 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift @@ -82,7 +82,7 @@ private struct VTableSpecializer { } private func specializeEntries(of vTable: VTable, _ notifyNewFunction: (Function) -> ()) -> [VTable.Entry] { - return vTable.entries.map { entry in + return vTable.entries.compactMap { entry in if !entry.implementation.isGeneric { return entry } @@ -95,6 +95,14 @@ private struct VTableSpecializer { let specializedMethod = context.specialize(function: entry.implementation, for: methodSubs, convertIndirectToDirect: true, isMandatory: true) else { + if let constructor = entry.methodDecl.decl as? ConstructorDecl, + !constructor.isInheritable + { + // For some reason, SILGen is putting constructors in the vtable, though they are never + // called through the vtable. + // Dropping those vtable entries allows using constructors with generic arguments. + return nil + } return entry } notifyNewFunction(specializedMethod) diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index c4c1154f3f8d8..d4f17ace66efe 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -351,6 +351,7 @@ struct BridgedDeclObj { BRIDGED_INLINE bool ProtocolDecl_requiresClass() const; BRIDGED_INLINE bool ProtocolDecl_isMarkerProtocol() const; BRIDGED_INLINE bool AbstractFunction_isOverridden() const; + BRIDGED_INLINE bool Constructor_isInheritable() const; BRIDGED_INLINE bool Destructor_isIsolated() const; BRIDGED_INLINE bool EnumElementDecl_hasAssociatedValues() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedParameterList diff --git a/include/swift/AST/ASTBridgingImpl.h b/include/swift/AST/ASTBridgingImpl.h index 511c3f3be22fe..128b1c444dd15 100644 --- a/include/swift/AST/ASTBridgingImpl.h +++ b/include/swift/AST/ASTBridgingImpl.h @@ -272,6 +272,10 @@ bool BridgedDeclObj::AbstractFunction_isOverridden() const { return getAs()->isOverridden(); } +bool BridgedDeclObj::Constructor_isInheritable() const { + return getAs()->isInheritable(); +} + bool BridgedDeclObj::Destructor_isIsolated() const { auto dd = getAs(); auto ai = swift::getActorIsolation(dd); diff --git a/lib/SIL/IR/SILVTable.cpp b/lib/SIL/IR/SILVTable.cpp index 241e127fb3ba8..ab4838a5bdf8e 100644 --- a/lib/SIL/IR/SILVTable.cpp +++ b/lib/SIL/IR/SILVTable.cpp @@ -78,15 +78,14 @@ void SILVTable::updateVTableCache(const Entry &entry) { void SILVTable::replaceEntries(ArrayRef newEntries) { auto entries = getMutableEntries(); ASSERT(newEntries.size() <= entries.size()); - for (unsigned i = 0; i < entries.size(); ++i) { - entries[i].getImplementation()->decrementRefCount(); - if (i < newEntries.size()) { - entries[i] = newEntries[i]; - entries[i].getImplementation()->incrementRefCount(); - updateVTableCache(entries[i]); - } else { - removeFromVTableCache(entries[i]); - } + for (Entry &entry : getMutableEntries()) { + entry.getImplementation()->decrementRefCount(); + removeFromVTableCache(entry); + } + for (unsigned i = 0; i < newEntries.size(); ++i) { + entries[i] = newEntries[i]; + entries[i].getImplementation()->incrementRefCount(); + updateVTableCache(entries[i]); } NumEntries = newEntries.size(); } diff --git a/test/embedded/classes.swift b/test/embedded/classes.swift index 5ca3ef093e19a..3f0904df20045 100644 --- a/test/embedded/classes.swift +++ b/test/embedded/classes.swift @@ -8,31 +8,57 @@ // REQUIRES: optimized_stdlib // REQUIRES: swift_feature_Embedded -class MyClass { +public class MyClass { init() { print("MyClass.init") } deinit { print("MyClass.deinit") } func foo() { print("MyClass.foo") } } -class MySubClass: MyClass { - var x = 27 +public class MySubClass: MyClass { + var x: Int + + override init() { + self.x = 27 + print("MySubClass.init") + } + + public init(p: some P) { + self.x = p.get() + super.init() + print("MySubClass.init") + } - override init() { print("MySubClass.init") } deinit { print("MySubClass.deinit") } - override func foo() { print("MySubClass.foo") } + + override func foo() { print("MySubClass.foo: \(x)") } func printX() { print(x) } } -class MySubSubClass: MySubClass { - override init() { print("MySubSubClass.init") } +public protocol P { + func get() -> Int +} + +struct S: P { + let i: Int + + func get() -> Int { i } +} + +public class MySubSubClass: MySubClass { + override init() { + print("MySubSubClass.init") + super.init() + } + deinit { print("MySubSubClass.deinit") } + override func foo() { print("MySubSubClass.foo") } } -class OtherSubClass: MyClass {} +public class OtherSubClass: MyClass {} func testCasting(_ title: StaticString, _ c: MyClass) { print(title, terminator: "") @@ -81,10 +107,15 @@ struct Main { o.1!.foo() o.2!.foo() // CHECK: MyClass.foo - // CHECK: MySubClass.foo + // CHECK: MySubClass.foo: 27 // CHECK: MySubSubClass.foo print("") + print("4b") // CHECK: 4b + o.1 = MySubClass(p: S(i: 42)) + o.1!.foo() + // CHECK: MySubClass.foo: 42 + print("5") // CHECK: 5 o.0 = nil // CHECK: MyClass.deinit