Skip to content

Commit 200b442

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. (cherry picked from commit 9ec2077)
1 parent e432296 commit 200b442

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
@@ -2725,7 +2725,7 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
27252725
if (Ctx.isSwiftVersionAtLeast(5)) {
27262726
if (wantDynamicSelf && CD->isConvenienceInit())
27272727
if (auto *classDecl = selfTy->getClassOrBoundGenericClass())
2728-
if (!classDecl->isFinal())
2728+
if (!classDecl->isSemanticallyFinal())
27292729
isDynamicSelf = true;
27302730
}
27312731
} 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) },
@@ -3208,13 +3225,13 @@ bool ValueDecl::shouldHideFromEditor() const {
32083225
static AccessLevel getMaximallyOpenAccessFor(const ValueDecl *decl) {
32093226
// Non-final classes are considered open to @testable importers.
32103227
if (auto cls = dyn_cast<ClassDecl>(decl)) {
3211-
if (!cls->isFinal())
3228+
if (!cls->isSemanticallyFinal())
32123229
return AccessLevel::Open;
32133230

32143231
// Non-final overridable class members are considered open to
32153232
// @testable importers.
32163233
} else if (decl->isPotentiallyOverridable()) {
3217-
if (!cast<ValueDecl>(decl)->isFinal())
3234+
if (!cast<ValueDecl>(decl)->isSemanticallyFinal())
32183235
return AccessLevel::Open;
32193236
}
32203237

lib/IDE/CodeCompletion.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5410,7 +5410,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
54105410
switch (Reason) {
54115411
case DeclVisibilityKind::MemberOfProtocolConformedToByCurrentNominal:
54125412
case DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal:
5413-
if (!C->isFinal())
5413+
if (!C->isSemanticallyFinal())
54145414
needRequired = true;
54155415
break;
54165416
case DeclVisibilityKind::MemberOfSuper:
@@ -5446,7 +5446,7 @@ class CompletionOverrideLookup : public swift::VisibleDeclConsumer {
54465446
if (D->shouldHideFromEditor())
54475447
return;
54485448

5449-
if (D->isFinal())
5449+
if (D->isSemanticallyFinal())
54505450
return;
54515451

54525452
bool hasIntroducer = hasFuncIntroducer ||

lib/Sema/CSSimplify.cpp

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

77047704
if (auto classDecl = type->getClassOrBoundGenericClass())
7705-
return !classDecl->isFinal();
7705+
return !classDecl->isSemanticallyFinal();
77067706

77077707
if (auto archetype = type->getAs<ArchetypeType>())
77087708
if (auto super = archetype->getSuperclass())

lib/Sema/DerivedConformanceCodable.cpp

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

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

lib/Sema/DerivedConformances.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ bool DerivedConformance::checkAndDiagnoseDisallowedContext(
547547
// A non-final class can't have an protocol-witnesss initializer in an
548548
// extension.
549549
if (auto CD = dyn_cast<ClassDecl>(Nominal)) {
550-
if (!CD->isFinal() && isa<ConstructorDecl>(synthesizing) &&
550+
if (!CD->isSemanticallyFinal() && isa<ConstructorDecl>(synthesizing) &&
551551
isa<ExtensionDecl>(ConformanceDecl)) {
552552
ConformanceDecl->diagnose(
553553
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
@@ -4505,7 +4505,7 @@ IndexSubset *DifferentiableAttributeTypeCheckRequest::evaluate(
45054505
if (diagnoseDynamicSelfResult) {
45064506
// Diagnose class initializers in non-final classes.
45074507
if (isa<ConstructorDecl>(original)) {
4508-
if (!classDecl->isFinal()) {
4508+
if (!classDecl->isSemanticallyFinal()) {
45094509
diags.diagnose(
45104510
attr->getLocation(),
45114511
diag::differentiable_attr_nonfinal_class_init_unsupported,
@@ -4807,7 +4807,7 @@ static bool typeCheckDerivativeAttr(ASTContext &Ctx, Decl *D,
48074807
if (diagnoseDynamicSelfResult) {
48084808
// Diagnose class initializers in non-final classes.
48094809
if (isa<ConstructorDecl>(originalAFD)) {
4810-
if (!classDecl->isFinal()) {
4810+
if (!classDecl->isSemanticallyFinal()) {
48114811
diags.diagnose(attr->getLocation(),
48124812
diag::derivative_attr_nonfinal_class_init_unsupported,
48134813
classDecl->getDeclaredInterfaceType());

lib/Sema/TypeCheckConcurrency.cpp

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

34963496
if (classDecl) {
34973497
// An non-final class cannot conform to `Sendable`.
3498-
if (!classDecl->isFinal()) {
3498+
if (!classDecl->isSemanticallyFinal()) {
34993499
classDecl->diagnose(diag::concurrent_value_nonfinal_class,
35003500
classDecl->getName())
35013501
.limitBehavior(behavior);

lib/Sema/TypeCheckDecl.cpp

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

865865
// The presence of 'final' blocks the inference of 'dynamic'.
866-
if (decl->isFinal())
866+
if (decl->isSemanticallyFinal())
867867
return false;
868868

869869
// Types are never 'dynamic'.
@@ -1860,7 +1860,7 @@ FunctionOperatorRequest::evaluate(Evaluator &evaluator, FuncDecl *FD) const {
18601860
if (dc->isTypeContext()) {
18611861
if (auto classDecl = dc->getSelfClassDecl()) {
18621862
// For a class, we also need the function or class to be 'final'.
1863-
if (!classDecl->isFinal() && !FD->isFinal() &&
1863+
if (!classDecl->isSemanticallyFinal() && !FD->isFinal() &&
18641864
FD->getStaticLoc().isValid() &&
18651865
FD->getStaticSpelling() != StaticSpellingKind::KeywordStatic) {
18661866
FD->diagnose(diag::nonfinal_operator_in_class,

0 commit comments

Comments
 (0)