Skip to content

Commit

Permalink
Allow inheritance from resilient classes with missing members
Browse files Browse the repository at this point in the history
When a class has missing vtable entries, we don’t allow it to be subclassed. This is unnecessarily restrictive for resilient classes, and @_implementationOnly imports now make missing vtable entries much more common. This commit carves out an exception to that rule for resilient classes.

Fixes <rdar://problem/50902125>.
  • Loading branch information
beccadax committed May 18, 2019
1 parent 64ce7b9 commit 9117c57
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
4 changes: 3 additions & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2958,7 +2958,9 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
break;
}

if (!isInvalidSuperclass && Super->hasMissingVTableEntries()) {
if (!isInvalidSuperclass && Super->hasMissingVTableEntries() &&
!Super->isResilient(CD->getParentModule(),
ResilienceExpansion::Minimal)) {
auto *superFile = Super->getModuleScopeContext();
if (auto *serialized = dyn_cast<SerializedASTFile>(superFile)) {
if (serialized->getLanguageVersionBuiltWith() !=
Expand Down
52 changes: 52 additions & 0 deletions test/decl/class/override-implementationOnly.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// RUN: %empty-directory(%t)

// For convenience, this file includes the three different "files" used in this
// test. It selects one with -DCoreDishwasher, -DDishwasherKit, or neither.

// RUN: %target-swift-frontend -emit-module %s -DCoreDishwasher -module-name CoreDishwasher -o %t/CoreDishwasher -emit-module-path %t/CoreDishwasher.swiftmodule -I %t
// RUN: %target-swift-frontend -emit-module %s -DDishwasherKit -module-name DishwasherKit -o %t/DishwasherKit -emit-module-path %t/DishwasherKit.swiftmodule -enable-library-evolution -I %t
// RUN: %target-typecheck-verify-swift -I %t

#if CoreDishwasher

public struct SpimsterWicket {
public init() {}
}

#elseif DishwasherKit

@_implementationOnly import CoreDishwasher

open class Dishwasher {
public init() {}

var wicket = SpimsterWicket()

open var modelName: String { "Dishwasher" }
}

open class NoUserServiceablePartsInside {
public init() {}
internal init(wicket: SpimsterWicket) {}
public convenience init(inconvenient: ()) {
self.init()
}
}

#else

import DishwasherKit

class FancyDishwasher: Dishwasher {
override var modelName: String { "Fancy \(super.modelName)" }
}

class VoidedWarranty: NoUserServiceablePartsInside {
override init() { super.init() }
}

// FIXME: This diagnostic should be better, but it matches what we're already
// doing for disallowed convenience inits.
let notAllowed = VoidedWarranty(inconvenient: ()) // expected-error{{argument passed to call that takes no arguments}}

#endif

0 comments on commit 9117c57

Please sign in to comment.