Skip to content

Commit 03bdbed

Browse files
committed
Sema: Diagnose missing class initializers late
This gives us a chance to synthesize the init(from:). Fixes <https://bugs.swift.org/browse/SR-7315>, <rdar://problem/39102390>.
1 parent a73bc7b commit 03bdbed

File tree

6 files changed

+45
-10
lines changed

6 files changed

+45
-10
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8575,6 +8575,27 @@ static void diagnoseClassWithoutInitializers(TypeChecker &tc,
85758575
}
85768576
}
85778577

8578+
void TypeChecker::maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
8579+
// Some heuristics to skip emitting a diagnostic if the class is already
8580+
// irreperably busted.
8581+
if (classDecl->isInvalid() ||
8582+
classDecl->inheritsSuperclassInitializers(nullptr))
8583+
return;
8584+
8585+
auto *superclassDecl = classDecl->getSuperclassDecl();
8586+
if (superclassDecl &&
8587+
superclassDecl->hasMissingDesignatedInitializers())
8588+
return;
8589+
8590+
for (auto member : classDecl->lookupDirect(DeclBaseName::createConstructor())) {
8591+
auto ctor = dyn_cast<ConstructorDecl>(member);
8592+
if (ctor && ctor->isDesignatedInit())
8593+
return;
8594+
}
8595+
8596+
diagnoseClassWithoutInitializers(*this, classDecl);
8597+
}
8598+
85788599
/// Diagnose a missing required initializer.
85798600
static void diagnoseMissingRequiredInitializer(
85808601
TypeChecker &TC,
@@ -8697,16 +8718,13 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
86978718
// Bail out if we're validating one of our constructors already; we'll
86988719
// revisit the issue later.
86998720
if (isa<ClassDecl>(decl)) {
8700-
bool alreadyValidatingCtor = false;
87018721
for (auto member : decl->getMembers()) {
87028722
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
87038723
validateDecl(ctor);
87048724
if (!ctor->hasValidSignature())
8705-
alreadyValidatingCtor = true;
8725+
return;
87068726
}
87078727
}
8708-
if (alreadyValidatingCtor)
8709-
return;
87108728
}
87118729

87128730
decl->setAddedImplicitInitializers();
@@ -8875,7 +8893,6 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
88758893
// stored properties.
88768894
if (SuppressDefaultInitializer && !FoundDesignatedInit
88778895
&& !FoundSynthesizedInit && !classDecl->hasClangNode()) {
8878-
diagnoseClassWithoutInitializers(*this, classDecl);
88798896
return;
88808897
}
88818898

@@ -8976,12 +8993,8 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
89768993
// constructor.
89778994

89788995
// ... unless there are uninitialized stored properties.
8979-
if (SuppressDefaultInitializer) {
8980-
if (!FoundSynthesizedInit)
8981-
diagnoseClassWithoutInitializers(*this, classDecl);
8982-
8996+
if (SuppressDefaultInitializer)
89838997
return;
8984-
}
89858998

89868999
defineDefaultConstructor(decl);
89879000
}

lib/Sema/TypeChecker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,10 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
450450
else {
451451
auto *ntd = cast<NominalTypeDecl>(decl);
452452
TC.checkConformancesInContext(ntd, ntd);
453+
454+
// Finally, we can check classes for missing initializers.
455+
if (auto *classDecl = dyn_cast<ClassDecl>(ntd))
456+
TC.maybeDiagnoseClassWithoutInitializers(classDecl);
453457
}
454458
}
455459
TC.ConformanceContexts.clear();

lib/Sema/TypeChecker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,10 @@ class TypeChecker final : public LazyResolver {
15351535
/// Retrieve the set of inherited protocols for this protocol type.
15361536
llvm::TinyPtrVector<ProtocolDecl *> getDirectConformsTo(ProtocolDecl *proto);
15371537

1538+
/// Diagnose if the class has no designated initializers.
1539+
void maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl);
1540+
1541+
///
15381542
/// \brief Add any implicitly-defined constructors required for the given
15391543
/// struct or class.
15401544
void addImplicitConstructors(NominalTypeDecl *typeDecl);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C1 : Decodable {
2+
let str: String
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class C2 : Decodable {
2+
let c: C1
3+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-typecheck-verify-swift -verify %S/Inputs/class_missing_init_multi1.swift %S/Inputs/class_missing_init_multi2.swift
2+
// RUN: %target-typecheck-verify-swift -verify %S/Inputs/class_missing_init_multi2.swift %S/Inputs/class_missing_init_multi1.swift
3+
4+
// RUN: %target-typecheck-verify-swift -verify -primary-file %S/Inputs/class_missing_init_multi1.swift %S/Inputs/class_missing_init_multi2.swift
5+
// RUN: %target-typecheck-verify-swift -verify %S/Inputs/class_missing_init_multi1.swift -primary-file %S/Inputs/class_missing_init_multi2.swift
6+
7+
// RUN: %target-typecheck-verify-swift -verify -primary-file %S/Inputs/class_missing_init_multi2.swift %S/Inputs/class_missing_init_multi1.swift
8+
// RUN: %target-typecheck-verify-swift -verify %S/Inputs/class_missing_init_multi2.swift -primary-file %S/Inputs/class_missing_init_multi1.swift

0 commit comments

Comments
 (0)