Skip to content

Commit b458cf2

Browse files
committed
[NFC] [ASTGen] Don’t form PBDs without SourceLocs
A PatternBindingEntry formed from a MissingPatternSyntax has no valid SourceLocs in it, and a PatternBindingDecl containing only PatternBindingEntries with no valid SourceLocs trips an assertion during availability checking. (Generating dummy SourceLocs can cause invalid overlaps between AvailabilityScopes, so that’s not a workable solution.) The fix is to: • Refuse to generate a PatternBindingEntry from a PatternBindingSyntax with a MissingPatternSyntax (MissingPatternSyntaxes at nested positions don’t have this problem) • Refuse to generate a PatternBindingDecl with no PatternBindingEntries This ensures that the invalid AST nodes are never formed. No current test cases hit this problem, but certain invalid module selector tests can run into this situation when run with ASTGen.
1 parent 8346bc6 commit b458cf2

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

lib/ASTGen/Sources/ASTGen/Decls.swift

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,15 @@ extension ASTGenVisitor {
499499
}
500500
}
501501

502-
func generate(patternBinding binding: PatternBindingSyntax, attrs: DeclAttributesResult, topLevelDecl: BridgedTopLevelCodeDecl?) -> BridgedPatternBindingEntry {
502+
func generate(patternBinding binding: PatternBindingSyntax, attrs: DeclAttributesResult, topLevelDecl: BridgedTopLevelCodeDecl?) -> BridgedPatternBindingEntry? {
503+
if binding.pattern.is(MissingPatternSyntax.self) {
504+
// The availability checker requires declarations to have valid SourceLocs, but MissingPatternSyntax lowers to
505+
// an implicit AnyPattern with invalid SourceLocs. A top-level MissingPatternSyntax could therefore cause us to
506+
// construct an invalid AST. Drop the whole binding instead.
507+
// No need to diagnose; SwiftParser should have already diagnosed the `MissingPatternSyntax`.
508+
return nil
509+
}
510+
503511
let pattern = generate(pattern: binding.pattern)
504512

505513
let equalLoc = generateSourceLoc(binding.initializer?.equal)
@@ -535,14 +543,17 @@ extension ASTGenVisitor {
535543
)
536544
}
537545

538-
private func generateBindingEntries(for node: VariableDeclSyntax, attrs: DeclAttributesResult, topLevelDecl: BridgedTopLevelCodeDecl?) -> BridgedArrayRef {
546+
private func generateBindingEntries(for node: VariableDeclSyntax, attrs: DeclAttributesResult, topLevelDecl: BridgedTopLevelCodeDecl?) -> BridgedArrayRef? {
539547
var propagatedType: BridgedTypeRepr?
540548
var entries: [BridgedPatternBindingEntry] = []
541549

542550
// Generate the bindings in reverse, keeping track of the TypeRepr to
543551
// propagate to earlier patterns if needed.
544552
for binding in node.bindings.reversed() {
545-
var entry = self.generate(patternBinding: binding, attrs: attrs, topLevelDecl: topLevelDecl)
553+
guard var entry = self.generate(patternBinding: binding, attrs: attrs, topLevelDecl: topLevelDecl) else {
554+
// Missing pattern. Drop this binding.
555+
continue
556+
}
546557

547558
// We can potentially propagate a type annotation back if we don't have an initializer, and are a bare NamedPattern.
548559
let canPropagateType = binding.initializer == nil && binding.pattern.is(IdentifierPatternSyntax.self)
@@ -572,10 +583,17 @@ extension ASTGenVisitor {
572583
}
573584
entries.append(entry)
574585
}
586+
587+
if entries.isEmpty {
588+
// A VariableDeclSyntax is syntactically required to have at least one binding, so this can only happen if all
589+
// of the bindings had missing patterns.
590+
return nil
591+
}
592+
575593
return entries.reversed().bridgedArray(in: self)
576594
}
577595

578-
func generate(variableDecl node: VariableDeclSyntax) -> BridgedDecl {
596+
func generate(variableDecl node: VariableDeclSyntax) -> BridgedDecl? {
579597
let attrs = self.generateDeclAttributes(node, allowStatic: true)
580598
let introducer: BridgedVarDeclIntroducer
581599
switch node.bindingSpecifier.rawText {
@@ -596,6 +614,12 @@ extension ASTGenVisitor {
596614
topLevelDecl = nil
597615
}
598616

617+
guard let entries = self.generateBindingEntries(for: node, attrs: attrs, topLevelDecl: topLevelDecl) else {
618+
// No bindings with valid SourceLocs. A PatternBindingDecl generated from this would have an invalid SourceRange,
619+
// violating availability checker invariants. Drop the PBD instead.
620+
return nil
621+
}
622+
599623
let decl = BridgedPatternBindingDecl.createParsed(
600624
self.ctx,
601625
declContext: topLevelDecl?.asDeclContext ?? self.declContext,
@@ -604,7 +628,7 @@ extension ASTGenVisitor {
604628
staticSpelling: attrs.staticSpelling,
605629
introducerLoc: self.generateSourceLoc(node.bindingSpecifier),
606630
introducer: introducer,
607-
entries: self.generateBindingEntries(for: node, attrs: attrs, topLevelDecl: topLevelDecl)
631+
entries: entries
608632
)
609633
if let topLevelDecl {
610634
let range = self.generateImplicitBraceRange(node)

0 commit comments

Comments
 (0)