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..cb3a5f184eb 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 f6ed8a61c82..00016bc72d1 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 2c820290b8b..029b4a3493c 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesAB.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesAB.swift @@ -1822,21 +1822,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) } @@ -1857,16 +1861,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 436e1e9acdc..6bd1c7a4294 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 6baae95f2e3..565c58d8843 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesAB.swift @@ -3757,6 +3757,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 @@ -3777,6 +3778,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( @@ -3785,7 +3787,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 @@ -3797,7 +3801,9 @@ public struct AttributedTypeSyntax: TypeSyntaxProtocol, SyntaxHashable, _LeafTyp specifiers, unexpectedBetweenSpecifiersAndAttributes, attributes, - unexpectedBetweenAttributesAndBaseType, + unexpectedBetweenAttributesAndLateSpecifiers, + lateSpecifiers, + unexpectedBetweenLateSpecifiersAndBaseType, baseType, unexpectedAfterBaseType ))) { (arena, _) in @@ -3806,7 +3812,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 ] @@ -3913,7 +3921,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) } @@ -3922,17 +3930,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) } @@ -3941,12 +3949,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 3f5367df4f0..19b0e428dd3 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -807,6 +807,17 @@ final class DeclarationTests: ParserTestCase { """ ) + assertParse( + """ + extension Int: @preconcurrency nonisolated Q {} + """ + ) + + assertParse( + """ + extension Int: @unsafe nonisolated Q {} + """ + ) } func testParseDynamicReplacement() {