Skip to content

Commit 5ce35b8

Browse files
authored
Merge pull request #3067 from swiftlang/automerge/merge-main-2025-04-28_09-39
Merge `main` into `release/6.2`
2 parents 447a849 + 77874c1 commit 5ce35b8

File tree

4 files changed

+95
-29
lines changed

4 files changed

+95
-29
lines changed

.github/workflows/pull_request.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Pull request
22

33
on:
44
pull_request:
5-
types: [opened, reopened, synchronize]
5+
types: [opened, reopened, synchronize, ready_for_review]
66

77
concurrency:
88
group: ${{ github.workflow }}-${{ github.ref }}
@@ -11,15 +11,20 @@ concurrency:
1111
jobs:
1212
tests:
1313
name: Test
14+
# PRs created by GitHub Actions don't kick off further actions (https://github.com/peter-evans/create-pull-request/blob/d57e551ebc1a16dee0b8c9ea6d24dba7627a6e35/docs/concepts-guidelines.md#triggering-further-workflow-runs).
15+
# As a workaround, we mark automerge PRs that are created by GitHub actions as draft and trigger the GitHub actions by marking the PR as ready for review. But we don't want to re-trigger testing this when a normal user's PR is marked as ready for review.
16+
if: (github.event.action != 'ready_for_review') || (github.event.action == 'ready_for_review' && github.event.pull_request.user.login == 'github-actions[bot]')
1417
uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
1518
soundness:
1619
name: Soundness
20+
if: (github.event.action != 'ready_for_review') || (github.event.action == 'ready_for_review' && github.event.pull_request.user.login == 'github-actions[bot]')
1721
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
1822
with:
1923
api_breakage_check_enabled: false # https://github.com/swiftlang/swift-syntax/issues/3010
2024
docs_check_additional_arguments: "--disable-parameters-and-returns-validation"
2125
verify_source_code:
2226
name: Validate generated code
27+
if: (github.event.action != 'ready_for_review') || (github.event.action == 'ready_for_review' && github.event.pull_request.user.login == 'github-actions[bot]')
2328
runs-on: ubuntu-latest
2429
container:
2530
image: swift:latest
@@ -32,6 +37,7 @@ jobs:
3237
run: "./swift-syntax-dev-utils verify-source-code --toolchain /usr"
3338
test_using_swift_syntax_dev_utils_linux:
3439
name: Run tests using swift-syntax-dev-utils (Linux)
40+
if: (github.event.action != 'ready_for_review') || (github.event.action == 'ready_for_review' && github.event.pull_request.user.login == 'github-actions[bot]')
3541
runs-on: ubuntu-latest
3642
container:
3743
image: swift:latest
@@ -44,6 +50,7 @@ jobs:
4450
run: "./swift-syntax-dev-utils test --enable-rawsyntax-validation --enable-test-fuzzing --toolchain /usr"
4551
test_using_swift_syntax_dev_utils_windows:
4652
name: Run tests using swift-syntax-dev-utils (Windows)
53+
if: (github.event.action != 'ready_for_review') || (github.event.action == 'ready_for_review' && github.event.pull_request.user.login == 'github-actions[bot]')
4754
runs-on: windows-2022
4855
steps:
4956
- name: Pull Docker image

