in src/consumers/typehint_from_ast.hack [15:267]
function typehint_from_ast(
ConsumerContext $context,
?HHAST\Node $node,
): ?ScannedTypehint {
if ($node === null) {
return null;
}
// Special cases
if ($node is HHAST\XHPClassNameToken) {
$resolved_type = HHAST\resolve_type(
mangle_xhp_name_token($node),
$context['ast'],
$node,
);
return new ScannedTypehint(
$node,
$resolved_type['kind'],
$resolved_type['name'],
vec[],
false,
null,
null,
);
}
if ($node is HHAST\NameToken || $node is HHAST\QualifiedName) {
$resolved_type = HHAST\resolve_type(
name_from_ast($node),
$context['ast'],
$node,
);
return new ScannedTypehint(
$node,
$resolved_type['kind'],
$resolved_type['name'],
vec[],
false,
null,
null,
);
}
if ($node is HHAST\Token) {
// Any other tokens (string, void, etc.) don't need to be resolved.
$name = name_from_ast($node);
return new ScannedTypehint($node, null, $name, vec[], false, null, null);
}
// This list is taken from the docblock of
// FunctionDeclarationheader::getType()
if ($node is HHAST\ClassnameTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'classname',
typehints_from_ast_va($context, $node->getType()),
/* nullable = */ false,
/* shape fields = */ null,
/* function typehints = */ null,
);
}
if ($node is HHAST\ClosureTypeSpecifier) {
return new ScannedTypehint(
$node,
HHAST\ResolvedTypeKind::CALLABLE,
'callable',
vec[],
false,
null,
tuple(
// parameters
Vec\map(
$node->getParameterList()?->getChildrenOfItems() ?? vec[],
$param_type ==> {
$inout = null;
if ($param_type is HHAST\ClosureParameterTypeSpecifier) {
$inout = $param_type->getCallConvention();
$param_type = $param_type->getType();
}
$ellipsis = null;
if ($param_type is HHAST\VariadicParameter) {
$ellipsis = $param_type->getEllipsis();
$param_type = $param_type->getType();
}
return tuple(
$inout,
typehint_from_ast($context, $param_type) as nonnull,
$ellipsis,
);
},
),
// return type
typehint_from_ast($context, $node->getReturnType()) as nonnull,
),
);
}
if ($node is HHAST\DarrayTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'darray',
typehints_from_ast_va($context, $node->getKey(), $node->getValue()),
false,
null,
null,
);
}
if ($node is HHAST\DictionaryTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'dict',
typehints_from_ast($context, $node->getMembers()),
false,
null,
null,
);
}
if ($node is HHAST\GenericTypeSpecifier) {
$inner = typehint_from_ast($context, $node->getClassType()) as nonnull;
return new ScannedTypehint(
$node,
$inner->getKind(),
$inner->getTypeName(),
typehints_from_ast($context, $node->getArgumentList()->getTypes()),
false,
null,
null,
);
}
if ($node is HHAST\KeysetTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'keyset',
// https://github.com/hhvm/hhast/issues/95
typehints_from_ast_va($context, $node->getTypeUNTYPED()),
false,
null,
null,
);
}
// HHAST\Missing was handled at top
if ($node is HHAST\NullableTypeSpecifier) {
$inner = nullthrows(typehint_from_ast($context, $node->getType()));
return new ScannedTypehint(
$node,
$inner->getKind(),
$inner->getTypeName(),
$inner->getGenericTypes(),
/* nullable = */ true,
$inner->isShape() ? $inner->getShapeFields() : null,
$inner->getFunctionTypehints(),
);
}
if ($node is HHAST\ShapeTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'shape',
vec[],
false,
Vec\map(
$node->getFields()?->getChildrenOfItems() ?? vec[],
$field ==> shape_field_from_ast($context, $field),
),
null,
);
}
if ($node is HHAST\SimpleTypeSpecifier) {
return typehint_from_ast($context, $node->getSpecifier());
}
if ($node is HHAST\SoftTypeSpecifier) {
return typehint_from_ast($context, $node->getType());
}
if ($node is HHAST\AttributizedSpecifier) {
return typehint_from_ast($context, $node->getType());
}
// HHAST\NoReturnToken was handled at top
if ($node is HHAST\TupleTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'tuple',
typehints_from_ast($context, $node->getTypes()),
false,
null,
null,
);
}
if ($node is HHAST\TypeConstant) {
$left = typehint_from_ast($context, $node->getLeftType()) as nonnull;
$str = $left->getTypeText().'::'.$node->getRightType()->getText();
return new ScannedTypehint(
$node,
$left->getKind(),
$str,
vec[],
false,
null,
null,
);
}
if ($node is HHAST\VarrayTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'varray',
typehints_from_ast_va($context, $node->getType()),
false,
null,
null,
);
}
if ($node is HHAST\VectorTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
'vec',
typehints_from_ast_va($context, $node->getType()),
false,
null,
null,
);
}
if ($node is HHAST\UnionTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
ScannedTypehint::UNION,
typehints_from_ast($context, $node->getTypes() as HHAST\NodeList<_>),
false,
null,
null,
);
}
if ($node is HHAST\IntersectionTypeSpecifier) {
return new ScannedTypehint(
$node,
null,
ScannedTypehint::INTERSECTION,
typehints_from_ast($context, $node->getTypes() as HHAST\NodeList<_>),
false,
null,
null,
);
}
if ($node is HHAST\ListItem<_>) {
return typehint_from_ast($context, $node->getItem());
}
invariant_violation('Unhandled type: %s', \get_class($node));
}