Skip to content

Commit 428d718

Browse files
committed
Diagnose *all* cases where a subclass fails to override a required init
In cases where a subclass was unable to synthesize any initializers (for example, because there were missing designated initializers in the superclass), we were skipping checking of superclass required initializers. This meant that we would silently accept subclasses that cannot be initialized directly (that would produce an error), but could at runtime be initialized via a required initializer... that didn't account for the subclass. Fixes the original problem from #69965, but not the most minimal one.
1 parent cfe2b3c commit 428d718

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

lib/Sema/CodeSynthesis.cpp

+18-7
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ createDesignatedInitOverride(ClassDecl *classDecl,
826826
static void diagnoseMissingRequiredInitializer(
827827
ClassDecl *classDecl,
828828
ConstructorDecl *superInitializer,
829+
bool downgradeToWarning,
829830
ASTContext &ctx) {
830831
// Find the location at which we should insert the new initializer.
831832
SourceLoc insertionLoc;
@@ -906,6 +907,7 @@ static void diagnoseMissingRequiredInitializer(
906907
ctx.Diags.diagnose(insertionLoc, diag::required_initializer_missing,
907908
superInitializer->getName(),
908909
superInitializer->getDeclContext()->getDeclaredInterfaceType())
910+
.warnUntilSwiftVersionIf(downgradeToWarning, 6)
909911
.fixItInsert(insertionLoc, initializerText);
910912

911913
ctx.Diags.diagnose(findNonImplicitRequiredInit(superInitializer),
@@ -1172,10 +1174,11 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
11721174
bool defaultInitable =
11731175
areAllStoredPropertiesDefaultInitializable(ctx.evaluator, decl);
11741176

1175-
// We can't define these overrides if we have any uninitialized
1176-
// stored properties.
1177-
if (!defaultInitable && !foundDesignatedInit)
1178-
return;
1177+
// In cases where we can't define any overrides, we used to suppress
1178+
// diagnostics about missing required initializers. Now we emit diagnostics,
1179+
// but downgrade them to warnings prior to Swift 6.
1180+
bool downgradeRequiredInitsToWarning =
1181+
!defaultInitable && !foundDesignatedInit;
11791182

11801183
SmallVector<ConstructorDecl *, 4> nonOverriddenSuperclassCtors;
11811184
collectNonOveriddenSuperclassInits(decl, nonOverriddenSuperclassCtors);
@@ -1187,8 +1190,10 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
11871190
if (superclassCtor->isRequired()) {
11881191
assert(superclassCtor->isInheritable() &&
11891192
"factory initializers cannot be 'required'");
1190-
if (!decl->inheritsSuperclassInitializers())
1191-
diagnoseMissingRequiredInitializer(decl, superclassCtor, ctx);
1193+
if (!decl->inheritsSuperclassInitializers()) {
1194+
diagnoseMissingRequiredInitializer(
1195+
decl, superclassCtor, downgradeRequiredInitsToWarning, ctx);
1196+
}
11921197
}
11931198
continue;
11941199
}
@@ -1204,12 +1209,18 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
12041209

12051210
// Diagnose a missing override of a required initializer.
12061211
if (superclassCtor->isRequired() && !inheritDesignatedInits) {
1207-
diagnoseMissingRequiredInitializer(decl, superclassCtor, ctx);
1212+
diagnoseMissingRequiredInitializer(
1213+
decl, superclassCtor, downgradeRequiredInitsToWarning, ctx);
12081214
continue;
12091215
}
12101216

12111217
// A designated or required initializer has not been overridden.
12121218

1219+
// We can't define any overrides if we have any uninitialized
1220+
// stored properties.
1221+
if (!defaultInitable && !foundDesignatedInit)
1222+
continue;
1223+
12131224
bool alreadyDeclared = false;
12141225

12151226
auto results = decl->lookupDirect(DeclBaseName::createConstructor());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -emit-module-path %t/MyModule.swiftmodule %t/Inputs/MyModule.swift
5+
6+
// RUN: %target-swift-frontend -typecheck -verify -I %t %t/test.swift
7+
8+
//--- Inputs/MyModule.swift
9+
open class MySuperclassA {
10+
required public init() { }
11+
internal init(boop: Bool) {}
12+
}
13+
14+
//--- test.swift
15+
import MyModule
16+
17+
class MySubclassA: MySuperclassA {
18+
// expected-warning{{'required' initializer 'init()' must be provided by subclass of 'MySuperclassA'; this is an error in Swift 6}}
19+
var hi: String
20+
}

0 commit comments

Comments
 (0)