Sources/SwiftParser/Attributes.swift

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extension Parser {
6666
case TokenSpec(._specialize): self = ._specialize
6767
case TokenSpec(._spi_available): self = ._spi_available
6868
case TokenSpec(.`rethrows`): self = .rethrows
69-
case TokenSpec(.abi) where experimentalFeatures.contains(.abiAttribute): self = .abi
69+
case TokenSpec(.abi): self = .abi
7070
case TokenSpec(.attached): self = .attached
7171
case TokenSpec(.available): self = .available
7272
case TokenSpec(.backDeployed): self = .backDeployed
@@ -139,8 +139,12 @@ extension Parser {
139139
/// - parseMissingArguments: If provided, called instead of `parseArgument` when an argument list was required but no opening parenthesis was present.
140140
mutating func parseAttribute(
141141
argumentMode: AttributeArgumentMode,
142-
parseArguments: (inout Parser) -> RawAttributeSyntax.Arguments,
143-
parseMissingArguments: ((inout Parser) -> RawAttributeSyntax.Arguments)? = nil
142+
parseArguments: (inout Parser) -> (
143+
unexpectedBefore: RawUnexpectedNodesSyntax?, arguments: RawAttributeSyntax.Arguments
144+
),
145+
parseMissingArguments: (
146+
(inout Parser) -> (unexpectedBefore: RawUnexpectedNodesSyntax?, arguments: RawAttributeSyntax.Arguments)
147+
)? = nil
144148
) -> RawAttributeListSyntax.Element {
145149
var (unexpectedBeforeAtSign, atSign) = self.expect(.atSign)
146150
if atSign.trailingTriviaByteLength > 0 || self.currentToken.leadingTriviaByteLength > 0 {
@@ -175,11 +179,12 @@ extension Parser {
175179
)
176180
leftParen = leftParen.tokenView.withTokenDiagnostic(tokenDiagnostic: diagnostic, arena: self.arena)
177181
}
182+
let unexpectedBeforeArguments: RawUnexpectedNodesSyntax?
178183
let argument: RawAttributeSyntax.Arguments
179184
if let parseMissingArguments, leftParen.presence == .missing {
180-
argument = parseMissingArguments(&self)
185+
(unexpectedBeforeArguments, argument) = parseMissingArguments(&self)
181186
} else {
182-
argument = parseArguments(&self)
187+
(unexpectedBeforeArguments, argument) = parseArguments(&self)
183188
}
184189
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
185190
return .attribute(
@@ -189,6 +194,7 @@ extension Parser {
189194
attributeName: attributeName,
190195
unexpectedBeforeLeftParen,
191196
leftParen: leftParen,
197+
unexpectedBeforeArguments,
192198
arguments: argument,
193199
unexpectedBeforeRightParen,
194200
rightParen: rightParen,
@@ -224,41 +230,41 @@ extension Parser {
224230
switch peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) {
225231
case .abi:
226232
return parseAttribute(argumentMode: .required) { parser in
227-
return .abiArguments(parser.parseABIAttributeArguments())
233+
return parser.parseABIAttributeArguments()
228234
} parseMissingArguments: { parser in
229-
return .abiArguments(parser.parseABIAttributeArguments(missingLParen: true))
235+
return parser.parseABIAttributeArguments(missingLParen: true)
230236
}
231237
case .available, ._spi_available:
232238
return parseAttribute(argumentMode: .required) { parser in
233-
return .availability(parser.parseAvailabilityArgumentSpecList())
239+
return (nil, .availability(parser.parseAvailabilityArgumentSpecList()))
234240
}
235241
case .backDeployed, ._backDeploy:
236242
return parseAttribute(argumentMode: .required) { parser in
237-
return .backDeployedArguments(parser.parseBackDeployedAttributeArguments())
243+
return (nil, .backDeployedArguments(parser.parseBackDeployedAttributeArguments()))
238244
}
239245
case .differentiable:
240246
return parseAttribute(argumentMode: .required) { parser in
241-
return .differentiableArguments(parser.parseDifferentiableAttributeArguments())
247+
return (nil, .differentiableArguments(parser.parseDifferentiableAttributeArguments()))
242248
}
243249
case .derivative, .transpose:
244250
return parseAttribute(argumentMode: .required) { parser in
245-
return .derivativeRegistrationArguments(parser.parseDerivativeAttributeArguments())
251+
return (nil, .derivativeRegistrationArguments(parser.parseDerivativeAttributeArguments()))
246252
}
247253
case .objc:
248254
return parseAttribute(argumentMode: .optional) { parser in
249-
return .objCName(parser.parseObjectiveCSelector())
255+
return (nil, .objCName(parser.parseObjectiveCSelector()))
250256
}
251257
case ._specialize:
252258
return parseAttribute(argumentMode: .required) { parser in
253-
return .specializeArguments(parser.parseSpecializeAttributeArgumentList())
259+
return (nil, .specializeArguments(parser.parseSpecializeAttributeArgumentList()))
254260
}
255261
case ._dynamicReplacement:
256262
return parseAttribute(argumentMode: .required) { parser in
257-
return .dynamicReplacementArguments(parser.parseDynamicReplacementAttributeArguments())
263+
return (nil, .dynamicReplacementArguments(parser.parseDynamicReplacementAttributeArguments()))
258264
}
259265
case ._documentation:
260266
return parseAttribute(argumentMode: .required) { parser in
261-
return .documentationArguments(parser.parseDocumentationAttributeArguments())
267+
return (nil, .documentationArguments(parser.parseDocumentationAttributeArguments()))
262268
}
263269
case ._effects:
264270
return parseAttribute(argumentMode: .required) { parser in
@@ -268,20 +274,20 @@ extension Parser {
268274
while !parser.at(.rightParen, .endOfFile) {
269275
tokens.append(parser.consumeAnyToken())
270276
}
271-
return .effectsArguments(RawEffectsAttributeArgumentListSyntax(elements: tokens, arena: parser.arena))
277+
return (nil, .effectsArguments(RawEffectsAttributeArgumentListSyntax(elements: tokens, arena: parser.arena)))
272278
}
273279
case ._implements:
274280
return parseAttribute(argumentMode: .required) { parser in
275-
return .implementsArguments(parser.parseImplementsAttributeArguments())
281+
return (nil, .implementsArguments(parser.parseImplementsAttributeArguments()))
276282
}
277283
case ._originallyDefinedIn:
278284
return parseAttribute(argumentMode: .required) { parser in
279-
return .originallyDefinedInArguments(parser.parseOriginallyDefinedInAttributeArguments())
285+
return (nil, .originallyDefinedInArguments(parser.parseOriginallyDefinedInAttributeArguments()))
280286
}
281287
case .attached, .freestanding:
282288
return parseAttribute(argumentMode: .customAttribute) { parser in
283289
let arguments = parser.parseMacroRoleArguments()
284-
return .argumentList(RawLabeledExprListSyntax(elements: arguments, arena: parser.arena))
290+
return (nil, .argumentList(RawLabeledExprListSyntax(elements: arguments, arena: parser.arena)))
285291
}
286292
case .rethrows:
287293
let (unexpectedBeforeAtSign, atSign) = self.expect(.atSign)
@@ -308,7 +314,7 @@ extension Parser {
308314
pattern: .none,
309315
allowTrailingComma: true
310316
)
311-
return .argumentList(RawLabeledExprListSyntax(elements: arguments, arena: parser.arena))
317+
return (nil, .argumentList(RawLabeledExprListSyntax(elements: arguments, arena: parser.arena)))
312318
}
313319
}
314320
}
@@ -786,9 +792,11 @@ extension Parser {
786792
/// Parse the arguments inside an `@abi(...)` attribute.
787793
///
788794
/// - Parameter missingLParen: `true` if the opening paren for the argument list was missing.
789-
mutating func parseABIAttributeArguments(missingLParen: Bool = false) -> RawABIAttributeArgumentsSyntax {
790-
func makeMissingProviderArguments(unexpectedBefore: [RawSyntax]) -> RawABIAttributeArgumentsSyntax {
791-
return RawABIAttributeArgumentsSyntax(
795+
mutating func parseABIAttributeArguments(
796+
missingLParen: Bool = false
797+
) -> (RawUnexpectedNodesSyntax?, RawAttributeSyntax.Arguments) {
798+
func makeMissingProviderArguments(unexpectedBefore: [RawSyntax]) -> RawAttributeSyntax.Arguments {
799+
let args = RawABIAttributeArgumentsSyntax(
792800
provider: .missing(
793801
RawMissingDeclSyntax(
794802
unexpectedBefore.isEmpty ? nil : RawUnexpectedNodesSyntax(elements: unexpectedBefore, arena: self.arena),
@@ -800,6 +808,7 @@ extension Parser {
800808
),
801809
arena: self.arena
802810
)
811+
return .abiArguments(args)
803812
}
804813

805814
// Consider the three kinds of mistakes we might see here:
@@ -815,16 +824,23 @@ extension Parser {
815824
// In lieu of that, we judge that recovering gracefully from #3 is more important than #2 and therefore do not even
816825
// attempt to parse the argument unless we've seen a left paren.
817826
guard !missingLParen && !self.at(.rightParen) else {
818-
return makeMissingProviderArguments(unexpectedBefore: [])
827+
return (nil, makeMissingProviderArguments(unexpectedBefore: []))
819828
}
820829

821830
let decl = parseDeclaration(in: .argumentList)
822831

832+
guard experimentalFeatures.contains(.abiAttribute) else {
833+
return (
834+
RawUnexpectedNodesSyntax([decl], arena: self.arena),
835+
.argumentList(RawLabeledExprListSyntax(elements: [], arena: self.arena))
836+
)
837+
}
838+
823839
guard let provider = RawABIAttributeArgumentsSyntax.Provider(decl) else {
824-
return makeMissingProviderArguments(unexpectedBefore: [decl.raw])
840+
return (nil, makeMissingProviderArguments(unexpectedBefore: [decl.raw]))
825841
}
826842

827-
return RawABIAttributeArgumentsSyntax(provider: provider, arena: self.arena)
843+
return (nil, .abiArguments(RawABIAttributeArgumentsSyntax(provider: provider, arena: self.arena)))
828844
}
829845
}
830846

Sources/SwiftParser/Types.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,15 +1291,15 @@ extension Parser {
12911291

12921292
case .isolated:
12931293
return parseAttribute(argumentMode: .required) { parser in
1294-
return .argumentList(parser.parseIsolatedAttributeArguments())
1294+
return (nil, .argumentList(parser.parseIsolatedAttributeArguments()))
12951295
}
12961296
case .convention, ._opaqueReturnTypeOf, nil: // Custom attribute
12971297
return parseAttribute(argumentMode: .customAttribute) { parser in
12981298
let arguments = parser.parseArgumentListElements(
12991299
pattern: .none,
13001300
allowTrailingComma: true
13011301
)
1302-
return .argumentList(RawLabeledExprListSyntax(elements: arguments, arena: parser.arena))
1302+
return (nil, .argumentList(RawLabeledExprListSyntax(elements: arguments, arena: parser.arena)))
13031303
}
13041304

13051305
}

Tests/SwiftParserTest/AttributeTests.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,49 @@ final class AttributeTests: ParserTestCase {
12831283
)
12841284
}
12851285

1286+
func testABIAttributeWithoutFeature() throws {
1287+
assertParse(
1288+
"""
1289+
@abi(1️⃣func fn() -> Int2️⃣)
1290+
func fn1() -> Int { }
1291+
""",
1292+
substructure: FunctionDeclSyntax(
1293+
attributes: [
1294+
.attribute(
1295+
AttributeSyntax(
1296+
attributeName: TypeSyntax("abi"),
1297+
leftParen: .leftParenToken(),
1298+
[Syntax(try FunctionDeclSyntax("func fn() -> Int"))],
1299+
arguments: .argumentList([]),
1300+
rightParen: .rightParenToken()
1301+
)
1302+
)
1303+
],
1304+
name: "fn1",
1305+
signature: FunctionSignatureSyntax(
1306+
parameterClause: FunctionParameterClauseSyntax {},
1307+
returnClause: ReturnClauseSyntax(type: TypeSyntax("Int"))
1308+
)
1309+
) {},
1310+
diagnostics: [
1311+
DiagnosticSpec(
1312+
locationMarker: "1️⃣",
1313+
message: "unexpected code 'func fn() -> Int' in attribute"
1314+
),
1315+
DiagnosticSpec(
1316+
locationMarker: "2️⃣",
1317+
message: "expected argument for '@abi' attribute",
1318+
fixIts: ["insert attribute argument"]
1319+
),
1320+
],
1321+
fixedSource: """
1322+
@abi(func fn() -> Int)
1323+
func fn1() -> Int { }
1324+
""",
1325+
experimentalFeatures: []
1326+
)
1327+
}
1328+
12861329
func testSpaceBetweenAtAndAttribute() {
12871330
assertParse(
12881331
"@1️⃣ custom func foo() {}",

0 commit comments

Comments
 (0)