Skip to content

Commit c6df500

Browse files
authored
Merge pull request #16050 from slavapestov/codable-missing-init-fix
Fix bogus diagnostic about missing initializers with Decodable in single-file mode
2 parents 107849a + 03bdbed commit c6df500

File tree

8 files changed

+61
-12
lines changed

8 files changed

+61
-12
lines changed

include/swift/AST/Decl.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ class alignas(1 << DeclAlignInBits) Decl {
367367
DefaultArgumentResilienceExpansion : 1
368368
);
369369

370-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+5+1+1+1+1+1,
370+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+5+1+1+1+1+1+1,
371371
/// \see AbstractFunctionDecl::BodyKind
372372
BodyKind : 3,
373373

@@ -390,7 +390,11 @@ class alignas(1 << DeclAlignInBits) Decl {
390390
HasComputedNeedsNewVTableEntry : 1,
391391

392392
/// The ResilienceExpansion to use for default arguments.
393-
DefaultArgumentResilienceExpansion : 1
393+
DefaultArgumentResilienceExpansion : 1,
394+
395+
/// Whether this member was synthesized as part of a derived
396+
/// protocol conformance.
397+
Synthesized : 1
394398
);
395399

396400
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+2+1+1+2,
@@ -5253,6 +5257,14 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
52535257
return Bits.AbstractFunctionDecl.NeedsNewVTableEntry;
52545258
}
52555259

5260+
bool isSynthesized() const {
5261+
return Bits.AbstractFunctionDecl.Synthesized;
5262+
}
5263+
5264+
void setSynthesized(bool value = true) {
5265+
Bits.AbstractFunctionDecl.Synthesized = value;
5266+
}
5267+
52565268
private:
52575269
void computeNeedsNewVTableEntry();
52585270

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,7 @@ static FuncDecl *deriveEncodable_encode(TypeChecker &tc, Decl *parentDecl,
750750
TypeLoc::withoutLoc(returnType),
751751
target);
752752
encodeDecl->setImplicit();
753+
encodeDecl->setSynthesized();
753754
encodeDecl->setBodySynthesizer(deriveBodyEncodable_encode);
754755

755756
// This method should be marked as 'override' for classes inheriting Encodable
@@ -1084,6 +1085,7 @@ static ValueDecl *deriveDecodable_init(TypeChecker &tc, Decl *parentDecl,
10841085
SourceLoc(), selfDecl, paramList,
10851086
/*GenericParams=*/nullptr, target);
10861087
initDecl->setImplicit();
1088+
initDecl->setSynthesized();
10871089
initDecl->setBodySynthesizer(deriveBodyDecodable_init);
10881090

10891091
// This constructor should be marked as `required` for non-final classes.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8589,6 +8589,27 @@ static void diagnoseClassWithoutInitializers(TypeChecker &tc,
85898589
}
85908590
}
85918591

8592+
void TypeChecker::maybeDiagnoseClassWithoutInitializers(ClassDecl *classDecl) {
8593+
// Some heuristics to skip emitting a diagnostic if the class is already
8594+
// irreperably busted.
8595+
if (classDecl->isInvalid() ||
8596+
classDecl->inheritsSuperclassInitializers(nullptr))
8597+
return;
8598+
8599+
auto *superclassDecl = classDecl->getSuperclassDecl();
8600+
if (superclassDecl &&
8601+
superclassDecl->hasMissingDesignatedInitializers())
8602+
return;
8603+
8604+
for (auto member : classDecl->lookupDirect(DeclBaseName::createConstructor())) {
8605+
auto ctor = dyn_cast<ConstructorDecl>(member);
8606+
if (ctor && ctor->isDesignatedInit())
8607+
return;
8608+
}
8609+
8610+
diagnoseClassWithoutInitializers(*this, classDecl);
8611+
}
8612+
85928613
/// Diagnose a missing required initializer.
85938614
static void diagnoseMissingRequiredInitializer(
85948615
TypeChecker &TC,
@@ -8711,16 +8732,13 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
87118732
// Bail out if we're validating one of our constructors already; we'll
87128733
// revisit the issue later.
87138734
if (isa<ClassDecl>(decl)) {
8714-
bool alreadyValidatingCtor = false;
87158735
for (auto member : decl->getMembers()) {
87168736
if (auto ctor = dyn_cast<ConstructorDecl>(member)) {
87178737
validateDecl(ctor);
87188738
if (!ctor->hasValidSignature())
8719-
alreadyValidatingCtor = true;
8739+
return;
87208740
}
87218741
}
8722-
if (alreadyValidatingCtor)
8723-
return;
87248742
}
87258743

87268744
decl->setAddedImplicitInitializers();
@@ -8889,7 +8907,6 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
88898907
// stored properties.
88908908
if (SuppressDefaultInitializer && !FoundDesignatedInit
88918909
&& !FoundSynthesizedInit && !classDecl->hasClangNode()) {
8892-
diagnoseClassWithoutInitializers(*this, classDecl);
88938910
return;
88948911
}
88958912

@@ -8990,12 +9007,8 @@ void TypeChecker::addImplicitConstructors(NominalTypeDecl *decl) {
89909007
// constructor.
89919008

89929009
// ... unless there are uninitialized stored properties.
8993-
if (SuppressDefaultInitializer) {
8994-
if (!FoundSynthesizedInit)
8995-
diagnoseClassWithoutInitializers(*this, classDecl);
8996-
9010+
if (SuppressDefaultInitializer)
89979011
return;
8998-
}
89999012

90009013
defineDefaultConstructor(decl);
90019014
}

lib/Sema/TypeChecker.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,10 @@ static void typeCheckFunctionsAndExternalDecls(SourceFile &SF, TypeChecker &TC)
438438
else {
439439
auto *ntd = cast<NominalTypeDecl>(decl);
440440
TC.checkConformancesInContext(ntd, ntd);
441+
442+
// Finally, we can check classes for missing initializers.
443+
if (auto *classDecl = dyn_cast<ClassDecl>(ntd))
444+
TC.maybeDiagnoseClassWithoutInitializers(classDecl);
441445
}
442446
}
443447
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)