diff --git a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift index f14f1de8e9d..b3d6e6dfa1e 100644 --- a/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift +++ b/CodeGeneration/Sources/SyntaxSupport/ExperimentalFeatures.swift @@ -23,6 +23,7 @@ public enum ExperimentalFeature: String, CaseIterable { case oldOwnershipOperatorSpellings case defaultIsolationPerFile case moduleSelector + case defaultGenerics /// The name of the feature as it is written in the compiler's `Features.def` file. public var featureName: String { @@ -47,6 +48,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "DefaultIsolationPerFile" case .moduleSelector: return "ModuleSelector" + case .defaultGenerics: + return "DefaultGenerics" } } @@ -73,6 +76,8 @@ public enum ExperimentalFeature: String, CaseIterable { return "set default actor isolation for a file" case .moduleSelector: return "Module selector syntax (`ModName::identifier`)" + case .defaultGenerics: + return "default generics" } } diff --git a/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift b/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift index c6254e9ebd1..668443d6f1b 100644 --- a/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift +++ b/CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift @@ -125,6 +125,13 @@ public let GENERIC_NODES: [Node] = [ nameForDiagnostics: "inherited type", isOptional: true ), + Child( + name: "initializer", + kind: .node(kind: .typeInitializerClause), + experimentalFeature: .defaultGenerics, + nameForDiagnostics: "default type", + isOptional: true, + ), Child( name: "trailingComma", kind: .token(choices: [.token(.comma)]), diff --git a/Release Notes/603.md b/Release Notes/603.md new file mode 100644 index 00000000000..fa61b3f938e --- /dev/null +++ b/Release Notes/603.md @@ -0,0 +1,24 @@ +# Swift Syntax 603 Release Notes + +## New APIs + +- `GenericParameterSyntax` now has a new `initializer` property. + - Description: Generic parameters can now optionally be passed a default type. The `initializer` is a `TypeInitializerSyntax` that captures both the `=` and the parsed `TypeSyntax`. + - Pull Request: https://github.com/swiftlang/swift-syntax/pull/3152 + +## API Behavior Changes + +## Deprecations + +## API-Incompatible Changes + +## Template + +- *Affected API or two word description* + - Description: *A 1-2 sentence description of the new/modified API* + - Issue: *If an issue exists for this change, a link to the issue* + - Pull Request: *Link to the pull request(s) that introduces this change* + - Migration steps: Steps that adopters of swift-syntax should take to move to the new API (required for deprecations and API-incompatible changes). + - Notes: *In case of deprecations or API-incompatible changes, the reason why this change was made and the suggested alternative* + +*Insert entries in chronological order, with newer entries at the bottom* diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift index 97e2c3e2c8b..5a9dd812082 100644 --- a/Sources/SwiftParser/Declarations.swift +++ b/Sources/SwiftParser/Declarations.swift @@ -675,6 +675,24 @@ extension Parser { unexpectedBeforeInherited = nil inherited = nil } + + // Parse the default type, if any. We only have defaults of regular + // type parameters, not parameter packs or value generics yet. + let defaultType: RawTypeInitializerClauseSyntax? + if self.experimentalFeatures.contains(.defaultGenerics), + specifier == nil, + let equal = self.consume(if: .equal) + { + let type = self.parseType() + defaultType = RawTypeInitializerClauseSyntax( + equal: equal, + value: type, + arena: self.arena + ) + } else { + defaultType = nil + } + keepGoing = self.consume(if: .comma) elements.append( RawGenericParameterSyntax( @@ -686,6 +704,7 @@ extension Parser { colon: colon, unexpectedBeforeInherited, inheritedType: inherited, + initializer: defaultType, trailingComma: keepGoing, arena: self.arena ) diff --git a/Sources/SwiftParser/generated/ExperimentalFeatures.swift b/Sources/SwiftParser/generated/ExperimentalFeatures.swift index 1c12c14a148..29bc7437c89 100644 --- a/Sources/SwiftParser/generated/ExperimentalFeatures.swift +++ b/Sources/SwiftParser/generated/ExperimentalFeatures.swift @@ -55,6 +55,9 @@ extension Parser.ExperimentalFeatures { /// Whether to enable the parsing of Module selector syntax (`ModName::identifier`). public static let moduleSelector = Self (rawValue: 1 << 9) + /// Whether to enable the parsing of default generics. + public static let defaultGenerics = Self (rawValue: 1 << 10) + /// Creates a new value representing the experimental feature with the /// given name, or returns nil if the name is not recognized. public init?(name: String) { @@ -79,6 +82,8 @@ extension Parser.ExperimentalFeatures { self = .defaultIsolationPerFile case "ModuleSelector": self = .moduleSelector + case "DefaultGenerics": + self = .defaultGenerics default: return nil } diff --git a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift index f047dc2cc51..1294c5ee333 100644 --- a/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift +++ b/Sources/SwiftParserDiagnostics/generated/ChildNameForDiagnostics.swift @@ -175,6 +175,8 @@ private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String? { return "name" case \GenericParameterSyntax.inheritedType: return "inherited type" + case \GenericParameterSyntax.initializer: + return "default type" case \GuardStmtSyntax.conditions: return "condition" case \GuardStmtSyntax.body: diff --git a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift index 7f199475e8b..7c7ea60224e 100644 --- a/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift +++ b/Sources/SwiftSyntax/generated/ChildNameForKeyPath.swift @@ -1596,8 +1596,12 @@ public func childName(_ keyPath: AnyKeyPath) -> String? { return "unexpectedBetweenColonAndInheritedType" case \GenericParameterSyntax.inheritedType: return "inheritedType" - case \GenericParameterSyntax.unexpectedBetweenInheritedTypeAndTrailingComma: - return "unexpectedBetweenInheritedTypeAndTrailingComma" + case \GenericParameterSyntax.unexpectedBetweenInheritedTypeAndInitializer: + return "unexpectedBetweenInheritedTypeAndInitializer" + case \GenericParameterSyntax.initializer: + return "initializer" + case \GenericParameterSyntax.unexpectedBetweenInitializerAndTrailingComma: + return "unexpectedBetweenInitializerAndTrailingComma" case \GenericParameterSyntax.trailingComma: return "trailingComma" case \GenericParameterSyntax.unexpectedAfterTrailingComma: diff --git a/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift b/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift index 1d82e4cbad3..acb8298040d 100644 --- a/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift +++ b/Sources/SwiftSyntax/generated/RenamedChildrenCompatibility.swift @@ -3648,6 +3648,15 @@ extension GenericParameterClauseSyntax { } extension GenericParameterSyntax { + public var unexpectedBetweenInheritedTypeAndTrailingComma: UnexpectedNodesSyntax? { + get { + return unexpectedBetweenInheritedTypeAndInitializer + } + set { + unexpectedBetweenInheritedTypeAndInitializer = newValue + } + } + @available(*, deprecated, renamed: "unexpectedBetweenAttributesAndSpecifier") public var unexpectedBetweenAttributesAndEachKeyword: UnexpectedNodesSyntax? { get { @@ -3678,7 +3687,45 @@ extension GenericParameterSyntax { } } - @available(*, deprecated, renamed: "init(leadingTrivia:_:attributes:_:specifier:_:name:_:colon:_:inheritedType:_:trailingComma:_:trailingTrivia:)") + public init( + leadingTrivia: Trivia? = nil, + _ unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil, + attributes: AttributeListSyntax = [], + _ unexpectedBetweenAttributesAndSpecifier: UnexpectedNodesSyntax? = nil, + specifier: TokenSyntax? = nil, + _ unexpectedBetweenSpecifierAndName: UnexpectedNodesSyntax? = nil, + name: TokenSyntax, + _ unexpectedBetweenNameAndColon: UnexpectedNodesSyntax? = nil, + colon: TokenSyntax? = nil, + _ unexpectedBetweenColonAndInheritedType: UnexpectedNodesSyntax? = nil, + inheritedType: (some TypeSyntaxProtocol)? = TypeSyntax?.none, + _ unexpectedBetweenInheritedTypeAndTrailingComma: UnexpectedNodesSyntax? = nil, + trailingComma: TokenSyntax? = nil, + _ unexpectedAfterTrailingComma: UnexpectedNodesSyntax? = nil, + trailingTrivia: Trivia? = nil + ) { + self.init( + leadingTrivia: leadingTrivia, + unexpectedBeforeAttributes, + attributes: attributes, + unexpectedBetweenAttributesAndSpecifier, + specifier: specifier, + unexpectedBetweenSpecifierAndName, + name: name, + unexpectedBetweenNameAndColon, + colon: colon, + unexpectedBetweenColonAndInheritedType, + inheritedType: inheritedType, + unexpectedBetweenInheritedTypeAndTrailingComma, + initializer: nil, + nil, + trailingComma: trailingComma, + unexpectedAfterTrailingComma, + trailingTrivia: trailingTrivia + ) + } + + @available(*, deprecated, renamed: "init(leadingTrivia:_:attributes:_:specifier:_:name:_:colon:_:inheritedType:_:initializer:_:trailingComma:_:trailingTrivia:)") @_disfavoredOverload public init( leadingTrivia: Trivia? = nil, @@ -3710,6 +3757,8 @@ extension GenericParameterSyntax { unexpectedBetweenColonAndInheritedType, inheritedType: inheritedType, unexpectedBetweenInheritedTypeAndTrailingComma, + initializer: nil, + nil, trailingComma: trailingComma, unexpectedAfterTrailingComma, trailingTrivia: trailingTrivia diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift index 76ca3886071..d8c434ff576 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxNodesGHI.swift @@ -435,13 +435,15 @@ public struct RawGenericParameterSyntax: RawSyntaxNodeProtocol { colon: RawTokenSyntax?, _ unexpectedBetweenColonAndInheritedType: RawUnexpectedNodesSyntax? = nil, inheritedType: RawTypeSyntax?, - _ unexpectedBetweenInheritedTypeAndTrailingComma: RawUnexpectedNodesSyntax? = nil, + _ unexpectedBetweenInheritedTypeAndInitializer: RawUnexpectedNodesSyntax? = nil, + initializer: RawTypeInitializerClauseSyntax?, + _ unexpectedBetweenInitializerAndTrailingComma: RawUnexpectedNodesSyntax? = nil, trailingComma: RawTokenSyntax?, _ unexpectedAfterTrailingComma: RawUnexpectedNodesSyntax? = nil, arena: __shared RawSyntaxArena ) { let raw = RawSyntax.makeLayout( - kind: .genericParameter, uninitializedCount: 13, arena: arena) { layout in + kind: .genericParameter, uninitializedCount: 15, arena: arena) { layout in layout.initialize(repeating: nil) layout[0] = unexpectedBeforeAttributes?.raw layout[1] = attributes.raw @@ -453,9 +455,11 @@ public struct RawGenericParameterSyntax: RawSyntaxNodeProtocol { layout[7] = colon?.raw layout[8] = unexpectedBetweenColonAndInheritedType?.raw layout[9] = inheritedType?.raw - layout[10] = unexpectedBetweenInheritedTypeAndTrailingComma?.raw - layout[11] = trailingComma?.raw - layout[12] = unexpectedAfterTrailingComma?.raw + layout[10] = unexpectedBetweenInheritedTypeAndInitializer?.raw + layout[11] = initializer?.raw + layout[12] = unexpectedBetweenInitializerAndTrailingComma?.raw + layout[13] = trailingComma?.raw + layout[14] = unexpectedAfterTrailingComma?.raw } self.init(unchecked: raw) } @@ -500,16 +504,24 @@ public struct RawGenericParameterSyntax: RawSyntaxNodeProtocol { layoutView.children[9].map(RawTypeSyntax.init(raw:)) } - public var unexpectedBetweenInheritedTypeAndTrailingComma: RawUnexpectedNodesSyntax? { + public var unexpectedBetweenInheritedTypeAndInitializer: RawUnexpectedNodesSyntax? { layoutView.children[10].map(RawUnexpectedNodesSyntax.init(raw:)) } + public var initializer: RawTypeInitializerClauseSyntax? { + layoutView.children[11].map(RawTypeInitializerClauseSyntax.init(raw:)) + } + + public var unexpectedBetweenInitializerAndTrailingComma: RawUnexpectedNodesSyntax? { + layoutView.children[12].map(RawUnexpectedNodesSyntax.init(raw:)) + } + public var trailingComma: RawTokenSyntax? { - layoutView.children[11].map(RawTokenSyntax.init(raw:)) + layoutView.children[13].map(RawTokenSyntax.init(raw:)) } public var unexpectedAfterTrailingComma: RawUnexpectedNodesSyntax? { - layoutView.children[12].map(RawUnexpectedNodesSyntax.init(raw:)) + layoutView.children[14].map(RawUnexpectedNodesSyntax.init(raw:)) } } diff --git a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift index a768f46192f..5127fb91e7c 100644 --- a/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift +++ b/Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift @@ -1497,7 +1497,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { } } func validateGenericParameterSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { - assert(layout.count == 13) + assert(layout.count == 15) assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 1, verify(layout[1], as: RawAttributeListSyntax.self)) assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self)) @@ -1509,8 +1509,10 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) { assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self)) assertNoError(kind, 9, verify(layout[9], as: RawTypeSyntax?.self)) assertNoError(kind, 10, verify(layout[10], as: RawUnexpectedNodesSyntax?.self)) - assertNoError(kind, 11, verify(layout[11], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.comma)])) + assertNoError(kind, 11, verify(layout[11], as: RawTypeInitializerClauseSyntax?.self)) assertNoError(kind, 12, verify(layout[12], as: RawUnexpectedNodesSyntax?.self)) + assertNoError(kind, 13, verify(layout[13], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.comma)])) + assertNoError(kind, 14, verify(layout[14], as: RawUnexpectedNodesSyntax?.self)) } func validateGenericRequirementListSyntax(kind: SyntaxKind, layout: RawSyntaxBuffer) { for (index, element) in layout.enumerated() { diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift index 3806f606106..4883047e547 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesGHI.swift @@ -636,6 +636,7 @@ public struct GenericParameterClauseSyntax: SyntaxProtocol, SyntaxHashable, _Lea /// - `name`: `` /// - `colon`: `:`? /// - `inheritedType`: ``TypeSyntax``? +/// - `initializer`: ``TypeInitializerClauseSyntax``? /// - `trailingComma`: `,`? /// /// ### Contained in @@ -659,7 +660,7 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta /// - 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. /// - 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( + @_spi(ExperimentalLanguageFeatures) public init( leadingTrivia: Trivia? = nil, _ unexpectedBeforeAttributes: UnexpectedNodesSyntax? = nil, attributes: AttributeListSyntax = [], @@ -671,7 +672,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta colon: TokenSyntax? = nil, _ unexpectedBetweenColonAndInheritedType: UnexpectedNodesSyntax? = nil, inheritedType: (some TypeSyntaxProtocol)? = TypeSyntax?.none, - _ unexpectedBetweenInheritedTypeAndTrailingComma: UnexpectedNodesSyntax? = nil, + _ unexpectedBetweenInheritedTypeAndInitializer: UnexpectedNodesSyntax? = nil, + initializer: TypeInitializerClauseSyntax? = nil, + _ unexpectedBetweenInitializerAndTrailingComma: UnexpectedNodesSyntax? = nil, trailingComma: TokenSyntax? = nil, _ unexpectedAfterTrailingComma: UnexpectedNodesSyntax? = nil, trailingTrivia: Trivia? = nil @@ -689,7 +692,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta colon, unexpectedBetweenColonAndInheritedType, inheritedType, - unexpectedBetweenInheritedTypeAndTrailingComma, + unexpectedBetweenInheritedTypeAndInitializer, + initializer, + unexpectedBetweenInitializerAndTrailingComma, trailingComma, unexpectedAfterTrailingComma ))) { (arena, _) in @@ -704,7 +709,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta colon?.raw, unexpectedBetweenColonAndInheritedType?.raw, inheritedType?.raw, - unexpectedBetweenInheritedTypeAndTrailingComma?.raw, + unexpectedBetweenInheritedTypeAndInitializer?.raw, + initializer?.raw, + unexpectedBetweenInitializerAndTrailingComma?.raw, trailingComma?.raw, unexpectedAfterTrailingComma?.raw ] @@ -847,7 +854,8 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta } } - public var unexpectedBetweenInheritedTypeAndTrailingComma: UnexpectedNodesSyntax? { + @_spi(ExperimentalLanguageFeatures) + public var unexpectedBetweenInheritedTypeAndInitializer: UnexpectedNodesSyntax? { get { return Syntax(self).child(at: 10)?.cast(UnexpectedNodesSyntax.self) } @@ -856,24 +864,44 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta } } + @_spi(ExperimentalLanguageFeatures) + public var initializer: TypeInitializerClauseSyntax? { + get { + return Syntax(self).child(at: 11)?.cast(TypeInitializerClauseSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 11, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(GenericParameterSyntax.self) + } + } + + @_spi(ExperimentalLanguageFeatures) + public var unexpectedBetweenInitializerAndTrailingComma: UnexpectedNodesSyntax? { + get { + return Syntax(self).child(at: 12)?.cast(UnexpectedNodesSyntax.self) + } + set(value) { + self = Syntax(self).replacingChild(at: 12, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(GenericParameterSyntax.self) + } + } + /// ### Tokens /// /// For syntax trees generated by the parser, this is guaranteed to be `,`. public var trailingComma: TokenSyntax? { get { - return Syntax(self).child(at: 11)?.cast(TokenSyntax.self) + return Syntax(self).child(at: 13)?.cast(TokenSyntax.self) } set(value) { - self = Syntax(self).replacingChild(at: 11, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(GenericParameterSyntax.self) + self = Syntax(self).replacingChild(at: 13, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(GenericParameterSyntax.self) } } public var unexpectedAfterTrailingComma: UnexpectedNodesSyntax? { get { - return Syntax(self).child(at: 12)?.cast(UnexpectedNodesSyntax.self) + return Syntax(self).child(at: 14)?.cast(UnexpectedNodesSyntax.self) } set(value) { - self = Syntax(self).replacingChild(at: 12, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(GenericParameterSyntax.self) + self = Syntax(self).replacingChild(at: 14, with: Syntax(value), rawAllocationArena: RawSyntaxArena()).cast(GenericParameterSyntax.self) } } @@ -888,7 +916,9 @@ public struct GenericParameterSyntax: SyntaxProtocol, SyntaxHashable, _LeafSynta \Self.colon, \Self.unexpectedBetweenColonAndInheritedType, \Self.inheritedType, - \Self.unexpectedBetweenInheritedTypeAndTrailingComma, + \Self.unexpectedBetweenInheritedTypeAndInitializer, + \Self.initializer, + \Self.unexpectedBetweenInitializerAndTrailingComma, \Self.trailingComma, \Self.unexpectedAfterTrailingComma ]) diff --git a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift index bf5973151ba..7003ec9e62b 100644 --- a/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift +++ b/Sources/SwiftSyntax/generated/syntaxNodes/SyntaxNodesTUVWXYZ.swift @@ -2494,6 +2494,7 @@ public struct TypeExprSyntax: ExprSyntaxProtocol, SyntaxHashable, _LeafExprSynta /// ### Contained in /// /// - ``AssociatedTypeDeclSyntax``.``AssociatedTypeDeclSyntax/initializer`` +/// - ``GenericParameterSyntax``.``GenericParameterSyntax/initializer`` /// - ``TypeAliasDeclSyntax``.``TypeAliasDeclSyntax/initializer`` public struct TypeInitializerClauseSyntax: SyntaxProtocol, SyntaxHashable, _LeafSyntaxNodeProtocol { public let _syntaxNode: Syntax diff --git a/Tests/SwiftParserTest/DefaultGenericsTest.swift b/Tests/SwiftParserTest/DefaultGenericsTest.swift new file mode 100644 index 00000000000..a2803acaf67 --- /dev/null +++ b/Tests/SwiftParserTest/DefaultGenericsTest.swift @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +@_spi(ExperimentalLanguageFeatures) import SwiftParser +import SwiftSyntax +import XCTest + +final class DefaultGenericsTest: ParserTestCase { + func testBasic() { + assertParse( + """ + struct A {} + """, + experimentalFeatures: [.defaultGenerics] + ) + + assertParse( + """ + enum A {} + """, + experimentalFeatures: [.defaultGenerics] + ) + + assertParse( + """ + class A {} + """, + experimentalFeatures: [.defaultGenerics] + ) + + // Note: We don't allow default generics on things other than types, but + // we'll diagnose it during sema. + assertParse( + """ + func foo() {} + """, + experimentalFeatures: [.defaultGenerics] + ) + + assertParse( + """ + struct A {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected type in generic parameter", + fixIts: ["insert type"] + ) + ], + fixedSource: """ + struct A> {} + """, + experimentalFeatures: [.defaultGenerics] + ) + + assertParse( + """ + struct Aℹ️ {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected '>' to end generic parameter clause", + notes: [ + NoteSpec(message: "to match this opening '<'") + ], + fixIts: ["insert '>'"] + ), + DiagnosticSpec( + message: "unexpected code '= Int>' in struct" + ), + ], + fixedSource: """ + struct A = Int> {} + """, + experimentalFeatures: [.defaultGenerics] + ) + + assertParse( + """ + struct Aℹ️ {} + """, + diagnostics: [ + DiagnosticSpec( + message: "expected '>' to end generic parameter clause", + notes: [ + NoteSpec(message: "to match this opening '<'") + ], + fixIts: ["insert '>'"] + ), + DiagnosticSpec( + message: "unexpected code '= Int>' in struct" + ), + ], + fixedSource: """ + struct A = Int> {} + """, + experimentalFeatures: [.defaultGenerics] + ) + } +}