Skip to content

fix(flow): apply deferred narrows after antecedent resolution#989

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

fix(flow): apply deferred narrows after antecedent resolution#989
lewis6991 wants to merge 2 commits intoEmmyLuaLs:mainfrom
lewis6991:fix/returnoverloadrecursion

Conversation

@lewis6991
Copy link
Collaborator

@lewis6991 lewis6991 commented Mar 20, 2026

When walking backward through flow, collect condition narrows as pending
actions instead of applying them while recursively querying antecedent
types. The eager path mixed narrowing with antecedent resolution, so
stacked guards could re-enter flow inference from inside condition
evaluation and build deep recursive chains across repeated truthiness,
type-guard, signature-cast, and correlated return-overload checks.

Resolve the antecedent type first, then apply the pending narrows in
reverse order. That keeps narrowing as a post-pass over an
already-resolved input, avoids re-entering the same condition chain
while answering the current flow query, and lets same-variable
self/member guards wait until earlier guards have narrowed the receiver
enough for reliable lookup.

Key the flow cache by whether condition narrowing is enabled, and
separate assignment source lookup from condition application. Reuse a
narrowed source only when the RHS preserves that precision; broader RHS
expressions fall back to the antecedent type with condition narrowing
disabled so reassignment clears stale branch narrows, while exact
literals and compatible partial table/object rewrites still preserve
useful narrowing.

Add regression coverage for stacked guards, correlated overload joins,
pcall aliases, and assign/return diagnostics.


These added tests fail on main:

  • test_stacked_same_var_type_guards_build_semantic_model
  • test_stacked_same_field_truthiness_guards_build_semantic_model
  • test_stacked_return_cast_guards_build_semantic_model
  • test_stacked_return_cast_self_guards_build_semantic_model
  • test_assignment_from_wider_single_return_call_drops_branch_narrowing
  • test_assignment_after_pending_return_cast_guard_drops_branch_narrowing
  • test_assignment_after_binary_call_guard_eq_false_drops_branch_narrowing
  • test_assignment_after_mixed_eager_and_pending_guards_drops_branch_narrowing
  • test_assignment_from_nullable_union_keeps_rhs_members
  • test_assignment_from_partially_overlapping_union_keeps_rhs_members
  • test_assignment_from_broad_string_drops_literal_branch_narrowing
  • test_partial_table_reassignment_with_conflicting_discriminant_drops_branch_narrowing
  • test_pcall_stacked_alias_guards_build_semantic_model
  • test_return_overload_stacked_eq_guards_build_semantic_model
  • test_return_overload_stacked_mixed_guards_build_semantic_model
  • test_return_overload_uncorrelated_later_guard_keeps_prior_narrowing
  • test_return_overload_unmatched_target_call_keeps_guard_union
  • test_return_overload_unmatched_target_root_then_truthiness_guard
  • test_return_overload_unmatched_target_root_then_type_guard
  • test_return_overload_post_guard_reassign_clears_mixed_root_narrowing
  • test_return_overload_branch_reassign_to_different_call_preserves_matching_root_narrowing
  • test_return_overload_branch_reassign_to_different_call_narrows_alternate_matching_root

@gemini-code-assist
Copy link
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 resolves a critical recursion bug within the type inference system, specifically affecting correlated @return_overload narrowing. By introducing a guard mechanism, it prevents infinite loops and stack overflows during complex type analysis, significantly enhancing the stability and reliability of the semantic model generation without altering the core inference logic for valid cases.

Highlights

  • Addressed recursive re-entry in @return_overload narrowing: Fixed an issue where correlated @return_overload narrowing could recursively re-enter itself for the same target return slot, leading to stack overflows or hung indexing due to a missing in-flight recursion break.
  • Introduced a recursion guard: Implemented a correlated_condition_guard (a HashSet) within LuaInferCache to prevent re-entry into narrow_var_from_return_overload_condition for an already in-flight correlated query.
  • Improved type inference stability: When re-entry is detected by the guard, the inference process now returns Continue, allowing the flow walk to fall back to non-correlated inference instead of repeating the problematic correlated query.
  • Added a regression test: Included a new regression test case that specifically reproduces the stack overflow issue with many repeated if-not-ok guards, confirming the fix allows the semantic model to build correctly.

