Skip to content

Commit aa54b10

Browse files
authored
Merge pull request #1727 from kimdv/kimdv/fix-specialize-error
Add diagnostic for wrong specialize label
2 parents bf1f861 + 11cffa3 commit aa54b10

File tree

11 files changed

+1220
-139
lines changed

11 files changed

+1220
-139
lines changed

CodeGeneration/Sources/SyntaxSupport/AttributeNodes.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,15 @@ public let ATTRIBUTE_NODES: [Node] = [
641641
children: [
642642
Child(
643643
name: "Label",
644-
kind: .node(kind: .token),
644+
kind: .token(choices: [
645+
.keyword(text: "target"),
646+
.keyword(text: "availability"),
647+
.keyword(text: "exported"),
648+
.keyword(text: "kind"),
649+
.keyword(text: "spi"),
650+
.keyword(text: "spiModule"),
651+
.keyword(text: "available"),
652+
]),
645653
nameForDiagnostics: "label",
646654
documentation: "The label of the argument"
647655
),

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/ParserTokenSpecSetFile.swift

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ let parserTokenSpecSetFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
2222
for child in layoutNode.children {
2323
if case let .token(choices, _, _) = child.kind, choices.count > 1 {
2424
try! ExtensionDeclSyntax("extension \(raw: layoutNode.kind.syntaxType)") {
25-
try EnumDeclSyntax("enum \(raw: child.name)Options: TokenSpecSet") {
25+
try EnumDeclSyntax(
26+
"""
27+
@_spi(Diagnostics)
28+
public enum \(raw: child.name)Options: TokenSpecSet
29+
"""
30+
) {
2631
for choice in choices {
2732
switch choice {
2833
case .keyword(let keywordText):
@@ -70,6 +75,39 @@ let parserTokenSpecSetFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
7075
}
7176
}
7277
}
78+
79+
try VariableDeclSyntax(
80+
"""
81+
/// Returns a token that satisfies the `TokenSpec` of this case.
82+
///
83+
/// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text.
84+
@_spi(Diagnostics)
85+
public var tokenSyntax: TokenSyntax
86+
"""
87+
) {
88+
try SwitchExprSyntax("switch self") {
89+
for choice in choices {
90+
switch choice {
91+
case .keyword(let keywordText):
92+
let keyword = KEYWORDS.first(where: { $0.name == keywordText })!
93+
SwitchCaseSyntax(
94+
"case .\(raw: keyword.escapedName): return .keyword(.\(raw: keyword.escapedName))"
95+
)
96+
case .token(let tokenText):
97+
let token = SYNTAX_TOKEN_MAP[tokenText]!
98+
if token.text != nil {
99+
SwitchCaseSyntax(
100+
"case .\(raw: token.varOrCaseName): return .\(raw: token.varOrCaseName)Token()"
101+
)
102+
} else {
103+
SwitchCaseSyntax(
104+
#"case .\#(raw: token.varOrCaseName): return .\#(raw: token.varOrCaseName)("")"#
105+
)
106+
}
107+
}
108+
}
109+
}
110+
}
73111
}
74112
}
75113
}

Sources/SwiftParser/Attributes.swift

Lines changed: 15 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -638,55 +638,21 @@ extension Parser {
638638
}
639639

640640
extension Parser {
641-
enum SpecializeParameter: TokenSpecSet {
642-
case target
643-
case availability
644-
case exported
645-
case kind
646-
case spi
647-
case spiModule
648-
case available
649-
650-
init?(lexeme: Lexer.Lexeme) {
651-
switch PrepareForKeywordMatch(lexeme) {
652-
case TokenSpec(.target): self = .target
653-
case TokenSpec(.availability): self = .availability
654-
case TokenSpec(.exported): self = .exported
655-
case TokenSpec(.kind): self = .kind
656-
case TokenSpec(.spi): self = .spi
657-
case TokenSpec(.spiModule): self = .spiModule
658-
case TokenSpec(.available): self = .available
659-
default: return nil
660-
}
661-
}
662-
663-
var spec: TokenSpec {
664-
switch self {
665-
case .target: return .keyword(.target)
666-
case .availability: return .keyword(.availability)
667-
case .exported: return .keyword(.exported)
668-
case .kind: return .keyword(.kind)
669-
case .spi: return .keyword(.spi)
670-
case .spiModule: return .keyword(.spiModule)
671-
case .available: return .keyword(.available)
672-
}
673-
}
674-
}
675641
mutating func parseSpecializeAttributeArgumentList() -> RawSpecializeAttributeArgumentListSyntax {
676642
var elements = [RawSpecializeAttributeArgumentListSyntax.Element]()
677643
// Parse optional "exported" and "kind" labeled parameters.
678644
var loopProgress = LoopProgressCondition()
679-
while !self.at(.endOfFile, .rightParen, .keyword(.where)) && self.hasProgressed(&loopProgress) {
680-
switch self.at(anyIn: SpecializeParameter.self) {
645+
LOOP: while !self.at(.endOfFile, .rightParen, .keyword(.where)) && self.hasProgressed(&loopProgress) {
646+
switch self.at(anyIn: LabeledSpecializeArgumentSyntax.LabelOptions.self) {
681647
case (.target, let handle)?:
682-
let ident = self.eat(handle)
648+
let label = self.eat(handle)
683649
let (unexpectedBeforeColon, colon) = self.expect(.colon)
684650
let declName = self.parseDeclReferenceExpr([.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators])
685651
let comma = self.consume(if: .comma)
686652
elements.append(
687653
.specializeTargetFunctionArgument(
688654
RawSpecializeTargetFunctionArgumentSyntax(
689-
targetLabel: ident,
655+
targetLabel: label,
690656
unexpectedBeforeColon,
691657
colon: colon,
692658
declName: declName,
@@ -696,14 +662,14 @@ extension Parser {
696662
)
697663
)
698664
case (.availability, let handle)?:
699-
let ident = self.eat(handle)
665+
let label = self.eat(handle)
700666
let (unexpectedBeforeColon, colon) = self.expect(.colon)
701667
let availability = self.parseAvailabilitySpecList()
702668
let (unexpectedBeforeSemi, semi) = self.expect(.semicolon)
703669
elements.append(
704670
.specializeAvailabilityArgument(
705671
RawSpecializeAvailabilityArgumentSyntax(
706-
availabilityLabel: ident,
672+
availabilityLabel: label,
707673
unexpectedBeforeColon,
708674
colon: colon,
709675
availabilityArguments: availability,
@@ -714,7 +680,7 @@ extension Parser {
714680
)
715681
)
716682
case (.available, let handle)?:
717-
let ident = self.eat(handle)
683+
let label = self.eat(handle)
718684
let (unexpectedBeforeColon, colon) = self.expect(.colon)
719685
// FIXME: I have no idea what this is supposed to be, but the Syntax
720686
// tree only allows us to insert a token so we'll take anything.
@@ -723,7 +689,7 @@ extension Parser {
723689
elements.append(
724690
.labeledSpecializeArgument(
725691
RawLabeledSpecializeArgumentSyntax(
726-
label: ident,
692+
label: label,
727693
unexpectedBeforeColon,
728694
colon: colon,
729695
value: available,
@@ -733,14 +699,14 @@ extension Parser {
733699
)
734700
)
735701
case (.exported, let handle)?:
736-
let ident = self.eat(handle)
702+
let label = self.eat(handle)
737703
let (unexpectedBeforeColon, colon) = self.expect(.colon)
738704
let (unexpectedBeforeValue, value) = self.expect(.keyword(.true), .keyword(.false), default: .keyword(.false))
739705
let comma = self.consume(if: .comma)
740706
elements.append(
741707
.labeledSpecializeArgument(
742708
RawLabeledSpecializeArgumentSyntax(
743-
label: ident,
709+
label: label,
744710
unexpectedBeforeColon,
745711
colon: colon,
746712
unexpectedBeforeValue,
@@ -751,14 +717,14 @@ extension Parser {
751717
)
752718
)
753719
case (.kind, let handle)?:
754-
let ident = self.eat(handle)
720+
let label = self.eat(handle)
755721
let (unexpectedBeforeColon, colon) = self.expect(.colon)
756722
let valueLabel = self.parseAnyIdentifier()
757723
let comma = self.consume(if: .comma)
758724
elements.append(
759725
.labeledSpecializeArgument(
760726
RawLabeledSpecializeArgumentSyntax(
761-
label: ident,
727+
label: label,
762728
unexpectedBeforeColon,
763729
colon: colon,
764730
value: valueLabel,
@@ -769,14 +735,14 @@ extension Parser {
769735
)
770736
case (.spiModule, let handle)?,
771737
(.spi, let handle)?:
772-
let ident = self.eat(handle)
738+
let label = self.eat(handle)
773739
let (unexpectedBeforeColon, colon) = self.expect(.colon)
774740
let valueLabel = self.consumeAnyToken()
775741
let comma = self.consume(if: .comma)
776742
elements.append(
777743
.labeledSpecializeArgument(
778744
RawLabeledSpecializeArgumentSyntax(
779-
label: ident,
745+
label: label,
780746
unexpectedBeforeColon,
781747
colon: colon,
782748
value: valueLabel,
@@ -786,22 +752,7 @@ extension Parser {
786752
)
787753
)
788754
case nil:
789-
let ident = self.consumeAnyToken()
790-
let (unexpectedBeforeColon, colon) = self.expect(.colon)
791-
let valueLabel = self.consumeAnyToken()
792-
let comma = self.consume(if: .comma)
793-
elements.append(
794-
.labeledSpecializeArgument(
795-
RawLabeledSpecializeArgumentSyntax(
796-
label: ident,
797-
unexpectedBeforeColon,
798-
colon: colon,
799-
value: valueLabel,
800-
trailingComma: comma,
801-
arena: self.arena
802-
)
803-
)
804-
)
755+
break LOOP
805756
}
806757
}
807758

Sources/SwiftParser/Parser.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public struct Parser {
119119
/// explicitly specify one. Debug builds of the parser consume a lot more stack
120120
/// space and thus have a lower default maximum nesting level.
121121
#if DEBUG
122-
static let defaultMaximumNestingLevel = 25
122+
static let defaultMaximumNestingLevel = 20
123123
#else
124124
static let defaultMaximumNestingLevel = 256
125125
#endif

0 commit comments

Comments
 (0)