Skip to content

[Swift][CSBindings] Assertion duplicate binding in BindingSet::addBinding when type-checking tuple var with two opaque return types and overloaded local function #89152

@YuanchengJiang

Description

@YuanchengJiang

Description

swift reproduce.swift crashes with an assertion failure std::find(Bindings.begin(), Bindings.end(), binding) == Bindings.end() in BindingSet::addBinding at CSBindings.cpp:1681 when the constraint system attempts to solve a tuple variable declaration (some Foo, some Foo) = (123, foo(123)) where foo is overloaded and returns some Foo, and the declaration is inside a local function scope. The constraint solver adds a duplicate binding for a type variable while resolving the overloaded foo(123) call in the context of the opaque return type tuple, triggering the assertion.

Reproducer

func outer() {
  protocol Foo {}
  extension Int: Foo {}

  func foo(_: Int) -> some Foo { return 1738 }
  func foo(_: String) -> some Foo { return 679 }
  func foo<T: Foo>(_ x: T) -> some Foo { return x }

  var globalVarTuple: (some Foo, some Foo) = (123, foo(123))
}

Command

swift reproduce.swift

Expected behavior

The compiler should successfully type-check the tuple variable declaration or emit a diagnostic. It should not crash with an assertion failure about duplicate bindings in the constraint system.

Actual behavior

Assertion failed: (std::find(Bindings.begin(), Bindings.end(), binding) == Bindings.end()),
function addBinding at CSBindings.cpp:1681.

While evaluating request TypeCheckFunctionBodyRequest for 'outer()'
While type-checking declaration (var globalVarTuple)
While type-checking expression at [reproduce.swift] RangeText="(123, foo(123)"
While type-checking-target starting at reproduce.swift

Call chain

TypeCheckPrimaryFileRequest::evaluate
  → TypeCheckFunctionBodyRequest::evaluate  (outer())
    → typeCheckPatternBinding               (var globalVarTuple)
      → typeCheckExpression
        → ConstraintSystem::solve
          → ConstraintSystem::salvage
            → ConstraintSystem::solveImpl
              → ComponentStep::take
                → ConstraintSystem::determineBestBindings
                  → BindingSet::BindingSet
                    → BindingSet::addBinding   ← assertion: duplicate binding

Root cause

When type-checking var globalVarTuple: (some Foo, some Foo) = (123, foo(123)) inside a local function scope, the constraint system generates bindings for the type variables associated with the two some Foo opaque return type positions. The overloaded foo(123) call — which could resolve to foo(_: Int) -> some Foo or foo<T: Foo>(_ x: T) -> some Foo — causes the constraint solver to produce duplicate potential bindings for the same type variable when iterating over disjunction candidates. BindingSet::addBinding asserts that each binding must be unique, but receives the same binding twice. The fix should deduplicate bindings before insertion in BindingSet::addBinding, or prevent the overload resolution from generating duplicate bindings for opaque return type variables in tuple contexts.

Environment

  • Compiler: Swift 6.5-dev (LLVM 7c86461e21cca7e, Swift 6da4da7)
  • Platform: x86_64 Linux (Ubuntu 24.04.4 LTS)
  • Command: swift reproduce.swift (no special flags required)
  • Crash site: swift/lib/Sema/CSBindings.cpp:1681 (BindingSet::addBinding)

This bug was found by fusion-fuzz

Metadata

Metadata

Assignees

No one assigned

    Labels

    compilerThe Swift compiler itselfcrashBug: A crash, i.e., an abnormal termination of softwareswift 6.4tuplesFeature: tuplestype checkerArea → compiler: Semantic analysis

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions