Skip to content
Open
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
45 changes: 45 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,11 @@ public let DECL_NODES: [Node] = [
documentation: "The effect indicators of the function, like `async` or `throws`",
isOptional: true
),
Child(
name: "yieldsClause",
kind: .node(kind: .yieldsClause),
isOptional: true
),
Child(
name: "returnClause",
kind: .node(kind: .returnClause),
Expand Down Expand Up @@ -2165,6 +2170,41 @@ public let DECL_NODES: [Node] = [
]
),

Node(
kind: .yieldsClause,
base: .syntax,
nameForDiagnostics: "yields clause",
children: [
Child(
name: "yieldsKeyword",
// .token(.identifier) here is a hack to not require SPI while compiling the generated syntax files
// as otherwise we're ending with `yieldsKeyword: TokenSyntax = .keyword(.yields)` with default argument
// being an SPI
kind: .token(choices: [.token(.identifier), .keyword(.yields)]),
documentation: "The `yields` keyword."
),
Child(
name: "leftParen",
kind: .token(choices: [.token(.leftParen)]),
documentation: "The '(' to open the yield type specification.",
isOptional: true
),
Child(
name: "type",
kind: .node(kind: .type),
nameForDiagnostics: "yield type",
documentation: "The yielded type.",
isOptional: true
),
Child(
name: "rightParen",
kind: .token(choices: [.token(.rightParen)]),
documentation: "The ')' to close the yield type specification.",
isOptional: true
),
],
),

