Skip to content

Commit fa5594a

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 b6e22cb commit fa5594a

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
@@ -502,7 +502,15 @@ extension ASTGenVisitor {
502502
}
503503
}
504504

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

508516
let equalLoc = generateSourceLoc(binding.initializer?.equal)
@@ -538,14 +546,17 @@ extension ASTGenVisitor {
538546
)
539547
}
540548

541-
private func generateBindingEntries(for node: VariableDeclSyntax, attrs: DeclAttributesResult, topLevelDecl: BridgedTopLevelCodeDecl?) -> BridgedArrayRef {
549+
private func generateBindingEntries(for node: VariableDeclSyntax, attrs: DeclAttributesResult, topLevelDecl: BridgedTopLevelCodeDecl?) -> BridgedArrayRef? {
542550
var propagatedType: BridgedTypeRepr?
543551
var entries: [BridgedPatternBindingEntry] = []
544552

545553
// Generate the bindings in reverse, keeping track of the TypeRepr to
546554
// propagate to earlier patterns if needed.
547555
for binding in node.bindings.reversed() {
548-
var entry = self.generate(patternBinding: binding, attrs: attrs, topLevelDecl: topLevelDecl)
556+
guard var entry = self.generate(patternBinding: binding, attrs: attrs, topLevelDecl: topLevelDecl) else {
557+
// Missing pattern. Drop this binding.
558+
continue
559+
}
549560

550561
// We can potentially propagate a type annotation back if we don't have an initializer, and are a bare NamedPattern.
551562
let canPropagateType = binding.initializer == nil && binding.pattern.is(IdentifierPatternSyntax.self)
@@ -575,10 +586,17 @@ extension ASTGenVisitor {
575586
}
576587
entries.append(entry)
577588
}
589+
590+
if entries.isEmpty {
591+
// A VariableDeclSyntax is syntactically required to have at least one binding, so this can only happen if all
592+
// of the bindings had missing patterns.
593+
return nil
594+
}
595+
578596
return entries.reversed().bridgedArray(in: self)
579597
}
580598

581-
func generate(variableDecl node: VariableDeclSyntax) -> BridgedDecl {
599+
func generate(variableDecl node: VariableDeclSyntax) -> BridgedDecl? {
582600
let attrs = self.generateDeclAttributes(node, allowStatic: true)
583601
let introducer: BridgedVarDeclIntroducer
584602
switch node.bindingSpecifier.rawText {
@@ -599,6 +617,12 @@ extension ASTGenVisitor {
599617
topLevelDecl = nil
600618
}
601619

620+
guard let entries = self.generateBindingEntries(for: node, attrs: attrs, topLevelDecl: topLevelDecl) else {
621+
// No bindings with valid SourceLocs. A PatternBindingDecl generated from this would have an invalid SourceRange,
622+
// violating availability checker invariants. Drop the PBD instead.
623+
return nil
624+
}
625+
602626
let decl = BridgedPatternBindingDecl.createParsed(
603627
self.ctx,
604628
declContext: topLevelDecl?.asDeclContext ?? self.declContext,
@@ -607,7 +631,7 @@ extension ASTGenVisitor {
607631
staticSpelling: attrs.staticSpelling,
608632
introducerLoc: self.generateSourceLoc(node.bindingSpecifier),
609633
introducer: introducer,
610-
entries: self.generateBindingEntries(for: node, attrs: attrs, topLevelDecl: topLevelDecl)
634+
entries: entries
611635
)
612636
if let topLevelDecl {
613637
let range = self.generateImplicitBraceRange(node)

0 commit comments

Comments
 (0)