Skip to content

Commit 1856087

Browse files
committed
Parse "late" specifiers for type attributes
The only "late" specifier at the moment is `nonisolated`, used by protocol conformances. Fixes issue #3109.
1 parent 6ecd032 commit 1856087

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

Sources/SwiftParser/Types.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ extension Parser {
100100
RawAttributedTypeSyntax(
101101
specifiers: specifiersAndAttributes.specifiers,
102102
attributes: specifiersAndAttributes.attributes,
103+
lateSpecifiers: specifiersAndAttributes.lateSpecifiers,
103104
baseType: base,
104105
arena: self.arena
105106
)
@@ -1221,7 +1222,8 @@ extension Parser {
12211222
misplacedSpecifiers: [RawTokenSyntax] = []
12221223
) -> (
12231224
specifiers: RawTypeSpecifierListSyntax,
1224-
attributes: RawAttributeListSyntax
1225+
attributes: RawAttributeListSyntax,
1226+
lateSpecifiers: RawTypeSpecifierListSyntax
12251227
)? {
12261228
var specifiers: [RawTypeSpecifierListSyntax.Element] = []
12271229
SPECIFIER_PARSING: while canHaveParameterSpecifier {
@@ -1260,7 +1262,14 @@ extension Parser {
12601262
attributes = nil
12611263
}
12621264

1263-
guard !specifiers.isEmpty || attributes != nil else {
1265+
// Only handle `nonisolated` as a late specifier.
1266+
var lateSpecifiers: [RawTypeSpecifierListSyntax.Element] = []
1267+
if self.at(.keyword(.nonisolated)) &&
1268+
!(self.peek(isAt: .leftParen) && self.peek().isAtStartOfLine) {
1269+
lateSpecifiers.append(parseNonisolatedTypeSpecifier())
1270+
}
1271+
1272+
guard !specifiers.isEmpty || attributes != nil || !lateSpecifiers.isEmpty else {
12641273
// No specifiers or attributes on this type
12651274
return nil
12661275
}
@@ -1271,9 +1280,17 @@ extension Parser {
12711280
specifierList = RawTypeSpecifierListSyntax(elements: specifiers, arena: arena)
12721281
}
12731282

1283+
let lateSpecifierList: RawTypeSpecifierListSyntax
1284+
if lateSpecifiers.isEmpty {
1285+
lateSpecifierList = self.emptyCollection(RawTypeSpecifierListSyntax.self)
1286+
} else {
1287+
lateSpecifierList = RawTypeSpecifierListSyntax(elements: lateSpecifiers, arena: arena)
1288+
}
1289+
12741290
return (
12751291
specifierList,
1276-
attributes ?? self.emptyCollection(RawAttributeListSyntax.self)
1292+
attributes ?? self.emptyCollection(RawAttributeListSyntax.self),
1293+
lateSpecifierList
12771294
)
12781295
}
12791296

Tests/SwiftParserTest/DeclarationTests.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,17 @@ final class DeclarationTests: ParserTestCase {
816816
"""
817817
)
818818

819+
assertParse(
820+
"""
821+
extension Int: @preconcurrency nonisolated Q {}
822+
"""
823+
)
824+
825+
assertParse(
826+
"""
827+
extension Int: @unsafe nonisolated Q {}
828+
"""
829+
)
819830
}
820831

821832
func testParseDynamicReplacement() {

0 commit comments

Comments
 (0)