Skip to content

Update lifetime dependence syntax #2564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,7 @@ public enum Keyword: CaseIterable {
case _Class
case _compilerInitialized
case _const
case _consume
case _consuming
case _copy
case _documentation
case _dynamicReplacement
case _effects
Expand All @@ -121,7 +119,6 @@ public enum Keyword: CaseIterable {
case _local
case _modify
case _move
case _mutate
case _mutating
case _NativeClass
case _NativeRefCountedObject
Expand Down Expand Up @@ -186,6 +183,7 @@ public enum Keyword: CaseIterable {
case `default`
case `defer`
case `deinit`
case dependsOn
case deprecated
case derivative
case didSet
Expand Down Expand Up @@ -275,6 +273,7 @@ public enum Keyword: CaseIterable {
case reverse
case right
case safe
case scoped
case `self`
case `Self`
case Sendable
Expand Down Expand Up @@ -343,12 +342,8 @@ public enum Keyword: CaseIterable {
return KeywordSpec("_compilerInitialized")
case ._const:
return KeywordSpec("_const")
case ._consume:
return KeywordSpec("_consume", experimentalFeature: .nonescapableTypes)
case ._consuming:
return KeywordSpec("_consuming", experimentalFeature: .referenceBindings)
case ._copy:
return KeywordSpec("_copy", experimentalFeature: .nonescapableTypes)
case ._documentation:
return KeywordSpec("_documentation")
case ._dynamicReplacement:
Expand All @@ -369,8 +364,6 @@ public enum Keyword: CaseIterable {
return KeywordSpec("_modify")
case ._move:
return KeywordSpec("_move")
case ._mutate:
return KeywordSpec("_mutate", experimentalFeature: .nonescapableTypes)
case ._mutating:
return KeywordSpec("_mutating", experimentalFeature: .referenceBindings)
case ._NativeClass:
Expand Down Expand Up @@ -499,6 +492,8 @@ public enum Keyword: CaseIterable {
return KeywordSpec("defer", isLexerClassified: true)
case .deinit:
return KeywordSpec("deinit", isLexerClassified: true)
case .dependsOn:
return KeywordSpec("dependsOn", experimentalFeature: .nonescapableTypes)
case .deprecated:
return KeywordSpec("deprecated")
case .derivative:
Expand Down Expand Up @@ -675,6 +670,8 @@ public enum Keyword: CaseIterable {
return KeywordSpec("right")
case .safe:
return KeywordSpec("safe")
case .scoped:
return KeywordSpec("scoped", experimentalFeature: .nonescapableTypes)
case .self:
return KeywordSpec("self", isLexerClassified: true)
case .Self:
Expand Down
38 changes: 19 additions & 19 deletions CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -553,25 +553,14 @@ public let TYPE_NODES: [Node] = [
### Example
`borrow(data)` in `func foo(data: Array<Item>) -> borrow(data) ComplexReferenceType`
""",
traits: [
"Parenthesized"
],
children: [
Child(
name: "leftParen",
kind: .token(choices: [.token(.leftParen)])
),
Child(
name: "arguments",
kind: .collection(kind: .lifetimeSpecifierArgumentList, collectionElementName: "Arguments"),
documentation: """
The function parameters that the lifetime of the annotated type depends on.
"""
),
Child(
name: "rightParen",
kind: .token(choices: [.token(.rightParen)])
),
)
]
),

Expand All @@ -581,21 +570,32 @@ public let TYPE_NODES: [Node] = [
experimentalFeature: .nonescapableTypes,
nameForDiagnostics: "lifetime specifier",
documentation: "A specifier that specifies function parameter on whose lifetime a type depends",
traits: [
"Parenthesized"
],
children: [
Child(
name: "specifier",
kind: .token(choices: [
.keyword(._copy),
.keyword(._consume),
.keyword(._borrow),
.keyword(._mutate),
]),
name: "dependsOnKeyword",
kind: .token(choices: [.keyword(.dependsOn)]),
documentation: "The specifier token that's attached to the type."
),
Child(
name: "leftParen",
kind: .token(choices: [.token(.leftParen)])
),
Child(
name: "scopedKeyword",
kind: .token(choices: [.keyword(.scoped)]),
isOptional: true
),
Child(
name: "arguments",
kind: .node(kind: .lifetimeSpecifierArguments)
),
Child(
name: "rightParen",
kind: .token(choices: [.token(.rightParen)])
),
]
),

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftParser/TokenPrecedence.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ enum TokenPrecedence: Comparable {
.__setter_access, .indirect, .isolated, .nonisolated, .distributed, ._local,
.inout, ._mutating, ._borrow, ._borrowing, .borrowing, ._consuming, .consuming, .consume, ._resultDependsOnSelf,
._resultDependsOn,
.transferring, ._consume, ._copy, ._mutate,
.transferring, .dependsOn, .scoped,
// Accessors
.get, .set, .didSet, .willSet, .unsafeAddress, .addressWithOwner, .addressWithNativeOwner, .unsafeMutableAddress,
.mutableAddressWithOwner, .mutableAddressWithNativeOwner, ._read, ._modify,
Expand Down
39 changes: 19 additions & 20 deletions Sources/SwiftParser/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -900,33 +900,33 @@ extension Parser.Lookahead {
}

extension Parser {
private mutating func parseLifetimeTypeSpecifier(
specifierHandle: TokenConsumptionHandle
) -> RawTypeSpecifierListSyntax.Element {
let specifier = self.eat(specifierHandle)
private mutating func parseLifetimeTypeSpecifier() -> RawTypeSpecifierListSyntax.Element {
let specifier = self.eat(TokenSpec(.dependsOn))

guard let leftParen = self.consume(if: .leftParen) else {
// If there is no left paren, add an entirely missing detail. Otherwise, we start to consume the following type
// name as a token inside the detail, which leads to confusing recovery results.
let arguments = RawLifetimeSpecifierArgumentsSyntax(
leftParen: missingToken(.leftParen),
arguments: RawLifetimeSpecifierArgumentListSyntax(
elements: [
RawLifetimeSpecifierArgumentSyntax(parameter: missingToken(.identifier), trailingComma: nil, arena: arena)
],
arena: self.arena
),
rightParen: missingToken(.rightParen),
arena: self.arena
)
let lifetimeSpecifier = RawLifetimeTypeSpecifierSyntax(
specifier: specifier,
dependsOnKeyword: specifier,
leftParen: missingToken(.leftParen),
scopedKeyword: nil,
arguments: arguments,
rightParen: missingToken(.rightParen),
arena: self.arena
)
return .lifetimeTypeSpecifier(lifetimeSpecifier)
}

let scoped = self.consume(if: .keyword(.scoped))
var keepGoing: RawTokenSyntax?
var arguments: [RawLifetimeSpecifierArgumentSyntax] = []
var loopProgress = LoopProgressCondition()
Expand All @@ -948,15 +948,16 @@ extension Parser {
let lifetimeSpecifierArgumentList = RawLifetimeSpecifierArgumentListSyntax(elements: arguments, arena: self.arena)
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
let argumentsSyntax = RawLifetimeSpecifierArgumentsSyntax(
leftParen: leftParen,
arguments: lifetimeSpecifierArgumentList,
unexpectedBeforeRightParen,
rightParen: rightParen,
arena: self.arena
)
let lifetimeSpecifier = RawLifetimeTypeSpecifierSyntax(
specifier: specifier,
dependsOnKeyword: specifier,
leftParen: leftParen,
scopedKeyword: scoped,
arguments: argumentsSyntax,
unexpectedBeforeRightParen,
rightParen: rightParen,
arena: self.arena
)
return .lifetimeTypeSpecifier(lifetimeSpecifier)
Expand All @@ -976,20 +977,18 @@ extension Parser {
specifiers: RawTypeSpecifierListSyntax,
attributes: RawAttributeListSyntax
)? {
typealias SimpleOrLifetimeSpecifier =
EitherTokenSpecSet<SimpleTypeSpecifierSyntax.SpecifierOptions, LifetimeTypeSpecifierSyntax.SpecifierOptions>
var specifiers: [RawTypeSpecifierListSyntax.Element] = []
SPECIFIER_PARSING: while canHaveParameterSpecifier,
let (specifierSpec, specifierHandle) = self.at(anyIn: SimpleOrLifetimeSpecifier.self)
{
switch specifierSpec {
case .lhs: specifiers.append(parseSimpleTypeSpecifier(specifierHandle: specifierHandle))
case .rhs:
SPECIFIER_PARSING: while canHaveParameterSpecifier {
if let (_, specifierHandle) = self.at(anyIn: SimpleTypeSpecifierSyntax.SpecifierOptions.self) {
specifiers.append(parseSimpleTypeSpecifier(specifierHandle: specifierHandle))
} else if self.at(TokenSpec(.dependsOn)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplified slightly to

} else if self.at(.keyword(.dependsOn)) {

if self.experimentalFeatures.contains(.nonescapableTypes) {
specifiers.append(parseLifetimeTypeSpecifier(specifierHandle: specifierHandle))
specifiers.append(parseLifetimeTypeSpecifier())
} else {
break SPECIFIER_PARSING
}
} else {
break SPECIFIER_PARSING
}
}
specifiers += misplacedSpecifiers.map {
Expand Down
73 changes: 0 additions & 73 deletions Sources/SwiftParser/generated/Parser+TokenSpecSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2623,79 +2623,6 @@ extension LifetimeSpecifierArgumentSyntax {
}
}

extension LifetimeTypeSpecifierSyntax {
@_spi(Diagnostics)
public enum SpecifierOptions: TokenSpecSet {
@_spi(ExperimentalLanguageFeatures)
case _copy
@_spi(ExperimentalLanguageFeatures)
case _consume
case _borrow
@_spi(ExperimentalLanguageFeatures)
case _mutate

init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
switch PrepareForKeywordMatch(lexeme) {
case TokenSpec(._copy) where experimentalFeatures.contains(.nonescapableTypes):
self = ._copy
case TokenSpec(._consume) where experimentalFeatures.contains(.nonescapableTypes):
self = ._consume
case TokenSpec(._borrow):
self = ._borrow
case TokenSpec(._mutate) where experimentalFeatures.contains(.nonescapableTypes):
self = ._mutate
default:
return nil
}
}

public init?(token: TokenSyntax) {
switch token {
case TokenSpec(._copy):
self = ._copy
case TokenSpec(._consume):
self = ._consume
case TokenSpec(._borrow):
self = ._borrow
case TokenSpec(._mutate):
self = ._mutate
default:
return nil
}
}

var spec: TokenSpec {
switch self {
case ._copy:
return .keyword(._copy)
case ._consume:
return .keyword(._consume)
case ._borrow:
return .keyword(._borrow)
case ._mutate:
return .keyword(._mutate)
}
}

/// Returns a token that satisfies the `TokenSpec` of this case.
///
/// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text.
@_spi(Diagnostics)
public var tokenSyntax: TokenSyntax {
switch self {
case ._copy:
return .keyword(._copy)
case ._consume:
return .keyword(._consume)
case ._borrow:
return .keyword(._borrow)
case ._mutate:
return .keyword(._mutate)
}
}
}
}

extension MemberTypeSyntax {
@_spi(Diagnostics)
public enum NameOptions: TokenSpecSet {
Expand Down
42 changes: 23 additions & 19 deletions Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2009,30 +2009,34 @@ public func childName(_ keyPath: AnyKeyPath) -> String? {
return "trailingComma"
case \LifetimeSpecifierArgumentSyntax.unexpectedAfterTrailingComma:
return "unexpectedAfterTrailingComma"
case \LifetimeSpecifierArgumentsSyntax.unexpectedBeforeLeftParen:
return "unexpectedBeforeLeftParen"
case \LifetimeSpecifierArgumentsSyntax.leftParen:
return "leftParen"
case \LifetimeSpecifierArgumentsSyntax.unexpectedBetweenLeftParenAndArguments:
return "unexpectedBetweenLeftParenAndArguments"
case \LifetimeSpecifierArgumentsSyntax.unexpectedBeforeArguments:
return "unexpectedBeforeArguments"
case \LifetimeSpecifierArgumentsSyntax.arguments:
return "arguments"
case \LifetimeSpecifierArgumentsSyntax.unexpectedBetweenArgumentsAndRightParen:
case \LifetimeSpecifierArgumentsSyntax.unexpectedAfterArguments:
return "unexpectedAfterArguments"
case \LifetimeTypeSpecifierSyntax.unexpectedBeforeDependsOnKeyword:
return "unexpectedBeforeDependsOnKeyword"
case \LifetimeTypeSpecifierSyntax.dependsOnKeyword:
return "dependsOnKeyword"
case \LifetimeTypeSpecifierSyntax.unexpectedBetweenDependsOnKeywordAndLeftParen:
return "unexpectedBetweenDependsOnKeywordAndLeftParen"
case \LifetimeTypeSpecifierSyntax.leftParen:
return "leftParen"
case \LifetimeTypeSpecifierSyntax.unexpectedBetweenLeftParenAndScopedKeyword:
return "unexpectedBetweenLeftParenAndScopedKeyword"
case \LifetimeTypeSpecifierSyntax.scopedKeyword:
return "scopedKeyword"
case \LifetimeTypeSpecifierSyntax.unexpectedBetweenScopedKeywordAndArguments:
return "unexpectedBetweenScopedKeywordAndArguments"
case \LifetimeTypeSpecifierSyntax.arguments:
return "arguments"
case \LifetimeTypeSpecifierSyntax.unexpectedBetweenArgumentsAndRightParen:
return "unexpectedBetweenArgumentsAndRightParen"
case \LifetimeSpecifierArgumentsSyntax.rightParen:
case \LifetimeTypeSpecifierSyntax.rightParen:
return "rightParen"
case \LifetimeSpecifierArgumentsSyntax.unexpectedAfterRightParen:
case \LifetimeTypeSpecifierSyntax.unexpectedAfterRightParen:
return "unexpectedAfterRightParen"
case \LifetimeTypeSpecifierSyntax.unexpectedBeforeSpecifier:
return "unexpectedBeforeSpecifier"
case \LifetimeTypeSpecifierSyntax.specifier:
return "specifier"
case \LifetimeTypeSpecifierSyntax.unexpectedBetweenSpecifierAndArguments:
return "unexpectedBetweenSpecifierAndArguments"
case \LifetimeTypeSpecifierSyntax.arguments:
return "arguments"
case \LifetimeTypeSpecifierSyntax.unexpectedAfterArguments:
return "unexpectedAfterArguments"
case \MacroDeclSyntax.unexpectedBeforeAttributes:
return "unexpectedBeforeAttributes"
case \MacroDeclSyntax.attributes:
Expand Down
Loading