diff --git a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift index 35fadbc0f2f..b0b1f36226d 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift @@ -19,6 +19,7 @@ public enum ExperimentalFeature: String, CaseIterable { case nonescapableTypes case trailingComma case coroutineAccessors + case valueGenerics /// The name of the feature, which is used in the doc comment. public var featureName: String { @@ -35,6 +36,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "trailing comma" case .coroutineAccessors: return "CoroutineAccessors" + case .valueGenerics: + return "ValueGenerics" } } diff --git a/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift b/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift index 99a37a8b352..a54368b8dd6 100644 --- a/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift @@ -334,8 +334,20 @@ public let GENERIC_NODES: [Node] = [ children: [ Child( name: "leftType", - kind: .node(kind: .type), - nameForDiagnostics: "left-hand type" + kind: .nodeChoices(choices: [ + Child( + name: "type", + kind: .node(kind: .type) + ), + Child( + name: "expr", + kind: .node(kind: .expr), + experimentalFeature: .valueGenerics + ), + ]), + nameForDiagnostics: "left-hand type", + documentation: + "The left hand side type for a same type requirement. This can either be a regular type argument or an expression for value generics." ), Child( name: "equal", @@ -343,8 +355,20 @@ public let GENERIC_NODES: [Node] = [ ), Child( name: "rightType", - kind: .node(kind: .type), - nameForDiagnostics: "right-hand type" + kind: .nodeChoices(choices: [ + Child( + name: "type", + kind: .node(kind: .type) + ), + Child( + name: "expr", + kind: .node(kind: .expr), + experimentalFeature: .valueGenerics + ), + ]), + nameForDiagnostics: "right-hand type", + documentation: + "The right hand side type for a same type requirement. This can either be a regular type argument or an expression for value generics." ), ], childHistory: [ diff --git a/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift b/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift index fb88fa18776..ac5b1a8f8a4 100644 --- a/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift @@ -257,7 +257,19 @@ public let TYPE_NODES: [Node] = [ children: [ Child( name: "argument", - kind: .node(kind: .type) + kind: .nodeChoices(choices: [ + Child( + name: "type", + kind: .node(kind: .type) + ), + Child( + name: "expr", + kind: .node(kind: .expr), + experimentalFeature: .valueGenerics + ), + ]), + documentation: + "The argument type for a generic argument. This can either be a regular type argument or an expression for value generics." ), Child( name: "trailingComma", diff --git a/Examples/Sources/MacroExamples/Implementation/ComplexMacros/OptionSetMacro.swift b/Examples/Sources/MacroExamples/Implementation/ComplexMacros/OptionSetMacro.swift index 5b7eed9de30..31fad649bb4 100644 --- a/Examples/Sources/MacroExamples/Implementation/ComplexMacros/OptionSetMacro.swift +++ b/Examples/Sources/MacroExamples/Implementation/ComplexMacros/OptionSetMacro.swift @@ -81,7 +81,7 @@ public struct OptionSetMacro { attachedTo decl: some DeclGroupSyntax, in context: some MacroExpansionContext, emitDiagnostics: Bool - ) -> (StructDeclSyntax, EnumDeclSyntax, TypeSyntax)? { + ) -> (StructDeclSyntax, EnumDeclSyntax, GenericArgumentSyntax.Argument)? { // Determine the name of the options enum. let optionsEnumName: String if case let .argumentList(arguments) = attribute.arguments, diff --git a/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift b/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift index 4e25660cff8..923f002c6c4 100644 --- a/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift +++ b/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import SwiftSyntax +@_spi(ExperimentalLanguageFeatures) import SwiftSyntax import SwiftSyntaxMacros extension SyntaxCollection { @@ -71,12 +71,24 @@ public struct AddAsyncMacro: PeerMacro { let returnType = completionHandlerParameter.parameters.first?.type let isResultReturn = returnType?.children(viewMode: .all).first?.description == "Result" - let successReturnType = - if isResultReturn { - returnType!.as(IdentifierTypeSyntax.self)!.genericArgumentClause?.arguments.first!.argument - } else { - returnType + let successReturnType: TypeSyntax? + + if isResultReturn { + let argument = returnType!.as(IdentifierTypeSyntax.self)!.genericArgumentClause?.arguments.first!.argument + + switch argument { + case .some(.type(let type)): + successReturnType = type + + case .some(.expr(_)): + throw CustomError.message("Found unexpected value generic in Result type") + + case .none: + successReturnType = nil } + } else { + successReturnType = returnType + } // Remove completionHandler and comma from the previous parameter var newParameterList = funcDecl.signature.parameterClause.parameters diff --git a/Release Notes/601.md b/Release Notes/601.md index 2f1d6264698..6e4a0b0c8d3 100644 --- a/Release Notes/601.md +++ b/Release Notes/601.md @@ -2,6 +2,18 @@ ## New APIs +- `SameTypeRequirementSyntax` has a new `RightType` nested type. + - Description: The Swift parser can now parse values as types in certain situations, so the new type reflects the possibility of the argument being either an `ExprSyntax` or a `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2859 + +- `SameTypeRequirementSyntax` has a new `LeftType` nested type. + - Description: The Swift parser can now parse values as types in certain situations, so the new type reflects the possibility of the argument being either an `ExprSyntax` or a `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2859 + +- `GenericArgumentSynax` has a new `Argument` nested type. + - Description: The Swift parser can now parse values as types in certain situations, so the new type reflects the possibility of the argument being either an `ExprSyntax` or a `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2859 + - `GenericParameterSyntax` now has a new `specifier` property. - Description: With the introduction of value generics, generic parameters can now be optionally preceded by either a `let` or an `each`. The `specifier` property captures the token representing which one was parsed. - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2785 @@ -54,6 +66,18 @@ ## API-Incompatible Changes +- `SameTypeRequirementSyntax.rightType` has changed types from `TypeSyntax` to `SameTypeRequirementSyntax.RightType` + - Description: The Swift parser can now parse values as types in certain situations, so the new type reflects the possibility of the argument being either an `ExprSyntax` or a `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2859 + +- `SameTypeRequirementSyntax.leftType` has changed types from `TypeSyntax` to `SameTypeRequirementSyntax.LeftType` + - Description: The Swift parser can now parse values as types in certain situations, so the new type reflects the possibility of the argument being either an `ExprSyntax` or a `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2859 + +- `GenericArgumentSyntax.argument` has changed types from `TypeSyntax` to `GenericArgumentSyntax.Argument` + - Description: The Swift parser can now parse values as types in certain situations, so the new type reflects the possibility of the argument being either an `ExprSyntax` or a `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/2859 + - Moved `Radix` and `IntegerLiteralExprSyntax.radix` from `SwiftRefactor` to `SwiftSyntax`. - Description: Allows retrieving the radix value from the `literal.text`. - Issue: https://github.com/apple/swift-syntax/issues/405 diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 6d8845d52a0..8b68c484eca 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -11,9 +11,9 @@ //===----------------------------------------------------------------------===// #if swift(>=6) -@_spi(RawSyntax) internal import SwiftSyntax +@_spi(RawSyntax) @_spi(ExperimentalLanguageFeatures) internal import SwiftSyntax #else -@_spi(RawSyntax) import SwiftSyntax +@_spi(RawSyntax) @_spi(ExperimentalLanguageFeatures) import SwiftSyntax #endif extension DeclarationModifier { @@ -524,6 +524,22 @@ extension Parser { return self.at(prefix: ">") } + mutating func parseSameTypeLeftType() -> RawSameTypeRequirementSyntax.LeftType { + if let valueType = self.parseValueType() { + return .expr(valueType) + } else { + return .type(self.parseType()) + } + } + + mutating func parseSameTypeRightType() -> RawSameTypeRequirementSyntax.RightType { + if let valueType = self.parseValueType() { + return .expr(valueType) + } else { + return .type(self.parseType()) + } + } + mutating func parseGenericWhereClause() -> RawGenericWhereClauseSyntax { let (unexpectedBeforeWhereKeyword, whereKeyword) = self.expect(.keyword(.where)) @@ -532,16 +548,17 @@ extension Parser { var keepGoing: RawTokenSyntax? = nil var loopProgress = LoopProgressCondition() repeat { - let firstType = self.parseType() - guard !firstType.is(RawMissingTypeSyntax.self) else { + let firstArgument = self.parseSameTypeLeftType() + + guard !firstArgument.raw.is(RawMissingTypeSyntax.self) else { keepGoing = self.consume(if: .comma) elements.append( RawGenericRequirementSyntax( requirement: .sameTypeRequirement( RawSameTypeRequirementSyntax( - leftType: RawMissingTypeSyntax(arena: self.arena), + leftType: firstArgument, equal: missingToken(.binaryOperator, text: "=="), - rightType: RawMissingTypeSyntax(arena: self.arena), + rightType: .type(RawTypeSyntax(RawMissingTypeSyntax(arena: self.arena))), arena: self.arena ) ), @@ -552,137 +569,161 @@ extension Parser { continue } - enum ExpectedTokenKind: TokenSpecSet { - case colon - case binaryOperator - case postfixOperator - case prefixOperator - - init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) { - switch (lexeme.rawTokenKind, lexeme.tokenText) { - case (.colon, _): self = .colon - case (.binaryOperator, "=="): self = .binaryOperator - case (.postfixOperator, "=="): self = .postfixOperator - case (.prefixOperator, "=="): self = .prefixOperator - default: return nil + let requirement: RawGenericRequirementSyntax.Requirement + + switch firstArgument { + // If the first argument is an expression, then we have to have a same + // type requirement. We do not allow conformance requirements like + // '123: Protocol' or layout constraints on expressions. + case .expr: + let (unexpectedBeforeEqual, equal) = self.expect( + anyIn: SameTypeRequirementSyntax.EqualOptions.self, + default: .binaryOperator + ) + let secondArgument = self.parseSameTypeRightType() + requirement = .sameTypeRequirement( + RawSameTypeRequirementSyntax( + leftType: firstArgument, + unexpectedBeforeEqual, + equal: equal, + rightType: secondArgument, + arena: self.arena + ) + ) + + // Otherwise, this can be a conformance, same type, or layout constraint. + case .type(let firstType): + enum ExpectedTokenKind: TokenSpecSet { + case colon + case binaryOperator + case postfixOperator + case prefixOperator + + init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) { + switch (lexeme.rawTokenKind, lexeme.tokenText) { + case (.colon, _): self = .colon + case (.binaryOperator, "=="): self = .binaryOperator + case (.postfixOperator, "=="): self = .postfixOperator + case (.prefixOperator, "=="): self = .prefixOperator + default: return nil + } } - } - var spec: TokenSpec { - switch self { - case .colon: return .colon - case .binaryOperator: return .binaryOperator - case .postfixOperator: return .postfixOperator - case .prefixOperator: return .prefixOperator + var spec: TokenSpec { + switch self { + case .colon: return .colon + case .binaryOperator: return .binaryOperator + case .postfixOperator: return .postfixOperator + case .prefixOperator: return .prefixOperator + } } } - } - let requirement: RawGenericRequirementSyntax.Requirement - switch self.at(anyIn: ExpectedTokenKind.self) { - case (.colon, let handle)?: - let colon = self.eat(handle) - // A conformance-requirement. - if let (layoutSpecifier, handle) = self.at(anyIn: LayoutRequirementSyntax.LayoutSpecifierOptions.self) { - // Parse a layout constraint. - let specifier = self.eat(handle) - - let unexpectedBeforeLeftParen: RawUnexpectedNodesSyntax? - let leftParen: RawTokenSyntax? - let size: RawTokenSyntax? - let comma: RawTokenSyntax? - let alignment: RawTokenSyntax? - let unexpectedBeforeRightParen: RawUnexpectedNodesSyntax? - let rightParen: RawTokenSyntax? - - var hasArguments: Bool { - switch layoutSpecifier { - case ._Trivial, - ._TrivialAtMost, - ._TrivialStride: - return true - - case ._UnknownLayout, - ._RefCountedObject, - ._NativeRefCountedObject, - ._Class, - ._NativeClass, - ._BridgeObject: - return false + switch self.at(anyIn: ExpectedTokenKind.self) { + case (.colon, let handle)?: + let colon = self.eat(handle) + // A conformance-requirement. + if let (layoutSpecifier, handle) = self.at(anyIn: LayoutRequirementSyntax.LayoutSpecifierOptions.self) { + // Parse a layout constraint. + let specifier = self.eat(handle) + + let unexpectedBeforeLeftParen: RawUnexpectedNodesSyntax? + let leftParen: RawTokenSyntax? + let size: RawTokenSyntax? + let comma: RawTokenSyntax? + let alignment: RawTokenSyntax? + let unexpectedBeforeRightParen: RawUnexpectedNodesSyntax? + let rightParen: RawTokenSyntax? + + var hasArguments: Bool { + switch layoutSpecifier { + case ._Trivial, + ._TrivialAtMost, + ._TrivialStride: + return true + + case ._UnknownLayout, + ._RefCountedObject, + ._NativeRefCountedObject, + ._Class, + ._NativeClass, + ._BridgeObject: + return false + } } - } - // Unlike the other layout constraints, _Trivial's argument list - // is optional. - if hasArguments && (layoutSpecifier != ._Trivial || self.at(.leftParen)) { - (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen) - size = self.expectWithoutRecovery(.integerLiteral) - comma = self.consume(if: .comma) - if comma != nil { - alignment = self.expectWithoutRecovery(.integerLiteral) + // Unlike the other layout constraints, _Trivial's argument list + // is optional. + if hasArguments && (layoutSpecifier != ._Trivial || self.at(.leftParen)) { + (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen) + size = self.expectWithoutRecovery(.integerLiteral) + comma = self.consume(if: .comma) + if comma != nil { + alignment = self.expectWithoutRecovery(.integerLiteral) + } else { + alignment = nil + } + (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen) } else { + unexpectedBeforeLeftParen = nil + leftParen = nil + size = nil + comma = nil alignment = nil + unexpectedBeforeRightParen = nil + rightParen = nil } - (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen) + + requirement = .layoutRequirement( + RawLayoutRequirementSyntax( + type: firstType, + colon: colon, + layoutSpecifier: specifier, + unexpectedBeforeLeftParen, + leftParen: leftParen, + size: size, + comma: comma, + alignment: alignment, + unexpectedBeforeRightParen, + rightParen: rightParen, + arena: self.arena + ) + ) } else { - unexpectedBeforeLeftParen = nil - leftParen = nil - size = nil - comma = nil - alignment = nil - unexpectedBeforeRightParen = nil - rightParen = nil + // Parse the protocol or composition. + let secondType = self.parseType() + requirement = .conformanceRequirement( + RawConformanceRequirementSyntax( + leftType: firstType, + colon: colon, + rightType: secondType, + arena: self.arena + ) + ) } - - requirement = .layoutRequirement( - RawLayoutRequirementSyntax( - type: firstType, - colon: colon, - layoutSpecifier: specifier, - unexpectedBeforeLeftParen, - leftParen: leftParen, - size: size, - comma: comma, - alignment: alignment, - unexpectedBeforeRightParen, - rightParen: rightParen, + case (.binaryOperator, let handle)?, + (.postfixOperator, let handle)?, + (.prefixOperator, let handle)?: + let equal = self.eat(handle) + let secondArgument = self.parseSameTypeRightType() + requirement = .sameTypeRequirement( + RawSameTypeRequirementSyntax( + leftType: firstArgument, + equal: equal, + rightType: secondArgument, arena: self.arena ) ) - } else { - // Parse the protocol or composition. - let secondType = self.parseType() - requirement = .conformanceRequirement( - RawConformanceRequirementSyntax( - leftType: firstType, - colon: colon, - rightType: secondType, + case nil: + requirement = .sameTypeRequirement( + RawSameTypeRequirementSyntax( + leftType: firstArgument, + equal: RawTokenSyntax(missing: .binaryOperator, text: "==", arena: self.arena), + rightType: .type(RawTypeSyntax(RawMissingTypeSyntax(arena: self.arena))), arena: self.arena ) ) } - case (.binaryOperator, let handle)?, - (.postfixOperator, let handle)?, - (.prefixOperator, let handle)?: - let equal = self.eat(handle) - let secondType = self.parseType() - requirement = .sameTypeRequirement( - RawSameTypeRequirementSyntax( - leftType: firstType, - equal: equal, - rightType: secondType, - arena: self.arena - ) - ) - case nil: - requirement = .sameTypeRequirement( - RawSameTypeRequirementSyntax( - leftType: firstType, - equal: RawTokenSyntax(missing: .binaryOperator, text: "==", arena: self.arena), - rightType: RawMissingTypeSyntax(arena: self.arena), - arena: self.arena - ) - ) } keepGoing = self.consume(if: .comma) diff --git a/Sources/SwiftParser/Names.swift b/Sources/SwiftParser/Names.swift index 7c9523190ac..98acb48243e 100644 --- a/Sources/SwiftParser/Names.swift +++ b/Sources/SwiftParser/Names.swift @@ -193,7 +193,7 @@ extension Parser { let (unexpectedBeforeName, name) = self.expect(anyIn: IdentifierTypeSyntax.NameOptions.self, default: .identifier) let generics: RawGenericArgumentClauseSyntax? - if self.atContextualPunctuator("<") { + if self.at(prefix: "<") { generics = self.parseGenericArguments() } else { generics = nil @@ -229,7 +229,7 @@ extension Parser { default: .identifier ) let generics: RawGenericArgumentClauseSyntax? - if self.atContextualPunctuator("<") { + if self.at(prefix: "<") { generics = self.parseGenericArguments() } else { generics = nil diff --git a/Sources/SwiftParser/Types.swift b/Sources/SwiftParser/Types.swift index 16198f9bad2..ab61c1c2bb6 100644 --- a/Sources/SwiftParser/Types.swift +++ b/Sources/SwiftParser/Types.swift @@ -295,7 +295,7 @@ extension Parser { name = missingToken(.identifier) } let generics: RawGenericArgumentClauseSyntax? - if self.atContextualPunctuator("<") { + if self.at(prefix: "<") { generics = self.parseGenericArguments() } else { generics = nil @@ -368,7 +368,7 @@ extension Parser { let (unexpectedBeforeName, name) = self.expect(anyIn: IdentifierTypeSyntax.NameOptions.self, default: .identifier) let generics: RawGenericArgumentClauseSyntax? - if self.atContextualPunctuator("<") { + if self.at(prefix: "<") { generics = self.parseGenericArguments() } else { generics = nil @@ -416,14 +416,16 @@ extension Parser { var keepGoing: RawTokenSyntax? = nil var loopProgress = LoopProgressCondition() repeat { - let type = self.parseType() - if arguments.isEmpty && type.is(RawMissingTypeSyntax.self) { + let argument = self.parseGenericArgumentType() + + if arguments.isEmpty, argument.raw.is(RawMissingTypeSyntax.self) { break } + keepGoing = self.consume(if: .comma) arguments.append( RawGenericArgumentSyntax( - argument: type, + argument: argument, trailingComma: keepGoing, arena: self.arena ) @@ -446,6 +448,14 @@ extension Parser { arena: self.arena ) } + + mutating func parseGenericArgumentType() -> RawGenericArgumentSyntax.Argument { + if let valueType = self.parseValueType() { + return .expr(valueType) + } else { + return .type(self.parseType()) + } + } } extension Parser { @@ -685,9 +695,14 @@ extension Parser.Lookahead { switch self.currentToken { case TokenSpec(.Any): self.consumeAnyToken() - case TokenSpec(.prefixOperator) where self.currentToken.tokenText == "~": - self.consumeAnyToken() - fallthrough + case TokenSpec(.prefixOperator): + // '~Copyable' + if self.currentToken.tokenText == "~" { + self.consumeAnyToken() + fallthrough + } + + return false case TokenSpec(.Self), TokenSpec(.identifier): guard self.canParseTypeIdentifier() else { return false @@ -837,7 +852,7 @@ extension Parser.Lookahead { } mutating func canParseAsGenericArgumentList() -> Bool { - guard self.atContextualPunctuator("<") else { + guard self.at(prefix: "<"), !self.at(prefix: "<>") else { return false } @@ -857,9 +872,21 @@ extension Parser.Lookahead { if !self.at(prefix: ">") { var loopProgress = LoopProgressCondition() repeat { - guard self.canParseType() else { - return false + // A generic argument can either be a type or an integer literal (who is + // optionally negative). + if self.canParseType() { + continue + } else if self.currentToken.tokenText == "-", + self.peek(isAt: .integerLiteral) + { + self.consumeAnyToken() + self.consumeAnyToken() + continue + } else if self.consume(if: .integerLiteral) != nil { + continue } + + return false // Parse the comma, if the list continues. } while self.consume(if: .comma) != nil && self.hasProgressed(&loopProgress) } @@ -1106,6 +1133,47 @@ extension Parser { } } +extension Parser { + mutating func parseValueType() -> RawExprSyntax? { + // If the 'ValueGenerics' experimental feature hasn't been added, then don't + // attempt to parse values as types. + guard self.experimentalFeatures.contains(.valueGenerics) else { + return nil + } + + // Eat any '-' preceding integer literals. + var minusSign: RawTokenSyntax? = nil + if self.atContextualPunctuator("-"), + self.peek(isAt: .integerLiteral) + { + minusSign = self.consumeIfContextualPunctuator("-", remapping: .prefixOperator) + } + + // Attempt to parse values first. Right now the only value that can be parsed + // as a type are integers. + if let integerLiteral = self.consume(if: .integerLiteral) { + let integerExpr = RawIntegerLiteralExprSyntax( + literal: integerLiteral, + arena: self.arena + ) + + guard let minusSign else { + return RawExprSyntax(integerExpr) + } + + return RawExprSyntax( + RawPrefixOperatorExprSyntax( + operator: minusSign, + expression: integerExpr, + arena: self.arena + ) + ) + } + + return nil + } +} + extension Lexer.Lexeme { var isGenericTypeDisambiguatingToken: Bool { switch self.rawTokenKind { diff --git a/Sources/SwiftParser/generated/ExperimentalFeatures.swift b/Sources/SwiftParser/generated/ExperimentalFeatures.swift index 63fe9639d8f..24aa8dce00b 100644 --- a/Sources/SwiftParser/generated/ExperimentalFeatures.swift +++ b/Sources/SwiftParser/generated/ExperimentalFeatures.swift @@ -41,4 +41,7 @@ extension Parser.ExperimentalFeatures { /// Whether to enable the parsing of CoroutineAccessors. public static let coroutineAccessors = Self (rawValue: 1 << 5) + + /// Whether to enable the parsing of ValueGenerics. + public static let valueGenerics = Self (rawValue: 1 << 6) } diff --git a/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift b/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift index fb3cd840904..c0b55967d15 100644 --- a/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift +++ b/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift @@ -3450,7 +3450,7 @@ extension GenericArgumentSyntax { } @available(*, deprecated, renamed: "argument") - public var argumentType: TypeSyntax { + public var argumentType: Argument { get { return argument } @@ -3474,7 +3474,7 @@ extension GenericArgumentSyntax { public init( leadingTrivia: Trivia? = nil, _ unexpectedBeforeArgumentType: UnexpectedNodesSyntax? = nil, - argumentType: some TypeSyntaxProtocol, + argumentType: Argument, _ unexpectedBetweenArgumentTypeAndTrailingComma: UnexpectedNodesSyntax? = nil, trailingComma: TokenSyntax? = nil, _ unexpectedAfterTrailingComma: UnexpectedNodesSyntax? = nil, @@ -6615,7 +6615,7 @@ extension SameTypeRequirementSyntax { } @available(*, deprecated, renamed: "leftType") - public var leftTypeIdentifier: TypeSyntax { + public var leftTypeIdentifier: LeftType { get { return leftType } @@ -6655,7 +6655,7 @@ extension SameTypeRequirementSyntax { } @available(*, deprecated, renamed: "rightType") - public var rightTypeIdentifier: TypeSyntax { + public var rightTypeIdentifier: RightType { get { return rightType } @@ -6679,11 +6679,11 @@ extension SameTypeRequirementSyntax { public init( leadingTrivia: Trivia? = nil, _ unexpectedBeforeLeftTypeIdentifier: UnexpectedNodesSyntax? = nil, - leftTypeIdentifier: some TypeSyntaxProtocol, + leftTypeIdentifier: LeftType, _ unexpectedBetweenLeftTypeIdentifierAndEqualityToken: UnexpectedNodesSyntax? = nil, equalityToken: TokenSyntax, _ unexpectedBetweenEqualityTokenAndRightTypeIdentifier: UnexpectedNodesSyntax? = nil, - rightTypeIdentifier: some TypeSyntaxProtocol, + rightTypeIdentifier: RightType, _ unexpectedAfterRightTypeIdentifier: UnexpectedNodesSyntax? = nil, trailingTrivia: Trivia? = nil ) { diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift index d9ae3a324d8..e9972b6df1a 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift @@ -146,6 +146,46 @@ public struct RawGenericArgumentListSyntax: RawSyntaxNodeProtocol { @_spi(RawSyntax) public struct RawGenericArgumentSyntax: RawSyntaxNodeProtocol { + public enum Argument: RawSyntaxNodeProtocol { + case type(RawTypeSyntax) + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + case expr(RawExprSyntax) + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + RawTypeSyntax.isKindOf(raw) || RawExprSyntax.isKindOf(raw) + } + + public var raw: RawSyntax { + switch self { + case .type(let node): + return node.raw + case .expr(let node): + return node.raw + } + } + + public init?(_ node: __shared some RawSyntaxNodeProtocol) { + if let node = node.as(RawTypeSyntax.self) { + self = .type(node) + } else if let node = node.as(RawExprSyntax.self) { + self = .expr(node) + } else { + return nil + } + } + + public init(type: some RawTypeSyntaxNodeProtocol) { + self = .type(RawTypeSyntax(type)) + } + + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public init(expr: some RawExprSyntaxNodeProtocol) { + self = .expr(RawExprSyntax(expr)) + } + } + @_spi(RawSyntax) public var layoutView: RawSyntaxLayoutView { return raw.layoutView! @@ -175,7 +215,7 @@ public struct RawGenericArgumentSyntax: RawSyntaxNodeProtocol { public init( _ unexpectedBeforeArgument: RawUnexpectedNodesSyntax? = nil, - argument: some RawTypeSyntaxNodeProtocol, + argument: Argument, _ unexpectedBetweenArgumentAndTrailingComma: RawUnexpectedNodesSyntax? = nil, trailingComma: RawTokenSyntax?, _ unexpectedAfterTrailingComma: RawUnexpectedNodesSyntax? = nil, @@ -197,8 +237,8 @@ public struct RawGenericArgumentSyntax: RawSyntaxNodeProtocol { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } - public var argument: RawTypeSyntax { - layoutView.children[1].map(RawTypeSyntax.init(raw:))! + public var argument: RawSyntax { + layoutView.children[1]! } public var unexpectedBetweenArgumentAndTrailingComma: RawUnexpectedNodesSyntax? { diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift index a2574cdd83e..fb8d2038f1a 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesQRS.swift @@ -357,6 +357,86 @@ public struct RawReturnStmtSyntax: RawStmtSyntaxNodeProtocol { @_spi(RawSyntax) public struct RawSameTypeRequirementSyntax: RawSyntaxNodeProtocol { + public enum LeftType: RawSyntaxNodeProtocol { + case type(RawTypeSyntax) + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + case expr(RawExprSyntax) + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + RawTypeSyntax.isKindOf(raw) || RawExprSyntax.isKindOf(raw) + } + + public var raw: RawSyntax { + switch self { + case .type(let node): + return node.raw + case .expr(let node): + return node.raw + } + } + + public init?(_ node: __shared some RawSyntaxNodeProtocol) { + if let node = node.as(RawTypeSyntax.self) { + self = .type(node) + } else if let node = node.as(RawExprSyntax.self) { + self = .expr(node) + } else { + return nil + } + } + + public init(type: some RawTypeSyntaxNodeProtocol) { + self = .type(RawTypeSyntax(type)) + } + + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public init(expr: some RawExprSyntaxNodeProtocol) { + self = .expr(RawExprSyntax(expr)) + } + } + + public enum RightType: RawSyntaxNodeProtocol { + case type(RawTypeSyntax) + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + case expr(RawExprSyntax) + + public static func isKindOf(_ raw: RawSyntax) -> Bool { + RawTypeSyntax.isKindOf(raw) || RawExprSyntax.isKindOf(raw) + } + + public var raw: RawSyntax { + switch self { + case .type(let node): + return node.raw + case .expr(let node): + return node.raw + } + } + + public init?(_ node: __shared some RawSyntaxNodeProtocol) { + if let node = node.as(RawTypeSyntax.self) { + self = .type(node) + } else if let node = node.as(RawExprSyntax.self) { + self = .expr(node) + } else { + return nil + } + } + + public init(type: some RawTypeSyntaxNodeProtocol) { + self = .type(RawTypeSyntax(type)) + } + + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public init(expr: some RawExprSyntaxNodeProtocol) { + self = .expr(RawExprSyntax(expr)) + } + } + @_spi(RawSyntax) public var layoutView: RawSyntaxLayoutView { return raw.layoutView! @@ -386,11 +466,11 @@ public struct RawSameTypeRequirementSyntax: RawSyntaxNodeProtocol { public init( _ unexpectedBeforeLeftType: RawUnexpectedNodesSyntax? = nil, - leftType: some RawTypeSyntaxNodeProtocol, + leftType: LeftType, _ unexpectedBetweenLeftTypeAndEqual: RawUnexpectedNodesSyntax? = nil, equal: RawTokenSyntax, _ unexpectedBetweenEqualAndRightType: RawUnexpectedNodesSyntax? = nil, - rightType: some RawTypeSyntaxNodeProtocol, + rightType: RightType, _ unexpectedAfterRightType: RawUnexpectedNodesSyntax? = nil, arena: __shared SyntaxArena ) { @@ -412,8 +492,8 @@ public struct RawSameTypeRequirementSyntax: RawSyntaxNodeProtocol { layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:)) } - public var leftType: RawTypeSyntax { - layoutView.children[1].map(RawTypeSyntax.init(raw:))! + public var leftType: RawSyntax { + layoutView.children[1]! } public var unexpectedBetweenLeftTypeAndEqual: RawUnexpectedNodesSyntax? { @@ -428,8 +508,8 @@ public struct RawSameTypeRequirementSyntax: RawSyntaxNodeProtocol { layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:)) } - public var rightType: RawTypeSyntax { - layoutView.children[5].map(RawTypeSyntax.init(raw:))! + public var rightType: RawSyntax { + layoutView.children[5]! } public var unexpectedAfterRightType: RawUnexpectedNodesSyntax? { diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index a5430c16f4a..55706f39f4c 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -1335,7 +1335,8 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { case .genericArgument: assert(layout.count == 5) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 1, verify(layout[1], as: RawTypeSyntax.self)) + assertAnyHasNoError(kind, 1, [ + verify(layout[1], as: RawSyntax.self)]) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.comma)])) assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) @@ -2261,11 +2262,13 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { case .sameTypeRequirement: assert(layout.count == 7) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 1, verify(layout[1], as: RawTypeSyntax.self)) + assertAnyHasNoError(kind, 1, [ + verify(layout[1], as: RawSyntax.self)]) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.binaryOperator), .tokenKind(.prefixOperator), .tokenKind(.postfixOperator)])) assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 5, verify(layout[5], as: RawTypeSyntax.self)) + assertAnyHasNoError(kind, 5, [ + verify(layout[5], as: RawSyntax.self)]) assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self)) case .sequenceExpr: assert(layout.count == 3) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift index 435fb46b38d..f71bcae8e42 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift @@ -194,13 +194,103 @@ public struct GenericArgumentClauseSyntax: SyntaxProtocol, SyntaxHashable, _Leaf /// ### Children /// -/// - `argument`: ``TypeSyntax`` +/// - `argument`: (``TypeSyntax`` | ``ExprSyntax``) /// - `trailingComma`: `,`? /// /// ### Contained in /// /// - ``GenericArgumentListSyntax`` public struct GenericArgumentSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNodeProtocol { + public enum Argument: SyntaxChildChoices, SyntaxHashable { + case type(TypeSyntax) + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + case expr(ExprSyntax) + + public var _syntaxNode: Syntax { + switch self { + case .type(let node): + return node._syntaxNode + case .expr(let node): + return node._syntaxNode + } + } + + public init(_ node: some TypeSyntaxProtocol) { + self = .type(TypeSyntax(node)) + } + + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public init(_ node: some ExprSyntaxProtocol) { + self = .expr(ExprSyntax(node)) + } + + public init?(_ node: __shared some SyntaxProtocol) { + if let node = node.as(TypeSyntax.self) { + self = .type(node) + } else if let node = node.as(ExprSyntax.self) { + self = .expr(node) + } else { + return nil + } + } + + public static var structure: SyntaxNodeStructure { + return .choices([.node(TypeSyntax.self), .node(ExprSyntax.self)]) + } + + /// Checks if the current syntax node can be cast to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + public func `is`(_ syntaxType: (some TypeSyntaxProtocol).Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type, or `nil` if the cast fails. + public func `as`<S: TypeSyntaxProtocol>(_ syntaxType: S.Type) -> S? { + return S.init(self) + } + + /// Force-casts the current syntax node to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + public func cast<S: TypeSyntaxProtocol>(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + + /// Checks if the current syntax node can be cast to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func `is`(_ syntaxType: (some ExprSyntaxProtocol).Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type, or `nil` if the cast fails. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func `as`<S: ExprSyntaxProtocol>(_ syntaxType: S.Type) -> S? { + return S.init(self) + } + + /// Force-casts the current syntax node to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func cast<S: ExprSyntaxProtocol>(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + } + public let _syntaxNode: Syntax public init?(_ node: __shared some SyntaxProtocol) { @@ -212,11 +302,12 @@ public struct GenericArgumentSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntax /// - Parameters: /// - 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. + /// - argument: The argument type for a generic argument. This can either be a regular type argument or an expression for value generics. /// - 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( leadingTrivia: Trivia? = nil, _ unexpectedBeforeArgument: UnexpectedNodesSyntax? = nil, - argument: some TypeSyntaxProtocol, + argument: Argument, _ unexpectedBetweenArgumentAndTrailingComma: UnexpectedNodesSyntax? = nil, trailingComma: TokenSyntax? = nil, _ unexpectedAfterTrailingComma: UnexpectedNodesSyntax? = nil, @@ -258,9 +349,10 @@ public struct GenericArgumentSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntax } } - public var argument: TypeSyntax { + /// The argument type for a generic argument. This can either be a regular type argument or an expression for value generics. + public var argument: Argument { get { - return Syntax(self).child(at: 1)!.cast(TypeSyntax.self) + return Syntax(self).child(at: 1)!.cast(Argument.self) } set(value) { self = Syntax(self).replacingChild(at: 1, with: Syntax(value), arena: SyntaxArena()).cast(GenericArgumentSyntax.self) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift index 87750e981a9..add1bca1a9f 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesQRS.swift @@ -626,14 +626,194 @@ public struct ReturnStmtSyntax: StmtSyntaxProtocol, SyntaxHashable, _LeafStmtSyn /// ### Children /// -/// - `leftType`: ``TypeSyntax`` +/// - `leftType`: (``TypeSyntax`` | ``ExprSyntax``) /// - `equal`: (`<binaryOperator>` | `<prefixOperator>` | `<postfixOperator>`) -/// - `rightType`: ``TypeSyntax`` +/// - `rightType`: (``TypeSyntax`` | ``ExprSyntax``) /// /// ### Contained in /// /// - ``GenericRequirementSyntax``.``GenericRequirementSyntax/requirement`` public struct SameTypeRequirementSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNodeProtocol { + public enum LeftType: SyntaxChildChoices, SyntaxHashable { + case type(TypeSyntax) + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + case expr(ExprSyntax) + + public var _syntaxNode: Syntax { + switch self { + case .type(let node): + return node._syntaxNode + case .expr(let node): + return node._syntaxNode + } + } + + public init(_ node: some TypeSyntaxProtocol) { + self = .type(TypeSyntax(node)) + } + + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public init(_ node: some ExprSyntaxProtocol) { + self = .expr(ExprSyntax(node)) + } + + public init?(_ node: __shared some SyntaxProtocol) { + if let node = node.as(TypeSyntax.self) { + self = .type(node) + } else if let node = node.as(ExprSyntax.self) { + self = .expr(node) + } else { + return nil + } + } + + public static var structure: SyntaxNodeStructure { + return .choices([.node(TypeSyntax.self), .node(ExprSyntax.self)]) + } + + /// Checks if the current syntax node can be cast to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + public func `is`(_ syntaxType: (some TypeSyntaxProtocol).Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type, or `nil` if the cast fails. + public func `as`<S: TypeSyntaxProtocol>(_ syntaxType: S.Type) -> S? { + return S.init(self) + } + + /// Force-casts the current syntax node to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + public func cast<S: TypeSyntaxProtocol>(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + + /// Checks if the current syntax node can be cast to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func `is`(_ syntaxType: (some ExprSyntaxProtocol).Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type, or `nil` if the cast fails. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func `as`<S: ExprSyntaxProtocol>(_ syntaxType: S.Type) -> S? { + return S.init(self) + } + + /// Force-casts the current syntax node to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func cast<S: ExprSyntaxProtocol>(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + } + + public enum RightType: SyntaxChildChoices, SyntaxHashable { + case type(TypeSyntax) + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + case expr(ExprSyntax) + + public var _syntaxNode: Syntax { + switch self { + case .type(let node): + return node._syntaxNode + case .expr(let node): + return node._syntaxNode + } + } + + public init(_ node: some TypeSyntaxProtocol) { + self = .type(TypeSyntax(node)) + } + + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public init(_ node: some ExprSyntaxProtocol) { + self = .expr(ExprSyntax(node)) + } + + public init?(_ node: __shared some SyntaxProtocol) { + if let node = node.as(TypeSyntax.self) { + self = .type(node) + } else if let node = node.as(ExprSyntax.self) { + self = .expr(node) + } else { + return nil + } + } + + public static var structure: SyntaxNodeStructure { + return .choices([.node(TypeSyntax.self), .node(ExprSyntax.self)]) + } + + /// Checks if the current syntax node can be cast to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + public func `is`(_ syntaxType: (some TypeSyntaxProtocol).Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type, or `nil` if the cast fails. + public func `as`<S: TypeSyntaxProtocol>(_ syntaxType: S.Type) -> S? { + return S.init(self) + } + + /// Force-casts the current syntax node to the type conforming to the ``TypeSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + public func cast<S: TypeSyntaxProtocol>(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + + /// Checks if the current syntax node can be cast to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: `true` if the node can be cast, `false` otherwise. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func `is`(_ syntaxType: (some ExprSyntaxProtocol).Type) -> Bool { + return self.as(syntaxType) != nil + } + + /// Attempts to cast the current syntax node to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type, or `nil` if the cast fails. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func `as`<S: ExprSyntaxProtocol>(_ syntaxType: S.Type) -> S? { + return S.init(self) + } + + /// Force-casts the current syntax node to the type conforming to the ``ExprSyntaxProtocol`` protocol. + /// + /// - Returns: An instance of the specialized type. + /// - Warning: This function will crash if the cast is not possible. Use `as` to safely attempt a cast. + /// - Note: Requires experimental feature `valueGenerics`. + @_spi(ExperimentalLanguageFeatures) + public func cast<S: ExprSyntaxProtocol>(_ syntaxType: S.Type) -> S { + return self.as(S.self)! + } + } + public let _syntaxNode: Syntax public init?(_ node: __shared some SyntaxProtocol) { @@ -645,15 +825,17 @@ public struct SameTypeRequirementSyntax: SyntaxProtocol, SyntaxHashable, _LeafSy /// - Parameters: /// - 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. + /// - leftType: The left hand side type for a same type requirement. This can either be a regular type argument or an expression for value generics. + /// - rightType: The right hand side type for a same type requirement. This can either be a regular type argument or an expression for value generics. /// - 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( leadingTrivia: Trivia? = nil, _ unexpectedBeforeLeftType: UnexpectedNodesSyntax? = nil, - leftType: some TypeSyntaxProtocol, + leftType: LeftType, _ unexpectedBetweenLeftTypeAndEqual: UnexpectedNodesSyntax? = nil, equal: TokenSyntax, _ unexpectedBetweenEqualAndRightType: UnexpectedNodesSyntax? = nil, - rightType: some TypeSyntaxProtocol, + rightType: RightType, _ unexpectedAfterRightType: UnexpectedNodesSyntax? = nil, trailingTrivia: Trivia? = nil ) { @@ -697,9 +879,10 @@ public struct SameTypeRequirementSyntax: SyntaxProtocol, SyntaxHashable, _LeafSy } } - public var leftType: TypeSyntax { + /// The left hand side type for a same type requirement. This can either be a regular type argument or an expression for value generics. + public var leftType: LeftType { get { - return Syntax(self).child(at: 1)!.cast(TypeSyntax.self) + return Syntax(self).child(at: 1)!.cast(LeftType.self) } set(value) { self = Syntax(self).replacingChild(at: 1, with: Syntax(value), arena: SyntaxArena()).cast(SameTypeRequirementSyntax.self) @@ -739,9 +922,10 @@ public struct SameTypeRequirementSyntax: SyntaxProtocol, SyntaxHashable, _LeafSy } } - public var rightType: TypeSyntax { + /// The right hand side type for a same type requirement. This can either be a regular type argument or an expression for value generics. + public var rightType: RightType { get { - return Syntax(self).child(at: 5)!.cast(TypeSyntax.self) + return Syntax(self).child(at: 5)!.cast(RightType.self) } set(value) { self = Syntax(self).replacingChild(at: 5, with: Syntax(value), arena: SyntaxArena()).cast(SameTypeRequirementSyntax.self) diff --git a/Sources/SwiftSyntaxMacroExpansion/MacroReplacement.swift b/Sources/SwiftSyntaxMacroExpansion/MacroReplacement.swift index 23961c8ec5c..1f991daef70 100644 --- a/Sources/SwiftSyntaxMacroExpansion/MacroReplacement.swift +++ b/Sources/SwiftSyntaxMacroExpansion/MacroReplacement.swift @@ -262,13 +262,13 @@ private final class MacroExpansionRewriter: SyntaxRewriter { let parameterReplacements: [DeclReferenceExprSyntax: Int] let arguments: [ExprSyntax] let genericParameterReplacements: [GenericArgumentSyntax: Int] - let genericArguments: [TypeSyntax] + let genericArguments: [GenericArgumentSyntax.Argument] init( parameterReplacements: [DeclReferenceExprSyntax: Int], arguments: [ExprSyntax], genericReplacements: [GenericArgumentSyntax: Int], - genericArguments: [TypeSyntax] + genericArguments: [GenericArgumentSyntax.Argument] ) { self.parameterReplacements = parameterReplacements self.arguments = arguments @@ -331,7 +331,7 @@ extension MacroDeclSyntax { }, uniquingKeysWith: { l, r in l } ) - let genericArguments: [TypeSyntax] = + let genericArguments: [GenericArgumentSyntax.Argument] = genericArgumentList?.arguments.map { $0.argument } ?? [] let rewriter = MacroExpansionRewriter( diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index 345ca2739e9..50a651948b2 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -2715,8 +2715,7 @@ final class DeclarationTests: ParserTestCase { genericArgumentClause: GenericArgumentClauseSyntax( arguments: GenericArgumentListSyntax([ GenericArgumentSyntax( - argument: - IdentifierTypeSyntax(name: .identifier("T")) + argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("T")))) ) ]) ) diff --git a/Tests/SwiftParserTest/PatternTests.swift b/Tests/SwiftParserTest/PatternTests.swift index a55e76a19ec..84bfb763183 100644 --- a/Tests/SwiftParserTest/PatternTests.swift +++ b/Tests/SwiftParserTest/PatternTests.swift @@ -27,7 +27,7 @@ final class PatternTests: ParserTestCase { expression: DeclReferenceExprSyntax(baseName: .identifier("E")), genericArgumentClause: GenericArgumentClauseSyntax( arguments: .init([ - .init(argument: IdentifierTypeSyntax(name: .identifier("Int"))) + .init(argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("Int"))))) ]) ) ), diff --git a/Tests/SwiftParserTest/StatementTests.swift b/Tests/SwiftParserTest/StatementTests.swift index cd82807bb01..13da04c7c70 100644 --- a/Tests/SwiftParserTest/StatementTests.swift +++ b/Tests/SwiftParserTest/StatementTests.swift @@ -376,9 +376,13 @@ final class StatementTests: ParserTestCase { leftAngle: .leftAngleToken(), arguments: GenericArgumentListSyntax([ GenericArgumentSyntax( - argument: OptionalTypeSyntax( - wrappedType: IdentifierTypeSyntax(name: .identifier("String")), - questionMark: .postfixQuestionMarkToken() + argument: .type( + TypeSyntax( + OptionalTypeSyntax( + wrappedType: IdentifierTypeSyntax(name: .identifier("String")), + questionMark: .postfixQuestionMarkToken() + ) + ) ) ) ]), @@ -398,7 +402,7 @@ final class StatementTests: ParserTestCase { leftAngle: .leftAngleToken(), arguments: GenericArgumentListSyntax([ GenericArgumentSyntax( - argument: IdentifierTypeSyntax(name: .keyword(.Any)) + argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .keyword(.Any)))) ) ]), rightAngle: .rightAngleToken() diff --git a/Tests/SwiftParserTest/TypeMemberTests.swift b/Tests/SwiftParserTest/TypeMemberTests.swift index 9e0e123ccc1..236e6af7ecb 100644 --- a/Tests/SwiftParserTest/TypeMemberTests.swift +++ b/Tests/SwiftParserTest/TypeMemberTests.swift @@ -150,7 +150,7 @@ final class TypeMemberTests: ParserTestCase { \.genericArgumentClause, GenericArgumentClauseSyntax( arguments: .init([ - GenericArgumentSyntax(argument: IdentifierTypeSyntax(name: .identifier("W"))) + GenericArgumentSyntax(argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("W"))))) ]) ) ), diff --git a/Tests/SwiftParserTest/TypeTests.swift b/Tests/SwiftParserTest/TypeTests.swift index 0e8bd40d38f..fa679445f37 100644 --- a/Tests/SwiftParserTest/TypeTests.swift +++ b/Tests/SwiftParserTest/TypeTests.swift @@ -260,8 +260,12 @@ final class TypeTests: ParserTestCase { genericArgumentClause: GenericArgumentClauseSyntax( arguments: GenericArgumentListSyntax([ GenericArgumentSyntax( - argument: IdentifierTypeSyntax( - name: .identifier("Foo") + argument: .type( + TypeSyntax( + IdentifierTypeSyntax( + name: .identifier("Foo") + ) + ) ) ) ]) diff --git a/Tests/SwiftParserTest/ValueGenericsTests.swift b/Tests/SwiftParserTest/ValueGenericsTests.swift index 482522a58a7..cc0620b06d5 100644 --- a/Tests/SwiftParserTest/ValueGenericsTests.swift +++ b/Tests/SwiftParserTest/ValueGenericsTests.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +@_spi(ExperimentalLanguageFeatures) import SwiftParser import SwiftSyntax import XCTest @@ -102,4 +103,207 @@ final class ValueGenericsTests: ParserTestCase { """ ) } + + func testIntegers() { + assertParse( + """ + let x: 1️⃣123 + """, + diagnostics: [ + DiagnosticSpec( + message: "expected type in type annotation", + fixIts: ["insert type"] + ), + DiagnosticSpec( + message: "expected '=' in variable", + fixIts: ["insert '='"] + ), + ], + fixedSource: """ + let x: <#type#> = 123 + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x: Generic<123> + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x: Generic<-123> + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x = Generic<123>.self + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x = Generic<-123>.self + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x = Generic<123, Int>.self + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x = Generic<-123, Int>.self + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x = Generic<Int, 123>.self + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + let x: Generic<Int, -123>.self + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + typealias One = 1️⃣1 + """, + diagnostics: [ + DiagnosticSpec( + message: "expected type in typealias declaration", + fixIts: ["insert type"] + ) + ], + fixedSource: """ + typealias One = <#type#>1 + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where N == 123 {} + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where 123 == N {} + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where N == -123 {} + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where -123 == N {} + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where N: 1️⃣123 {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected type in conformance requirement", + fixIts: ["insert type"] + ), + DiagnosticSpec( + message: "unexpected code '123' in extension" + ), + ], + fixedSource: """ + extension Vector where N: <#type#> 123 {} + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where N: 1️⃣-123 {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected type in conformance requirement", + fixIts: ["insert type"] + ), + DiagnosticSpec( + message: "unexpected code '-123' in extension" + ), + ], + fixedSource: """ + extension Vector where N: <#type#> -123 {} + """, + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where 1231️⃣: N {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected ':' or '==' to indicate a conformance or same-type requirement" + ), + DiagnosticSpec( + message: "unexpected code ': N' in extension" + ), + ], + experimentalFeatures: .valueGenerics + ) + + assertParse( + """ + extension Vector where -1231️⃣: N {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected ':' or '==' to indicate a conformance or same-type requirement" + ), + DiagnosticSpec( + message: "unexpected code ': N' in extension" + ), + ], + experimentalFeatures: .valueGenerics + ) + + assertParse( + "func foo() -> (1️⃣-1) X", + diagnostics: [ + DiagnosticSpec( + message: "expected type in tuple type", + fixIts: ["insert type"] + ), + DiagnosticSpec(message: "unexpected code '-1' in tuple type"), + ], + fixedSource: "func foo() -> (<#type#>-1) X", + experimentalFeatures: [.valueGenerics] + ) + } } diff --git a/Tests/SwiftParserTest/translated/GenericDisambiguationTests.swift b/Tests/SwiftParserTest/translated/GenericDisambiguationTests.swift index 98d5849cfd8..925a007e567 100644 --- a/Tests/SwiftParserTest/translated/GenericDisambiguationTests.swift +++ b/Tests/SwiftParserTest/translated/GenericDisambiguationTests.swift @@ -91,11 +91,11 @@ final class GenericDisambiguationTests: ParserTestCase { """, substructure: GenericArgumentListSyntax([ GenericArgumentSyntax( - argument: IdentifierTypeSyntax(name: .identifier("b")), + argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("b")))), trailingComma: .commaToken() ), GenericArgumentSyntax( - argument: IdentifierTypeSyntax(name: .identifier("c")) + argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("c")))) ), ]) ) @@ -109,11 +109,11 @@ final class GenericDisambiguationTests: ParserTestCase { """, substructure: GenericArgumentListSyntax([ GenericArgumentSyntax( - argument: IdentifierTypeSyntax(name: .identifier("b")), + argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("b")))), trailingComma: .commaToken() ), GenericArgumentSyntax( - argument: IdentifierTypeSyntax(name: .identifier("c")) + argument: .type(TypeSyntax(IdentifierTypeSyntax(name: .identifier("c")))) ), ]) )