Skip to content

Commit b517015

Browse files
committed
Introduce genericArgumentType and parse integer generics
1 parent 51eb17a commit b517015

29 files changed

+754
-173
lines changed

CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ public let GENERIC_NODES: [Node] = [
307307
Child(
308308
name: "leftType",
309309
deprecatedName: "leftTypeIdentifier",
310-
kind: .node(kind: .type),
310+
kind: .node(kind: .genericArgumentType),
311311
nameForDiagnostics: "left-hand type"
312312
),
313313
Child(
@@ -318,7 +318,7 @@ public let GENERIC_NODES: [Node] = [
318318
Child(
319319
name: "rightType",
320320
deprecatedName: "rightTypeIdentifier",
321-
kind: .node(kind: .type),
321+
kind: .node(kind: .genericArgumentType),
322322
nameForDiagnostics: "right-hand type"
323323
),
324324
]

CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
142142
case genericArgument
143143
case genericArgumentClause
144144
case genericArgumentList
145+
case genericArgumentType
145146
case genericParameter
146147
case genericParameterClause
147148
case genericParameterList

CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift

+22-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public let TYPE_NODES: [Node] = [
238238
Child(
239239
name: "argument",
240240
deprecatedName: "argumentType",
241-
kind: .node(kind: .type)
241+
kind: .node(kind: .genericArgumentType)
242242
),
243243
Child(
244244
name: "trailingComma",
@@ -604,4 +604,25 @@ public let TYPE_NODES: [Node] = [
604604
nameForDiagnostics: nil,
605605
elementChoices: [.simpleTypeSpecifier, .lifetimeTypeSpecifier]
606606
),
607+
608+
Node(
609+
kind: .genericArgumentType,
610+
base: .type,
611+
nameForDiagnostics: "generic argument type",
612+
children: [
613+
Child(
614+
name: "value",
615+
kind: .nodeChoices(choices: [
616+
Child(
617+
name: "type",
618+
kind: .node(kind: .type)
619+
),
620+
Child(
621+
name: "expr",
622+
kind: .node(kind: .expr)
623+
)
624+
])
625+
)
626+
]
627+
)
607628
]

Sources/SwiftParser/Declarations.swift

+144-116
Original file line numberDiff line numberDiff line change
@@ -532,16 +532,17 @@ extension Parser {
532532
var keepGoing: RawTokenSyntax? = nil
533533
var loopProgress = LoopProgressCondition()
534534
repeat {
535-
let firstType = self.parseType()
536-
guard !firstType.is(RawMissingTypeSyntax.self) else {
535+
let firstArgument = self.parseGenericArgumentType()
536+
537+
guard !firstArgument.value.raw.is(RawMissingTypeSyntax.self) else {
537538
keepGoing = self.consume(if: .comma)
538539
elements.append(
539540
RawGenericRequirementSyntax(
540541
requirement: .sameTypeRequirement(
541542
RawSameTypeRequirementSyntax(
542-
leftType: RawMissingTypeSyntax(arena: self.arena),
543+
leftType: firstArgument,
543544
equal: missingToken(.binaryOperator, text: "=="),
544-
rightType: RawMissingTypeSyntax(arena: self.arena),
545+
rightType: firstArgument,
545546
arena: self.arena
546547
)
547548
),
@@ -552,137 +553,164 @@ extension Parser {
552553
continue
553554
}
554555

555-
enum ExpectedTokenKind: TokenSpecSet {
556-
case colon
557-
case binaryOperator
558-
case postfixOperator
559-
case prefixOperator
560-
561-
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
562-
switch (lexeme.rawTokenKind, lexeme.tokenText) {
563-
case (.colon, _): self = .colon
564-
case (.binaryOperator, "=="): self = .binaryOperator
565-
case (.postfixOperator, "=="): self = .postfixOperator
566-
case (.prefixOperator, "=="): self = .prefixOperator
567-
default: return nil
556+
let requirement: RawGenericRequirementSyntax.Requirement
557+
558+
switch RawGenericArgumentTypeSyntax.Value(firstArgument.value.raw)! {
559+
// If the first argument is an expression, then we have to have a same
560+
// type requirement. We do not allow conformance requirements like
561+
// '123: Protocol' or layout constraints on expressions.
562+
case .expr:
563+
let (unexpectedBeforeEqual, equal) = self.expect(
564+
anyIn: SameTypeRequirementSyntax.EqualOptions.self,
565+
default: .binaryOperator
566+
)
567+
let secondArgument = self.parseGenericArgumentType()
568+
requirement = .sameTypeRequirement(
569+
RawSameTypeRequirementSyntax(
570+
leftType: firstArgument,
571+
unexpectedBeforeEqual,
572+
equal: equal,
573+
rightType: secondArgument,
574+
arena: self.arena
575+
)
576+
)
577+
578+
// Otherwise, this can be a conformance, same type, or layout constraint.
579+
case .type(let firstType):
580+
enum ExpectedTokenKind: TokenSpecSet {
581+
case colon
582+
case binaryOperator
583+
case postfixOperator
584+
case prefixOperator
585+
586+
init?(lexeme: Lexer.Lexeme, experimentalFeatures: Parser.ExperimentalFeatures) {
587+
switch (lexeme.rawTokenKind, lexeme.tokenText) {
588+
case (.colon, _): self = .colon
589+
case (.binaryOperator, "=="): self = .binaryOperator
590+
case (.postfixOperator, "=="): self = .postfixOperator
591+
case (.prefixOperator, "=="): self = .prefixOperator
592+
default: return nil
593+
}
568594
}
569-
}
570595

571-
var spec: TokenSpec {
572-
switch self {
573-
case .colon: return .colon
574-
case .binaryOperator: return .binaryOperator
575-
case .postfixOperator: return .postfixOperator
576-
case .prefixOperator: return .prefixOperator
596+
var spec: TokenSpec {
597+
switch self {
598+
case .colon: return .colon
599+
case .binaryOperator: return .binaryOperator
600+
case .postfixOperator: return .postfixOperator
601+
case .prefixOperator: return .prefixOperator
602+
}
577603
}
578604
}
579-
}
580605

581-
let requirement: RawGenericRequirementSyntax.Requirement
582-
switch self.at(anyIn: ExpectedTokenKind.self) {
583-
case (.colon, let handle)?:
584-
let colon = self.eat(handle)
585-
// A conformance-requirement.
586-
if let (layoutSpecifier, handle) = self.at(anyIn: LayoutRequirementSyntax.LayoutSpecifierOptions.self) {
587-
// Parse a layout constraint.
588-
let specifier = self.eat(handle)
589-
590-
let unexpectedBeforeLeftParen: RawUnexpectedNodesSyntax?
591-
let leftParen: RawTokenSyntax?
592-
let size: RawTokenSyntax?
593-
let comma: RawTokenSyntax?
594-
let alignment: RawTokenSyntax?
595-
let unexpectedBeforeRightParen: RawUnexpectedNodesSyntax?
596-
let rightParen: RawTokenSyntax?
597-
598-
var hasArguments: Bool {
599-
switch layoutSpecifier {
600-
case ._Trivial,
601-
._TrivialAtMost,
602-
._TrivialStride:
603-
return true
604-
605-
case ._UnknownLayout,
606-
._RefCountedObject,
607-
._NativeRefCountedObject,
608-
._Class,
609-
._NativeClass,
610-
._BridgeObject:
611-
return false
606+
switch self.at(anyIn: ExpectedTokenKind.self) {
607+
case (.colon, let handle)?:
608+
let colon = self.eat(handle)
609+
// A conformance-requirement.
610+
if let (layoutSpecifier, handle) = self.at(anyIn: LayoutRequirementSyntax.LayoutSpecifierOptions.self) {
611+
// Parse a layout constraint.
612+
let specifier = self.eat(handle)
613+
614+
let unexpectedBeforeLeftParen: RawUnexpectedNodesSyntax?
615+
let leftParen: RawTokenSyntax?
616+
let size: RawTokenSyntax?
617+
let comma: RawTokenSyntax?
618+
let alignment: RawTokenSyntax?
619+
let unexpectedBeforeRightParen: RawUnexpectedNodesSyntax?
620+
let rightParen: RawTokenSyntax?
621+
622+
var hasArguments: Bool {
623+
switch layoutSpecifier {
624+
case ._Trivial,
625+
._TrivialAtMost,
626+
._TrivialStride:
627+
return true
628+
629+
case ._UnknownLayout,
630+
._RefCountedObject,
631+
._NativeRefCountedObject,
632+
._Class,
633+
._NativeClass,
634+
._BridgeObject:
635+
return false
636+
}
612637
}
613-
}
614638

615-
// Unlike the other layout constraints, _Trivial's argument list
616-
// is optional.
617-
if hasArguments && (layoutSpecifier != ._Trivial || self.at(.leftParen)) {
618-
(unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
619-
size = self.expectWithoutRecovery(.integerLiteral)
620-
comma = self.consume(if: .comma)
621-
if comma != nil {
622-
alignment = self.expectWithoutRecovery(.integerLiteral)
639+
// Unlike the other layout constraints, _Trivial's argument list
640+
// is optional.
641+
if hasArguments && (layoutSpecifier != ._Trivial || self.at(.leftParen)) {
642+
(unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
643+
size = self.expectWithoutRecovery(.integerLiteral)
644+
comma = self.consume(if: .comma)
645+
if comma != nil {
646+
alignment = self.expectWithoutRecovery(.integerLiteral)
647+
} else {
648+
alignment = nil
649+
}
650+
(unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
623651
} else {
652+
unexpectedBeforeLeftParen = nil
653+
leftParen = nil
654+
size = nil
655+
comma = nil
624656
alignment = nil
657+
unexpectedBeforeRightParen = nil
658+
rightParen = nil
625659
}
626-
(unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
660+
661+
requirement = .layoutRequirement(
662+
RawLayoutRequirementSyntax(
663+
type: firstType,
664+
colon: colon,
665+
layoutSpecifier: specifier,
666+
unexpectedBeforeLeftParen,
667+
leftParen: leftParen,
668+
size: size,
669+
comma: comma,
670+
alignment: alignment,
671+
unexpectedBeforeRightParen,
672+
rightParen: rightParen,
673+
arena: self.arena
674+
)
675+
)
627676
} else {
628-
unexpectedBeforeLeftParen = nil
629-
leftParen = nil
630-
size = nil
631-
comma = nil
632-
alignment = nil
633-
unexpectedBeforeRightParen = nil
634-
rightParen = nil
677+
// Parse the protocol or composition.
678+
let secondType = self.parseType()
679+
requirement = .conformanceRequirement(
680+
RawConformanceRequirementSyntax(
681+
leftType: firstType,
682+
colon: colon,
683+
rightType: secondType,
684+
arena: self.arena
685+
)
686+
)
635687
}
636-
637-
requirement = .layoutRequirement(
638-
RawLayoutRequirementSyntax(
639-
type: firstType,
640-
colon: colon,
641-
layoutSpecifier: specifier,
642-
unexpectedBeforeLeftParen,
643-
leftParen: leftParen,
644-
size: size,
645-
comma: comma,
646-
alignment: alignment,
647-
unexpectedBeforeRightParen,
648-
rightParen: rightParen,
688+
case (.binaryOperator, let handle)?,
689+
(.postfixOperator, let handle)?,
690+
(.prefixOperator, let handle)?:
691+
let equal = self.eat(handle)
692+
let secondArgument = self.parseGenericArgumentType()
693+
requirement = .sameTypeRequirement(
694+
RawSameTypeRequirementSyntax(
695+
leftType: firstArgument,
696+
equal: equal,
697+
rightType: secondArgument,
649698
arena: self.arena
650699
)
651700
)
652-
} else {
653-
// Parse the protocol or composition.
654-
let secondType = self.parseType()
655-
requirement = .conformanceRequirement(
656-
RawConformanceRequirementSyntax(
657-
leftType: firstType,
658-
colon: colon,
659-
rightType: secondType,
701+
case nil:
702+
requirement = .sameTypeRequirement(
703+
RawSameTypeRequirementSyntax(
704+
leftType: firstArgument,
705+
equal: RawTokenSyntax(missing: .binaryOperator, text: "==", arena: self.arena),
706+
rightType: RawGenericArgumentTypeSyntax(
707+
value: .type(RawTypeSyntax(RawMissingTypeSyntax(arena: self.arena))),
708+
arena: self.arena
709+
),
660710
arena: self.arena
661711
)
662712
)
663713
}
664-
case (.binaryOperator, let handle)?,
665-
(.postfixOperator, let handle)?,
666-
(.prefixOperator, let handle)?:
667-
let equal = self.eat(handle)
668-
let secondType = self.parseType()
669-
requirement = .sameTypeRequirement(
670-
RawSameTypeRequirementSyntax(
671-
leftType: firstType,
672-
equal: equal,
673-
rightType: secondType,
674-
arena: self.arena
675-
)
676-
)
677-
case nil:
678-
requirement = .sameTypeRequirement(
679-
RawSameTypeRequirementSyntax(
680-
leftType: firstType,
681-
equal: RawTokenSyntax(missing: .binaryOperator, text: "==", arena: self.arena),
682-
rightType: RawMissingTypeSyntax(arena: self.arena),
683-
arena: self.arena
684-
)
685-
)
686714
}
687715

688716
keepGoing = self.consume(if: .comma)

0 commit comments

Comments
 (0)