diff --git a/CodeGeneration/Sources/SyntaxSupport/AttributeKinds.swift b/CodeGeneration/Sources/SyntaxSupport/AttributeKinds.swift index 6381dae719e..71e71618759 100644 --- a/CodeGeneration/Sources/SyntaxSupport/AttributeKinds.swift +++ b/CodeGeneration/Sources/SyntaxSupport/AttributeKinds.swift @@ -676,10 +676,57 @@ public let DECL_ATTR_KINDS: [Attribute] = [ /// /// If you're adding a new kind of attribute that is spelled with a leading /// '@' symbol, add an entry to the `DECL_ATTR_KINDS` array instead. -public let DECL_MODIFIER_KINDS: [Attribute] = [ - // These are not really attributes or modifiers in the C++ AST and they are - // serialized directly into the ASTs they are attached to rather than using - // the generic attribute serialization infrastructure. + +// These are not really attributes or modifiers in the C++ AST and they are +// serialized directly into the ASTs they are attached to rather than using +// the generic attribute serialization infrastructure. +public let DECL_MODIFIER_KINDS: [Attribute] = CONTEXTUAL_DECL_MODIFIER_KINDS + NONCONTEXTUAL_DECL_MODIFIER_KINDS + +// Modifiers that not exclusively used for declarations +public let CONTEXTUAL_DECL_MODIFIER_KINDS: [Attribute] = [ + ContextualDeclAttribute( + name: "weak", + className: "ReferenceOwnership" + ), + ContextualDeclAttributeAlias( + name: "unowned", + className: "ReferenceOwnership", + swiftName: "unowned" + ), + SimpleDeclAttribute( + name: "rethrows", + className: "Rethrows", + swiftName: "`rethrows`" + ), + ContextualSimpleDeclAttribute( + name: "isolated", + className: "Isolated" + ), + ContextualSimpleDeclAttribute( + name: "async", + className: "Async" + ), + SimpleDeclAttribute( + name: "reasync", + className: "Reasync", + swiftName: "reasync" + ), + ContextualSimpleDeclAttribute( + name: "consuming", + className: "Consuming" + ), + ContextualSimpleDeclAttribute( + name: "borrowing", + className: "Borrowing" + ), + ContextualSimpleDeclAttribute( + name: "_const", + className: "CompileTimeConst" + ), +] + +// Modifiers that exclusively used for declarations +public let NONCONTEXTUAL_DECL_MODIFIER_KINDS: [Attribute] = [ BuiltinDeclModifier( name: "static", swiftName: "`static`" @@ -775,37 +822,10 @@ public let DECL_MODIFIER_KINDS: [Attribute] = [ className: "SetterAccess", swiftName: "__setter_access" ), - ContextualDeclAttribute( - name: "weak", - className: "ReferenceOwnership" - ), - ContextualDeclAttributeAlias( - name: "unowned", - className: "ReferenceOwnership", - swiftName: "unowned" - ), - SimpleDeclAttribute( - name: "rethrows", - className: "Rethrows", - swiftName: "`rethrows`" - ), ContextualSimpleDeclAttribute( name: "indirect", className: "Indirect" ), - ContextualSimpleDeclAttribute( - name: "isolated", - className: "Isolated" - ), - ContextualSimpleDeclAttribute( - name: "async", - className: "Async" - ), - SimpleDeclAttribute( - name: "reasync", - className: "Reasync", - swiftName: "reasync" - ), ContextualSimpleDeclAttribute( name: "nonisolated", className: "Nonisolated" @@ -814,22 +834,10 @@ public let DECL_MODIFIER_KINDS: [Attribute] = [ name: "distributed", className: "DistributedActor" ), - ContextualSimpleDeclAttribute( - name: "_const", - className: "CompileTimeConst" - ), ContextualSimpleDeclAttribute( name: "_local", className: "KnownToBeLocal" ), - ContextualSimpleDeclAttribute( - name: "consuming", - className: "Consuming" - ), - ContextualSimpleDeclAttribute( - name: "borrowing", - className: "Borrowing" - ), ] public let DEPRECATED_MODIFIER_KINDS: [Attribute] = [ diff --git a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift index 683f192b21c..c455c4b9c6b 100644 --- a/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/DeclNodes.swift @@ -1422,25 +1422,14 @@ public let DECL_NODES: [Node] = [ nameForDiagnostics: "operator declaration", documentation: "A Swift `operator` declaration.", traits: [ - "IdentifiedDecl", - "WithAttributes", - "WithModifiers", + "IdentifiedDecl" ], children: [ Child( - name: "Attributes", - kind: .collection(kind: .attributeList, collectionElementName: "Attribute"), - nameForDiagnostics: "attributes", - documentation: "The attributes applied to the 'operator' declaration.", - isOptional: true - ), - Child( - name: "Modifiers", - kind: .collection(kind: .modifierList, collectionElementName: "Modifier"), - nameForDiagnostics: "modifiers", - documentation: "The declaration modifiers applied to the 'operator' declaration.", - isOptional: true, - classification: "Attribute" + name: "Fixity", + kind: .token(choices: [.keyword(text: "prefix"), .keyword(text: "postfix"), .keyword(text: "infix")]), + nameForDiagnostics: "fixity", + documentation: "The fixity applied to the 'operator' declaration." ), Child( name: "OperatorKeyword", diff --git a/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/DeclarationModifierFile.swift b/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/DeclarationModifierFile.swift index 00eba6aa7d4..007bb8cbcb7 100644 --- a/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/DeclarationModifierFile.swift +++ b/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/DeclarationModifierFile.swift @@ -38,13 +38,14 @@ let declarationModifierFile = SourceFileSyntax(leadingTrivia: copyrightHeader) { try VariableDeclSyntax("var spec: TokenSpec") { try SwitchExprSyntax("switch self") { - for attribute in DECL_MODIFIER_KINDS { + for attribute in NONCONTEXTUAL_DECL_MODIFIER_KINDS { + SwitchCaseSyntax("case .\(raw: attribute.swiftName):") { + StmtSyntax("return .keyword(.\(raw: attribute.swiftName))") + } + } + for attribute in CONTEXTUAL_DECL_MODIFIER_KINDS { SwitchCaseSyntax("case .\(raw: attribute.swiftName):") { - if attribute.swiftName.hasSuffix("Keyword") { - StmtSyntax("return .\(raw: attribute.swiftName)") - } else { - StmtSyntax("return .keyword(.\(raw: attribute.swiftName))") - } + StmtSyntax("return TokenSpec(.\(raw: attribute.swiftName), recoveryPrecedence: .declKeyword)") } } } diff --git a/Sources/SwiftIDEUtils/generated/SyntaxClassification.swift b/Sources/SwiftIDEUtils/generated/SyntaxClassification.swift index 12db3b80da2..b80208fcabc 100644 --- a/Sources/SwiftIDEUtils/generated/SyntaxClassification.swift +++ b/Sources/SwiftIDEUtils/generated/SyntaxClassification.swift @@ -87,8 +87,6 @@ extension SyntaxClassification { return (.buildConfigId, false) case \MemberTypeIdentifierSyntax.name: return (.typeIdentifier, false) - case \OperatorDeclSyntax.modifiers: - return (.attribute, false) case \OperatorDeclSyntax.identifier: return (.operatorIdentifier, false) case \PrecedenceGroupAssociativitySyntax.associativityKeyword: diff --git a/Sources/SwiftOperators/OperatorTable+Semantics.swift b/Sources/SwiftOperators/OperatorTable+Semantics.swift index 58574388492..d990e472acc 100644 --- a/Sources/SwiftOperators/OperatorTable+Semantics.swift +++ b/Sources/SwiftOperators/OperatorTable+Semantics.swift @@ -68,11 +68,7 @@ extension Operator { /// TODO: This ignores all semantic errors. init(from syntax: OperatorDeclSyntax) { self.syntax = syntax - - kind = - syntax.modifiers?.compactMap { - OperatorKind(rawValue: $0.name.text) - }.first ?? .infix + kind = OperatorKind(rawValue: syntax.fixity.text) ?? .infix name = syntax.identifier.text diff --git a/Sources/SwiftOperators/SyntaxSynthesis.swift b/Sources/SwiftOperators/SyntaxSynthesis.swift index dc83e453ac5..f7eb9c24b8e 100644 --- a/Sources/SwiftOperators/SyntaxSynthesis.swift +++ b/Sources/SwiftOperators/SyntaxSynthesis.swift @@ -26,9 +26,7 @@ extension Operator { /// Synthesize a syntactic representation of this operator based on its /// semantic definition. public func synthesizedSyntax() -> OperatorDeclSyntax { - let modifiers = ModifierListSyntax( - [DeclModifierSyntax(name: .keyword(kind.keyword))] - ) + let fixity = TokenSyntax.keyword(kind.keyword) let operatorKeyword = TokenSyntax.keyword(.operator, leadingTrivia: .space) let identifierSyntax = TokenSyntax.binaryOperator(name, leadingTrivia: .space) @@ -41,7 +39,7 @@ extension Operator { } return OperatorDeclSyntax( - modifiers: modifiers, + fixity: fixity, operatorKeyword: operatorKeyword, identifier: identifierSyntax, operatorPrecedenceAndTypes: precedenceGroupSyntax diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 2ec0b8f5658..a7e7cb6bc14 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -89,15 +89,15 @@ extension TokenConsumer { return attrLookahead.consumeIfConfigOfAttributes() } - let declStartKeyword: DeclarationStart? + let declStartKeyword: DeclarationKeyword? if allowRecovery { declStartKeyword = subparser.canRecoverTo( - anyIn: DeclarationStart.self, + anyIn: DeclarationKeyword.self, overrideRecoveryPrecedence: isAtTopLevel ? nil : .closingBrace )?.0 } else { - declStartKeyword = subparser.at(anyIn: DeclarationStart.self)?.0 + declStartKeyword = subparser.at(anyIn: DeclarationKeyword.self)?.0 } switch declStartKeyword { case .actor: @@ -233,7 +233,7 @@ extension Parser { // while recoverying to the declaration start. let recoveryPrecedence = inMemberDeclList ? TokenPrecedence.closingBrace : nil - switch self.canRecoverTo(anyIn: DeclarationStart.self, overrideRecoveryPrecedence: recoveryPrecedence) { + switch self.canRecoverTo(anyIn: DeclarationKeyword.self, overrideRecoveryPrecedence: recoveryPrecedence) { case (.import, let handle)?: return RawDeclSyntax(self.parseImportDeclaration(attrs, handle)) case (.class, let handle)?: @@ -1694,11 +1694,69 @@ extension Parser { /// postfix-operator-declaration → 'postfix' 'operator' operator /// infix-operator-declaration → 'infix' 'operator' operator infix-operator-group? /// infix-operator-group → ':' precedence-group-name + + struct OperatorDeclIntroducer { + var unexpectedBeforeFixity: RawUnexpectedNodesSyntax? + var fixity: RawTokenSyntax + var unexpectedBeforeOperatorKeyword: RawUnexpectedNodesSyntax? + var operatorKeyword: RawTokenSyntax + } + + mutating func parseOperatorDeclIntroducer(_ attrs: DeclAttributes, _ handle: RecoveryConsumptionHandle) -> OperatorDeclIntroducer { + func isFixity(_ modifier: RawDeclModifierSyntax) -> Bool { + switch modifier.name { + case .keyword(.prefix), + .keyword(.infix), + .keyword(.postfix): + return true + default: + return false + } + } + + var unexpectedBeforeFixity = RawUnexpectedNodesSyntax(attrs.attributes?.elements ?? [], arena: self.arena) + + var fixity: RawTokenSyntax? + var unexpectedAfterFixity: RawUnexpectedNodesSyntax? + + if let modifiers = attrs.modifiers?.elements { + if let firstFixityIndex = modifiers.firstIndex(where: { isFixity($0) }) { + let fixityModifier = modifiers[firstFixityIndex] + fixity = fixityModifier.name + + unexpectedBeforeFixity = RawUnexpectedNodesSyntax(combining: unexpectedBeforeFixity, RawUnexpectedNodesSyntax(Array(modifiers[0.. RawOperatorDeclSyntax { - let (unexpectedBeforeOperatorKeyword, operatorKeyword) = self.eat(handle) + let introducer = parseOperatorDeclIntroducer(attrs, handle) + let unexpectedBeforeName: RawUnexpectedNodesSyntax? let name: RawTokenSyntax switch self.canRecoverTo(anyIn: OperatorLike.self) { @@ -1775,10 +1833,10 @@ extension Parser { unexpectedAtEnd = nil } return RawOperatorDeclSyntax( - attributes: attrs.attributes, - modifiers: attrs.modifiers, - unexpectedBeforeOperatorKeyword, - operatorKeyword: operatorKeyword, + introducer.unexpectedBeforeFixity, + fixity: introducer.fixity, + introducer.unexpectedBeforeOperatorKeyword, + operatorKeyword: introducer.operatorKeyword, unexpectedBeforeName, identifier: name, RawUnexpectedNodesSyntax(identifiersAfterOperatorName, arena: self.arena), diff --git a/Sources/SwiftParser/Modifiers.swift b/Sources/SwiftParser/Modifiers.swift index 9c1a5592dfa..0e82726d64e 100644 --- a/Sources/SwiftParser/Modifiers.swift +++ b/Sources/SwiftParser/Modifiers.swift @@ -17,36 +17,38 @@ extension Parser { var elements = [RawDeclModifierSyntax]() var modifierLoopCondition = LoopProgressCondition() MODIFIER_LOOP: while modifierLoopCondition.evaluate(currentToken) { - switch self.at(anyIn: DeclarationModifier.self) { - case (.private, _)?, - (.fileprivate, _)?, - (.internal, _)?, - (.public, _)?: + switch self.canRecoverTo(anyIn: DeclarationStart.self) { + case (.declarationModifier(.private), _)?, + (.declarationModifier(.fileprivate), _)?, + (.declarationModifier(.internal), _)?, + (.declarationModifier(.public), _)?: elements.append(parseAccessLevelModifier()) - case (.package, _)?: + case (.declarationModifier(.package), _)?: elements.append(parsePackageAccessLevelModifier()) - case (.open, _)?: + case (.declarationModifier(.open), _)?: elements.append(parseOpenAccessLevelModifier()) - case (.static, let handle)?: - let staticKeyword = self.eat(handle) + case (.declarationModifier(.static), let handle)?: + let (unexpectedBeforeKeyword, staticKeyword) = self.eat(handle) elements.append( RawDeclModifierSyntax( + unexpectedBeforeKeyword, name: staticKeyword, detail: nil, arena: self.arena ) ) - case (.class, let handle)?: + case (.declarationModifier(.class), let handle)?: var lookahead = self.lookahead() - lookahead.eat(.keyword(.class)) + lookahead.consume(to: .keyword(.class)) // When followed by an 'override' or CC token inside a class, // treat 'class' as a modifier in the case of a following CC // token, we cannot be sure there is no intention to override // or witness something static. if lookahead.atStartOfDeclaration() || lookahead.at(.keyword(.override)) { - let classKeyword = self.eat(handle) + let (unexpectedBeforeKeyword, classKeyword) = self.eat(handle) elements.append( RawDeclModifierSyntax( + unexpectedBeforeKeyword, name: classKeyword, detail: nil, arena: self.arena @@ -56,38 +58,38 @@ extension Parser { } else { break MODIFIER_LOOP } - case (.unowned, _)?: - elements.append(self.parseUnownedModifier()) - case (.final, let handle)?, - (.required, let handle)?, - (.optional, let handle)?, - (.lazy, let handle)?, - (.dynamic, let handle)?, - (.infix, let handle)?, - (.prefix, let handle)?, - (.postfix, let handle)?, - (.__consuming, let handle)?, - (.borrowing, let handle)?, - (.consuming, let handle)?, - (.mutating, let handle)?, - (.nonmutating, let handle)?, - (.convenience, let handle)?, - (.override, let handle)?, - (.weak, let handle)?, - (.indirect, let handle)?, - (.isolated, let handle)?, - (.async, let handle)?, - (.nonisolated, let handle)?, - (.distributed, let handle)?, - (._const, let handle)?, - (._local, let handle)?, - (.__setter_access, let handle)?, - (.reasync, let handle)?: - let keyword = self.eat(handle) - elements.append(RawDeclModifierSyntax(name: keyword, detail: nil, arena: self.arena)) - case (.rethrows, _)?: + case (.declarationModifier(.unowned), let handle)?: + elements.append(self.parseUnownedModifier(handle)) + case (.declarationModifier(.final), let handle)?, + (.declarationModifier(.required), let handle)?, + (.declarationModifier(.optional), let handle)?, + (.declarationModifier(.lazy), let handle)?, + (.declarationModifier(.dynamic), let handle)?, + (.declarationModifier(.infix), let handle)?, + (.declarationModifier(.prefix), let handle)?, + (.declarationModifier(.postfix), let handle)?, + (.declarationModifier(.__consuming), let handle)?, + (.declarationModifier(.borrowing), let handle)?, + (.declarationModifier(.consuming), let handle)?, + (.declarationModifier(.mutating), let handle)?, + (.declarationModifier(.nonmutating), let handle)?, + (.declarationModifier(.convenience), let handle)?, + (.declarationModifier(.override), let handle)?, + (.declarationModifier(.weak), let handle)?, + (.declarationModifier(.indirect), let handle)?, + (.declarationModifier(.isolated), let handle)?, + (.declarationModifier(.async), let handle)?, + (.declarationModifier(.nonisolated), let handle)?, + (.declarationModifier(.distributed), let handle)?, + (.declarationModifier(._const), let handle)?, + (.declarationModifier(._local), let handle)?, + (.declarationModifier(.__setter_access), let handle)?, + (.declarationModifier(.reasync), let handle)?: + let (unexpectedBeforeKeyword, keyword) = self.eat(handle) + elements.append(RawDeclModifierSyntax(unexpectedBeforeKeyword, name: keyword, detail: nil, arena: self.arena)) + case (.declarationModifier(.rethrows), _)?: fallthrough - case nil: + default: break MODIFIER_LOOP } } @@ -111,8 +113,8 @@ extension Parser { ) } - mutating func parseUnownedModifier() -> RawDeclModifierSyntax { - let (unexpectedBeforeKeyword, keyword) = self.expect(.keyword(.unowned)) + mutating func parseUnownedModifier(_ handle: RecoveryConsumptionHandle) -> RawDeclModifierSyntax { + let (unexpectedBeforeKeyword, keyword) = self.eat(handle) let detail: RawDeclModifierDetailSyntax? if self.at(.leftParen) { diff --git a/Sources/SwiftParser/SyntaxUtils.swift b/Sources/SwiftParser/SyntaxUtils.swift index f52c2d9d3d7..c8cc852d545 100644 --- a/Sources/SwiftParser/SyntaxUtils.swift +++ b/Sources/SwiftParser/SyntaxUtils.swift @@ -80,6 +80,10 @@ extension RawUnexpectedNodesSyntax { init?(combining syntax1: some UnexpectedNodesCombinable, _ syntax2: some UnexpectedNodesCombinable, _ syntax3: some UnexpectedNodesCombinable, arena: __shared SyntaxArena) { self.init(syntax1.elements + syntax2.elements + syntax3.elements, arena: arena) } + + init?(combining syntax1: some UnexpectedNodesCombinable, _ syntax2: some UnexpectedNodesCombinable, _ syntax3: some UnexpectedNodesCombinable, _ syntax4: some UnexpectedNodesCombinable, arena: __shared SyntaxArena) { + self.init(syntax1.elements + syntax2.elements + syntax3.elements + syntax4.elements, arena: arena) + } } // MARK: - Misc diff --git a/Sources/SwiftParser/TokenPrecedence.swift b/Sources/SwiftParser/TokenPrecedence.swift index 65c6da41e85..ea99e5d462e 100644 --- a/Sources/SwiftParser/TokenPrecedence.swift +++ b/Sources/SwiftParser/TokenPrecedence.swift @@ -218,6 +218,8 @@ enum TokenPrecedence: Comparable { .let, .var, // Operator stuff .operator, .precedencegroup, + // Declaration Modifiers + .__consuming, .final, .required, .optional, .lazy, .dynamic, .infix, .postfix, .prefix, .mutating, .nonmutating, .convenience, .override, .package, .open, .__setter_access, .indirect, .nonisolated, .distributed, ._local, // Misc .import: self = .declKeyword diff --git a/Sources/SwiftParser/TokenSpecSet.swift b/Sources/SwiftParser/TokenSpecSet.swift index 79cc38cfa76..4004fdd6c80 100644 --- a/Sources/SwiftParser/TokenSpecSet.swift +++ b/Sources/SwiftParser/TokenSpecSet.swift @@ -251,7 +251,7 @@ enum ContextualDeclKeyword: TokenSpecSet { } } -enum DeclarationStart: TokenSpecSet { +enum DeclarationKeyword: TokenSpecSet { case actor case `associatedtype` case `case` @@ -328,6 +328,35 @@ enum DeclarationStart: TokenSpecSet { } } +/// Union of the following token kind subsets: +/// - `DeclarationModifier` +/// - `DeclarationKeyword` +enum DeclarationStart: TokenSpecSet { + case declarationModifier(DeclarationModifier) + case declarationKeyword(DeclarationKeyword) + + init?(lexeme: Lexer.Lexeme) { + if let subset = DeclarationModifier(lexeme: lexeme) { + self = .declarationModifier(subset) + } else if let subset = DeclarationKeyword(lexeme: lexeme) { + self = .declarationKeyword(subset) + } else { + return nil + } + } + + static var allCases: [DeclarationStart] { + return DeclarationModifier.allCases.map(Self.declarationModifier) + DeclarationKeyword.allCases.map(Self.declarationKeyword) + } + + var spec: TokenSpec { + switch self { + case .declarationModifier(let underlyingKind): return underlyingKind.spec + case .declarationKeyword(let underlyingKind): return underlyingKind.spec + } + } +} + enum Operator: TokenSpecSet { case binaryOperator case postfixOperator diff --git a/Sources/SwiftParser/generated/DeclarationModifier.swift b/Sources/SwiftParser/generated/DeclarationModifier.swift index 7147bf34d4c..ce4a56335b5 100644 --- a/Sources/SwiftParser/generated/DeclarationModifier.swift +++ b/Sources/SwiftParser/generated/DeclarationModifier.swift @@ -15,6 +15,15 @@ @_spi(RawSyntax) import SwiftSyntax enum DeclarationModifier: TokenSpecSet { + case weak + case unowned + case `rethrows` + case isolated + case async + case reasync + case consuming + case borrowing + case _const case `static` case `class` case final @@ -37,22 +46,31 @@ enum DeclarationModifier: TokenSpecSet { case package case open case __setter_access - case weak - case unowned - case `rethrows` case indirect - case isolated - case async - case reasync case nonisolated case distributed - case _const case _local - case consuming - case borrowing init?(lexeme: Lexer.Lexeme) { switch PrepareForKeywordMatch(lexeme) { + case TokenSpec(.weak): + self = .weak + case TokenSpec(.unowned): + self = .unowned + case TokenSpec(.`rethrows`): + self = .`rethrows` + case TokenSpec(.isolated): + self = .isolated + case TokenSpec(.async): + self = .async + case TokenSpec(.reasync): + self = .reasync + case TokenSpec(.consuming): + self = .consuming + case TokenSpec(.borrowing): + self = .borrowing + case TokenSpec(._const): + self = ._const case TokenSpec(.`static`): self = .`static` case TokenSpec(.`class`): @@ -97,32 +115,14 @@ enum DeclarationModifier: TokenSpecSet { self = .open case TokenSpec(.__setter_access): self = .__setter_access - case TokenSpec(.weak): - self = .weak - case TokenSpec(.unowned): - self = .unowned - case TokenSpec(.`rethrows`): - self = .`rethrows` case TokenSpec(.indirect): self = .indirect - case TokenSpec(.isolated): - self = .isolated - case TokenSpec(.async): - self = .async - case TokenSpec(.reasync): - self = .reasync case TokenSpec(.nonisolated): self = .nonisolated case TokenSpec(.distributed): self = .distributed - case TokenSpec(._const): - self = ._const case TokenSpec(._local): self = ._local - case TokenSpec(.consuming): - self = .consuming - case TokenSpec(.borrowing): - self = .borrowing default: return nil } @@ -174,32 +174,32 @@ enum DeclarationModifier: TokenSpecSet { return .keyword(.open) case .__setter_access: return .keyword(.__setter_access) - case .weak: - return .keyword(.weak) - case .unowned: - return .keyword(.unowned) - case .`rethrows`: - return .keyword(.`rethrows`) case .indirect: return .keyword(.indirect) - case .isolated: - return .keyword(.isolated) - case .async: - return .keyword(.async) - case .reasync: - return .keyword(.reasync) case .nonisolated: return .keyword(.nonisolated) case .distributed: return .keyword(.distributed) - case ._const: - return .keyword(._const) case ._local: return .keyword(._local) + case .weak: + return TokenSpec(.weak, recoveryPrecedence: .declKeyword) + case .unowned: + return TokenSpec(.unowned, recoveryPrecedence: .declKeyword) + case .`rethrows`: + return TokenSpec(.`rethrows`, recoveryPrecedence: .declKeyword) + case .isolated: + return TokenSpec(.isolated, recoveryPrecedence: .declKeyword) + case .async: + return TokenSpec(.async, recoveryPrecedence: .declKeyword) + case .reasync: + return TokenSpec(.reasync, recoveryPrecedence: .declKeyword) case .consuming: - return .keyword(.consuming) + return TokenSpec(.consuming, recoveryPrecedence: .declKeyword) case .borrowing: - return .keyword(.borrowing) + return TokenSpec(.borrowing, recoveryPrecedence: .declKeyword) + case ._const: + return TokenSpec(._const, recoveryPrecedence: .declKeyword) } } } diff --git a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift index 70d2df47bf1..1e2c08b6a2f 100644 --- a/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift +++ b/Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift @@ -1115,6 +1115,20 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor { if shouldSkip(node) { return .skipChildren } + + if node.fixity.presence == .missing { + addDiagnostic( + node.fixity, + .missingFixityInOperatorDeclaration, + fixIts: [ + FixIt(message: InsertFixIt(tokenToBeInserted: .keyword(.prefix)), changes: .makePresent(node.fixity)), + FixIt(message: InsertFixIt(tokenToBeInserted: .keyword(.infix)), changes: [FixIt.MultiNodeChange(.replace(oldNode: Syntax(node.fixity), newNode: Syntax(TokenSyntax(.keyword(.infix), presence: .present))))]), + FixIt(message: InsertFixIt(tokenToBeInserted: .keyword(.postfix)), changes: [FixIt.MultiNodeChange(.replace(oldNode: Syntax(node.fixity), newNode: Syntax(TokenSyntax(.keyword(.postfix), presence: .present))))]), + ], + handledNodes: [node.fixity.id] + ) + } + if let unexpected = node.unexpectedAfterOperatorPrecedenceAndTypes, unexpected.contains(where: { $0.is(PrecedenceGroupAttributeListSyntax.self) }) == true { diff --git a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift index 442cfde55da..3d570edd3ec 100644 --- a/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift +++ b/Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift @@ -195,6 +195,9 @@ extension DiagnosticMessage where Self == StaticParserError { public static var misspelledThrows: Self { .init("expected throwing specifier; did you mean 'throws'?") } + public static var missingFixityInOperatorDeclaration: Self { + .init("operator must be declared as 'prefix', 'postfix', or 'infix'") + } public static var multiLineStringLiteralMustBeginOnNewLine: Self { .init("multi-line string literal content must begin on a new line") } diff --git a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift index d5b003f2d2b..b810a75b0ed 100644 --- a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift @@ -254,10 +254,8 @@ private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String? { return "label" case \ObjCSelectorPieceSyntax.name: return "name" - case \OperatorDeclSyntax.attributes: - return "attributes" - case \OperatorDeclSyntax.modifiers: - return "modifiers" + case \OperatorDeclSyntax.fixity: + return "fixity" case \OperatorPrecedenceAndTypesSyntax.precedenceGroup: return "precedence group" case \ParameterClauseSyntax.parameterList: diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index fb65abbe426..87c33e660fe 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -2281,16 +2281,12 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "ordinal" case \OpaqueReturnTypeOfAttributeArgumentsSyntax.unexpectedAfterOrdinal: return "unexpectedAfterOrdinal" - case \OperatorDeclSyntax.unexpectedBeforeAttributes: - return "unexpectedBeforeAttributes" - case \OperatorDeclSyntax.attributes: - return "attributes" - case \OperatorDeclSyntax.unexpectedBetweenAttributesAndModifiers: - return "unexpectedBetweenAttributesAndModifiers" - case \OperatorDeclSyntax.modifiers: - return "modifiers" - case \OperatorDeclSyntax.unexpectedBetweenModifiersAndOperatorKeyword: - return "unexpectedBetweenModifiersAndOperatorKeyword" + case \OperatorDeclSyntax.unexpectedBeforeFixity: + return "unexpectedBeforeFixity" + case \OperatorDeclSyntax.fixity: + return "fixity" + case \OperatorDeclSyntax.unexpectedBetweenFixityAndOperatorKeyword: + return "unexpectedBetweenFixityAndOperatorKeyword" case \OperatorDeclSyntax.operatorKeyword: return "operatorKeyword" case \OperatorDeclSyntax.unexpectedBetweenOperatorKeywordAndIdentifier: diff --git a/Sources/SwiftSyntax/generated/SyntaxTraits.swift b/Sources/SwiftSyntax/generated/SyntaxTraits.swift index da04cbb8e45..c18f6450766 100644 --- a/Sources/SwiftSyntax/generated/SyntaxTraits.swift +++ b/Sources/SwiftSyntax/generated/SyntaxTraits.swift @@ -591,7 +591,7 @@ extension MemberDeclBlockSyntax: BracedSyntax {} extension MissingDeclSyntax: WithAttributesSyntax, WithModifiersSyntax {} -extension OperatorDeclSyntax: IdentifiedDeclSyntax, WithAttributesSyntax, WithModifiersSyntax {} +extension OperatorDeclSyntax: IdentifiedDeclSyntax {} extension ParameterClauseSyntax: ParenthesizedSyntax {} diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift index 2b67a29bf84..a811fd67ef9 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift @@ -15206,11 +15206,9 @@ public struct RawOperatorDeclSyntax: RawDeclSyntaxNodeProtocol { } public init( - _ unexpectedBeforeAttributes: RawUnexpectedNodesSyntax? = nil, - attributes: RawAttributeListSyntax?, - _ unexpectedBetweenAttributesAndModifiers: RawUnexpectedNodesSyntax? = nil, - modifiers: RawModifierListSyntax?, - _ unexpectedBetweenModifiersAndOperatorKeyword: RawUnexpectedNodesSyntax? = nil, + _ unexpectedBeforeFixity: RawUnexpectedNodesSyntax? = nil, + fixity: RawTokenSyntax, + _ unexpectedBetweenFixityAndOperatorKeyword: RawUnexpectedNodesSyntax? = nil, operatorKeyword: RawTokenSyntax, _ unexpectedBetweenOperatorKeywordAndIdentifier: RawUnexpectedNodesSyntax? = nil, identifier: RawTokenSyntax, @@ -15220,65 +15218,55 @@ public struct RawOperatorDeclSyntax: RawDeclSyntaxNodeProtocol { arena: __shared SyntaxArena ) { let raw = RawSyntax.makeLayout( - kind: .operatorDecl, uninitializedCount: 11, arena: arena) { layout in + kind: .operatorDecl, uninitializedCount: 9, arena: arena) { layout in layout.initialize(repeating: nil) - layout[0] = unexpectedBeforeAttributes?.raw - layout[1] = attributes?.raw - layout[2] = unexpectedBetweenAttributesAndModifiers?.raw - layout[3] = modifiers?.raw - layout[4] = unexpectedBetweenModifiersAndOperatorKeyword?.raw - layout[5] = operatorKeyword.raw - layout[6] = unexpectedBetweenOperatorKeywordAndIdentifier?.raw - layout[7] = identifier.raw - layout[8] = unexpectedBetweenIdentifierAndOperatorPrecedenceAndTypes?.raw - layout[9] = operatorPrecedenceAndTypes?.raw - layout[10] = unexpectedAfterOperatorPrecedenceAndTypes?.raw + layout[0] = unexpectedBeforeFixity?.raw + layout[1] = fixity.raw + layout[2] = unexpectedBetweenFixityAndOperatorKeyword?.raw + layout[3] = operatorKeyword.raw + layout[4] = unexpectedBetweenOperatorKeywordAndIdentifier?.raw + layout[5] = identifier.raw + layout[6] = unexpectedBetweenIdentifierAndOperatorPrecedenceAndTypes?.raw + layout[7] = operatorPrecedenceAndTypes?.raw + layout[8] = unexpectedAfterOperatorPrecedenceAndTypes?.raw } self.init(unchecked: raw) } - public var unexpectedBeforeAttributes: RawUnexpectedNodesSyntax? { + public var unexpectedBeforeFixity: RawUnexpectedNodesSyntax? { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } - public var attributes: RawAttributeListSyntax? { - layoutView.children[1].map(RawAttributeListSyntax.init(raw:)) + public var fixity: RawTokenSyntax { + layoutView.children[1].map(RawTokenSyntax.init(raw:))! } - public var unexpectedBetweenAttributesAndModifiers: RawUnexpectedNodesSyntax? { + public var unexpectedBetweenFixityAndOperatorKeyword: RawUnexpectedNodesSyntax? { layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:)) } - public var modifiers: RawModifierListSyntax? { - layoutView.children[3].map(RawModifierListSyntax.init(raw:)) - } - - public var unexpectedBetweenModifiersAndOperatorKeyword: RawUnexpectedNodesSyntax? { - layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) - } - public var operatorKeyword: RawTokenSyntax { - layoutView.children[5].map(RawTokenSyntax.init(raw:))! + layoutView.children[3].map(RawTokenSyntax.init(raw:))! } public var unexpectedBetweenOperatorKeywordAndIdentifier: RawUnexpectedNodesSyntax? { - layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) } public var identifier: RawTokenSyntax { - layoutView.children[7].map(RawTokenSyntax.init(raw:))! + layoutView.children[5].map(RawTokenSyntax.init(raw:))! } public var unexpectedBetweenIdentifierAndOperatorPrecedenceAndTypes: RawUnexpectedNodesSyntax? { - layoutView.children[8].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:)) } public var operatorPrecedenceAndTypes: RawOperatorPrecedenceAndTypesSyntax? { - layoutView.children[9].map(RawOperatorPrecedenceAndTypesSyntax.init(raw:)) + layoutView.children[7].map(RawOperatorPrecedenceAndTypesSyntax.init(raw:)) } public var unexpectedAfterOperatorPrecedenceAndTypes: RawUnexpectedNodesSyntax? { - layoutView.children[10].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 4cd02542024..99d4e852135 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -1902,18 +1902,16 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.integerLiteral)])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) case .operatorDecl: - assert(layout.count == 11) + assert(layout.count == 9) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 1, verify(layout[1], as: RawAttributeListSyntax?.self)) + assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.keyword("prefix"), .keyword("postfix"), .keyword("infix")])) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 3, verify(layout[3], as: RawModifierListSyntax?.self)) + assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self, tokenChoices: [.keyword("operator")])) assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.keyword("operator")])) + assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.binaryOperator), .tokenKind(.prefixOperator), .tokenKind(.postfixOperator)])) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 7, verify(layout[7], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.binaryOperator), .tokenKind(.prefixOperator), .tokenKind(.postfixOperator)])) + assertNoError(kind, 7, verify(layout[7], as: RawOperatorPrecedenceAndTypesSyntax?.self)) assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 9, verify(layout[9], as: RawOperatorPrecedenceAndTypesSyntax?.self)) - assertNoError(kind, 10, verify(layout[10], as: RawUnexpectedNodesSyntax?.self)) case .operatorPrecedenceAndTypes: assert(layout.count == 7) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift index 758e8e50f09..f9661548b6d 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxDeclNodes.swift @@ -4283,11 +4283,9 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { public init( leadingTrivia: Trivia? = nil, - _ unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil, - attributes: AttributeListSyntax? = nil, - _ unexpectedBetweenAttributesAndModifiers: UnexpectedNodesSyntax? = nil, - modifiers: ModifierListSyntax? = nil, - _ unexpectedBetweenModifiersAndOperatorKeyword: UnexpectedNodesSyntax? = nil, + _ unexpectedBeforeFixity: UnexpectedNodesSyntax? = nil, + fixity: TokenSyntax, + _ unexpectedBetweenFixityAndOperatorKeyword: UnexpectedNodesSyntax? = nil, operatorKeyword: TokenSyntax = .keyword(.operator), _ unexpectedBetweenOperatorKeywordAndIdentifier: UnexpectedNodesSyntax? = nil, identifier: TokenSyntax, @@ -4300,11 +4298,9 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { // Extend the lifetime of all parameters so their arenas don't get destroyed // before they can be added as children of the new arena. let data: SyntaxData = withExtendedLifetime((SyntaxArena(), ( - unexpectedBeforeAttributes, - attributes, - unexpectedBetweenAttributesAndModifiers, - modifiers, - unexpectedBetweenModifiersAndOperatorKeyword, + unexpectedBeforeFixity, + fixity, + unexpectedBetweenFixityAndOperatorKeyword, operatorKeyword, unexpectedBetweenOperatorKeywordAndIdentifier, identifier, @@ -4313,11 +4309,9 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { unexpectedAfterOperatorPrecedenceAndTypes ))) {(arena, _) in let layout: [RawSyntax?] = [ - unexpectedBeforeAttributes?.raw, - attributes?.raw, - unexpectedBetweenAttributesAndModifiers?.raw, - modifiers?.raw, - unexpectedBetweenModifiersAndOperatorKeyword?.raw, + unexpectedBeforeFixity?.raw, + fixity.raw, + unexpectedBetweenFixityAndOperatorKeyword?.raw, operatorKeyword.raw, unexpectedBetweenOperatorKeywordAndIdentifier?.raw, identifier.raw, @@ -4338,7 +4332,7 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { self.init(data) } - public var unexpectedBeforeAttributes: UnexpectedNodesSyntax? { + public var unexpectedBeforeFixity: UnexpectedNodesSyntax? { get { return data.child(at: 0, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -4347,36 +4341,17 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } - /// The attributes applied to the 'operator' declaration. - public var attributes: AttributeListSyntax? { + /// The fixity applied to the 'operator' declaration. + public var fixity: TokenSyntax { get { - return data.child(at: 1, parent: Syntax(self)).map(AttributeListSyntax.init) + return TokenSyntax(data.child(at: 1, parent: Syntax(self))!) } set(value) { - self = OperatorDeclSyntax(data.replacingChild(at: 1, with: value?.raw, arena: SyntaxArena())) - } - } - - /// Adds the provided `Attribute` to the node's `attributes` - /// collection. - /// - param element: The new `Attribute` to add to the node's - /// `attributes` collection. - /// - returns: A copy of the receiver with the provided `Attribute` - /// appended to its `attributes` collection. - public func addAttribute(_ element: Syntax) -> OperatorDeclSyntax { - var collection: RawSyntax - let arena = SyntaxArena() - if let col = raw.layoutView!.children[1] { - collection = col.layoutView!.appending(element.raw, arena: arena) - } else { - collection = RawSyntax.makeLayout(kind: SyntaxKind.attributeList, - from: [element.raw], arena: arena) + self = OperatorDeclSyntax(data.replacingChild(at: 1, with: value.raw, arena: SyntaxArena())) } - let newData = data.replacingChild(at: 1, with: collection, arena: arena) - return OperatorDeclSyntax(newData) } - public var unexpectedBetweenAttributesAndModifiers: UnexpectedNodesSyntax? { + public var unexpectedBetweenFixityAndOperatorKeyword: UnexpectedNodesSyntax? { get { return data.child(at: 2, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -4385,36 +4360,16 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } - /// The declaration modifiers applied to the 'operator' declaration. - public var modifiers: ModifierListSyntax? { + public var operatorKeyword: TokenSyntax { get { - return data.child(at: 3, parent: Syntax(self)).map(ModifierListSyntax.init) + return TokenSyntax(data.child(at: 3, parent: Syntax(self))!) } set(value) { - self = OperatorDeclSyntax(data.replacingChild(at: 3, with: value?.raw, arena: SyntaxArena())) - } - } - - /// Adds the provided `Modifier` to the node's `modifiers` - /// collection. - /// - param element: The new `Modifier` to add to the node's - /// `modifiers` collection. - /// - returns: A copy of the receiver with the provided `Modifier` - /// appended to its `modifiers` collection. - public func addModifier(_ element: DeclModifierSyntax) -> OperatorDeclSyntax { - var collection: RawSyntax - let arena = SyntaxArena() - if let col = raw.layoutView!.children[3] { - collection = col.layoutView!.appending(element.raw, arena: arena) - } else { - collection = RawSyntax.makeLayout(kind: SyntaxKind.modifierList, - from: [element.raw], arena: arena) + self = OperatorDeclSyntax(data.replacingChild(at: 3, with: value.raw, arena: SyntaxArena())) } - let newData = data.replacingChild(at: 3, with: collection, arena: arena) - return OperatorDeclSyntax(newData) } - public var unexpectedBetweenModifiersAndOperatorKeyword: UnexpectedNodesSyntax? { + public var unexpectedBetweenOperatorKeywordAndIdentifier: UnexpectedNodesSyntax? { get { return data.child(at: 4, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -4423,7 +4378,7 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } - public var operatorKeyword: TokenSyntax { + public var identifier: TokenSyntax { get { return TokenSyntax(data.child(at: 5, parent: Syntax(self))!) } @@ -4432,7 +4387,7 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } - public var unexpectedBetweenOperatorKeywordAndIdentifier: UnexpectedNodesSyntax? { + public var unexpectedBetweenIdentifierAndOperatorPrecedenceAndTypes: UnexpectedNodesSyntax? { get { return data.child(at: 6, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } @@ -4441,50 +4396,30 @@ public struct OperatorDeclSyntax: DeclSyntaxProtocol, SyntaxHashable { } } - public var identifier: TokenSyntax { - get { - return TokenSyntax(data.child(at: 7, parent: Syntax(self))!) - } - set(value) { - self = OperatorDeclSyntax(data.replacingChild(at: 7, with: value.raw, arena: SyntaxArena())) - } - } - - public var unexpectedBetweenIdentifierAndOperatorPrecedenceAndTypes: UnexpectedNodesSyntax? { - get { - return data.child(at: 8, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) - } - set(value) { - self = OperatorDeclSyntax(data.replacingChild(at: 8, with: value?.raw, arena: SyntaxArena())) - } - } - /// Optionally specify a precedence group and designated types. public var operatorPrecedenceAndTypes: OperatorPrecedenceAndTypesSyntax? { get { - return data.child(at: 9, parent: Syntax(self)).map(OperatorPrecedenceAndTypesSyntax.init) + return data.child(at: 7, parent: Syntax(self)).map(OperatorPrecedenceAndTypesSyntax.init) } set(value) { - self = OperatorDeclSyntax(data.replacingChild(at: 9, with: value?.raw, arena: SyntaxArena())) + self = OperatorDeclSyntax(data.replacingChild(at: 7, with: value?.raw, arena: SyntaxArena())) } } public var unexpectedAfterOperatorPrecedenceAndTypes: UnexpectedNodesSyntax? { get { - return data.child(at: 10, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) + return data.child(at: 8, parent: Syntax(self)).map(UnexpectedNodesSyntax.init) } set(value) { - self = OperatorDeclSyntax(data.replacingChild(at: 10, with: value?.raw, arena: SyntaxArena())) + self = OperatorDeclSyntax(data.replacingChild(at: 8, with: value?.raw, arena: SyntaxArena())) } } public static var structure: SyntaxNodeStructure { return .layout([ - \Self.unexpectedBeforeAttributes, - \Self.attributes, - \Self.unexpectedBetweenAttributesAndModifiers, - \Self.modifiers, - \Self.unexpectedBetweenModifiersAndOperatorKeyword, + \Self.unexpectedBeforeFixity, + \Self.fixity, + \Self.unexpectedBetweenFixityAndOperatorKeyword, \Self.operatorKeyword, \Self.unexpectedBetweenOperatorKeywordAndIdentifier, \Self.identifier, diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index 4ad1f5f63e6..2bfd92d4933 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -2163,4 +2163,31 @@ final class DeclarationTests: XCTestCase { ] ) } + + func testUnexpectedTokenInClassFollowedByUnownedModifier() { + assertParse( + """ + class A ℹ️{ + 1️⃣^ + } + unowned 2️⃣B 3️⃣{ + }4️⃣ + """, + diagnostics: [ + DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code before modifier"), + DiagnosticSpec(locationMarker: "2️⃣", message: "expected 'func' in function", fixIts: ["insert 'func'"]), + DiagnosticSpec(locationMarker: "3️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), + DiagnosticSpec(locationMarker: "4️⃣", message: "expected '}' to end class", notes: [NoteSpec(message: "to match this opening '{'")], fixIts: ["insert '}'"]), + ], + fixedSource: + """ + class A { + ^ + } + unowned func B() { + } + } + """ + ) + } } diff --git a/Tests/SwiftParserTest/Parser+EntryTests.swift b/Tests/SwiftParserTest/Parser+EntryTests.swift index f58f16b8e63..7323f990de6 100644 --- a/Tests/SwiftParserTest/Parser+EntryTests.swift +++ b/Tests/SwiftParserTest/Parser+EntryTests.swift @@ -49,7 +49,7 @@ public class EntryTests: XCTestCase { func testRemainderUnexpectedDoesntOverrideExistingUnexpected() throws { assertParse( - "operator 1️⃣test 2️⃣{} other tokens", + "1️⃣operator 2️⃣test 3️⃣{} other tokens", { DeclSyntax.parse(from: &$0) }, substructure: Syntax( UnexpectedNodesSyntax([ @@ -60,13 +60,14 @@ public class EntryTests: XCTestCase { TokenSyntax.identifier("tokens"), ]) ), - substructureAfterMarker: "2️⃣", + substructureAfterMarker: "3️⃣", diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "'test' is considered an identifier and must not appear within an operator name"), - DiagnosticSpec(locationMarker: "2️⃣", message: "operator should not be declared with body", fixIts: ["remove operator body"]), + DiagnosticSpec(locationMarker: "1️⃣", message: "operator must be declared as 'prefix', 'postfix', or 'infix'", fixIts: ["insert 'prefix'", "insert 'infix'", "insert 'postfix'"]), + DiagnosticSpec(locationMarker: "2️⃣", message: "'test' is considered an identifier and must not appear within an operator name"), + DiagnosticSpec(locationMarker: "3️⃣", message: "operator should not be declared with body", fixIts: ["remove operator body"]), ], fixedSource: """ - operator test + prefix operator test """ ) } diff --git a/Tests/SwiftParserTest/translated/OperatorDeclTests.swift b/Tests/SwiftParserTest/translated/OperatorDeclTests.swift index 80b73422f34..c182335d2f5 100644 --- a/Tests/SwiftParserTest/translated/OperatorDeclTests.swift +++ b/Tests/SwiftParserTest/translated/OperatorDeclTests.swift @@ -132,25 +132,29 @@ final class OperatorDeclTests: XCTestCase { func testOperatorDecl6() { assertParse( """ - operator ++*** : A + 1️⃣operator ++*** : A """, diagnostics: [ - // TODO: Old parser expected error on line 1: operator must be declared as 'prefix', 'postfix', or 'infix' - ] + DiagnosticSpec(message: "operator must be declared as 'prefix', 'postfix', or 'infix'", fixIts: ["insert 'prefix'", "insert 'infix'", "insert 'postfix'"]) + ], + fixedSource: + """ + prefix operator ++*** : A + """ ) } func testOperatorDecl7() { assertParse( """ - operator +*+++ 1️⃣{ } + 1️⃣operator +*+++ 2️⃣{ } """, diagnostics: [ - // TODO: Old parser expected error on line 1: operator must be declared as 'prefix', 'postfix', or 'infix' - DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) + DiagnosticSpec(locationMarker: "1️⃣", message: "operator must be declared as 'prefix', 'postfix', or 'infix'", fixIts: ["insert 'prefix'", "insert 'infix'", "insert 'postfix'"]), + DiagnosticSpec(locationMarker: "2️⃣", message: "operator should not be declared with body", fixIts: ["remove operator body"]), ], fixedSource: """ - operator +*+++ + prefix operator +*+++ """ ) } @@ -158,14 +162,14 @@ final class OperatorDeclTests: XCTestCase { func testOperatorDecl8() { assertParse( """ - operator +*++* : A 1️⃣{ } + 1️⃣operator +*++* : A 2️⃣{ } """, diagnostics: [ - // TODO: Old parser expected error on line 1: operator must be declared as 'prefix', 'postfix', or 'infix' - DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) + DiagnosticSpec(locationMarker: "1️⃣", message: "operator must be declared as 'prefix', 'postfix', or 'infix'", fixIts: ["insert 'prefix'", "insert 'infix'", "insert 'postfix'"]), + DiagnosticSpec(locationMarker: "2️⃣", message: "operator should not be declared with body", fixIts: ["remove operator body"]), ], fixedSource: """ - operator +*++* : A + prefix operator +*++* : A """ ) } @@ -191,8 +195,13 @@ final class OperatorDeclTests: XCTestCase { prefix operator %%+ """, diagnostics: [ - DiagnosticSpec(message: "unexpected code before operator declaration") - ] + DiagnosticSpec(message: "unexpected ';' separator", fixIts: ["remove ';'"]) + ], + fixedSource: + """ + + prefix operator %%+ + """ ) } @@ -539,6 +548,67 @@ final class OperatorDeclTests: XCTestCase { ) } + func testOperatorDecl124() { + assertParse( + """ + 1️⃣@objc + postfix operator ++: PrecedenceGroup + """, + diagnostics: [ + DiagnosticSpec(message: "unexpected code '@objc' before operator declaration") + ] + ) + } + + func testOperatorDecl125() { + assertParse( + """ + 1️⃣mutating postfix operator --: UndefinedPrecedenceGroup + """, + diagnostics: [ + DiagnosticSpec(message: "unexpected code 'mutating' before operator declaration") + ] + ) + } + + func testOperatorDecl126() { + assertParse( + """ + 1️⃣private(set) infix operator ~~~ + """, + diagnostics: [ + DiagnosticSpec(message: "unexpected code 'private(set)' before operator declaration") + ] + ) + } + + func testOperatorDecl127() { + assertParse( + """ + 1️⃣dynamic 2️⃣operator ~~~ + """, + diagnostics: [ + DiagnosticSpec(message: "unexpected code 'dynamic' before operator declaration"), + DiagnosticSpec(locationMarker: "2️⃣", message: "operator must be declared as 'prefix', 'postfix', or 'infix'", fixIts: ["insert 'prefix'", "insert 'infix'", "insert 'postfix'"]), + ], + fixedSource: + """ + dynamic prefix operator ~~~ + """ + ) + } + + func testMultipleFixity() { + assertParse( + """ + prefix 1️⃣infix operator &+& + """, + diagnostics: [ + DiagnosticSpec(message: "unexpected code 'infix' in operator declaration") + ] + ) + } + func testIdentifierAsOperatorName() { assertParse( "postfix operator 1️⃣aa",