Skip to content

Commit dc156a6

Browse files
committed
[ASTGen] Generate Swift key-path expressions
1 parent 919ec93 commit dc156a6

File tree

6 files changed

+401
-8
lines changed

6 files changed

+401
-8
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,18 @@ BridgedIsExpr BridgedIsExpr_createParsed(BridgedASTContext cContext,
13351335
BridgedSourceLoc cIsLoc,
13361336
BridgedTypeRepr cType);
13371337

1338+
SWIFT_NAME("BridgedKeyPathDotExpr.createParsed(_:loc:)")
1339+
BridgedKeyPathDotExpr
1340+
BridgedKeyPathDotExpr_createParsed(BridgedASTContext cContext,
1341+
BridgedSourceLoc cLoc);
1342+
1343+
SWIFT_NAME("BridgedKeyPathExpr.createParsed(_:backslashLoc:parsedRoot:"
1344+
"parsedPath:hasLeadingDot:)")
1345+
BridgedKeyPathExpr BridgedKeyPathExpr_createParsed(
1346+
BridgedASTContext cContext, BridgedSourceLoc cBackslashLoc,
1347+
BridgedNullableExpr cParsedRoot, BridgedNullableExpr cParsedPath,
1348+
bool hasLeadingDot);
1349+
13381350
SWIFT_NAME("BridgedMacroExpansionExpr.createParsed(_:poundLoc:macroNameRef:"
13391351
"macroNameLoc:leftAngleLoc:genericArgs:rightAngleLoc:args:)")
13401352
BridgedMacroExpansionExpr BridgedMacroExpansionExpr_createParsed(

lib/AST/Bridging/DeclBridging.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ static void setParsedMembers(IterableDeclContext *IDC,
346346
}
347347
}
348348

349+
IDC->setMaybeHasOperatorDeclarations();
350+
IDC->setMaybeHasNestedClassDeclarations();
349351
ctx.evaluator.cacheOutput(
350352
ParseMembersRequest{IDC},
351353
FingerprintAndMembers{std::nullopt, ctx.AllocateCopy(members)});

lib/AST/Bridging/ExprBridging.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,21 @@ BridgedIntegerLiteralExpr_createParsed(BridgedASTContext cContext,
281281
IntegerLiteralExpr(cStr.unbridged(), cTokenLoc.unbridged());
282282
}
283283