🧠 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.

Copy link
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 correctly identifies and fixes a potential stack overflow issue caused by recursive re-entry in correlated @return_overload narrowing. The approach of adding a guard to LuaInferCache is sound. The added regression test is also a great way to ensure this issue does not reappear. I have one suggestion to improve the robustness of the re-entrancy guard implementation.

@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch from efa1423 to 81ac6be Compare March 20, 2026 12:46
@lewis6991 lewis6991 marked this pull request as draft March 20, 2026 12:58
@lewis6991 lewis6991 marked this pull request as ready for review March 20, 2026 13:10
@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch from 81ac6be to 231495e Compare March 20, 2026 16:31
@lewis6991 lewis6991 marked this pull request as draft March 20, 2026 16:36
@lewis6991 lewis6991 changed the title fix(flow): guard correlated return-overload reentry fix(flow): defer stacked condition narrowing during flow walks Mar 20, 2026
@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch from 231495e to efc8d41 Compare March 20, 2026 22:18
@lewis6991 lewis6991 changed the title fix(flow): defer stacked condition narrowing during flow walks fix(flow): stop re-entering get_type_at_flow from condition narrows Mar 20, 2026
@lewis6991 lewis6991 marked this pull request as ready for review March 20, 2026 22:19
@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch 2 times, most recently from 6d04cf4 to bf14cab Compare March 20, 2026 23:15
@clason

This comment was marked as resolved.

@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch from bf14cab to 2054627 Compare March 21, 2026 17:42
@lewis6991 lewis6991 changed the title fix(flow): stop re-entering get_type_at_flow from condition narrows fix(flow): replay deferred condition narrows after antecedent lookup Mar 21, 2026
@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch 2 times, most recently from 3fa1774 to 7ad7200 Compare March 22, 2026 00:59
@lewis6991 lewis6991 changed the title fix(flow): replay deferred condition narrows after antecedent lookup fix(flow): apply deferred narrows after antecedent resolution Mar 22, 2026
When walking backward through flow, collect condition narrows as pending
actions instead of applying them while recursively querying antecedent
types. The eager path mixed narrowing with antecedent resolution, so
stacked guards could re-enter flow inference from inside condition
evaluation and build deep recursive chains across repeated truthiness,
type-guard, signature-cast, and correlated return-overload checks.

Resolve the antecedent type first, then apply the pending narrows in
reverse order. That keeps narrowing as a post-pass over an
already-resolved input, avoids re-entering the same condition chain
while answering the current flow query, and lets same-variable
self/member guards wait until earlier guards have narrowed the receiver
enough for reliable lookup.

Key the flow cache by whether condition narrowing is enabled, and
separate assignment source lookup from condition application. Reuse a
narrowed source only when the RHS preserves that precision; broader RHS
expressions fall back to the antecedent type with condition narrowing
disabled so reassignment clears stale branch narrows, while exact
literals and compatible partial table/object rewrites still preserve
useful narrowing.

Add regression coverage for stacked guards, correlated overload joins,
pcall aliases, and assign/return diagnostics.
@lewis6991
Copy link
Collaborator Author

/gemini review

Copy link
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 refactors the control flow analysis to defer type narrowing. By collecting narrowing actions and applying them after resolving the antecedent type, you've addressed potential deep recursion issues and improved the correctness of type inference, especially for complex scenarios involving stacked guards and reassignments. The changes are substantial and well-supported by an impressive suite of new regression tests, which gives great confidence in the robustness of this new approach. The implementation of pending narrows and the updated caching strategy are well-executed. Overall, this is a high-quality improvement to the type system's core logic.

@lewis6991 lewis6991 force-pushed the fix/returnoverloadrecursion branch from 7ad7200 to e102572 Compare March 23, 2026 12:48
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