Skip to content

SwiftSyntax support for module selectors #3091

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

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ public let ATTRIBUTE_NODES: [Node] = [
Node(
kind: .implementsAttributeArguments,
base: .syntax,
nameForDiagnostics: "@_implements arguemnts",
nameForDiagnostics: "@_implements arguments",
documentation:
"The arguments for the `@_implements` attribute of the form `Type, methodName(arg1Label:arg2Label:)`",
children: [
Expand Down
18 changes: 18 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,24 @@ public let COMMON_NODES: [Node] = [
]
),

Node(
kind: .moduleSelector,
base: .syntax,
nameForDiagnostics: "module selector",
children: [
Child(
name: "moduleName",
kind: .token(choices: [.token(.identifier)]),
nameForDiagnostics: "module name"
),
Child(
name: "colonColon",
kind: .token(choices: [.token(.colonColon)]),
nameForDiagnostics: "'::' operator"
),
]
),

Node(
kind: .pattern,
base: .syntax,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public enum ExperimentalFeature: String, CaseIterable {
case keypathWithMethodMembers
case oldOwnershipOperatorSpellings
case inlineArrayTypeSugar
case moduleSelector

/// The name of the feature as it is written in the compiler's `Features.def` file.
public var featureName: String {
Expand All @@ -44,6 +45,8 @@ public enum ExperimentalFeature: String, CaseIterable {
return "OldOwnershipOperatorSpellings"
case .inlineArrayTypeSugar:
return "InlineArrayTypeSugar"
case .moduleSelector:
return "ModuleSelector"
}
}

Expand All @@ -68,6 +71,8 @@ public enum ExperimentalFeature: String, CaseIterable {
return "`_move` and `_borrow` as ownership operators"
case .inlineArrayTypeSugar:
return "sugar type for InlineArray"
case .moduleSelector:
return "Module selector syntax (`ModName::identifier`)"
}
}

Expand Down
12 changes: 12 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/ExprNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,12 @@ public let EXPR_NODES: [Node] = [
base: .expr,
nameForDiagnostics: nil,
children: [
Child(
name: "moduleSelector",
kind: .node(kind: .moduleSelector),
experimentalFeature: .moduleSelector,
isOptional: true
),
Child(
name: "baseName",
kind: .token(choices: [
Expand Down Expand Up @@ -1358,6 +1364,12 @@ public let EXPR_NODES: [Node] = [
kind: .token(choices: [.token(.pound)]),
documentation: "The `#` sign."
),
Child(
name: "moduleSelector",
kind: .node(kind: .moduleSelector),
experimentalFeature: .moduleSelector,
isOptional: true
),
Child(
name: "macroName",
kind: .token(choices: [.token(.identifier)])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ public enum SyntaxNodeKind: String, CaseIterable, IdentifierConvertible, TypeCon
case missingPattern
case missingStmt
case missingType
case moduleSelector
case multipleTrailingClosureElement
case multipleTrailingClosureElementList
case namedOpaqueReturnType
Expand Down
3 changes: 3 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/TokenSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public enum Token: CaseIterable {
case backtick
case binaryOperator
case colon
case colonColon
case comma
case dollarIdentifier
case ellipsis
Expand Down Expand Up @@ -185,6 +186,8 @@ public enum Token: CaseIterable {
return .other(name: "binaryOperator", nameForDiagnostics: "binary operator")
case .colon:
return .punctuator(name: "colon", text: ":")
case .colonColon:
return .punctuator(name: "colonColon", text: "::")
case .comma:
return .punctuator(name: "comma", text: ",")
case .dollarIdentifier:
Expand Down
14 changes: 14 additions & 0 deletions CodeGeneration/Sources/SyntaxSupport/TypeNodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@ public let TYPE_NODES: [Node] = [
name: "period",
kind: .token(choices: [.token(.period)])
),
Child(
name: "moduleSelector",
kind: .node(kind: .moduleSelector),
experimentalFeature: .moduleSelector,
nameForDiagnostics: "module selector",
isOptional: true
),
Child(
name: "name",
kind: .token(choices: [.token(.identifier), .keyword(.self)]),
Expand Down Expand Up @@ -501,6 +508,13 @@ public let TYPE_NODES: [Node] = [
base: .type,
nameForDiagnostics: "type",
children: [
Child(
name: "moduleSelector",
kind: .node(kind: .moduleSelector),
experimentalFeature: .moduleSelector,
nameForDiagnostics: "module selector",
isOptional: true
),
Child(
name: "name",
kind: .token(choices: [
Expand Down
2 changes: 2 additions & 0 deletions Sources/SwiftBasicFormat/BasicFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,12 @@ open class BasicFormat: SyntaxRewriter {
case (.atSign, _),
(.backslash, _),
(.backtick, _),
(.colonColon, .identifier),
(.dollarIdentifier, .period), // a.b
(.endOfFile, _),
(.exclamationMark, .period), // myOptionalBar!.foo()
(.regexPoundDelimiter, .regexSlash), // opening extended regex delimiter should never be separate by a space
(.identifier, .colonColon),
(.identifier, .leftAngle), // MyType<Int>
(.identifier, .leftSquare), // myArray[1]
(.identifier, .period), // a.b
Expand Down
2 changes: 2 additions & 0 deletions Sources/SwiftIDEUtils/SyntaxClassification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ extension RawTokenKind {
return .operator
case .colon:
return .none
case .colonColon:
return .operator
case .comma:
return .none
case .dollarIdentifier:
Expand Down
92 changes: 68 additions & 24 deletions Sources/SwiftParser/Attributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,11 @@ extension Parser {
)
}

switch peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) {
// An attribute qualified by a module selector is *always* a custom attribute, even if it has the same name (or
// module name) as a builtin attribute.
let builtinAttr = self.unlessPeekModuleSelector { $0.peek(isAtAnyIn: DeclarationAttributeWithSpecialSyntax.self) }

switch builtinAttr {
case .abi:
return parseAttribute(argumentMode: .required) { parser in
return (nil, .abiArguments(parser.parseABIAttributeArguments()))
Expand Down Expand Up @@ -297,7 +301,12 @@ extension Parser {
unexpectedBeforeAtSign,
atSign: atSign,
unexpectedBeforeAttributeName,
attributeName: RawIdentifierTypeSyntax(name: attributeName, genericArgumentClause: nil, arena: self.arena),
attributeName: RawIdentifierTypeSyntax(
moduleSelector: nil,
name: attributeName,
genericArgumentClause: nil,
arena: self.arena
),
leftParen: nil,
arguments: nil,
rightParen: nil,
Expand All @@ -322,7 +331,9 @@ extension Parser {

extension RawLabeledExprSyntax {
fileprivate init(
_ unexpectedBeforeIdentifier: RawUnexpectedNodesSyntax? = nil,
_ unexpectedBeforeModuleSelector: RawUnexpectedNodesSyntax? = nil,
moduleSelector: RawModuleSelectorSyntax?,
_ unexpectedBetweenModuleSelectorAndIdentifier: RawUnexpectedNodesSyntax? = nil,
identifier: RawTokenSyntax,
_ unexpectedBetweenIdentifierAndTrailingComma: RawUnexpectedNodesSyntax? = nil,
trailingComma: RawTokenSyntax? = nil,
Expand All @@ -332,7 +343,9 @@ extension RawLabeledExprSyntax {
label: nil,
colon: nil,
expression: RawDeclReferenceExprSyntax(
unexpectedBeforeIdentifier,
unexpectedBeforeModuleSelector,
moduleSelector: moduleSelector,
unexpectedBetweenModuleSelectorAndIdentifier,
baseName: identifier,
argumentNames: nil,
arena: arena
Expand All @@ -354,6 +367,7 @@ extension Parser {
let roleTrailingComma = self.consume(if: .comma)

let roleElement = RawLabeledExprSyntax(
moduleSelector: nil,
unexpectedBeforeRole,
identifier: role,
trailingComma: roleTrailingComma,
Expand Down Expand Up @@ -383,7 +397,12 @@ extension Parser {
unexpectedBeforeAtSign,
atSign: atSign,
unexpectedBeforeDifferentiable,
attributeName: RawIdentifierTypeSyntax(name: differentiable, genericArgumentClause: nil, arena: self.arena),
attributeName: RawIdentifierTypeSyntax(
moduleSelector: nil,
name: differentiable,
genericArgumentClause: nil,
arena: self.arena
),
unexpectedBeforeLeftParen,
leftParen: leftParen,
arguments: .differentiableArguments(argument),
Expand Down Expand Up @@ -524,8 +543,13 @@ extension Parser {
return RawAttributeSyntax(
unexpectedBeforeAtSign,
atSign: atSign,
unexpectedBeforeDerivative,
attributeName: RawIdentifierTypeSyntax(name: derivative, genericArgumentClause: nil, arena: self.arena),
attributeName: RawIdentifierTypeSyntax(
moduleSelector: nil,
unexpectedBeforeDerivative,
name: derivative,
genericArgumentClause: nil,
arena: self.arena
),
unexpectedBeforeLeftParen,
leftParen: leftParen,
arguments: .derivativeRegistrationArguments(argument),
Expand All @@ -547,7 +571,12 @@ extension Parser {
unexpectedBeforeAtSign,
atSign: atSign,
unexpectedBeforeTranspose,
attributeName: RawIdentifierTypeSyntax(name: transpose, genericArgumentClause: nil, arena: self.arena),
attributeName: RawIdentifierTypeSyntax(
moduleSelector: nil,
name: transpose,
genericArgumentClause: nil,
arena: self.arena
),
unexpectedBeforeLeftParen,
leftParen: leftParen,
arguments: .derivativeRegistrationArguments(argument),
Expand Down Expand Up @@ -602,8 +631,8 @@ extension Parser {
var elements = [RawObjCSelectorPieceSyntax]()
var loopProgress = LoopProgressCondition()
while self.hasProgressed(&loopProgress) {
// Empty selector piece.
if let colon = self.consume(if: .colon) {
// Empty selector piece, splitting `::` into two colons.
if let colon = self.consume(ifPrefix: ":", as: .colon) {
elements.append(
RawObjCSelectorPieceSyntax(
name: nil,
Expand All @@ -627,7 +656,8 @@ extension Parser {
break
}

let (unexpectedBeforeColon, colon) = self.expect(.colon)
// Match ending colon, spliting `::` into two colons.
let (unexpectedBeforeColon, colon) = self.expect(prefix: ":", as: .colon)
elements.append(
RawObjCSelectorPieceSyntax(
name: name,
Expand All @@ -654,7 +684,11 @@ extension Parser {
case (.target, let handle)?:
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let declName = self.parseDeclReferenceExpr([.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators])
let moduleSelector = self.parseModuleSelector()
let declName = self.parseDeclReferenceExpr(
moduleSelector: moduleSelector,
[.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators]
)
let comma = self.consume(if: .comma)
elements.append(
.specializeTargetFunctionArgument(
Expand Down Expand Up @@ -707,15 +741,16 @@ extension Parser {
case (.kind, let handle)?:
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let valueLabel = self.parseAnyIdentifier()
let (unexpectedBeforeValue, value) = self.parseAnyIdentifier()
let comma = self.consume(if: .comma)
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: label,
unexpectedBeforeColon,
colon: colon,
value: valueLabel,
unexpectedBeforeValue,
value: value,
trailingComma: comma,
arena: self.arena
)
Expand All @@ -725,15 +760,16 @@ extension Parser {
(.spi, let handle)?:
let label = self.eat(handle)
let (unexpectedBeforeColon, colon) = self.expect(.colon)
let valueLabel = self.consumeAnyToken()
let (unexpectedBeforeValue, value) = self.expectIdentifier()
let comma = self.consume(if: .comma)
elements.append(
.labeledSpecializeArgument(
RawLabeledSpecializeArgumentSyntax(
label: label,
unexpectedBeforeColon,
colon: colon,
value: valueLabel,
unexpectedBeforeValue,
value: value,
trailingComma: comma,
arena: self.arena
)
Expand All @@ -757,14 +793,17 @@ extension Parser {
mutating func parseImplementsAttributeArguments() -> RawImplementsAttributeArgumentsSyntax {
let type = self.parseType()
let (unexpectedBeforeComma, comma) = self.expect(.comma)
let declName = self.parseDeclReferenceExpr([
.zeroArgCompoundNames,
.operators,
])

// You can't put a module selector on the member name--it's meaningless because the member has to come from the
// same module as the protocol.
let moduleSelector = self.parseModuleSelector()
let declName = self.parseDeclReferenceExpr(moduleSelector: nil, [.zeroArgCompoundNames, .operators])

return RawImplementsAttributeArgumentsSyntax(
type: type,
unexpectedBeforeComma,
comma: comma,
unexpected(moduleSelector),
declName: declName,
arena: self.arena
)
Expand All @@ -776,6 +815,7 @@ extension Parser {
let (unexpectedBeforeIsolationKind, isolationKind) =
self.expectIdentifier(allowKeywordsAsIdentifier: true)
let isolationKindElement = RawLabeledExprSyntax(
moduleSelector: nil,
unexpectedBeforeIsolationKind,
identifier: isolationKind,
arena: self.arena
Expand Down Expand Up @@ -903,17 +943,21 @@ extension Parser {
mutating func parseDynamicReplacementAttributeArguments() -> RawDynamicReplacementAttributeArgumentsSyntax {
let (unexpectedBeforeLabel, label) = self.expect(.keyword(.for))
let (unexpectedBeforeColon, colon) = self.expect(.colon)

let declName: RawDeclReferenceExprSyntax
if label.isMissing && colon.isMissing && self.atStartOfLine {
declName = RawDeclReferenceExprSyntax(
moduleSelector: nil,
baseName: RawTokenSyntax(missing: .identifier, arena: self.arena),
argumentNames: nil,
arena: self.arena
)
} else {
declName = self.parseDeclReferenceExpr([
.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators,
])
let moduleSelector = self.parseModuleSelector()
declName = self.parseDeclReferenceExpr(
moduleSelector: moduleSelector,
[.zeroArgCompoundNames, .keywordsUsingSpecialNames, .operators]
)
}
return RawDynamicReplacementAttributeArgumentsSyntax(
unexpectedBeforeLabel,
Expand Down Expand Up @@ -978,7 +1022,7 @@ extension Parser {
unexpectedBeforeValue = unexpected
value = .token(token)
case "metadata":
unexpectedBeforeValue = nil
unexpectedBeforeValue = unexpected(self.parseModuleSelector())
if let identifier = self.consume(if: .identifier) {
value = .token(identifier)
} else {
Expand Down
Loading