fix: avoid flow replay for unrelated call conditions#1101
Conversation
There was a problem hiding this comment.
Code Review Summary
Changes Overview
This PR modifies the condition flow inference logic in the Lua type checker, specifically handling call expressions in condition contexts. It replaces the Truthiness continuation pattern with direct inline inference using try_infer_expr_no_flow.
Issues Found
-
Potential Performance Regression 🔴
- The new code calls
try_infer_expr_no_flowfor every call expression encountered in condition flow, even when the result may not be needed. The old approach deferred this computation via theTruthinesscontinuation. - Recommendation: Consider adding a quick pre-check (e.g., checking if the call expression has side effects or is a known pure function) before invoking the full inference.
- The new code calls
-
Missing Error Handling for
try_infer_expr_no_flow⚠️ - The
matchstatement handlesOk(Some(...))and_cases, buttry_infer_expr_no_flowcould returnOk(None)which falls through toConditionFlowAction::Continue. This might hide legitimate inference failures. - Recommendation: Log or track cases where
try_infer_expr_no_flowreturnsOk(None)to aid debugging.
- The
-
Redundant
is_never()Check 🟡- The first arm checks
expr_type.is_never()and returnsLuaType::Never. However, the subsequent arms foris_always_falsy()andis_always_truthy()would also catchNevertypes (sinceNeveris typically both falsy and truthy). This creates dead code. - Recommendation: Remove the first arm or add a comment explaining why it's necessary (e.g., if
Neverdoesn't satisfyis_always_falsy()in your type system).
- The first arm checks
-
Test Coverage Gap 🟡
- The test only verifies the happy path (successful inference). It doesn't test edge cases like:
- Call expressions that return
never - Call expressions with side effects
- Nested condition flows with multiple call expressions
- Call expressions that return
- Recommendation: Add more comprehensive tests covering these scenarios.
- The test only verifies the happy path (successful inference). It doesn't test edge cases like:
-
Code Duplication 🟡
- The logic for checking
is_never(),is_always_falsy(), andis_always_truthy()is duplicated between the new inline code and the removedTruthinesscontinuation handler. - Recommendation: Extract this logic into a helper function to improve maintainability.
- The logic for checking
Positive Aspects
- ✅ The change simplifies the control flow by removing the
Truthinesscontinuation variant - ✅ The test is well-structured and includes a timeout to prevent infinite loops
- ✅ The constant
ISSUE_1100_HIGHLIGHT_GROUPSmakes the test configurable
Security Considerations
- No security vulnerabilities identified in this change
Overall Assessment
The change is functionally correct but introduces potential performance concerns and code duplication. Consider optimizing the call to try_infer_expr_no_flow and consolidating the repeated type-checking logic.
There was a problem hiding this comment.
Code Review
This pull request optimizes type inference in condition flows by avoiding flow-aware replays for call expressions that do not narrow the reference. Instead, it evaluates call expressions directly using try_infer_expr_no_flow and handles unreachable branches accordingly. A test case for issue 1100 has been added to verify performance and correctness. Feedback suggests refactoring the new match statement in get_type_at_condition_flow to reduce repetition and improve readability.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
When a call condition does not narrow the queried ref, infer the call without flow and only use it to reject impossible branches. This avoids recursively replaying previous flow for every unrelated call condition while preserving the flow-aware paths that perform narrowing. Fixes EmmyLuaLs#1100 Assisted-by: Codex
Problem
Repeated unrelated call conditions like
if enabled(...) thencould make condition flow replay the call's expression type against prior flow for every branch. Large generated highlight tables then spent too much time repeatedly re-inferring unrelated table field reads.Solution
When a call condition does not narrow the queried ref, infer the call without flow and only use the result to reject impossible branches. The existing flow-aware call paths still handle calls that narrow the queried ref, such as type guards and return casts.
Tests
cargo test -p emmylua_code_analysiscargo test -p emmylua_code_analysis flowcargo fmt --all --checkgit diff --check