private function getUnifiedSyntaxClass()

in src/__Private/codegen/CodegenSyntax.hack [129:209]


  private function getUnifiedSyntaxClass(keyset<string> $types): string {
    unset($types['']);
    if (C\is_empty($types)) {
      return 'Node';
    }

    if (C\contains_key($types, 'missing')) {
      unset($types['missing']);
      return '?'.$this->getUnifiedSyntaxClass($types);
    }

    if (C\count($types) === 1) {
      $type = C\onlyx($types);
      if ($type === 'list<>') {
        return 'NodeList<Node>';
      }
      return $this->getSyntaxClass($type);
    }

    if (C\every($types, $t ==> Str\starts_with($t, 'token:'))) {
      return 'Token';
    }

    if (C\every($types, $t ==> Str\starts_with($t, 'list<'))) {
      $have_empty = C\contains_key($types, 'list<>');
      if ($have_empty) {
        if (C\count($types) === 1) {
          return 'NodeList<Node>';
        }
        unset($types['list<>']);
      }
      return Vec\map(
        $types,
        $t ==> $t
          |> Str\strip_prefix($$, 'list<')
          |> Str\strip_suffix($$, '>')
          |> Str\split($$, '|'),
      )
        |> Keyset\flatten($$)
        |> $this->getUnifiedSyntaxClass($$)
        |> 'NodeList<'.$$.'>';
    }

    if (C\every($types, $t ==> Str\starts_with($t, 'list_item<'))) {
      return Keyset\map(
        $types,
        $t ==> $t
          |> Str\strip_prefix($$, 'list_item<')
          |> Str\strip_suffix($$, '>'),
      )
        |> $this->getUnifiedSyntaxClass($$)
        |> 'ListItem<'.$$.'>';
    }

    $expanded = $types
      |> Vec\map($$, $t ==> $this->getSyntaxClass($t))
      |> Vec\map(
        $$,
        $type ==> Keyset\union(
          keyset[$type],
          $this->getMarkerInterfacesByImplementingClass()[$type] ?? keyset[],
          $this->getInterfaceWrappers()[$type] ?? keyset[],
        ),
      );
    $intersected = C\reduce(
      $expanded,
      ($acc, $i) ==> Keyset\intersect($acc, $i),
      C\firstx($expanded),
    );
    if ($intersected) {
      // Return the most-specific; for example, INameish can be converted to
      // IExpression, and we want INameish
      return Dict\map(
        $intersected,
        $if ==> C\count($this->getMarkerInterfacesByInterface()[$if]),
      )
        |> Dict\sort($$)
        |> C\first_keyx($$);
    }
    return 'Node';
  }