diff --git a/CodeGeneration/Sources/SyntaxSupport/Child.swift b/CodeGeneration/Sources/SyntaxSupport/Child.swift index 683c0441953..ce631b5950e 100644 --- a/CodeGeneration/Sources/SyntaxSupport/Child.swift +++ b/CodeGeneration/Sources/SyntaxSupport/Child.swift @@ -47,7 +47,8 @@ public enum ChildKind { kind: SyntaxNodeKind, collectionElementName: String? = nil, defaultsToEmpty: Bool = false, - deprecatedCollectionElementName: String? = nil + deprecatedCollectionElementName: String? = nil, + generateDeprecatedAddFunction: Bool = true ) /// The child is a token that matches one of the given `choices`. /// If `requiresLeadingSpace` or `requiresTrailingSpace` is not `nil`, it @@ -132,7 +133,7 @@ public class Child: NodeChoiceConvertible { return kind case .nodeChoices: return .syntax - case .collection(kind: let kind, _, _, _): + case .collection(kind: let kind, _, _, _, _): return kind case .token: return .token @@ -268,7 +269,7 @@ public class Child: NodeChoiceConvertible { /// Whether this child has syntax kind `UnexpectedNodes`. public var isUnexpectedNodes: Bool { switch kind { - case .collection(kind: .unexpectedNodes, _, _, _): + case .collection(kind: .unexpectedNodes, _, _, _, _): return true default: return false @@ -283,7 +284,7 @@ public class Child: NodeChoiceConvertible { return choices.isEmpty case .node(let kind): return kind.isBase - case .collection(kind: let kind, _, _, _): + case .collection(kind: let kind, _, _, _, _): return kind.isBase case .token: return false diff --git a/CodeGeneration/Sources/SyntaxSupport/GrammarGenerator.swift b/CodeGeneration/Sources/SyntaxSupport/GrammarGenerator.swift index ae84735dbf9..4d28dff2564 100644 --- a/CodeGeneration/Sources/SyntaxSupport/GrammarGenerator.swift +++ b/CodeGeneration/Sources/SyntaxSupport/GrammarGenerator.swift @@ -41,7 +41,7 @@ struct GrammarGenerator { case .nodeChoices(let choices, _): let choicesDescriptions = choices.map { grammar(for: $0) } return "(\(choicesDescriptions.joined(separator: " | ")))\(optionality)" - case .collection(kind: let kind, _, _, _): + case .collection(kind: let kind, _, _, _, _): return "\(kind.doccLink)\(optionality)" case .token(let choices, _, _): if choices.count == 1 { diff --git a/CodeGeneration/Sources/SyntaxSupport/Node.swift b/CodeGeneration/Sources/SyntaxSupport/Node.swift index 913473c1c85..f1341f7e355 100644 --- a/CodeGeneration/Sources/SyntaxSupport/Node.swift +++ b/CodeGeneration/Sources/SyntaxSupport/Node.swift @@ -391,7 +391,7 @@ fileprivate extension Child { return [kind] case .nodeChoices(let choices, _): return choices.flatMap(\.kinds) - case .collection(kind: let kind, _, _, _): + case .collection(kind: let kind, _, _, _, _): return [kind] case .token: return [.token] diff --git a/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift b/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift index ab81dde2a2d..12dd1d385cc 100644 --- a/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift @@ -57,6 +57,17 @@ public let TYPE_NODES: [Node] = [ kind: .collection(kind: .attributeList, collectionElementName: "Attribute", defaultsToEmpty: true), documentation: "A list of attributes that can be attached to the type, such as `@escaping`." ), + Child( + name: "lateSpecifiers", + kind: .collection( + kind: .typeSpecifierList, + collectionElementName: "Specifier", + defaultsToEmpty: true, + generateDeprecatedAddFunction: false + ), + documentation: + "A list of specifiers that can be attached to the type after the attributes, such as 'nonisolated'." + ), Child( name: "baseType", kind: .node(kind: .type), diff --git a/CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift b/CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift index 9ad78761e04..6e4fb79941a 100644 --- a/CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift +++ b/CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift @@ -33,7 +33,7 @@ extension Child { buildableKind = .node(kind: kind) case .nodeChoices: buildableKind = .node(kind: .syntax) - case .collection(kind: let kind, _, _, _): + case .collection(kind: let kind, _, _, _, _): buildableKind = .node(kind: kind) case .token: buildableKind = .token(self.tokenKind!) @@ -65,7 +65,7 @@ extension Child { return ExprSyntax("nil") } } - if case .collection(_, _, defaultsToEmpty: true, _) = kind { + if case .collection(_, _, defaultsToEmpty: true, _, _) = kind { return ExprSyntax("[]") } guard let token = token, isToken else { diff --git a/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/RenamedChildrenCompatibilityFile.swift b/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/RenamedChildrenCompatibilityFile.swift index aea1375e54c..77f4548117b 100644 --- a/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/RenamedChildrenCompatibilityFile.swift +++ b/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/RenamedChildrenCompatibilityFile.swift @@ -85,7 +85,8 @@ func makeCompatibilityAddMethod(for child: Child) -> DeclSyntax? { kind: _, collectionElementName: let collectionElementName?, defaultsToEmpty: _, - deprecatedCollectionElementName: let deprecatedCollectionElementName? + deprecatedCollectionElementName: let deprecatedCollectionElementName?, + generateDeprecatedAddFunction: _ ) = child.kind { let childEltType = childNode.collectionElementType.syntaxBaseName diff --git a/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/SyntaxNodesFile.swift b/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/SyntaxNodesFile.swift index 6c5bd8bad67..3cfc96d85fd 100644 --- a/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/SyntaxNodesFile.swift +++ b/CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/SyntaxNodesFile.swift @@ -176,7 +176,8 @@ func syntaxNode(nodesStartingWith: [Character]) -> SourceFileSyntax { // If needed, this could be added in the future, but for now withUnexpected should be sufficient. if let childNode = SYNTAX_NODE_MAP[child.syntaxNodeKind]?.collectionNode, !child.isUnexpectedNodes, - case .collection(_, collectionElementName: let childElt?, _, _) = child.kind + case .collection(_, collectionElementName: let childElt?, _, _, generateDeprecatedAddFunction: true) = child + .kind { let childEltType = childNode.collectionElementType.syntaxBaseName diff --git a/CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift b/CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift index 164b1505895..e1b9a73df15 100644 --- a/CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift +++ b/CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift @@ -55,13 +55,13 @@ fileprivate extension ChildKind { return kind == otherKind case (.nodeChoices(let choices, _), .nodeChoices(let otherChoices, _)): return choices.count == otherChoices.count && zip(choices, otherChoices).allSatisfy { $0.hasSameType(as: $1) } - case (.collection(kind: let kind, _, _, _), .collection(kind: let otherKind, _, _, _)): + case (.collection(kind: let kind, _, _, _, _), .collection(kind: let otherKind, _, _, _, _)): return kind == otherKind case (.token(let choices, _, _), .token(let otherChoices, _, _)): return choices == otherChoices - case (.node(let kind), .collection(kind: let otherKind, _, _, _)): + case (.node(let kind), .collection(kind: let otherKind, _, _, _, _)): return kind == otherKind - case (.collection(kind: let kind, _, _, _), .node(let otherKind)): + case (.collection(kind: let kind, _, _, _, _), .node(let otherKind)): return kind == otherKind default: return false diff --git a/Sources/SwiftParser/Types.swift b/Sources/SwiftParser/Types.swift index 67ad666c5df..deb3ef9a617 100644 --- a/Sources/SwiftParser/Types.swift +++ b/Sources/SwiftParser/Types.swift @@ -100,6 +100,7 @@ extension Parser { RawAttributedTypeSyntax( specifiers: specifiersAndAttributes.specifiers, attributes: specifiersAndAttributes.attributes, + lateSpecifiers: specifiersAndAttributes.lateSpecifiers, baseType: base, arena: self.arena ) @@ -1221,7 +1222,8 @@ extension Parser { misplacedSpecifiers: [RawTokenSyntax] = [] ) -> ( specifiers: RawTypeSpecifierListSyntax, - attributes: RawAttributeListSyntax + attributes: RawAttributeListSyntax, + lateSpecifiers: RawTypeSpecifierListSyntax )? { var specifiers: [RawTypeSpecifierListSyntax.Element] = [] SPECIFIER_PARSING: while canHaveParameterSpecifier { @@ -1260,7 +1262,15 @@ extension Parser { attributes = nil } - guard !specifiers.isEmpty || attributes != nil else { + // Only handle `nonisolated` as a late specifier. + var lateSpecifiers: [RawTypeSpecifierListSyntax.Element] = [] + if self.at(.keyword(.nonisolated)) && !(self.peek(isAt: .leftParen) && self.peek().isAtStartOfLine) + && canHaveParameterSpecifier + { + lateSpecifiers.append(parseNonisolatedTypeSpecifier()) + } + + guard !specifiers.isEmpty || attributes != nil || !lateSpecifiers.isEmpty else { // No specifiers or attributes on this type return nil } @@ -1271,9 +1281,17 @@ extension Parser { specifierList = RawTypeSpecifierListSyntax(elements: specifiers, arena: arena) } + let lateSpecifierList: RawTypeSpecifierListSyntax + if lateSpecifiers.isEmpty { + lateSpecifierList = self.emptyCollection(RawTypeSpecifierListSyntax.self) + } else { + lateSpecifierList = RawTypeSpecifierListSyntax(elements: lateSpecifiers, arena: arena) + } + return ( specifierList, - attributes ?? self.emptyCollection(RawAttributeListSyntax.self) + attributes ?? self.emptyCollection(RawAttributeListSyntax.self), + lateSpecifierList ) } diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index d64489aa01b..0bcd20aee62 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -286,8 +286,12 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "unexpectedBetweenSpecifiersAndAttributes" case \AttributedTypeSyntax.attributes: return "attributes" - case \AttributedTypeSyntax.unexpectedBetweenAttributesAndBaseType: - return "unexpectedBetweenAttributesAndBaseType" + case \AttributedTypeSyntax.unexpectedBetweenAttributesAndLateSpecifiers: + return "unexpectedBetweenAttributesAndLateSpecifiers" + case \AttributedTypeSyntax.lateSpecifiers: + return "lateSpecifiers" + case \AttributedTypeSyntax.unexpectedBetweenLateSpecifiersAndBaseType: + return "unexpectedBetweenLateSpecifiersAndBaseType" case \AttributedTypeSyntax.baseType: return "baseType" case \AttributedTypeSyntax.unexpectedAfterBaseType: diff --git a/Sources/SwiftSyntax/generated/SyntaxCollections.swift b/Sources/SwiftSyntax/generated/SyntaxCollections.swift index a34717855b7..529785471e9 100644 --- a/Sources/SwiftSyntax/generated/SyntaxCollections.swift +++ b/Sources/SwiftSyntax/generated/SyntaxCollections.swift @@ -1918,6 +1918,7 @@ public struct TupleTypeElementListSyntax: SyntaxCollection, SyntaxHashable { /// ### Contained in /// /// - ``AttributedTypeSyntax``.``AttributedTypeSyntax/specifiers`` +/// - ``AttributedTypeSyntax``.``AttributedTypeSyntax/lateSpecifiers`` public struct TypeSpecifierListSyntax: SyntaxCollection, SyntaxHashable { public enum Element: SyntaxChildChoices, SyntaxHashable { /// A specifier that can be attached to a type to eg. mark a parameter as `inout` or `consuming` diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesAB.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesAB.swift index 1dc419a7df4..a04d4c66d1a 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesAB.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesAB.swift @@ -1827,21 +1827,25 @@ public struct RawAttributedTypeSyntax: RawTypeSyntaxNodeProtocol { specifiers: RawTypeSpecifierListSyntax, _ unexpectedBetweenSpecifiersAndAttributes: RawUnexpectedNodesSyntax? = nil, attributes: RawAttributeListSyntax, - _ unexpectedBetweenAttributesAndBaseType: RawUnexpectedNodesSyntax? = nil, + _ unexpectedBetweenAttributesAndLateSpecifiers: RawUnexpectedNodesSyntax? = nil, + lateSpecifiers: RawTypeSpecifierListSyntax, + _ unexpectedBetweenLateSpecifiersAndBaseType: RawUnexpectedNodesSyntax? = nil, baseType: some RawTypeSyntaxNodeProtocol, _ unexpectedAfterBaseType: RawUnexpectedNodesSyntax? = nil, arena: __shared RawSyntaxArena ) { let raw = RawSyntax.makeLayout( - kind: .attributedType, uninitializedCount: 7, arena: arena) { layout in + kind: .attributedType, uninitializedCount: 9, arena: arena) { layout in layout.initialize(repeating: nil) layout[0] = unexpectedBeforeSpecifiers?.raw layout[1] = specifiers.raw layout[2] = unexpectedBetweenSpecifiersAndAttributes?.raw layout[3] = attributes.raw - layout[4] = unexpectedBetweenAttributesAndBaseType?.raw - layout[5] = baseType.raw - layout[6] = unexpectedAfterBaseType?.raw + layout[4] = unexpectedBetweenAttributesAndLateSpecifiers?.raw + layout[5] = lateSpecifiers.raw + layout[6] = unexpectedBetweenLateSpecifiersAndBaseType?.raw + layout[7] = baseType.raw + layout[8] = unexpectedAfterBaseType?.raw } self.init(unchecked: raw) } @@ -1862,16 +1866,24 @@ public struct RawAttributedTypeSyntax: RawTypeSyntaxNodeProtocol { layoutView.children[3].map(RawAttributeListSyntax.init(raw:))! } - public var unexpectedBetweenAttributesAndBaseType: RawUnexpectedNodesSyntax? { + public var unexpectedBetweenAttributesAndLateSpecifiers: RawUnexpectedNodesSyntax? { layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) } + public var lateSpecifiers: RawTypeSpecifierListSyntax { + layoutView.children[5].map(RawTypeSpecifierListSyntax.init(raw:))! + } + + public var unexpectedBetweenLateSpecifiersAndBaseType: RawUnexpectedNodesSyntax? { + layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + } + public var baseType: RawTypeSyntax { - layoutView.children[5].map(RawTypeSyntax.init(raw:))! + layoutView.children[7].map(RawTypeSyntax.init(raw:))! } public var unexpectedAfterBaseType: RawUnexpectedNodesSyntax? { - layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[8].map(RawUnexpectedNodesSyntax.init(raw:)) } } diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index 7a85c165961..4def2848664 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -422,14 +422,16 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 10, verify(layout[10], as: RawUnexpectedNodesSyntax?.self)) } func validateAttributedTypeSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { - assert(layout.count == 7) + assert(layout.count == 9) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 1, verify(layout[1], as: RawTypeSpecifierListSyntax.self)) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 3, verify(layout[3], as: RawAttributeListSyntax.self)) assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 5, verify(layout[5], as: RawTypeSyntax.self)) + assertNoError(kind, 5, verify(layout[5], as: RawTypeSpecifierListSyntax.self)) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 7, verify(layout[7], as: RawTypeSyntax.self)) + assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self)) } func validateAvailabilityArgumentListSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { for (index, element) in layout.enumerated() { diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift index c36ad53e31d..4e07265bc4a 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift @@ -3789,6 +3789,7 @@ public struct AttributeSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNodePr /// /// - `specifiers`: ``TypeSpecifierListSyntax`` /// - `attributes`: ``AttributeListSyntax`` +/// - `lateSpecifiers`: ``TypeSpecifierListSyntax`` /// - `baseType`: ``TypeSyntax`` public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTypeSyntaxNodeProtocol { public let _syntaxNode: Syntax @@ -3809,6 +3810,7 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp /// - leadingTrivia: Trivia to be prepended to the leading trivia of the node’s first token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. /// - specifiers: A list of specifiers that can be attached to the type, such as `inout`, `isolated`, or `consuming`. /// - attributes: A list of attributes that can be attached to the type, such as `@escaping`. + /// - lateSpecifiers: A list of specifiers that can be attached to the type after the attributes, such as 'nonisolated'. /// - baseType: The type to with the specifiers and attributes are applied. /// - trailingTrivia: Trivia to be appended to the trailing trivia of the node’s last token. If the node is empty, there is no token to attach the trivia to and the parameter is ignored. public init( @@ -3817,7 +3819,9 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp specifiers: TypeSpecifierListSyntax = [], _ unexpectedBetweenSpecifiersAndAttributes: UnexpectedNodesSyntax? = nil, attributes: AttributeListSyntax = [], - _ unexpectedBetweenAttributesAndBaseType: UnexpectedNodesSyntax? = nil, + _ unexpectedBetweenAttributesAndLateSpecifiers: UnexpectedNodesSyntax? = nil, + lateSpecifiers: TypeSpecifierListSyntax = [], + _ unexpectedBetweenLateSpecifiersAndBaseType: UnexpectedNodesSyntax? = nil, baseType: some TypeSyntaxProtocol, _ unexpectedAfterBaseType: UnexpectedNodesSyntax? = nil, trailingTrivia: Trivia? = nil @@ -3829,7 +3833,9 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp specifiers, unexpectedBetweenSpecifiersAndAttributes, attributes, - unexpectedBetweenAttributesAndBaseType, + unexpectedBetweenAttributesAndLateSpecifiers, + lateSpecifiers, + unexpectedBetweenLateSpecifiersAndBaseType, baseType, unexpectedAfterBaseType ))) { (arena, _) in @@ -3838,7 +3844,9 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp specifiers.raw, unexpectedBetweenSpecifiersAndAttributes?.raw, attributes.raw, - unexpectedBetweenAttributesAndBaseType?.raw, + unexpectedBetweenAttributesAndLateSpecifiers?.raw, + lateSpecifiers.raw, + unexpectedBetweenLateSpecifiersAndBaseType?.raw, baseType.raw, unexpectedAfterBaseType?.raw ] @@ -3945,7 +3953,7 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp .cast(AttributedTypeSyntax.self) } - public var unexpectedBetweenAttributesAndBaseType: UnexpectedNodesSyntax? { + public var unexpectedBetweenAttributesAndLateSpecifiers: UnexpectedNodesSyntax? { get { return Syntax(self).child(at: 4)?.cast(UnexpectedNodesSyntax.self) } @@ -3954,17 +3962,17 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp } } - /// The type to with the specifiers and attributes are applied. - public var baseType: TypeSyntax { + /// A list of specifiers that can be attached to the type after the attributes, such as 'nonisolated'. + public var lateSpecifiers: TypeSpecifierListSyntax { get { - return Syntax(self).child(at: 5)!.cast(TypeSyntax.self) + return Syntax(self).child(at: 5)!.cast(TypeSpecifierListSyntax.self) } set(value) { self = Syntax(self).replacingChild(at: 5, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(AttributedTypeSyntax.self) } } - public var unexpectedAfterBaseType: UnexpectedNodesSyntax? { + public var unexpectedBetweenLateSpecifiersAndBaseType: UnexpectedNodesSyntax? { get { return Syntax(self).child(at: 6)?.cast(UnexpectedNodesSyntax.self) } @@ -3973,12 +3981,33 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp } } + /// The type to with the specifiers and attributes are applied. + public var baseType: TypeSyntax { + get { + return Syntax(self).child(at: 7)!.cast(TypeSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 7, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(AttributedTypeSyntax.self) + } + } + + public var unexpectedAfterBaseType: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 8)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 8, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(AttributedTypeSyntax.self) + } + } + public static let structure: SyntaxNodeStructure = .layout([ \Self.unexpectedBeforeSpecifiers, \Self.specifiers, \Self.unexpectedBetweenSpecifiersAndAttributes, \Self.attributes, - \Self.unexpectedBetweenAttributesAndBaseType, + \Self.unexpectedBetweenAttributesAndLateSpecifiers, + \Self.lateSpecifiers, + \Self.unexpectedBetweenLateSpecifiersAndBaseType, \Self.baseType, \Self.unexpectedAfterBaseType ]) diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index c76a7f78459..6a7bac74f68 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -816,6 +816,17 @@ final class DeclarationTests: ParserTestCase { """ ) + assertParse( + """ + extension Int: @preconcurrency nonisolated Q {} + """ + ) + + assertParse( + """ + extension Int: @unsafe nonisolated Q {} + """ + ) } func testParseDynamicReplacement() {