From d99509dbf72e53060b0fd68e667a0e009f81250b Mon Sep 17 00:00:00 2001 From: MahdiBM Date: Sun, 7 Jul 2024 23:44:55 +0330 Subject: [PATCH] Keep the original TypeSyntax --- Sources/SyntaxKit/ParsedType.swift | 149 +++++++++--------- Tests/SyntaxKitTests/ParsedTypeTests.swift | 173 +++++++++++---------- 2 files changed, 164 insertions(+), 158 deletions(-) diff --git a/Sources/SyntaxKit/ParsedType.swift b/Sources/SyntaxKit/ParsedType.swift index e4fd160..d60afd5 100644 --- a/Sources/SyntaxKit/ParsedType.swift +++ b/Sources/SyntaxKit/ParsedType.swift @@ -1,7 +1,7 @@ -import SwiftSyntax +public import SwiftSyntax /// A parsed `TypeSyntax`. -public indirect enum ParsedType { +public struct ParsedType { enum Error: Swift.Error, CustomStringConvertible { case unknownParameterType(String, syntaxType: Any.Type) case unknownSomeOrAnySpecifier(token: TokenSyntax) @@ -16,48 +16,56 @@ public indirect enum ParsedType { } } - /// An element of a tuple. - public struct TupleElement { - public let firstName: TokenSyntax? - public let secondName: TokenSyntax? - public let type: ParsedType + public indirect enum BaseType { + /// A simple type identifier. + /// Example: `String`. + case identifier(TokenSyntax) + /// An optional type. + /// Example: `Bool?`. + case optional(of: ParsedType) + /// An array. + /// Example: `[Double]`, `Array`. + case array(of: ParsedType) + /// A dictionary. + /// Example: `[String: Bool]`, `[_: UInt]`. + case dictionary(key: ParsedType, value: ParsedType) + /// A tuple. + /// Example: `(String)`, `(val1 _: String, val2: _, _ val3: MyType)`. + case tuple(of: [ParsedType]) + /// An opaque-`some` type. + /// Example: `some StringProtocol`, `some View`. + case some(of: ParsedType) + /// An existential-`any` type. + /// Example: `any StringProtocol`, `any Decodable`. + case any(of: ParsedType) + /// A member type. + /// Example: `String.Iterator`, `ContinuousClock.Duration`, `Foo.Bar.Baz`. + /// In `String.Iterator`, `String` is `base` and `Iterator` is `extension`. + /// In `Foo.Bar.Baz`, `Foo.Bar` is `base` (of another `ParsedType.member`) and `Baz` is `extension`. + case member(base: ParsedType, `extension`: ParsedType) + /// A metatype. + /// Example: `String.Type`, `(some Decodable).Type`, `(Int, String).Type`. + case metatype(base: ParsedType) + /// A generic type other than the ones above (`Optional`, `Array`, `Dictionary`). + /// Example: `Collection`, `Result`. + case unknownGeneric(ParsedType, arguments: [ParsedType]) + } + + public let syntax: TypeSyntax? + public let type: BaseType + + private init(syntax: TypeSyntax?, type: BaseType) { + self.syntax = syntax + self.type = type + } + + static func identifier(_ identifier: TokenSyntax) -> Self { + ParsedType(syntax: nil, type: .identifier(identifier)) } - - /// A simple type identfier. - /// Example: `String`. - case identifier(TokenSyntax) - /// An optional type. - /// Example: `Bool?`. - case optional(of: Self) - /// An array. - /// Example: `[Double]`, `Array`. - case array(of: Self) - /// A dictionary. - /// Example: `[String: Bool]`, `[_: UInt]`. - case dictionary(key: Self, value: Self) - /// A tuple. - /// Example: `(String)`, `(val1 _: String, val2: _, _ val3: MyType)`. - case tuple(of: [TupleElement]) - /// An opaque-`some` type. - /// Example: `some StringProtocol`, `some View`. - case some(of: Self) - /// An existential-`any` type. - /// Example: `any StringProtocol`, `any Decodable`. - case any(of: Self) - /// A member type. - /// Example: `String.Iterator`, `ContinuousClock.Duration`, `Foo.Bar.Baz`. - /// In `String.Iterator`, `String` is `base` and `Iterator` is `extension`. - /// In `Foo.Bar.Baz`, `Foo.Bar` is `base` (of another `ParsedType.member`) and `Baz` is `extension`. - case member(base: Self, `extension`: Self) - /// A metatype. - /// Example: `String.Type`, `(some Decodable).Type`, `(Int, String).Type`. - case metatype(base: Self) - /// A generic type other than the ones above (`Optional`, `Array`, `Dictionary`). - /// Example: `Collection`, `Result`. - case unknownGeneric(Self, arguments: [Self]) /// Parses any `TypeSyntax`. public init(syntax: some TypeSyntaxProtocol) throws { + self.syntax = TypeSyntax(syntax) if let type = syntax.as(IdentifierTypeSyntax.self) { let name = type.name.trimmed if let genericArgumentClause = type.genericArgumentClause, @@ -65,44 +73,41 @@ public indirect enum ParsedType { let arguments = genericArgumentClause.arguments switch (arguments.count, name.trimmedDescription) { // FIXME: Change from TRIMMED case (1, "Optional"): - self = try .optional(of: Self(syntax: arguments.first!.argument)) + self.type = try .optional(of: Self(syntax: arguments.first!.argument)) case (1, "Array"): - self = try .array(of: Self(syntax: arguments.first!.argument)) + self.type = try .array(of: Self(syntax: arguments.first!.argument)) case (2, "Dictionary"): let key = try Self(syntax: arguments.first!.argument) let value = try Self(syntax: arguments.last!.argument) - self = .dictionary(key: key, value: value) + self.type = .dictionary(key: key, value: value) default: let arguments = try arguments.map(\.argument).map(Self.init(syntax:)) - self = .unknownGeneric(.identifier(name), arguments: arguments) + let base = ParsedType.identifier(name) + self.type = .unknownGeneric(base, arguments: arguments) } } else { - self = .identifier(name) + self.type = .identifier(name) } } else if let type = syntax.as(OptionalTypeSyntax.self) { - self = try .optional(of: Self(syntax: type.wrappedType)) + self.type = try .optional(of: Self(syntax: type.wrappedType)) } else if let type = syntax.as(ArrayTypeSyntax.self) { - self = try .array(of: Self(syntax: type.element)) + self.type = try .array(of: Self(syntax: type.element)) } else if let type = syntax.as(DictionaryTypeSyntax.self) { let key = try Self(syntax: type.key) let value = try Self(syntax: type.value) - self = .dictionary(key: key, value: value) + self.type = .dictionary(key: key, value: value) } else if let type = syntax.as(TupleTypeSyntax.self) { - let elements = try type.elements.map { element in - try TupleElement( - firstName: element.firstName, - secondName: element.secondName, - type: Self(syntax: element.type) - ) + let elements = try type.elements.map { + try Self(syntax: $0.type) } - self = .tuple(of: elements) + self.type = .tuple(of: elements) } else if let type = syntax.as(SomeOrAnyTypeSyntax.self) { let constraint = try Self(syntax: type.constraint) switch type.someOrAnySpecifier.tokenKind { case .keyword(.some): - self = .some(of: constraint) + self.type = .some(of: constraint) case .keyword(.any): - self = .any(of: constraint) + self.type = .any(of: constraint) default: throw Error.unknownSomeOrAnySpecifier( token: type.someOrAnySpecifier @@ -111,10 +116,10 @@ public indirect enum ParsedType { } else if let type = syntax.as(MemberTypeSyntax.self) { let base = try Self(syntax: type.baseType) let `extension` = ParsedType.identifier(type.name) - self = .member(base: base, extension: `extension`) + self.type = .member(base: base, extension: `extension`) } else if let type = syntax.as(MetatypeTypeSyntax.self) { let baseType = try Self(syntax: type.baseType) - self = .metatype(base: baseType) + self.type = .metatype(base: baseType) } else { throw Error.unknownParameterType( syntax.trimmed.description, @@ -125,6 +130,18 @@ public indirect enum ParsedType { } extension ParsedType: CustomStringConvertible { + public var description: String { + "ParsedType(syntax: \(String(describing: self.syntax)), type: \(self.type))" + } +} + +extension ParsedType: CustomDebugStringConvertible { + public var debugDescription: String { + "ParsedType(syntax: \(String(reflecting: self.syntax)), type: \(self.type.debugDescription))" + } +} + +extension ParsedType.BaseType: CustomStringConvertible { public var description: String { switch self { case let .identifier(type): @@ -151,7 +168,7 @@ extension ParsedType: CustomStringConvertible { } } -extension ParsedType: CustomDebugStringConvertible { +extension ParsedType.BaseType: CustomDebugStringConvertible { public var debugDescription: String { switch self { case let .identifier(type): @@ -177,15 +194,3 @@ extension ParsedType: CustomDebugStringConvertible { } } } - -extension ParsedType.TupleElement: CustomStringConvertible { - public var description: String { - "ParsedType.TupleElement(firstName: \(String(describing: self.firstName)), secondName: \(String(describing: self.secondName)), type: \(self.type))" - } -} - -extension ParsedType.TupleElement: CustomDebugStringConvertible { - public var debugDescription: String { - "ParsedType.TupleElement(firstName: \(String(reflecting: self.firstName)), secondName: \(String(reflecting: self.secondName)), type: \(self.type.debugDescription))" - } -} diff --git a/Tests/SyntaxKitTests/ParsedTypeTests.swift b/Tests/SyntaxKitTests/ParsedTypeTests.swift index 07cf4a3..98d36cb 100644 --- a/Tests/SyntaxKitTests/ParsedTypeTests.swift +++ b/Tests/SyntaxKitTests/ParsedTypeTests.swift @@ -8,7 +8,8 @@ import SyntaxKit @Test func parseString() throws { let typeSyntax = try makeTypeSyntax(for: "String") let parsed = try ParsedType(syntax: typeSyntax) - if case let .identifier(syntax) = parsed { + #expect(parsed.syntax == typeSyntax) + if case let .identifier(syntax) = parsed.type { #expect(syntax.tokenKind == .identifier("String")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -18,8 +19,9 @@ import SyntaxKit @Test func parseOptionalString() throws { let typeSyntax = try makeTypeSyntax(for: "String?") let parsed = try ParsedType(syntax: typeSyntax) - if case let .optional(wrapped) = parsed, - case let .identifier(syntax) = wrapped { + #expect(parsed.syntax == typeSyntax) + if case let .optional(wrapped) = parsed.type, + case let .identifier(syntax) = wrapped.type { #expect(syntax.tokenKind == .identifier("String")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -29,8 +31,9 @@ import SyntaxKit @Test func parseArrayOfDoubles() throws { let typeSyntax = try makeTypeSyntax(for: "[Double]") let parsed = try ParsedType(syntax: typeSyntax) - if case let .array(element) = parsed, - case let .identifier(syntax) = element { + #expect(parsed.syntax == typeSyntax) + if case let .array(element) = parsed.type, + case let .identifier(syntax) = element.type { #expect(syntax.tokenKind == .identifier("Double")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -40,9 +43,10 @@ import SyntaxKit @Test func parseArrayOfOptionalDoubles() throws { let typeSyntax = try makeTypeSyntax(for: "[ Double? ]") let parsed = try ParsedType(syntax: typeSyntax) - if case let .array(element) = parsed, - case let .optional(wrapped) = element, - case let .identifier(syntax) = wrapped { + #expect(parsed.syntax == typeSyntax) + if case let .array(element) = parsed.type, + case let .optional(wrapped) = element.type, + case let .identifier(syntax) = wrapped.type { #expect(syntax.tokenKind == .identifier("Double")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -52,14 +56,15 @@ import SyntaxKit @Test func parseGenericOfSomeOfThingOfOptionalFoo() throws { let typeSyntax = try makeTypeSyntax(for: "Some< Thing>") let parsed = try ParsedType(syntax: typeSyntax) - if case let .unknownGeneric(first, arguments) = parsed, - case let .identifier(firstSyntax) = first, + #expect(parsed.syntax == typeSyntax) + if case let .unknownGeneric(first, arguments) = parsed.type, + case let .identifier(firstSyntax) = first.type, arguments.count == 1, - case let .unknownGeneric(second, arguments) = arguments.first, - case let .identifier(secondSyntax) = second, + case let .unknownGeneric(second, arguments) = arguments.first?.type, + case let .identifier(secondSyntax) = second.type, arguments.count == 1, - case let .optional(wrapped) = arguments.first, - case let .identifier(third) = wrapped { + case let .optional(wrapped) = arguments.first?.type, + case let .identifier(third) = wrapped.type { #expect(firstSyntax.tokenKind == .identifier("Some")) #expect(secondSyntax.tokenKind == .identifier("Thing")) #expect(third.tokenKind == .identifier("Foo")) @@ -71,15 +76,16 @@ import SyntaxKit @Test func parseGenericOfSomeOfThingOfOptionalFooAndBarAndBaz() throws { let typeSyntax = try makeTypeSyntax(for: "Some, Bar, Baz>") let parsed = try ParsedType(syntax: typeSyntax) - if case .unknownGeneric(let first, var baseArguments) = parsed, - case let .identifier(firstSyntax) = first, + #expect(parsed.syntax == typeSyntax) + if case .unknownGeneric(let first, var baseArguments) = parsed.type, + case let .identifier(firstSyntax) = first.type, baseArguments.count == 3, - case let .unknownGeneric(second, arguments) = baseArguments.removeFirst(), - case let .identifier(secondSyntax) = second, + case let .unknownGeneric(second, arguments) = baseArguments.removeFirst().type, + case let .identifier(secondSyntax) = second.type, arguments.count == 1, - case let .identifier(inSecondSyntax) = arguments.first, - case let .identifier(thirdSyntax) = baseArguments.removeFirst(), - case let .identifier(fourthSyntax) = baseArguments.removeFirst() { + case let .identifier(inSecondSyntax) = arguments.first?.type, + case let .identifier(thirdSyntax) = baseArguments.removeFirst().type, + case let .identifier(fourthSyntax) = baseArguments.removeFirst().type { #expect(firstSyntax.tokenKind == .identifier("Some")) #expect(secondSyntax.tokenKind == .identifier("Thing")) #expect(inSecondSyntax.tokenKind == .identifier("Foo")) @@ -93,12 +99,11 @@ import SyntaxKit @Test func parseTupleOfDouble() throws { let typeSyntax = try makeTypeSyntax(for: "(Double)") let parsed = try ParsedType(syntax: typeSyntax) - if case var .tuple(elements) = parsed, + #expect(parsed.syntax == typeSyntax) + if case var .tuple(elements) = parsed.type, elements.count == 1 { let first = elements.removeFirst() - if case let .identifier(firstSyntax) = first.type, - first.firstName == nil, - first.secondName == nil { + if case let .identifier(firstSyntax) = first.type { #expect(firstSyntax.tokenKind == .identifier("Double")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -111,21 +116,16 @@ import SyntaxKit @Test func parseTupleOfStringAndInferretTypeAndArrayOfMyType() throws { let typeSyntax = try makeTypeSyntax(for: "(String, _, labeled: [MyType])") let parsed = try ParsedType(syntax: typeSyntax) - if case var .tuple(elements) = parsed, + #expect(parsed.syntax == typeSyntax) + if case var .tuple(elements) = parsed.type, elements.count == 3 { let first = elements.removeFirst() let second = elements.removeFirst() let third = elements.removeFirst() if case let .identifier(firstSyntax) = first.type, - first.firstName == nil, - first.secondName == nil, case let .identifier(secondSyntax) = second.type, - second.firstName == nil, - second.secondName == nil, case let .array(thirdElementType) = third.type, - case let .identifier(thirdSyntax) = thirdElementType, - third.firstName?.tokenKind == .identifier("labeled"), - third.secondName == nil { + case let .identifier(thirdSyntax) = thirdElementType.type { #expect(firstSyntax.tokenKind == .identifier("String")) #expect(secondSyntax.tokenKind == .wildcard) #expect(thirdSyntax.tokenKind == .identifier("MyType")) @@ -140,17 +140,14 @@ import SyntaxKit @Test func parseLabeledTupleOfStringAndOptionalInt() throws { let typeSyntax = try makeTypeSyntax(for: "(some _:String, _ thing:Int?)") let parsed = try ParsedType(syntax: typeSyntax) - if case var .tuple(elements) = parsed, + #expect(parsed.syntax == typeSyntax) + if case var .tuple(elements) = parsed.type, elements.count == 2 { let first = elements.removeFirst() let second = elements.removeFirst() if case let .identifier(firstSyntax) = first.type, - first.firstName?.tokenKind == .identifier("some"), - first.secondName?.tokenKind == .wildcard, case let .optional(secondWrapped) = second.type, - case let .identifier(secondSyntax) = secondWrapped, - second.firstName?.tokenKind == .wildcard, - second.secondName?.tokenKind == .identifier("thing") { + case let .identifier(secondSyntax) = secondWrapped.type { #expect(firstSyntax.tokenKind == .identifier("String")) #expect(secondSyntax.tokenKind == .identifier("Int")) } else { @@ -164,12 +161,13 @@ import SyntaxKit @Test func parseDictionaryWithKeyOfBarOfBieAndValueOfAny() throws { let typeSyntax = try makeTypeSyntax(for: "[ Bar< Bie >:Any]") let parsed = try ParsedType(syntax: typeSyntax) - if case let .dictionary(key, value) = parsed, - case let .unknownGeneric(firstInKey, arguments) = key, - case let .identifier(firstInKeySyntax) = firstInKey, + #expect(parsed.syntax == typeSyntax) + if case let .dictionary(key, value) = parsed.type, + case let .unknownGeneric(firstInKey, arguments) = key.type, + case let .identifier(firstInKeySyntax) = firstInKey.type, arguments.count == 1, - case let .identifier(secondInKey) = arguments.first, - case let .identifier(valueSyntax) = value { + case let .identifier(secondInKey) = arguments.first?.type, + case let .identifier(valueSyntax) = value.type { #expect(firstInKeySyntax.tokenKind == .identifier("Bar")) #expect(secondInKey.tokenKind == .identifier("Bie")) #expect(valueSyntax.tokenKind == .keyword(.Any)) @@ -181,8 +179,9 @@ import SyntaxKit @Test func parseOpaqueSomeOfThing() throws { let typeSyntax = try makeTypeSyntax(for: "some Thing") let parsed = try ParsedType(syntax: typeSyntax) - if case let .some(type) = parsed, - case let .identifier(syntax) = type { + #expect(parsed.syntax == typeSyntax) + if case let .some(type) = parsed.type, + case let .identifier(syntax) = type.type { #expect(syntax.tokenKind == .identifier("Thing")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -192,11 +191,12 @@ import SyntaxKit @Test func parseOpaqueSomeOfBarOfBie() throws { let typeSyntax = try makeTypeSyntax(for: "some Bar< Bie >") let parsed = try ParsedType(syntax: typeSyntax) - if case let .some(type) = parsed, - case let .unknownGeneric(first, arguments) = type, - case let .identifier(firstSyntax) = first, + #expect(parsed.syntax == typeSyntax) + if case let .some(type) = parsed.type, + case let .unknownGeneric(first, arguments) = type.type, + case let .identifier(firstSyntax) = first.type, arguments.count == 1, - case let .identifier(secondSyntax) = arguments.first { + case let .identifier(secondSyntax) = arguments.first?.type { #expect(firstSyntax.tokenKind == .identifier("Bar")) #expect(secondSyntax.tokenKind == .identifier("Bie")) } else { @@ -207,8 +207,9 @@ import SyntaxKit @Test func parseExistentialAnyOfThing() throws { let typeSyntax = try makeTypeSyntax(for: "any Thing") let parsed = try ParsedType(syntax: typeSyntax) - if case let .any(type) = parsed, - case let .identifier(syntax) = type { + #expect(parsed.syntax == typeSyntax) + if case let .any(type) = parsed.type, + case let .identifier(syntax) = type.type { #expect(syntax.tokenKind == .identifier("Thing")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -218,11 +219,12 @@ import SyntaxKit @Test func parseExistentialAnyOfBarOfBie() throws { let typeSyntax = try makeTypeSyntax(for: "any Bar< Bie>") let parsed = try ParsedType(syntax: typeSyntax) - if case let .any(type) = parsed, - case let .unknownGeneric(first, arguments) = type, - case let .identifier(firstSyntax) = first, + #expect(parsed.syntax == typeSyntax) + if case let .any(type) = parsed.type, + case let .unknownGeneric(first, arguments) = type.type, + case let .identifier(firstSyntax) = first.type, arguments.count == 1, - case let .identifier(secondSyntax) = arguments.first { + case let .identifier(secondSyntax) = arguments.first?.type { #expect(firstSyntax.tokenKind == .identifier("Bar")) #expect(secondSyntax.tokenKind == .identifier("Bie")) } else { @@ -233,12 +235,13 @@ import SyntaxKit @Test func parseNestedTypesOfFirstOfOptionalSecondOfThird() throws { let typeSyntax = try makeTypeSyntax(for: "First.Second? .Third") let parsed = try ParsedType(syntax: typeSyntax) - if case let .member(base, `extension`) = parsed, - case let .identifier(firstSyntax) = `extension`, - case let .optional(wrapped) = base, - case let .member(base, `extension`) = wrapped, - case let .identifier(secondSyntax) = `extension`, - case let .identifier(thirdSyntax) = base { + #expect(parsed.syntax == typeSyntax) + if case let .member(base, `extension`) = parsed.type, + case let .identifier(firstSyntax) = `extension`.type, + case let .optional(wrapped) = base.type, + case let .member(base, `extension`) = wrapped.type, + case let .identifier(secondSyntax) = `extension`.type, + case let .identifier(thirdSyntax) = base.type { #expect(firstSyntax.tokenKind == .identifier("Third")) #expect(secondSyntax.tokenKind == .identifier("Second")) #expect(thirdSyntax.tokenKind == .identifier("First")) @@ -250,8 +253,9 @@ import SyntaxKit @Test func parseMetatype() throws { let typeSyntax = try makeTypeSyntax(for: "Foo .Type") let parsed = try ParsedType(syntax: typeSyntax) - if case let .metatype(base) = parsed, - case let .identifier(firstSyntax) = base { + #expect(parsed.syntax == typeSyntax) + if case let .metatype(base) = parsed.type, + case let .identifier(firstSyntax) = base.type { #expect(firstSyntax.tokenKind == .identifier("Foo")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -261,11 +265,12 @@ import SyntaxKit @Test func parseMetatypeOfBarOfBie() throws { let typeSyntax = try makeTypeSyntax(for: "Bar.Type") let parsed = try ParsedType(syntax: typeSyntax) - if case let .metatype(base) = parsed, - case let .unknownGeneric(first, arguments) = base, - case let .identifier(firstSyntax) = first, + #expect(parsed.syntax == typeSyntax) + if case let .metatype(base) = parsed.type, + case let .unknownGeneric(first, arguments) = base.type, + case let .identifier(firstSyntax) = first.type, arguments.count == 1, - case let .identifier(secondSyntax) = arguments.first { + case let .identifier(secondSyntax) = arguments.first?.type { #expect(firstSyntax.tokenKind == .identifier("Bar")) #expect(secondSyntax.tokenKind == .identifier("Bie")) } else { @@ -276,14 +281,13 @@ import SyntaxKit @Test func parseLabeledMetatypeTupleOfSomeDecodable() throws { let typeSyntax = try makeTypeSyntax(for: "(some Decodable).Type") let parsed = try ParsedType(syntax: typeSyntax) - if case let .metatype(type) = parsed, - case var .tuple(elements) = type, + #expect(parsed.syntax == typeSyntax) + if case let .metatype(type) = parsed.type, + case var .tuple(elements) = type.type, elements.count == 1 { let first = elements.removeFirst() if case let .some(firstType) = first.type, - case let .identifier(firstSyntax) = firstType, - first.firstName == nil, - first.secondName == nil { + case let .identifier(firstSyntax) = firstType.type { #expect(firstSyntax.tokenKind == .identifier("Decodable")) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -296,18 +300,15 @@ import SyntaxKit @Test func parseLabeledMetatypeTupleOfStringAndOptionalInt() throws { let typeSyntax = try makeTypeSyntax(for: "(some _:String, _ thing:Int?).Type") let parsed = try ParsedType(syntax: typeSyntax) - if case let .metatype(type) = parsed, - case var .tuple(elements) = type, + #expect(parsed.syntax == typeSyntax) + if case let .metatype(type) = parsed.type, + case var .tuple(elements) = type.type, elements.count == 2 { let first = elements.removeFirst() let second = elements.removeFirst() if case let .identifier(firstSyntax) = first.type, - first.firstName?.tokenKind == .identifier("some"), - first.secondName?.tokenKind == .wildcard, case let .optional(secondWrapped) = second.type, - case let .identifier(secondSyntax) = secondWrapped, - second.firstName?.tokenKind == .wildcard, - second.secondName?.tokenKind == .identifier("thing") { + case let .identifier(secondSyntax) = secondWrapped.type { #expect(firstSyntax.tokenKind == .identifier("String")) #expect(secondSyntax.tokenKind == .identifier("Int")) } else { @@ -321,7 +322,8 @@ import SyntaxKit @Test func parseInferredType() throws { let typeSyntax = try makeTypeSyntax(for: "_") let parsed = try ParsedType(syntax: typeSyntax) - if case let .identifier(firstSyntax) = parsed { + #expect(parsed.syntax == typeSyntax) + if case let .identifier(firstSyntax) = parsed.type { #expect(firstSyntax.tokenKind == .wildcard) } else { #expect(Bool(false), "Unexpected 'ParsedType': \(parsed.debugDescription)") @@ -331,9 +333,10 @@ import SyntaxKit @Test func parseDictionaryWithKeyOfInferredTypeAndValueOfBool() throws { let typeSyntax = try makeTypeSyntax(for: "[_: Bool]") let parsed = try ParsedType(syntax: typeSyntax) - if case let .dictionary(key, value) = parsed, - case let .identifier(keySyntax) = key, - case let .identifier(valueSyntax) = value { + #expect(parsed.syntax == typeSyntax) + if case let .dictionary(key, value) = parsed.type, + case let .identifier(keySyntax) = key.type, + case let .identifier(valueSyntax) = value.type { #expect(keySyntax.tokenKind == .wildcard) #expect(valueSyntax.tokenKind == .identifier("Bool")) } else { @@ -341,8 +344,6 @@ import SyntaxKit } } - // TODO: More tests, for e.g. `descriptionWithoutOptionality()` - private func makeTypeSyntax(for type: String) throws -> TypeSyntax { let code = "let variable: \(type)" let syntax = Parser.parse(source: code)