@@ -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
72217286ParserResult<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
0 commit comments