Skip to content

[ Typechecker ] <<__Memoize>> can cause the same object to be typed in incompatible ways #9797

Open

Description

@lexidor

Describe the bug
<<__Memoize>> can cause the same object to be typed in incompatible ways.

Standalone code, or other way to reproduce the problem

final class Box<T> {
  public function __construct(public ?T $value)[] {}
}

<<__Memoize>>
function smuggling_boxes<Tv>()[]: Box<Tv> {
  return new Box<Tv>(null);
}

<<__EntryPoint>>
function main()[write_props]: void {
  $int_box = smuggling_boxes<int>();
  $int_box->value = 2;

  $string_box = smuggling_boxes<string>();
  $string_box->value = 'Oh no!';

  $oh_no = $int_box->value;

  if ($oh_no !== null) {
    $_ = $oh_no * 6;
  }
}

Steps to reproduce the behavior:

  1. <<__Memoize>> says, if the arguments (all zero) are the same, return the old object.
  2. The hack typechecker believes that $int_box and $string_box are different objects.
  3. Setting ->value via either typed reference updates the other to a value of the wrong type.
  4. In this example, multiplying 'Oh no!' by 6 blows up at runtime.

Expected behavior

This typehole exists in strict Hack. Closing this typehole would cause churn in correct code. I am not sure if it should be closed.

Actual behavior

hh_client No errors!

Fatal error: Uncaught exception 'InvalidOperationException' with message 'Cannot perform mathematical operation on string and int'

Environment

  • Operating system

For example, 'Docker Ubuntu 26.04 on host, 24.04 in container'

  • Installation method

'docker hersheltheodorelayton/hhvm-basic'

  • HHVM Version
HipHop VM 26.3.28 (rel) (non-lowptr)
Compiler: heads/hhvm-oss-20260328-0-gcf488896c50fc865bc5d3e15608f9f1503f1343f
Repo schema: 768e783da4ee9ceac6534045f6369f37c27f9539

Additional context
A reified type argument gets a separate memoization cache, closing the typehole.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions