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';
}