Node(
kind: .returnClause,
base: .syntax,
Expand Down Expand Up @@ -2383,6 +2423,11 @@ public let DECL_NODES: [Node] = [
name: "parameterClause",
kind: .node(kind: .functionParameterClause)
),
Child(
name: "yieldsClause",
kind: .node(kind: .yieldsClause),
isOptional: true
),
Child(
name: "returnClause",
kind: .node(kind: .returnClause)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum ExperimentalFeature: String, CaseIterable {
case oldOwnershipOperatorSpellings
case defaultIsolationPerFile
case borrowAndMutateAccessors
case coroutineFunctions

/// The name of the feature as it is written in the compiler's `Features.def` file.
public var featureName: String {
Expand All @@ -47,6 +48,8 @@ public enum ExperimentalFeature: String, CaseIterable {
return "DefaultIsolationPerFile"
case .borrowAndMutateAccessors:
return "BorrowAndMutateAccessors"
case .coroutineFunctions:
return "CoroutineFunctions"
}
}

Expand All @@ -73,6 +76,8 @@ public enum ExperimentalFeature: String, CaseIterable {
return "set default actor isolation for a file"
case .borrowAndMutateAccessors:
return "borrow and mutate accessors"
case .coroutineFunctions:
return "functions as coroutines"
}
}

Expand Down
5 changes: 5 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,11 @@ public let EXPR_NODES: [Node] = [
kind: .node(kind: .typeEffectSpecifiers),
isOptional: true
),
Child(
name: "yieldsClause",
kind: .node(kind: .yieldsClause),
isOptional: true
),
Child(
name: "returnClause",
kind: .node(kind: .returnClause),
Expand Down
6 changes: 6 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/KeywordSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ public enum Keyword: CaseIterable {
case willSet
case wrt
case yield
case `yields`
case `yield_once`

public var spec: KeywordSpec {
switch self {
Expand Down Expand Up @@ -692,6 +694,10 @@ public enum Keyword: CaseIterable {
return KeywordSpec("wrt")
case .yield:
return KeywordSpec("yield")
case .yield_once:
return KeywordSpec("yield_once", experimentalFeature: .coroutineFunctions)
case .yields:
return KeywordSpec("yields", experimentalFeature: .coroutineFunctions)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
case whereClause
case whileStmt
case wildcardPattern
case yieldsClause
case yieldedExpression
case yieldedExpressionList
case yieldedExpressionsClause
Expand Down
5 changes: 5 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ public let TYPE_NODES: [Node] = [
kind: .node(kind: .typeEffectSpecifiers),
isOptional: true
),
Child(
name: "yieldsClause",
kind: .node(kind: .yieldsClause),
isOptional: true
),
Child(
name: "returnClause",
kind: .node(kind: .returnClause)
Expand Down
10 changes: 9 additions & 1 deletion Sources/SwiftParser/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ extension Parser {
case objc
case Sendable
case transpose
case `yield_once`

init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
switch PrepareForKeywordMatch(lexeme) {
Expand All @@ -112,6 +113,7 @@ extension Parser {
case TokenSpec(.objc): self = .objc
case TokenSpec(.Sendable): self = .Sendable
case TokenSpec(.transpose): self = .transpose
case TokenSpec(.`yield_once`): self = .yield_once
default:
return nil
}
Expand Down Expand Up @@ -139,6 +141,7 @@ extension Parser {
case .objc: return .keyword(.objc)
case .Sendable: return .keyword(.Sendable)
case .transpose: return .keyword(.transpose)
case .`yield_once`: return .keyword(.yield_once)
}
}
}
Expand Down Expand Up @@ -347,6 +350,10 @@ extension Parser {
return parseAttribute(argumentMode: .noArgument) { parser in
preconditionFailure("Sendable has no argument")
}
case .yield_once:
return parseAttribute(argumentMode: .noArgument) { parser in
preconditionFailure("yield_once has no argument")
}
case nil:
return parseAttribute(argumentMode: .customAttribute) { parser in
let arguments = parser.parseArgumentListElements(
Expand Down Expand Up @@ -1139,7 +1146,8 @@ extension Parser.Lookahead {
TokenSpec(.rightParen),
TokenSpec(.rightBrace),
TokenSpec(.rightSquare),
TokenSpec(.rightAngle):
TokenSpec(.rightAngle),
TokenSpec(.yields):
return false
case _ where lookahead.at(.keyword(.async)):
return false
Expand Down
8 changes: 5 additions & 3 deletions Sources/SwiftParser/Declarations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1334,12 +1334,13 @@ extension Parser {
}

extension Parser {
/// If a `throws` keyword appears right in front of the `arrow`, it is returned as `misplacedThrowsKeyword` so it can be synthesized in front of the arrow.
/// If a `throws` keyword appears right behind of the `arrow`, it is returned as `misplacedThrowsKeyword` so it can be synthesized in front of the arrow.
mutating func parseFunctionReturnClause(
effectSpecifiers: inout (some RawMisplacedEffectSpecifiersTrait)?,
allowNamedOpaqueResultType: Bool
) -> RawReturnClauseSyntax {
let (unexpectedBeforeArrow, arrow) = self.expect(.arrow)

let unexpectedBeforeReturnType = self.parseMisplacedEffectSpecifiers(&effectSpecifiers)
let type: RawTypeSyntax
if allowNamedOpaqueResultType {
Expand Down Expand Up @@ -1429,7 +1430,7 @@ extension Parser {
parser.parseFunctionParameter()
}

var effectSpecifiers = self.parseFunctionEffectSpecifiers()
var (effectSpecifiers, yields) = self.parseFunctionEffectSpecifiers()

var returnClause: RawReturnClauseSyntax?

Expand All @@ -1443,10 +1444,10 @@ extension Parser {
} else {
returnClause = nil
}

return RawFunctionSignatureSyntax(
parameterClause: parameterClause,
effectSpecifiers: effectSpecifiers,
yieldsClause: yields,
returnClause: returnClause,
arena: self.arena
)
Expand Down Expand Up @@ -1509,6 +1510,7 @@ extension Parser {
RawUnexpectedNodesSyntax([unexpectedName], arena: self.arena),
genericParameterClause: genericParameterClause,
parameterClause: parameterClause,
yieldsClause: nil,
returnClause: returnClause,
genericWhereClause: genericWhereClause,
accessorBlock: accessor,
Expand Down
15 changes: 13 additions & 2 deletions Sources/SwiftParser/Expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ extension Parser {
return nil
}
case (.arrow, _)?, (.throws, _)?:
var effectSpecifiers = self.parseTypeEffectSpecifiers()
var (effectSpecifiers, _) = self.parseTypeEffectSpecifiers()

let (unexpectedBeforeArrow, arrow) = self.expect(.arrow)

Expand Down Expand Up @@ -2003,6 +2003,7 @@ extension Parser {

var parameterClause: RawClosureSignatureSyntax.ParameterClause?
var effectSpecifiers: RawTypeEffectSpecifiersSyntax?
var yields: RawYieldsClauseSyntax? = nil
var returnClause: RawReturnClauseSyntax? = nil
if !self.at(.keyword(.in)) {
// If the next token is ':', then it looks like the code contained a non-shorthand closure parameter with a type annotation.
Expand Down Expand Up @@ -2043,7 +2044,7 @@ extension Parser {
parameterClause = .simpleInput(RawClosureShorthandParameterListSyntax(elements: params, arena: self.arena))
}

effectSpecifiers = self.parseTypeEffectSpecifiers()
(effectSpecifiers, yields) = self.parseTypeEffectSpecifiers()

if self.at(.arrow) {
returnClause = self.parseFunctionReturnClause(
Expand All @@ -2060,6 +2061,7 @@ extension Parser {
capture: captures,
parameterClause: parameterClause,
effectSpecifiers: effectSpecifiers,
yieldsClause: yields,
returnClause: returnClause,
unexpectedBeforeInKeyword,
inKeyword: inKeyword,
Expand Down Expand Up @@ -2697,6 +2699,15 @@ extension Parser.Lookahead {
}
}

// Consume 'yields'
mutating func consumeYields() {
if self.consume(if: .keyword(.yields)) != nil, self.consume(if: .leftParen) != nil {
_ = self.canParseTypeAttributeList()
_ = self.canParseSimpleOrCompositionType()
self.consume(if: .rightParen)
}
}

mutating func canParseClosureSignature() -> Bool {
// Consume attributes.
var lookahead = self.lookahead()
Expand Down
65 changes: 51 additions & 14 deletions Sources/SwiftParser/Specifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
//===----------------------------------------------------------------------===//

#if compiler(>=6)
@_spi(RawSyntax) public import SwiftSyntax
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) public import SwiftSyntax
#else
@_spi(RawSyntax) import SwiftSyntax
@_spi(ExperimentalLanguageFeatures) @_spi(RawSyntax) import SwiftSyntax
#endif

// MARK: - TokenSpecSet
Expand Down Expand Up @@ -620,7 +620,39 @@ extension Parser {
)
}

private mutating func parseEffectSpecifiers<S: RawEffectSpecifiersTrait>(_: S.Type) -> S? {
mutating func parseYields() -> RawYieldsClauseSyntax? {
let (unexpectedBeforeYields, yieldsKeyword) = self.expect(.keyword(.yields))
// If there is no `yields` at all, then let result type parsing handle everything else
if yieldsKeyword.isMissing {
return nil
}

guard let leftParen = self.consume(if: .leftParen) else {
return RawYieldsClauseSyntax(
unexpectedBeforeYields,
yieldsKeyword: yieldsKeyword,
leftParen: nil,
type: nil,
rightParen: nil,
arena: self.arena
)
}

let type = self.parseType()
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)

return RawYieldsClauseSyntax(
unexpectedBeforeYields,
yieldsKeyword: yieldsKeyword,
leftParen: leftParen,
type: type,
unexpectedBeforeRightParen,
rightParen: rightParen,
arena: self.arena
)
}

private mutating func parseEffectSpecifiers<S: RawEffectSpecifiersTrait>(_: S.Type) -> (S?, RawYieldsClauseSyntax?) {
var unexpectedBeforeAsync: [RawSyntax] = []
var asyncKeyword: RawTokenSyntax? = nil
var unexpectedBeforeThrows: [RawSyntax] = []
Expand Down Expand Up @@ -690,32 +722,37 @@ extension Parser {
}
}

let yields = parseYields()

if unexpectedBeforeAsync.isEmpty && asyncKeyword == nil && unexpectedBeforeThrows.isEmpty && throwsClause == nil
&& unexpectedAfterThrowsClause.isEmpty
{
return nil
return (nil, yields)
}

return S(
RawUnexpectedNodesSyntax(unexpectedBeforeAsync, arena: self.arena),
asyncSpecifier: asyncKeyword,
RawUnexpectedNodesSyntax(unexpectedBeforeThrows, arena: self.arena),
throwsClause: throwsClause,
RawUnexpectedNodesSyntax(unexpectedAfterThrowsClause, arena: self.arena),
arena: self.arena
return (
S(
RawUnexpectedNodesSyntax(unexpectedBeforeAsync, arena: self.arena),
asyncSpecifier: asyncKeyword,
RawUnexpectedNodesSyntax(unexpectedBeforeThrows, arena: self.arena),
throwsClause: throwsClause,
RawUnexpectedNodesSyntax(unexpectedAfterThrowsClause, arena: self.arena),
arena: self.arena
),
yields
)
}

mutating func parseTypeEffectSpecifiers() -> RawTypeEffectSpecifiersSyntax? {
mutating func parseTypeEffectSpecifiers() -> (RawTypeEffectSpecifiersSyntax?, RawYieldsClauseSyntax?) {
return parseEffectSpecifiers(RawTypeEffectSpecifiersSyntax.self)
}

mutating func parseFunctionEffectSpecifiers() -> RawFunctionEffectSpecifiersSyntax? {
mutating func parseFunctionEffectSpecifiers() -> (RawFunctionEffectSpecifiersSyntax?, RawYieldsClauseSyntax?) {
return parseEffectSpecifiers(RawFunctionEffectSpecifiersSyntax.self)
}

mutating func parseAccessorEffectSpecifiers() -> RawAccessorEffectSpecifiersSyntax? {
return parseEffectSpecifiers(RawAccessorEffectSpecifiersSyntax.self)
return parseEffectSpecifiers(RawAccessorEffectSpecifiersSyntax.self).0
}

mutating func parseDeinitEffectSpecifiers() -> RawDeinitializerEffectSpecifiersSyntax? {
Expand Down
Loading
Loading