Skip to content

Add diagnostic for wrong specialize label #1727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion CodeGeneration/Sources/SyntaxSupport/AttributeNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,15 @@ public let ATTRIBUTE_NODES: [Node] = [
children: [
Child(
name: "Label",
kind: .node(kind: .token),
kind: .token(choices: [
.keyword(text: "target"),
.keyword(text: "availability"),
.keyword(text: "exported"),
.keyword(text: "kind"),
.keyword(text: "spi"),
.keyword(text: "spiModule"),
.keyword(text: "available"),
]),
nameForDiagnostics: "label",
documentation: "The label of the argument"
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ let parserTokenSpecSetFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
for child in layoutNode.children {
if case let .token(choices, _, _) = child.kind, choices.count > 1 {
try! ExtensionDeclSyntax("extension \(raw: layoutNode.kind.syntaxType)") {
try EnumDeclSyntax("enum \(raw: child.name)Options: TokenSpecSet") {
try EnumDeclSyntax(
"""
@_spi(Diagnostics)
public enum \(raw: child.name)Options: TokenSpecSet
"""
) {
for choice in choices {
switch choice {
case .keyword(let keywordText):
Expand Down Expand Up @@ -70,6 +75,39 @@ let parserTokenSpecSetFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
}
}
}

try VariableDeclSyntax(
"""
/// Returns a token that satisfies the `TokenSpec` of this case.
///
/// If the token kind of this spec has variable text, e.g. for an identifier, this returns a token with empty text.
@_spi(Diagnostics)
public var tokenSyntax: TokenSyntax
"""
) {
try SwitchExprSyntax("switch self") {
for choice in choices {
switch choice {
case .keyword(let keywordText):
let keyword = KEYWORDS.first(where: { $0.name == keywordText })!
SwitchCaseSyntax(
"case .\(raw: keyword.escapedName): return .keyword(.\(raw: keyword.escapedName))"
)
case .token(let tokenText):
let token = SYNTAX_TOKEN_MAP[tokenText]!
if token.text != nil {
SwitchCaseSyntax(
"case .\(raw: token.varOrCaseName): return .\(raw: token.varOrCaseName)Token()"
)
} else {
SwitchCaseSyntax(
#"case .\#(raw: token.varOrCaseName): return .\#(raw: token.varOrCaseName)("")"#
)
}
}
}
}
}
}
}
}
Expand Down
79 changes: 15 additions & 64 deletions Sources/SwiftParser/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -638,55 +638,21 @@ extension Parser {
}

extension Parser {
enum SpecializeParameter: TokenSpecSet {
case target
case availability
case exported
case kind
case spi
case spiModule
case available

init?(lexeme: Lexer.Lexeme) {
switch PrepareForKeywordMatch(lexeme) {
case TokenSpec(.target): self = .target
case TokenSpec(.availability): self = .availability
case TokenSpec(.exported): self = .exported
case TokenSpec(.kind): self = .kind
case TokenSpec(.spi): self = .spi
case TokenSpec(.spiModule): self = .spiModule
case TokenSpec(.available): self = .available
default: return nil
}
}

var spec: TokenSpec {
switch self {
case .target: return .keyword(.target)
case .availability: return .keyword(.availability)
case .exported: return .keyword(.exported)
case .kind: return .keyword(.kind)
case .spi: return .keyword(.spi)
case .spiModule: return .keyword(.spiModule)
case .available: return .keyword(.available)
}
}
}
mutating func parseSpecializeAttributeArgumentList() -> RawSpecializeAttributeArgumentListSyntax {
var elements = [RawSpecializeAttributeArgumentListSyntax.Element]()
// Parse optional "exported" and "kind" labeled parameters.
var loopProgress = LoopProgressCondition()
while !self.at(.endOfFile, .rightParen, .keyword(.where)) && self.hasProgressed(&loopProgress) {
switch self.at(anyIn: SpecializeParameter.self) {
LOOP: while !self.at(.endOfFile, .rightParen, .keyword(.where)) && self.hasProgressed(&loopProgress) {
switch self.at(anyIn: LabeledSpecializeArgumentSyntax.LabelOptions.self) {
case (.target, let handle)?:
let ident = self.eat(handle)
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let declName = self.parseDeclReferenceExpr([.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators])
let comma = self.consume(if: .comma)
elements.append(
.specializeTargetFunctionArgument(
RawSpecializeTargetFunctionArgumentSyntax(
targetLabel: ident,
targetLabel: label,
unexpectedBeforeColon,
colon: colon,
declName: declName,
Expand All @@ -696,14 +662,14 @@ extension Parser {
)
)
case (.availability, let handle)?:
let ident = self.eat(handle)
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let availability = self.parseAvailabilitySpecList()
let (unexpectedBeforeSemi, semi) = self.expect(.semicolon)
elements.append(
.specializeAvailabilityArgument(
RawSpecializeAvailabilityArgumentSyntax(
availabilityLabel: ident,
availabilityLabel: label,
unexpectedBeforeColon,
colon: colon,
availabilityArguments: availability,
Expand All @@ -714,7 +680,7 @@ extension Parser {
)
)
case (.available, let handle)?:
let ident = self.eat(handle)
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
// FIXME: I have no idea what this is supposed to be, but the Syntax
// tree only allows us to insert a token so we'll take anything.
Expand All @@ -723,7 +689,7 @@ extension Parser {
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: ident,
label: label,
unexpectedBeforeColon,
colon: colon,
value: available,
Expand All @@ -733,14 +699,14 @@ extension Parser {
)
)
case (.exported, let handle)?:
let ident = self.eat(handle)
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let (unexpectedBeforeValue, value) = self.expect(.keyword(.true), .keyword(.false), default: .keyword(.false))
let comma = self.consume(if: .comma)
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: ident,
label: label,
unexpectedBeforeColon,
colon: colon,
unexpectedBeforeValue,
Expand All @@ -751,14 +717,14 @@ extension Parser {
)
)
case (.kind, let handle)?:
let ident = self.eat(handle)
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let valueLabel = self.parseAnyIdentifier()
let comma = self.consume(if: .comma)
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: ident,
label: label,
unexpectedBeforeColon,
colon: colon,
value: valueLabel,
Expand All @@ -769,14 +735,14 @@ extension Parser {
)
case (.spiModule, let handle)?,
(.spi, let handle)?:
let ident = self.eat(handle)
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let valueLabel = self.consumeAnyToken()
let comma = self.consume(if: .comma)
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: ident,
label: label,
unexpectedBeforeColon,
colon: colon,
value: valueLabel,
Expand All @@ -786,22 +752,7 @@ extension Parser {
)
)
case nil:
let ident = self.consumeAnyToken()
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let valueLabel = self.consumeAnyToken()
let comma = self.consume(if: .comma)
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: ident,
unexpectedBeforeColon,
colon: colon,
value: valueLabel,
trailingComma: comma,
arena: self.arena
)
)
)
break LOOP
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftParser/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public struct Parser {
/// explicitly specify one. Debug builds of the parser consume a lot more stack
/// space and thus have a lower default maximum nesting level.
#if DEBUG
static let defaultMaximumNestingLevel = 25
static let defaultMaximumNestingLevel = 20
#else
static let defaultMaximumNestingLevel = 256
#endif
Expand Down
Loading