Skip to content

Commit 9ec2077

Browse files
committed
[SE-0306] Make actors semantically "final".
Treat actors as being semantically `final` throughout the type checker. This allows, for example, a non-`required` initializer to satisfy a protocol requirement. We're leaving the ABI open for actor inheritance should we need it. Addresses rdar://78269551.
1 parent 6801eba commit 9ec2077

15 files changed

+71
-24
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,10 @@ class ValueDecl : public Decl {
23742374
/// Note whether this declaration is known to be exposed to Objective-C.
23752375
void setIsObjC(bool Value);
23762376

2377+
/// Is this declaration semantically 'final', meaning that the type checker
2378+
/// should treat it as final even if the ABI does not?
2379+
bool isSemanticallyFinal() const;
2380+
23772381
/// Is this declaration 'final'?
23782382
bool isFinal() const;
23792383

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2828,7 +2828,7 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
28282828
if (Ctx.isSwiftVersionAtLeast(5)) {
28292829
if (wantDynamicSelf && CD->isConvenienceInit())
28302830
if (auto *classDecl = selfTy->getClassOrBoundGenericClass())
2831-
if (!classDecl->isFinal())
2831+
if (!classDecl->isSemanticallyFinal())
28322832
isDynamicSelf = true;
28332833
}
28342834
} else if (isa<DestructorDecl>(AFD)) {

lib/AST/Decl.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2868,6 +2868,23 @@ void ValueDecl::setIsObjC(bool value) {
28682868
LazySemanticInfo.isObjC = value;
28692869
}
28702870

2871+
bool ValueDecl::isSemanticallyFinal() const {
2872+
// Actor types are semantically final.
2873+
if (auto classDecl = dyn_cast<ClassDecl>(this)) {
2874+
if (classDecl->isActor())
2875+
return true;
2876+
}
2877+
2878+
// As are members of actor types.
2879+
if (auto classDecl = getDeclContext()->getSelfClassDecl()) {
2880+
if (classDecl->isActor())
2881+
return true;
2882+
}
2883+
2884+
// For everything else, the same as 'final'.
2885+
return isFinal();
2886+
}
2887+
28712888
bool ValueDecl::isFinal() const {
28722889
return evaluateOrDefault(getASTContext().evaluator,
28732890
IsFinalRequest { const_cast<ValueDecl *>(this) },
@@ -3212,13 +3229,13 @@ bool ValueDecl::shouldHideFromEditor() const {
32123229
static AccessLevel getMaximallyOpenAccessFor(const ValueDecl *decl) {
32133230
// Non-final classes are considered open to @testable importers.
32143231
if (auto cls = dyn_cast<ClassDecl>(decl)) {
3215-
if (!cls->isFinal())
3232+
if (!cls->isSemanticallyFinal())
32163233
return AccessLevel::Open;
32173234

32183235
// Non-final overridable class members are considered open to
32193236
// @testable importers.
32203237
} else if (decl->isPotentiallyOverridable()) {
3221-
if (!cast<ValueDecl>(decl)->isFinal())
3238+
if (!cast<ValueDecl>(decl)->isSemanticallyFinal())
32223239
return AccessLevel::Open;
32233240
}
32243241

lib/IDE/CodeCompletion.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5422,7 +5422,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
54225422
switch (Reason) {
54235423
case DeclVisibilityKind::MemberOfProtocolConformedToByCurrentNominal:
54245424
case DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal:
5425-
if (!C->isFinal())
5425+
if (!C->isSemanticallyFinal())
54265426
needRequired = true;
54275427
break;
54285428
case DeclVisibilityKind::MemberOfSuper:
@@ -5458,7 +5458,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
54585458
if (D->shouldHideFromEditor())
54595459
return;
54605460

5461-
if (D->isFinal())
5461+
if (D->isSemanticallyFinal())
54625462
return;
54635463

54645464
bool hasIntroducer = hasFuncIntroducer ||

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7720,7 +7720,7 @@ static bool isNonFinalClass(Type type) {
77207720
type = dynamicSelf->getSelfType();
77217721

77227722
if (auto classDecl = type->getClassOrBoundGenericClass())
7723-
return !classDecl->isFinal();
7723+
return !classDecl->isSemanticallyFinal();
77247724

77257725
if (auto archetype = type->getAs<ArchetypeType>())
77267726
if (auto super = archetype->getSuperclass())

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,7 @@ static ValueDecl *deriveDecodable_init(DerivedConformance &derived) {
17891789
}
17901790

17911791
// This constructor should be marked as `required` for non-final classes.
1792-
if (classDecl && !classDecl->isFinal()) {
1792+
if (classDecl && !classDecl->isSemanticallyFinal()) {
17931793
auto *reqAttr = new (C) RequiredAttr(/*IsImplicit=*/true);
17941794
initDecl->getAttrs().add(reqAttr);
17951795
}

lib/Sema/DerivedConformances.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ bool DerivedConformance::checkAndDiagnoseDisallowedContext(
545545
// A non-final class can't have an protocol-witnesss initializer in an
546546
// extension.
547547
if (auto CD = dyn_cast<ClassDecl>(Nominal)) {
548-
if (!CD->isFinal() && isa<ConstructorDecl>(synthesizing) &&
548+
if (!CD->isSemanticallyFinal() && isa<ConstructorDecl>(synthesizing) &&
549549
isa<ExtensionDecl>(ConformanceDecl)) {
550550
ConformanceDecl->diagnose(
551551
diag::cannot_synthesize_init_in_extension_of_nonfinal,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4489,7 +4489,7 @@ IndexSubset *DifferentiableAttributeTypeCheckRequest::evaluate(
44894489
if (diagnoseDynamicSelfResult) {
44904490
// Diagnose class initializers in non-final classes.
44914491
if (isa<ConstructorDecl>(original)) {
4492-
if (!classDecl->isFinal()) {
4492+
if (!classDecl->isSemanticallyFinal()) {
44934493
diags.diagnose(
44944494
attr->getLocation(),
44954495
diag::differentiable_attr_nonfinal_class_init_unsupported,
@@ -4790,7 +4790,7 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D,
47904790
if (diagnoseDynamicSelfResult) {
47914791
// Diagnose class initializers in non-final classes.
47924792
if (isa<ConstructorDecl>(originalAFD)) {
4793-
if (!classDecl->isFinal()) {
4793+
if (!classDecl->isSemanticallyFinal()) {
47944794
diags.diagnose(attr->getLocation(),
47954795
diag::derivative_attr_nonfinal_class_init_unsupported,
47964796
classDecl->getDeclaredInterfaceType());

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3545,7 +3545,7 @@ bool swift::checkSendableConformance(
35453545

35463546
if (classDecl) {
35473547
// An non-final class cannot conform to `Sendable`.
3548-
if (!classDecl->isFinal()) {
3548+
if (!classDecl->isSemanticallyFinal()) {
35493549
classDecl->diagnose(diag::concurrent_value_nonfinal_class,
35503550
classDecl->getName())
35513551
.limitBehavior(behavior);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
871871
return true;
872872

873873
// The presence of 'final' blocks the inference of 'dynamic'.
874-
if (decl->isFinal())
874+
if (decl->isSemanticallyFinal())
875875
return false;
876876

877877
// Types are never 'dynamic'.
@@ -1868,7 +1868,7 @@ FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
18681868
if (dc->isTypeContext()) {
18691869
if (auto classDecl = dc->getSelfClassDecl()) {
18701870
// For a class, we also need the function or class to be 'final'.
1871-
if (!classDecl->isFinal() && !FD->isFinal() &&
1871+
if (!classDecl->isSemanticallyFinal() && !FD->isFinal() &&
18721872
FD->getStaticLoc().isValid() &&
18731873
FD->getStaticSpelling() != StaticSpellingKind::KeywordStatic) {
18741874
FD->diagnose(diag::nonfinal_operator_in_class,

0 commit comments

Comments
 (0)