Skip to content

[Swift][TypeChecker] Assertion "Querying VarDecl's type before type-checking parent stmt" in NamingPatternRequest::evaluate when a top-level var references a variable declared across a TopLevelCodeDecl boundary via guard let #89073

@YuanchengJiang

Description

@YuanchengJiang

Description

swift reproduce.swift crashes with an assertion failure in NamingPatternRequest::evaluate (TypeCheckDecl.cpp:2766) when the type checker attempts to resolve the type of a top-level variable fusion_0e59 that references c, which is itself declared in a later TopLevelCodeDecl (separated by a func declaration) and depends on a guard let b binding from an earlier TopLevelCodeDecl. The type checker queries b's type before its parent guard statement has been type-checked, violating the ordering invariant.

Reproducer

var fusion_0e59 = c

let a: Int? = fusion_0e59
guard let b = a else {
    fatalError()
}

func foo() {}

let c = b

Command

swift reproduce.swift

Expected behavior

The compiler should emit a diagnostic about the use of c before it is declared, or handle the forward reference gracefully. It should not crash with an assertion failure.

Actual behavior

Assertion failed: (Context.SourceMgr.hasIDEInspectionTargetBuffer() ||
  Context.LangOpts.IsForSourceKit ||
  Context.TypeCheckerOpts.EnableLazyTypecheck ||
  inSecondaryScriptFile() &&
  "Querying VarDecl's type before type-checking parent stmt"),
function evaluate at TypeCheckDecl.cpp:2766.

While evaluating request TypeCheckPrimaryFileRequest(source_file "reproduce.swift")
While type-checking declaration (at reproduce.swift:1:1) [var fusion_0e59]
While evaluating request PatternBindingEntryRequest
While evaluating request InterfaceTypeRequest [c]
While evaluating request NamingPatternRequest [c]
While evaluating request PatternBindingEntryRequest
While type-checking expression [c = b]
While evaluating request InterfaceTypeRequest [b]
While evaluating request NamingPatternRequest [b]
← assertion failure

Call chain

TypeCheckPrimaryFileRequest::evaluate
  → typeCheckTopLevelCodeDecl
    → typeCheckPatternBinding        (var fusion_0e59 = c)
      → PatternBindingEntryRequest   (fusion_0e59)
        → InterfaceTypeRequest       (c)
          → NamingPatternRequest     (c)
            → PatternBindingEntryRequest  (let c = b)
              → InterfaceTypeRequest (b)
                → NamingPatternRequest (b)    ← assertion: parent stmt not yet type-checked

Root cause

func foo() interrupts the top-level code, splitting it into separate TopLevelCodeDecl nodes. let c = b is in a later TopLevelCodeDecl than guard let b = a. When var fusion_0e59 = c triggers type resolution of c, which requires b's type, the type checker queries b's NamingPattern before the guard let b statement has been type-checked. This violates the invariant that VarDecl::getInterfaceType() must not be called before the parent statement is type-checked. The fix should either detect the forward reference and emit a diagnostic before attempting type resolution, or ensure that cross-TopLevelCodeDecl variable references do not trigger out-of-order type-checking.

Environment

  • Compiler: Swift 6.4-dev (LLVM d2079213f1d4451, Swift 82b7720)
  • Platform: x86_64 Linux (Ubuntu 24.04.4 LTS)
  • Command: swift reproduce.swift (no special flags required)
  • Crash site: swift/lib/Sema/TypeCheckDecl.cpp:2766 (NamingPatternRequest::evaluate)

This bug was found by fusion-fuzz

Metadata

Metadata

Assignees

No one assigned

    Labels

    crashBug: A crash, i.e., an abnormal termination of softwaretriage neededThis issue needs more specific labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions