Skip to content

Commit fc41826

Browse files
committed
Rename 'actor class' -> 'actor'
This patch softly updates the spelling of actors from `actor class` to `actor`. We still accept using `actor` as a modifying attribute of class, but emit a warning and fix-it to make the change. One of the challenges that makes this messier is that the modifier list can be in any order. e.g, `public actor class Foo {}` is the same as `actor public class Foo {}`. Classes have been updated to include whether they were explicitly declared as an actor. This change updates the swiftmodule serialization version number to 0.591. The additional bit only gets set of the class declaration was declared as an actor, not if the actor was applied as an attribute. This allows us to correctly emit `actor class` vs `actor` emitting the code back out.
1 parent 10a4e1e commit fc41826

File tree

12 files changed

+130
-30
lines changed

12 files changed

+130
-30
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(

utils/gyb_syntax_support/DeclNodes.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@
197197
]),
198198

199199
# class-declaration -> attributes? access-level-modifier?
200-
# 'class' class-name
200+
# ('class' | 'actor') class-name
201201
# generic-parameter-clause?
202202
# type-inheritance-clause?
203203
# generic-where-clause?
@@ -210,7 +210,8 @@
210210
collection_element_name='Attribute', is_optional=True),
211211
Child('Modifiers', kind='ModifierList',
212212
collection_element_name='Modifier', is_optional=True),
213-
Child('ClassKeyword', kind='ClassToken'),
213+
Child('ClassOrActorKeyword', kind='Token',
214+
token_choices=['ClassToken', 'ContextualKeywordToken']),
214215
Child('Identifier', kind='IdentifierToken'),
215216
Child('GenericParameterClause', kind='GenericParameterClause',
216217
is_optional=True),

0 commit comments

Comments
 (0)