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.
This commit is contained in:
Evan Wilde
2021-02-09 11:12:49 -08:00
parent 10a4e1eac4
commit fc41826da9
12 changed files with 130 additions and 30 deletions

View File

@@ -3455,6 +3455,52 @@ bool Parser::parseDeclModifierList(DeclAttributes &Attributes,
if (Kind == DAK_Count)
break;
if (Kind == DAK_Actor && shouldParseExperimentalConcurrency()) {
// If the next token is a startOfSwiftDecl, we are part of the modifier
// list and should consume the actor token (e.g, actor public class Foo)
// otherwise, it's the decl keyword (e.g. actor Foo) and shouldn't be.
// Unfortunately, the BacktrackingScope will eat diagnostics emitted in
// that scope, so we have to store enough state to emit the diagnostics
// outside of the scope.
bool isActorModifier = false;
bool isClassNext = false;
SourceLoc actorLoc = Tok.getLoc();
SourceLoc classLoc;
{
BacktrackingScope Scope(*this);
// Is this the class token before the identifier?
auto atClassDecl = [this]() -> bool {
return peekToken().is(tok::identifier) ||
Tok.is(tok::kw_class) ||
Tok.is(tok::kw_enum) ||
Tok.is(tok::kw_struct);
};
consumeToken(); // consume actor
isActorModifier = isStartOfSwiftDecl();
if (isActorModifier) {
isClassNext = atClassDecl();
while (!atClassDecl())
consumeToken();
classLoc = Tok.getLoc();
}
}
if (!isActorModifier)
break;
auto diag = diagnose(actorLoc,
diag::renamed_platform_condition_argument, "actor class", "actor");
if (isClassNext)
diag.fixItRemove(classLoc);
else
diag.fixItReplace(classLoc, "actor")
.fixItRemove(actorLoc);
Attributes.add(new (Context) ActorAttr({}, Tok.getLoc()));
consumeToken();
continue;
}
SyntaxParsingContext ModContext(SyntaxContext,
SyntaxKind::DeclModifier);
isError |= parseNewDeclAttribute(Attributes, /*AtLoc=*/{}, Kind);
@@ -3782,8 +3828,6 @@ bool Parser::isStartOfSwiftDecl() {
// If this is obviously not the start of a decl, then we're done.
return false;
}
// When 'init' appears inside another 'init', it's likely the user wants to
// invoke an initializer but forgets to prefix it with 'self.' or 'super.'
@@ -3881,6 +3925,20 @@ bool Parser::isStartOfSwiftDecl() {
return isStartOfSwiftDecl();
}
if (shouldParseExperimentalConcurrency() &&
Tok.isContextualKeyword("actor")) {
if (Tok2.is(tok::identifier)) // actor Foo {}
return true;
BacktrackingScope Scope(*this);
// actor may be somewhere in the modifier list. Eat the tokens until we get
// to something that isn't the start of a decl. If that is an identifier,
// it's an actor declaration, otherwise, it isn't.
do {
consumeToken();
} while (isStartOfSwiftDecl());
return Tok.is(tok::identifier);
}
// If the next token is obviously not the start of a decl, bail early.
if (!isKeywordPossibleDeclStart(Tok2))
return false;
@@ -4220,6 +4278,13 @@ Parser::parseDecl(ParseDeclOptions Flags,
// Obvious nonsense.
default:
if (shouldParseExperimentalConcurrency() &&
Tok.isContextualKeyword("actor") && peekToken().is(tok::identifier)) {
DeclParsingContext.setCreateSyntax(SyntaxKind::ClassDecl);
DeclResult = parseDeclClass(Flags, Attributes);
break;
}
if (Flags.contains(PD_HasContainerType) &&
IsAtStartOfLineOrPreviousHadSemi) {
@@ -7220,21 +7285,31 @@ ParserResult<StructDecl> Parser::parseDeclStruct(ParseDeclOptions Flags,
/// \endverbatim
ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
DeclAttributes &Attributes) {
SourceLoc ClassLoc = consumeToken(tok::kw_class);
bool isExplicitActorDecl = Tok.isContextualKeyword("actor");
// part of
SourceLoc ClassLoc;
if (isExplicitActorDecl) {
assert(Tok.is(tok::identifier) && Tok.isContextualKeyword("actor"));
ClassLoc = consumeToken();
} else {
ClassLoc = consumeToken(tok::kw_class);
}
Identifier ClassName;
SourceLoc ClassNameLoc;
ParserStatus Status;
Status |= parseIdentifierDeclName(
*this, ClassName, ClassNameLoc, "class", [&](const Token &next) {
*this, ClassName, ClassNameLoc, isExplicitActorDecl ? "actor" : "class",
[&](const Token &next) {
return next.isAny(tok::colon, tok::l_brace) || startsWithLess(next);
});
if (Status.isErrorOrHasCompletion())
return Status;
DebuggerContextChange DCC (*this, ClassName, DeclKind::Class);
// Parse the generic-params, if present.
GenericParamList *GenericParams = nullptr;
{
@@ -7246,7 +7321,8 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
// Create the class.
ClassDecl *CD = new (Context) ClassDecl(ClassLoc, ClassName, ClassNameLoc,
{ }, GenericParams, CurDeclContext);
{ }, GenericParams, CurDeclContext,
isExplicitActorDecl);
setLocalDiscriminator(CD);
CD->getAttrs() = Attributes;
@@ -7262,7 +7338,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
/*allowClassRequirement=*/false,
/*allowAnyObject=*/false);
CD->setInherited(Context.AllocateCopy(Inherited));
// Parse python style inheritance clause and replace parentheses with a colon
} else if (Tok.is(tok::l_paren)) {
bool isParenStyleInheritance = false;
@@ -7285,7 +7361,7 @@ ParserResult<ClassDecl> Parser::parseDeclClass(ParseDeclOptions Flags,
.fixItReplace(LParenLoc, ": ")
.fixItRemove(RParenLoc);
}
}
}
diagnoseWhereClauseInGenericParamList(GenericParams);