Skip to content

Commit ec5ba41

Browse files
committed
Simplify diagnoseResilientConstructor all the way away.
Now that struct initializers "just" fall into the delegating case when they're made inlinable, the only interesting case is class initializers, which can be checked in a more direct way than what we were doing before.
1 parent 85e84a8 commit ec5ba41

File tree

4 files changed

+47
-42
lines changed

4 files changed

+47
-42
lines changed

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,11 @@
1919
#include "swift/AST/Decl.h"
2020
#include "swift/AST/Initializer.h"
2121
#include "swift/AST/DeclContext.h"
22-
using namespace swift;
2322

24-
enum FragileFunctionKind : unsigned {
25-
Transparent,
26-
InlineAlways,
27-
Inlineable,
28-
DefaultArgument
29-
};
23+
using namespace swift;
24+
using FragileFunctionKind = TypeChecker::FragileFunctionKind;
3025

31-
FragileFunctionKind getFragileFunctionKind(const DeclContext *DC) {
26+
FragileFunctionKind TypeChecker::getFragileFunctionKind(const DeclContext *DC) {
3227
for (; DC->isLocalContext(); DC = DC->getParent()) {
3328
if (auto *DAI = dyn_cast<DefaultArgumentInitializer>(DC))
3429
if (DAI->getResilienceExpansion() == ResilienceExpansion::Minimal)
@@ -69,7 +64,8 @@ void TypeChecker::diagnoseInlineableLocalType(const NominalTypeDecl *NTD) {
6964
auto expansion = DC->getResilienceExpansion();
7065
if (expansion == ResilienceExpansion::Minimal) {
7166
diagnose(NTD, diag::local_type_in_inlineable_function,
72-
NTD->getFullName(), getFragileFunctionKind(DC));
67+
NTD->getFullName(),
68+
static_cast<unsigned>(getFragileFunctionKind(DC)));
7369
}
7470
}
7571

@@ -117,7 +113,7 @@ bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
117113
diagnose(loc, diag::resilience_decl_unavailable,
118114
D->getDescriptiveKind(), D->getFullName(),
119115
D->getFormalAccessScope().accessLevelForDiagnostics(),
120-
getFragileFunctionKind(DC));
116+
static_cast<unsigned>(getFragileFunctionKind(DC)));
121117

122118
bool isDefaultArgument = false;
123119
while (DC->isLocalContext()) {
@@ -140,32 +136,3 @@ bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
140136
return true;
141137
}
142138

143-
void TypeChecker::diagnoseResilientConstructor(ConstructorDecl *ctor) {
144-
auto nominalDecl = ctor->getDeclContext()
145-
->getAsNominalTypeOrNominalTypeExtensionContext();
146-
147-
// These restrictions only apply to concrete types, and not protocol
148-
// extensions.
149-
if (isa<ProtocolDecl>(nominalDecl))
150-
return;
151-
152-
bool isDelegating =
153-
(ctor->getDelegatingOrChainedInitKind(&Diags) ==
154-
ConstructorDecl::BodyInitKind::Delegating);
155-
156-
if (!isDelegating &&
157-
!nominalDecl->hasFixedLayout(ctor->getParentModule(),
158-
ctor->getResilienceExpansion())) {
159-
if (ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) {
160-
// An @_inlineable designated initializer defined in a resilient type
161-
// cannot initialize stored properties directly, and must chain to
162-
// another initializer.
163-
diagnose(ctor->getLoc(),
164-
isa<ClassDecl>(nominalDecl)
165-
? diag::class_designated_init_inlineable_resilient
166-
: diag::designated_init_inlineable_resilient,
167-
nominalDecl->getDeclaredInterfaceType(),
168-
getFragileFunctionKind(ctor));
169-
}
170-
}
171-
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,9 +1551,15 @@ bool TypeChecker::typeCheckConstructorBodyUntil(ConstructorDecl *ctor,
15511551
diagnose(initExpr->getLoc(), diag::delegation_here);
15521552
ctor->setInitKind(CtorInitializerKind::Convenience);
15531553
}
1554-
}
15551554

1556-
diagnoseResilientConstructor(ctor);
1555+
// An inlinable constructor in a class must always be delegating.
1556+
if (!isDelegating && !ClassD->hasFixedLayout() &&
1557+
ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) {
1558+
diagnose(ctor, diag::class_designated_init_inlineable_resilient,
1559+
ClassD->getDeclaredInterfaceType(),
1560+
static_cast<unsigned>(getFragileFunctionKind(ctor)));
1561+
}
1562+
}
15571563

15581564
// If we want a super.init call...
15591565
if (wantSuperInitCall) {

lib/Sema/TypeChecker.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2272,7 +2272,19 @@ class TypeChecker final : public LazyResolver {
22722272
bool diagnoseInlineableDeclRef(SourceLoc loc, const ValueDecl *D,
22732273
const DeclContext *DC);
22742274

2275-
void diagnoseResilientConstructor(ConstructorDecl *ctor);
2275+
/// Used in diagnostic %selects.
2276+
enum class FragileFunctionKind : unsigned {
2277+
Transparent,
2278+
InlineAlways,
2279+
Inlineable,
2280+
DefaultArgument
2281+
};
2282+
2283+
/// Given that \p DC is within a fragile context for some reason, describe
2284+
/// why.
2285+
///
2286+
/// \see FragileFunctionKind
2287+
FragileFunctionKind getFragileFunctionKind(const DeclContext *DC);
22762288

22772289
/// \name Availability checking
22782290
///

test/decl/init/resilience.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,31 @@ public struct Animal {
5454

5555
public class Widget {
5656
public let name: String
57+
58+
public init(nonInlinableName name: String) {
59+
self.name = name
60+
}
5761

5862
@_inlineable public init(name: String) {
5963
// expected-error@-1 {{initializer for class 'Widget' is '@_inlineable' and must delegate to another initializer}}
6064
self.name = name
6165
}
66+
67+
@_inlineable public convenience init(goodName name: String) {
68+
// This is OK
69+
self.init(nonInlinableName: name)
70+
}
71+
}
72+
73+
public protocol Gadget {
74+
init()
75+
}
76+
77+
extension Gadget {
78+
@_inlineable public init(unused: Int) {
79+
// This is OK
80+
self.init()
81+
}
6282
}
6383

6484
// Protocol extension initializers are OK too

0 commit comments

Comments
 (0)