#9852·hhvm

[ Typechecker ] Typechecker forgets to analyze the second iteration of a loop that is inside a loop

Author: lexidorCreated Sep 7, 2026Updated Sep 7, 2026
Labelshack

Describe the bug When inside the inner loop, the later assignment to $previous is ignored.

Standalone code, or other way to reproduce the problem

hack
use namespace HH\Lib\{PseudoRandom, Vec};

<<__EntryPoint>>
function repro()[defaults]: void {
  $indeterminate_loop = Vec\fill(PseudoRandom\int(0, 100), true);
  $indeterminate_loop_2 = Vec\fill(PseudoRandom\int(0, 100), true);

  foreach ($indeterminate_loop as $_) {
    $previous = null;

    // On the second iteration of this loop, $previous is `true`.
    foreach ($indeterminate_loop_2 as $_) {
      takes_null($previous);
      $previous = true;
    }
  }
}

function takes_null(null $_)[]: void {}

Steps to reproduce the behavior:

  1. Typecheck with hh_client 2026.06.05
  2. Observe No errors!
  3. Invoke with hhvm
  4. Observe TypeError, bool cannot be passed where null is expected

Expected behavior

When analyzing the inner loop the typechecker should assume the loop can run more than once.

Actual behavior

root@2e29e99892c2:/mnt/project# hh_client 
No errors!
root@2e29e99892c2:/mnt/project# hhvm repro.hack 

Fatal error: Uncaught TypeError: Argument 1 passed to takes_null() must be an instance of null, bool given in /mnt/project/repro.hack:13
Stack trace:
#0 (): repro()
#1 {main}

Environment

  • Operating system

Debian GNU/Linux 13 (trixie)

  • Installation method

docker pull hersheltheodorelayton/hhvm-full:26.06.05

  • HHVM Version
HipHop VM 26.6.5 (rel) (non-lowptr)
Compiler: heads/hhvm-oss-20260605-vec-slice-0-gb983bd51b1256cd8c3fed53b2eb9970870723e50
Repo schema: 2cfae41f53ce07c231d45e895efa412f7abc7be3
hackc-c74a4d6e4f97e2c15841c0fbf374c44811ed4799-26.6.5

Additional context N/A