Skip to content

Conversation

@lewis6991
Copy link
Collaborator

@lewis6991 lewis6991 commented Jan 17, 2026

Fixes #921

Improve type narrowing for the 'and' and 'or' operators when used with
nullable types and table/literal expressions.

The analyzer was not properly narrowing types in three scenarios:

  1. opts or {} where opts: Opts? was not narrowing to Opts
  2. Self-assignment opts = opts or {} resulted in type table instead of Opts
  3. opts.a and { 'a' } where opts.a: string? was not properly typed
  • Added special case in special_or_rule() to detect empty table expressions

  • When right side is {} and left type is nullable class/table, remove nil

  • Result: opts or {} where opts: Opts? correctly narrows to Opts

  • Modified get_type_at_assign_stat() to distinguish DocType from InferType

  • Only use explicit ---@type annotations, not inferred types

  • Allows flow-based narrowing when no explicit annotation exists

  • Result: opts = opts or {} now correctly narrows opts to Opts

  • Created new file with special_and_rule() for 'and' operator patterns

  • Moved infer_binary_expr_and() from mod.rs to new file

  • For 'x and y' where x is nullable: result is falsy_part(x) | y

  • Examples:

    • string? and 'value' → 'value' | nil
    • boolean? and 'value' → 'value' | false | nil
  • Added union handling to properly extract falsy parts

  • For boolean: returns BooleanConst(false)

  • For boolean?: returns false | nil

  • For string?: returns nil

  • Recursively processes union members


This commit was created with AI assistance (OpenCode/Claude).

@gemini-code-assist
Copy link

Summary of Changes

Hello @lewis6991, 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 enhances the type narrowing capabilities of the analyzer for Lua's logical and and or operators. The changes ensure more accurate type inference when dealing with nullable types, empty table expressions, and self-assignments, leading to a more robust and precise type checking experience for users.

Highlights

  • Improved 'or' operator narrowing: The type analyzer now correctly narrows nullable types (e.g., Opts?) to their non-nullable form (Opts) when used with an empty table literal (opts or {}). This specifically addresses cases where the left-hand side is a nullable class or table type.
  • Corrected self-assignment narrowing: Type inference for self-assignments like opts = opts or {} has been fixed. The system now correctly narrows the type of opts to its non-nullable form (Opts) by prioritizing explicit ---@type annotations over inferred types during assignment flow analysis.
  • Enhanced 'and' operator narrowing: A new special_and_rule has been introduced to improve type narrowing for the and operator, particularly when the left-hand side is a nullable type and the right-hand side is a literal or table expression. The result now accurately reflects the union of the left-hand side's falsy parts and the right-hand side's type.
  • Refactored 'and' operator inference: The logic for and operator type inference has been moved into a dedicated module (infer_binary_and.rs), improving code organization and maintainability.
  • Accurate falsy type extraction for unions: The narrow_false_or_nil function has been enhanced to recursively process union types, ensuring that all potential falsy components (e.g., false from boolean?, nil from string?) are correctly extracted for more precise type narrowing.

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

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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

@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 improves type narrowing for and and or operators with nullable types, fixing several scenarios where types were not correctly inferred. The changes include adding special handling for x or {} and x and y patterns, and refining how self-assignments are handled in flow analysis. The introduction of comprehensive tests for these cases is a great addition.

My review focuses on improving code clarity and maintainability. I've suggested refactoring a complex if/else if chain to a more readable match statement, and using idiomatic Rust iterator patterns to reduce code duplication and improve conciseness in a few places. Overall, this is a solid improvement to the type inference engine.

Fixes EmmyLuaLs#921

Improve type narrowing for the 'and' and 'or' operators when used with
nullable types and table/literal expressions.

The analyzer was not properly narrowing types in three scenarios:
1. 'opts or {}' where opts: Opts? was not narrowing to Opts
2. Self-assignment 'opts = opts or {}' resulted in type 'table' instead of Opts
3. 'opts.a and { 'a' }' where opts.a: string? was not properly typed

- Added special case in special_or_rule() to detect empty table expressions
- When right side is {} and left type is nullable class/table, remove nil
- Result: 'opts or {}' where opts: Opts? correctly narrows to Opts

- Modified get_type_at_assign_stat() to distinguish DocType from InferType
- Only use explicit ---@type annotations, not inferred types
- Allows flow-based narrowing when no explicit annotation exists
- Result: 'opts = opts or {}' now correctly narrows opts to Opts

- Created new file with special_and_rule() for 'and' operator patterns
- Moved infer_binary_expr_and() from mod.rs to new file
- For 'x and y' where x is nullable: result is falsy_part(x) | y
- Examples:
  - string? and 'value' → 'value' | nil
  - boolean? and 'value' → 'value' | false | nil

- Added union handling to properly extract falsy parts
- For boolean: returns BooleanConst(false)
- For boolean?: returns false | nil
- For string?: returns nil
- Recursively processes union members

---
This commit was created with AI assistance (OpenCode/Claude).
@CppCXY CppCXY merged commit 6acf41d into EmmyLuaLs:main Jan 19, 2026
22 checks passed
@lewis6991 lewis6991 deleted the fix/issue921 branch January 19, 2026 08:10
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.

bad type narrowing with table and and

2 participants