From 91f5d4f3e3a0440a5d032df8c3ca29743e6c3b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= Date: Fri, 24 Apr 2026 20:42:49 +0200 Subject: [PATCH] Fix type resolution for fully-qualified type hints with leading backslash Fully-qualified types like `\HH\Awaitable<_>` were not matching known type patterns in `get_type_from_hint` because the leading `\` was not stripped before the match. This caused them to fall through to `TReference` -> `TNamedObject` instead of the correct `TAwaitable`, making them incompatible with parameter types resolved from stubs. Co-Authored-By: Claude --- src/code_info_builder/typehint_resolver.rs | 7 +++++-- .../FunctionCall/aliasedArgumentType/input.hack | 13 +++++++++++++ .../FunctionCall/aliasedArgumentType/output.txt | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/inference/FunctionCall/aliasedArgumentType/input.hack create mode 100644 tests/inference/FunctionCall/aliasedArgumentType/output.txt diff --git a/src/code_info_builder/typehint_resolver.rs b/src/code_info_builder/typehint_resolver.rs index 68a21086..d43d7651 100644 --- a/src/code_info_builder/typehint_resolver.rs +++ b/src/code_info_builder/typehint_resolver.rs @@ -510,6 +510,9 @@ pub fn get_type_from_hint( let base = match hint { Hint_::Happly(id, extra_info) => { let applied_type = &id.1; + let applied_type_str = applied_type + .strip_prefix('\\') + .unwrap_or(applied_type.as_str()); if let Some(resolved_name) = resolved_names.get(&(id.0.start_offset() as u32)) { if let Some((_, type_name)) = type_context @@ -521,7 +524,7 @@ pub fn get_type_from_hint( } } - match applied_type.as_str() { + match applied_type_str { "int" => TAtomic::TInt, "string" => TAtomic::TString, "arraykey" => TAtomic::TArraykey { from_any: false }, @@ -664,7 +667,7 @@ pub fn get_type_from_hint( } "resource" => TAtomic::TResource, "_" => TAtomic::TPlaceholder, - "HH\\FIXME\\MISSING_RETURN_TYPE" | "\\HH\\FIXME\\MISSING_RETURN_TYPE" => { + "HH\\FIXME\\MISSING_RETURN_TYPE" => { return None; } _ => get_reference_type( diff --git a/tests/inference/FunctionCall/aliasedArgumentType/input.hack b/tests/inference/FunctionCall/aliasedArgumentType/input.hack new file mode 100644 index 00000000..b09cf401 --- /dev/null +++ b/tests/inference/FunctionCall/aliasedArgumentType/input.hack @@ -0,0 +1,13 @@ +namespace A; + +function foo(mixed $test): void { + if ($test is \HH\Awaitable<_>) { + \HH\Asio\join($test); + } +} + +function bar(mixed $test): void { + if ($test is Awaitable<_>) { + Asio\join($test); + } +} diff --git a/tests/inference/FunctionCall/aliasedArgumentType/output.txt b/tests/inference/FunctionCall/aliasedArgumentType/output.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/tests/inference/FunctionCall/aliasedArgumentType/output.txt @@ -0,0 +1 @@ +