284+
BridgedKeyPathDotExpr
285+
BridgedKeyPathDotExpr_createParsed(BridgedASTContext cContext,
286+
BridgedSourceLoc cLoc) {
287+
return new (cContext.unbridged()) KeyPathDotExpr(cLoc.unbridged());
288+
}
289+
290+
BridgedKeyPathExpr BridgedKeyPathExpr_createParsed(
291+
BridgedASTContext cContext, BridgedSourceLoc cBackslashLoc,
292+
BridgedNullableExpr cParsedRoot, BridgedNullableExpr cParsedPath,
293+
bool hasLeadingDot) {
294+
return KeyPathExpr::createParsed(
295+
cContext.unbridged(), cBackslashLoc.unbridged(), cParsedRoot.unbridged(),
296+
cParsedPath.unbridged(), hasLeadingDot);
297+
}
298+
284299
BridgedSuperRefExpr
285300
BridgedSuperRefExpr_createParsed(BridgedASTContext cContext,
286301
BridgedSourceLoc cSuperLoc) {

lib/ASTGen/Sources/ASTGen/Decls.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,13 @@ extension ASTGenVisitor {
349349
accessorDecl node: AccessorDeclSyntax,
350350
for storage: BridgedAbstractStorageDecl
351351
) -> BridgedAccessorDecl? {
352-
// TODO: Attributes and modifier.
352+
// FIXME: Attributes.
353+
var attrs = BridgedDeclAttributes()
354+
if
355+
let modifier = node.modifier,
356+
let attr = self.generate(declModifier: modifier) {
357+
attrs.add(attr)
358+
}
353359

354360
guard let kind = self.generate(accessorSpecifier: node.accessorSpecifier) else {
355361
// TODO: We could potentially recover if this is the first accessor by treating
@@ -368,6 +374,7 @@ extension ASTGenVisitor {
368374
throwsSpecifierLoc: self.generateSourceLoc(node.effectSpecifiers?.throwsClause),
369375
thrownType: self.generate(type: node.effectSpecifiers?.thrownError)
370376
)
377+
accessor.asDecl.setAttrs(attrs)
371378
if let body = node.body {
372379
self.withDeclContext(accessor.asDeclContext) {
373380
accessor.setParsedBody(self.generate(codeBlock: body))

lib/ASTGen/Sources/ASTGen/Exprs.swift

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,14 @@ func isExprMigrated(_ node: ExprSyntax) -> Bool {
4646
.discardAssignmentExpr, .declReferenceExpr, .dictionaryExpr, .doExpr,
4747
.editorPlaceholderExpr, .floatLiteralExpr, .forceUnwrapExpr, .functionCallExpr,
4848
.genericSpecializationExpr, .ifExpr, .infixOperatorExpr, .inOutExpr,
49-
.integerLiteralExpr, .isExpr, .macroExpansionExpr, .memberAccessExpr, .nilLiteralExpr,
49+
.integerLiteralExpr, .isExpr, .keyPathExpr, .macroExpansionExpr, .memberAccessExpr, .nilLiteralExpr,
5050
.optionalChainingExpr, .packElementExpr, .packExpansionExpr, .patternExpr, .postfixIfConfigExpr,
5151
.postfixOperatorExpr, .prefixOperatorExpr, .regexLiteralExpr, .sequenceExpr,
5252
.simpleStringLiteralExpr, .subscriptCallExpr, .stringLiteralExpr, .superExpr,
5353
.switchExpr, .tryExpr, .tupleExpr, .typeExpr, .unresolvedAsExpr, .unresolvedIsExpr,
5454
.unresolvedTernaryExpr, .ternaryExpr:
5555
break
5656

57-
// Known unimplemented kinds.
58-
case .keyPathExpr:
59-
return false
60-
6157
// Unknown expr kinds.
6258
case _ where current.is(ExprSyntax.self):
6359
return false
@@ -129,8 +125,8 @@ extension ASTGenVisitor {
129125
return self.generate(integerLiteralExpr: node).asExpr
130126
case .isExpr:
131127
preconditionFailure("IsExprSyntax only appear after operator folding")
132-
case .keyPathExpr:
133-
break
128+
case .keyPathExpr(let node):
129+
return self.generate(keyPathExpr: node)
134130
case .macroExpansionExpr(let node):
135131
return self.generate(macroExpansionExpr: node).asExpr
136132
case .memberAccessExpr(let node):
@@ -535,6 +531,118 @@ extension ASTGenVisitor {
535531
)
536532
}
537533

534+
func generate(keyPathComponent node: KeyPathComponentSyntax, baseExpr: BridgedExpr) -> BridgedExpr {
535+
switch node.component {
536+
case .property(let prop):
537+
let dotLoc = self.generateSourceLoc(node.period)
538+
if prop.declName.baseName.presence == .missing {
539+
return BridgedErrorExpr.create(
540+
self.ctx,
541+
loc: BridgedSourceRange(start: dotLoc, end: dotLoc)
542+
).asExpr
543+
} else if prop.declName.baseName.keywordKind == .`self` {
544+
// TODO: Diagnose if there's arguments
545+
assert(prop.declName.argumentNames == nil)
546+
547+
return BridgedDotSelfExpr.createParsed(
548+
self.ctx,
549+
subExpr: baseExpr,
550+
dotLoc: dotLoc,
551+
selfLoc: self.generateSourceLoc(prop.declName)
552+
).asExpr
553+
} else {
554+
let declNameRef = self.generateDeclNameRef(declReferenceExpr: prop.declName)
555+
return BridgedUnresolvedDotExpr.createParsed(
556+
self.ctx,
557+
base: baseExpr,
558+
dotLoc: dotLoc,
559+
name: declNameRef.name,
560+
nameLoc: declNameRef.loc
561+
).asExpr
562+
}
563+
564+
case .optional(let comp):
565+
if comp.questionOrExclamationMark.rawText == "!" {
566+
return BridgedForceValueExpr.createParsed(
567+
self.ctx,
568+
subExpr: baseExpr,
569+
exclaimLoc: self.generateSourceLoc(comp.questionOrExclamationMark)
570+
).asExpr
571+
} else {
572+
return BridgedBindOptionalExpr.createParsed(
573+
self.ctx,
574+
subExpr: baseExpr,
575+
questionLoc: self.generateSourceLoc(comp.questionOrExclamationMark)
576+
).asExpr
577+
}
578+
579+
case .subscript(let comp):
580+
return BridgedSubscriptExpr.createParsed(
581+
self.ctx,
582+
baseExpr: baseExpr,
583+
args: self.generateArgumentList(
584+
leftParen: comp.leftSquare,
585+
labeledExprList: comp.arguments,
586+
rightParen: comp.rightSquare,
587+
trailingClosure: nil,
588+
additionalTrailingClosures: nil
589+
)
590+
).asExpr
591+
}
592+
}
593+
594+
func generate(keyPathExpr node: KeyPathExprSyntax) -> BridgedExpr {
595+
guard !node.components.isEmpty else {
596+
// FIXME: Diagnostics KeyPath expression without any component.
597+
return BridgedErrorExpr.create(self.ctx, loc: self.generateSourceRange(node)).asExpr
598+
}
599+
600+
var rootExpr: BridgedExpr?
601+
if let parsedType = node.root, !parsedType.is(MissingTypeSyntax.self) {
602+
let rootType = self.generate(type: parsedType)
603+
rootExpr = BridgedTypeExpr.createParsed(self.ctx, type: rootType).asExpr
604+
} else {
605+
rootExpr = nil
606+
}
607+
608+
var inRoot = rootExpr != nil
609+
var pathExpr: BridgedExpr? = nil
610+
611+
for component in node.components {
612+
if inRoot {
613+
switch component.component {
614+
case // "root" expression is separated by '.?' or '.[idx]'
615+
.optional(_) where component.period != nil,
616+
.subscript(_) where component.period != nil:
617+
inRoot = false
618+
default:
619+
rootExpr = self.generate(keyPathComponent: component, baseExpr: rootExpr!)
620+
continue
621+
}
622+
}
623+
624+
if pathExpr == nil {
625+
// 'KeyPathDotExpr' is a dummy base expression.
626+
pathExpr = BridgedKeyPathDotExpr.createParsed(
627+
self.ctx,
628+
// Use 'component' instead of 'component.period' because period can
629+
// be nil (e.g. '\?'), but 'loc' must be a valid location.
630+
loc: self.generateSourceLoc(component)
631+
).asExpr
632+
}
633+
634+
pathExpr = self.generate(keyPathComponent: component, baseExpr: pathExpr!)
635+
}
636+
637+
return BridgedKeyPathExpr.createParsed(
638+
self.ctx,
639+
backslashLoc: self.generateSourceLoc(node.backslash),
640+
parsedRoot: rootExpr.asNullable,
641+
parsedPath: pathExpr.asNullable,
642+
hasLeadingDot: rootExpr == nil
643+
).asExpr
644+
}
645+
538646
struct FreestandingMacroExpansionInfo {
539647
var poundLoc: BridgedSourceLoc
540648
var macroNameRef: BridgedDeclNameRef

0 commit comments

Comments
 (0)