Skip to content

Commit 1f3879b

Browse files
authored
Merge pull request #35794 from etcwilde/ewilde/all-the-world-is-a-stage-with-actors
Change 'actor class' to 'actor'
2 parents f0d361a + 8b80331 commit 1f3879b

File tree

55 files changed

+301
-152
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+301
-152
lines changed

include/swift/AST/Attr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ SIMPLE_DECL_ATTR(asyncHandler, AsyncHandler,
570570
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
571571
101)
572572

573+
// TODO: Remove this once we don't need to support 'actor' as a modifier
573574
CONTEXTUAL_SIMPLE_DECL_ATTR(actor, Actor,
574575
DeclModifier | OnClass | ConcurrencyOnly |
575576
ABIBreakingToAdd | ABIBreakingToRemove |

include/swift/AST/Decl.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ class alignas(1 << DeclAlignInBits) Decl {
546546
NumRequirementsInSignature : 16
547547
);
548548

549-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1,
549+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1,
550550
/// Whether this class inherits its superclass's convenience initializers.
551551
InheritsSuperclassInits : 1,
552552
ComputedInheritsSuperclassInits : 1,
@@ -562,7 +562,10 @@ class alignas(1 << DeclAlignInBits) Decl {
562562

563563
/// Whether instances of this class are incompatible
564564
/// with weak and unowned references.
565-
IsIncompatibleWithWeakReferences : 1
565+
IsIncompatibleWithWeakReferences : 1,
566+
567+
/// Set when the class represents an actor
568+
IsActor : 1
566569
);
567570

568571
SWIFT_INLINE_BITFIELD(
@@ -3589,7 +3592,8 @@ class ClassDecl final : public NominalTypeDecl {
35893592
public:
35903593
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
35913594
ArrayRef<TypeLoc> Inherited,
3592-
GenericParamList *GenericParams, DeclContext *DC);
3595+
GenericParamList *GenericParams, DeclContext *DC,
3596+
bool isActor);
35933597

35943598
SourceLoc getStartLoc() const { return ClassLoc; }
35953599
SourceRange getSourceRange() const {
@@ -3689,6 +3693,9 @@ class ClassDecl final : public NominalTypeDecl {
36893693
/// i.e. the first class in its hierarchy that is a default actor.
36903694
bool isRootDefaultActor() const;
36913695

3696+
/// Whether the class was explicitly declared with the `actor` keyword.
3697+
bool isExplicitActor() const { return Bits.ClassDecl.IsActor; }
3698+
36923699
/// Does this class explicitly declare any of the methods that
36933700
/// would prevent it from being a default actor?
36943701
bool hasExplicitCustomActorMethods() const;

lib/AST/ASTPrinter.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,8 +2832,13 @@ void PrintAST::visitClassDecl(ClassDecl *decl) {
28322832
printSourceRange(CharSourceRange(Ctx.SourceMgr, decl->getStartLoc(),
28332833
decl->getBraces().Start.getAdvancedLoc(-1)), Ctx);
28342834
} else {
2835-
if (!Options.SkipIntroducerKeywords)
2836-
Printer << tok::kw_class << " ";
2835+
if (!Options.SkipIntroducerKeywords) {
2836+
if (decl->isExplicitActor()) {
2837+
Printer.printKeyword("actor", Options, " ");
2838+
} else {
2839+
Printer << tok::kw_class << " ";
2840+
}
2841+
}
28372842
printContextIfNeeded(decl);
28382843
recordDeclLoc(decl,
28392844
[&]{

lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4093,7 +4093,8 @@ VarDecl *NominalTypeDecl::getGlobalActorInstance() const {
40934093

40944094
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
40954095
ArrayRef<TypeLoc> Inherited,
4096-
GenericParamList *GenericParams, DeclContext *Parent)
4096+
GenericParamList *GenericParams, DeclContext *Parent,
4097+
bool isActor)
40974098
: NominalTypeDecl(DeclKind::Class, Parent, Name, NameLoc, Inherited,
40984099
GenericParams),
40994100
ClassLoc(ClassLoc) {
@@ -4105,6 +4106,7 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
41054106
Bits.ClassDecl.HasMissingVTableEntries = 0;
41064107
Bits.ClassDecl.ComputedHasMissingVTableEntries = 0;
41074108
Bits.ClassDecl.IsIncompatibleWithWeakReferences = 0;
4109+
Bits.ClassDecl.IsActor = isActor;
41084110
}
41094111

41104112
bool ClassDecl::hasResilientMetadata() const {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5146,7 +5146,8 @@ namespace {
51465146
AccessLevel::Public,
51475147
SourceLoc(), name,
51485148
SourceLoc(), None,
5149-
nullptr, dc);
5149+
nullptr, dc,
5150+
/*isActor*/false);
51505151
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
51515152
result->setSuperclass(Type());
51525153
result->setAddedImplicitInitializers(); // suppress all initializers
@@ -5236,7 +5237,8 @@ namespace {
52365237
// Create the class declaration and record it.
52375238
auto result = Impl.createDeclWithClangNode<ClassDecl>(
52385239
decl, access, Impl.importSourceLoc(decl->getBeginLoc()), name,
5239-
Impl.importSourceLoc(decl->getLocation()), None, nullptr, dc);
5240+
Impl.importSourceLoc(decl->getLocation()), None, nullptr, dc,
5241+
/*isActor*/false);
52405242

52415243
// Import generic arguments, if any.
52425244
if (auto gpImportResult = importObjCGenericParams(decl, dc)) {
@@ -5695,7 +5697,7 @@ SwiftDeclConverter::importCFClassType(const clang::TypedefNameDecl *decl,
56955697

56965698
auto theClass = Impl.createDeclWithClangNode<ClassDecl>(
56975699
decl, AccessLevel::Public, SourceLoc(), className, SourceLoc(), None,
5698-
nullptr, dc);
5700+
nullptr, dc, /*isActor*/false);
56995701
theClass->setSuperclass(superclass);
57005702
theClass->setAddedImplicitInitializers(); // suppress all initializers
57015703
theClass->setHasMissingVTableEntries(false);

lib/IRGen/GenClass.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2415,7 +2415,8 @@ ClassDecl *IRGenModule::getObjCRuntimeBaseClass(Identifier name,
24152415
auto SwiftRootClass = new (Context) ClassDecl(SourceLoc(), name, SourceLoc(),
24162416
ArrayRef<TypeLoc>(),
24172417
/*generics*/ nullptr,
2418-
Context.TheBuiltinModule);
2418+
Context.TheBuiltinModule,
2419+
/*isActor*/false);
24192420
SwiftRootClass->setIsObjC(Context.LangOpts.EnableObjCInterop);
24202421
SwiftRootClass->getAttrs().add(ObjCAttr::createNullary(Context, objcName,
24212422
/*isNameImplicit=*/true));

lib/Parse/ParseDecl.cpp

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3455,6 +3455,52 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes,
34553455
if (Kind == DAK_Count)
34563456
break;
34573457

3458+
if (Kind == DAK_Actor && shouldParseExperimentalConcurrency()) {
3459+
// If the next token is a startOfSwiftDecl, we are part of the modifier
3460+
// list and should consume the actor token (e.g, actor public class Foo)
3461+
// otherwise, it's the decl keyword (e.g. actor Foo) and shouldn't be.
3462+
// Unfortunately, the BacktrackingScope will eat diagnostics emitted in
3463+
// that scope, so we have to store enough state to emit the diagnostics
3464+
// outside of the scope.
3465+
bool isActorModifier = false;
3466+
bool isClassNext = false;
3467+
SourceLoc actorLoc = Tok.getLoc();
3468+
SourceLoc classLoc;
3469+
{
3470+
BacktrackingScope Scope(*this);
3471+
3472+
// Is this the class token before the identifier?
3473+
auto atClassDecl = [this]() -> bool {
3474+
return peekToken().is(tok::identifier) ||
3475+
Tok.is(tok::kw_class) ||
3476+
Tok.is(tok::kw_enum) ||
3477+
Tok.is(tok::kw_struct);
3478+
};
3479+
consumeToken(); // consume actor
3480+
isActorModifier = isStartOfSwiftDecl();
3481+
if (isActorModifier) {
3482+
isClassNext = atClassDecl();
3483+
while (!atClassDecl())
3484+
consumeToken();
3485+
classLoc = Tok.getLoc();
3486+
}
3487+
}
3488+
3489+
if (!isActorModifier)
3490+
break;
3491+
3492+
auto diag = diagnose(actorLoc,
3493+
diag::renamed_platform_condition_argument, "actor class", "actor");
3494+
if (isClassNext)
3495+
diag.fixItRemove(classLoc);
3496+
else
3497+
diag.fixItReplace(classLoc, "actor")
3498+
.fixItRemove(actorLoc);
3499+
Attributes.add(new (Context) ActorAttr({}, Tok.getLoc()));
3500+
consumeToken();
3501+
continue;
3502+
}
3503+
34583504
SyntaxParsingContext ModContext(SyntaxContext,
34593505
SyntaxKind::DeclModifier);
34603506
isError |= parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, Kind);
@@ -3782,8 +3828,6 @@ bool Parser::isStartOfSwiftDecl() {
37823828
// If this is obviously not the start of a decl, then we're done.
37833829
return false;
37843830
}
3785-
3786-
37873831

37883832
// When 'init' appears inside another 'init', it's likely the user wants to
37893833
// invoke an initializer but forgets to prefix it with 'self.' or 'super.'
@@ -3881,6 +3925,20 @@ bool Parser::isStartOfSwiftDecl() {
38813925
return isStartOfSwiftDecl();
38823926
}
38833927

3928+
if (shouldParseExperimentalConcurrency() &&
3929+
Tok.isContextualKeyword("actor")) {
3930+
if (Tok2.is(tok::identifier)) // actor Foo {}
3931+
return true;
3932+
BacktrackingScope Scope(*this);
3933+
// actor may be somewhere in the modifier list. Eat the tokens until we get
3934+
// to something that isn't the start of a decl. If that is an identifier,
3935+
// it's an actor declaration, otherwise, it isn't.
3936+
do {
3937+
consumeToken();
3938+
} while (isStartOfSwiftDecl());
3939+
return Tok.is(tok::identifier);
3940+
}
3941+
38843942
// If the next token is obviously not the start of a decl, bail early.
38853943
if (!isKeywordPossibleDeclStart(Tok2))
38863944
return false;
@@ -4220,6 +4278,13 @@ Parser::parseDecl(ParseDeclOptions Flags,
42204278
// Obvious nonsense.
42214279
default:
42224280

4281+
if (shouldParseExperimentalConcurrency() &&
4282+
Tok.isContextualKeyword("actor") && peekToken().is(tok::identifier)) {
4283+
DeclParsingContext.setCreateSyntax(SyntaxKind::ClassDecl);
4284+
DeclResult = parseDeclClass(Flags, Attributes);
4285+
break;
4286+
}
4287+
42234288
if (Flags.contains(PD_HasContainerType) &&
42244289
IsAtStartOfLineOrPreviousHadSemi) {
42254290

@@ -7220,21 +7285,31 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
72207285
/// \endverbatim
72217286
ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
72227287
DeclAttributes &Attributes) {
7223-
SourceLoc ClassLoc = consumeToken(tok::kw_class);
7288+
bool isExplicitActorDecl = Tok.isContextualKeyword("actor");
7289+
7290+
// part of
7291+
SourceLoc ClassLoc;
7292+
if (isExplicitActorDecl) {
7293+
assert(Tok.is(tok::identifier) && Tok.isContextualKeyword("actor"));
7294+
ClassLoc = consumeToken();
7295+
} else {
7296+
ClassLoc = consumeToken(tok::kw_class);
7297+
}
72247298

72257299
Identifier ClassName;
72267300
SourceLoc ClassNameLoc;
72277301
ParserStatus Status;
72287302

72297303
Status |= parseIdentifierDeclName(
7230-
*this, ClassName, ClassNameLoc, "class", [&](const Token &next) {
7304+
*this, ClassName, ClassNameLoc, isExplicitActorDecl ? "actor" : "class",
7305+
[&](const Token &next) {
72317306
return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next);
72327307
});
72337308
if (Status.isErrorOrHasCompletion())
72347309
return Status;
72357310

72367311
DebuggerContextChange DCC (*this, ClassName, DeclKind::Class);
7237-
7312+
72387313
// Parse the generic-params, if present.
72397314
GenericParamList *GenericParams = nullptr;
72407315
{
@@ -7246,7 +7321,8 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
72467321

72477322
// Create the class.
72487323
ClassDecl *CD = new (Context) ClassDecl(ClassLoc, ClassName, ClassNameLoc,
7249-
{ }, GenericParams, CurDeclContext);
7324+
{ }, GenericParams, CurDeclContext,
7325+
isExplicitActorDecl);
72507326
setLocalDiscriminator(CD);
72517327
CD->getAttrs() = Attributes;
72527328

@@ -7262,7 +7338,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
72627338
/*allowClassRequirement=*/false,
72637339
/*allowAnyObject=*/false);
72647340
CD->setInherited(Context.AllocateCopy(Inherited));
7265-
7341+
72667342
// Parse python style inheritance clause and replace parentheses with a colon
72677343
} else if (Tok.is(tok::l_paren)) {
72687344
bool isParenStyleInheritance = false;
@@ -7285,7 +7361,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
72857361
.fixItReplace(LParenLoc, ": ")
72867362
.fixItRemove(RParenLoc);
72877363
}
7288-
}
7364+
}
72897365

72907366
diagnoseWhereClauseInGenericParamList(GenericParams);
72917367

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ bool CanBeAsyncHandlerRequest::evaluate(
212212

213213
bool IsActorRequest::evaluate(
214214
Evaluator &evaluator, ClassDecl *classDecl) const {
215-
// If concurrency is not enabled, we don't have actors.
216-
auto actorAttr = classDecl->getAttrs().getAttribute<ActorAttr>();
215+
bool isExplicitActor = classDecl->isExplicitActor() ||
216+
classDecl->getAttrs().getAttribute<ActorAttr>();
217217

218218
// If there is a superclass, we can infer actor-ness from it.
219219
if (auto superclassDecl = classDecl->getSuperclassDecl()) {
@@ -223,21 +223,21 @@ bool IsActorRequest::evaluate(
223223

224224
// The superclass is 'NSObject', which is known to have no state and no
225225
// superclass.
226-
if (superclassDecl->isNSObject() && actorAttr != nullptr)
226+
if (superclassDecl->isNSObject() && isExplicitActor)
227227
return true;
228228

229229
// This class cannot be an actor; complain if the 'actor' modifier was
230230
// provided.
231-
if (actorAttr) {
232-
classDecl->diagnose(
233-
diag::actor_with_nonactor_superclass, superclassDecl->getName())
234-
.highlight(actorAttr->getRange());
231+
if (isExplicitActor) {
232+
classDecl->diagnose(diag::actor_with_nonactor_superclass,
233+
superclassDecl->getName())
234+
.highlight(classDecl->getStartLoc());
235235
}
236236

237237
return false;
238238
}
239239

240-
return actorAttr != nullptr;
240+
return isExplicitActor;
241241
}
242242

243243
bool IsDefaultActorRequest::evaluate(

lib/Serialization/Deserialization.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,7 @@ class DeclDeserializer {
35843584
IdentifierID nameID;
35853585
DeclContextID contextID;
35863586
bool isImplicit, isObjC;
3587+
bool isExplicitActorDecl;
35873588
bool inheritsSuperclassInitializers;
35883589
bool hasMissingDesignatedInits;
35893590
GenericSignatureID genericSigID;
@@ -3593,6 +3594,7 @@ class DeclDeserializer {
35933594
ArrayRef<uint64_t> rawInheritedAndDependencyIDs;
35943595
decls_block::ClassLayout::readRecord(scratch, nameID, contextID,
35953596
isImplicit, isObjC,
3597+
isExplicitActorDecl,
35963598
inheritsSuperclassInitializers,
35973599
hasMissingDesignatedInits,
35983600
genericSigID, superclassID,
@@ -3621,7 +3623,8 @@ class DeclDeserializer {
36213623
return declOrOffset;
36223624

36233625
auto theClass = MF.createDecl<ClassDecl>(SourceLoc(), name, SourceLoc(),
3624-
None, genericParams, DC);
3626+
None, genericParams, DC,
3627+
isExplicitActorDecl);
36253628
declOrOffset = theClass;
36263629

36273630
theClass->setGenericSignature(MF.getGenericSignature(genericSigID));

lib/Serialization/ModuleFormat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5656
/// describe what change you made. The content of this comment isn't important;
5757
/// it just ensures a conflict if two people change the module format.
5858
/// Don't worry about adhering to the 80-column limit for this line.
59-
const uint16_t SWIFTMODULE_VERSION_MINOR = 594; // @differentiable(reverse) attr
59+
const uint16_t SWIFTMODULE_VERSION_MINOR = 595; // Adding Actor class decls
6060

6161
/// A standard hash seed used for all string hashes in a serialized module.
6262
///
@@ -1208,6 +1208,7 @@ namespace decls_block {
12081208
DeclContextIDField, // context decl
12091209
BCFixed<1>, // implicit?
12101210
BCFixed<1>, // explicitly objc?
1211+
BCFixed<1>, // Explicitly actor?
12111212
BCFixed<1>, // inherits convenience initializers from its superclass?
12121213
BCFixed<1>, // has missing designated initializers?
12131214
GenericSignatureIDField, // generic environment

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3397,6 +3397,7 @@ class Serializer::DeclSerializer : public DeclVisitor<DeclSerializer> {
33973397
contextID.getOpaqueValue(),
33983398
theClass->isImplicit(),
33993399
theClass->isObjC(),
3400+
theClass->isExplicitActor(),
34003401
mutableClass->inheritsSuperclassInitializers(),
34013402
mutableClass->hasMissingDesignatedInitializers(),
34023403
S.addGenericSignatureRef(

stdlib/public/Concurrency/Actor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fileprivate func _registerMainActor(actor: AnyObject)
4848
@globalActor public final class MainActor {
4949
public static let shared = _Impl()
5050

51-
public actor class _Impl {
51+
public actor _Impl {
5252
init() { _registerMainActor(actor: self) }
5353
}
5454
}

test/ClangImporter/objc_async.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func testSlowServerOldSchool(slowServer: SlowServer) {
7171
// Check import of attributes
7272
func globalAsync() async { }
7373

74-
actor class MySubclassCheckingSwiftAttributes : ProtocolWithSwiftAttributes {
74+
actor MySubclassCheckingSwiftAttributes : ProtocolWithSwiftAttributes {
7575
func syncMethod() { } // expected-note 2{{calls to instance method 'syncMethod()' from outside of its actor context are implicitly asynchronous}}
7676

7777
func independentMethod() {

test/Concurrency/Runtime/actor_counters.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Darwin
1313
import Glibc
1414
#endif
1515

16-
actor class Counter {
16+
actor Counter {
1717
private var value = 0
1818
private let scratchBuffer: UnsafeMutableBufferPointer<Int>
1919

0 commit comments

Comments
 (0)