Skip to content

Commit 2b73e52

Browse files
committed
Introduce genericArgumentType and parse integer generics
1 parent 0386d87 commit 2b73e52

29 files changed

+754
-173
lines changed

CodeGeneration/Sources/SyntaxSupport/GenericNodes.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ public let GENERIC_NODES: [Node] = [
334334
children: [
335335
Child(
336336
name: "leftType",
337-
kind: .node(kind: .type),
337+
kind: .node(kind: .genericArgumentType),
338338
nameForDiagnostics: "left-hand type"
339339
),
340340
Child(
@@ -343,7 +343,7 @@ public let GENERIC_NODES: [Node] = [
343343
),
344344
Child(
345345
name: "rightType",
346-
kind: .node(kind: .type),
346+
kind: .node(kind: .genericArgumentType),
347347
nameForDiagnostics: "right-hand type"
348348
),
349349
],

CodeGeneration/Sources/SyntaxSupport/SyntaxNodeKind.swift

Lines changed: 1 addition & 0 deletions
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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ public let TYPE_NODES: [Node] = [
257257
children: [
258258
Child(
259259
name: "argument",
260-
kind: .node(kind: .type)
260+
kind: .node(kind: .genericArgumentType)
261261
),
262262
Child(
263263
name: "trailingComma",
@@ -652,4 +652,25 @@ public let TYPE_NODES: [Node] = [
652652
nameForDiagnostics: nil,
653653
elementChoices: [.simpleTypeSpecifier, .lifetimeTypeSpecifier]
654654
),
655+
656+
Node(
657+
kind: .genericArgumentType,
658+
base: .type,
659+
nameForDiagnostics: "generic argument type",
660+
children: [
661+
Child(
662+
name: "value",
663+
kind: .nodeChoices(choices: [
664+
Child(
665+
name: "type",
666+
kind: .node(kind: .type)
667+
),
668+
Child(
669+
name: "expr",
670+
kind: .node(kind: .expr)
671+
)
672+
])
673+
)
674+
]
675+
)
655676
]

Sources/SwiftParser/Declarations.swift

Lines changed: 144 additions & 116 deletions
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)