Skip to content

fix(generic): stabilize higher-order callable overload inference#990

Open
lewis6991 wants to merge 2 commits intoEmmyLuaLs:mainfrom
lewis6991:fix/overloadinfer
Open

fix(generic): stabilize higher-order callable overload inference#990
lewis6991 wants to merge 2 commits intoEmmyLuaLs:mainfrom
lewis6991:fix/overloadinfer

Conversation

@lewis6991
Copy link
Copy Markdown
Collaborator

@lewis6991 lewis6991 commented Mar 20, 2026

Improve overload inference for callable values.

The main rule is: match callable candidates by the actual argument shape before using their return types. That makes higher-order callback inference and direct callable-union calls less order-dependent.

This also clarifies the broad callable cases:

  • unknown returns stay unknown instead of falling through to a concrete overload.
  • bare function is treated as an erased callable fallback.
  • compatible callable union/intersection members contribute a union of returns.

Regression tests cover apply-style callbacks, direct callable unions, and pcall return overloads.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the type inference logic for higher-order callable types, particularly when they involve unions or intersections. The system now employs a more robust overload resolution strategy, where argument types are used to select the most appropriate callable signature from a set of candidates, thereby yielding a more precise return type. This change improves the accuracy of type analysis for complex function definitions and calls.

Highlights

  • Enhanced Callable Return Type Resolution: Implemented a new mechanism to resolve return types for higher-order callable types (unions and intersections) by leveraging overload resolution based on provided argument types, rather than simply unioning all possible returns.
  • New Helper Functions for Overload Collection and Instantiation: Introduced collect_callable_overloads to systematically gather all potential callable candidates from complex type structures and instantiate_callable_from_arg_types to infer generic parameters for individual callable candidates based on call arguments.
  • Integration of Overload Resolution: The infer_callable_return_from_remaining_args function was refactored to utilize resolve_signature_by_args to select the most appropriate callable signature and its corresponding return type from a set of instantiated overloads.
  • New Regression Tests: Added specific test cases for pcall to validate the correct inference of return types when dealing with callable unions and intersections, ensuring the new logic behaves as expected.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

Gemini is experiencing higher than usual traffic and was unable to create the review. Please try again in a few hours by commenting /gemini review.

@lewis6991 lewis6991 force-pushed the fix/overloadinfer branch 4 times, most recently from 4705986 to be9caeb Compare March 20, 2026 14:37
@CppCXY
Copy link
Copy Markdown
Member

CppCXY commented Apr 1, 2026

please fix conflicts

@lewis6991 lewis6991 force-pushed the fix/overloadinfer branch from be9caeb to 963c3ce Compare April 2, 2026 13:07
@lewis6991 lewis6991 changed the title fix(generic): resolve higher-order callable returns by args fix(generic): stabilize higher-order callable overload inference Apr 2, 2026
@lewis6991 lewis6991 marked this pull request as draft April 2, 2026 13:11
@lewis6991 lewis6991 force-pushed the fix/overloadinfer branch 2 times, most recently from 7b80f2a to 9cf7e55 Compare April 2, 2026 14:26
@lewis6991 lewis6991 marked this pull request as ready for review April 2, 2026 14:29
@lewis6991 lewis6991 force-pushed the fix/overloadinfer branch 2 times, most recently from 75166d3 to 3b763c6 Compare April 2, 2026 16:43
@CppCXY
Copy link
Copy Markdown
Member

CppCXY commented Apr 8, 2026

please fix conflicts

@lewis6991 lewis6991 marked this pull request as draft April 30, 2026 09:23
Collect callable overload groups through aliases, unions, intersections,
and signatures.

Expose the argument-shape matcher so generic return inference and call
inference can resolve candidates through the same path.

Assisted-by: Codex
@lewis6991 lewis6991 force-pushed the fix/overloadinfer branch from 3b763c6 to 0c65700 Compare May 1, 2026 14:51
@lewis6991 lewis6991 marked this pull request as ready for review May 1, 2026 14:53
@lewis6991
Copy link
Copy Markdown
Collaborator Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly improves callable return type inference, particularly for complex types involving unions, intersections, and generic overloads. Key enhancements include the introduction of collect_callable_overload_groups to flatten nested callable structures and filter_callable_overloads_by_call_args to more accurately narrow down applicable overloads based on argument shapes. The logic for matching template patterns was also refined to handle unknown arguments more gracefully. Feedback was provided regarding a performance optimization in infer_union, where argument types are currently inferred multiple times within a loop instead of being cached.

Comment on lines 502 to 545
for ty in union.into_vec() {
match ty {
LuaType::Signature(signature_id) => {
if let Some(signature) = db.get_signature_index().get(&signature_id) {
// 处理 overloads
let overloads = if signature.is_generic() {
signature
.overloads
.iter()
.map(|func| {
Ok(Arc::new(instantiate_func_generic(
db,
cache,
func,
call_expr.clone(),
)?))
})
.collect::<Result<Vec<_>, _>>()?
} else {
signature.overloads.clone()
};
all_overloads.extend(overloads);

// 处理 signature 本身的函数类型
let mut fake_doc_function = LuaFunctionType::new(
signature.async_state,
signature.is_colon_define,
signature.is_vararg,
signature.get_type_params(),
signature.get_return_type(),
);
if signature.is_generic() {
fake_doc_function = instantiate_func_generic(
db,
cache,
&fake_doc_function,
call_expr.clone(),
)?;
let mut overload_groups = Vec::new();
collect_callable_overload_groups(db, &ty, &mut overload_groups)?;
for overloads in overload_groups {
let compatible_overloads = filter_callable_overloads_by_call_args(
db,
cache,
overloads.clone(),
&call_expr,
args_count,
true,
)?;
if compatible_overloads.is_empty() {
fallback_overloads.extend(overloads);
continue;
}

let contains_tpl = compatible_overloads.iter().any(|func| func.contain_tpl());
match resolve_signature(
db,
cache,
compatible_overloads,
call_expr.clone(),
contains_tpl,
args_count,
) {
Ok(func) => {
returns.push(func.get_ret().clone());
if first_func.is_none() {
first_func = Some(func);
}
base_signatures.push(Arc::new(fake_doc_function));
}
Err(InferFailReason::RecursiveInfer) => {
return Err(InferFailReason::RecursiveInfer);
}
Err(reason) if reason.is_need_resolve() => {
if need_resolve.is_none() {
need_resolve = Some(reason);
}
}
Err(_) => {}
}
LuaType::DocFunction(func) => {
let func_to_push = if func.contain_tpl() {
Arc::new(instantiate_func_generic(
db,
cache,
&func,
call_expr.clone(),
)?)
} else {
func.clone()
};
base_signatures.push(func_to_push);
}
_ => {}
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In infer_union, argument types are inferred multiple times because filter_callable_overloads_by_call_args and resolve_signature are called within a loop, and both perform their own argument inference. For large unions or complex argument lists, this redundancy can impact performance. It would be more efficient to infer the argument types once at the start of infer_union and pass them to the helper functions.

Infer higher-order callable returns from compatible overload members
instead of a single order-dependent branch.

Keep unknown returns when the argument shape is unknown, treat function
as an erased callable fallback, and union compatible callable-union
returns.

Assisted-by: Codex
@lewis6991 lewis6991 force-pushed the fix/overloadinfer branch from 0c65700 to 538cec3 Compare May 3, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants