Skip to content

feat(infer): resolve nested table literals as Instance types#987

Open
NeOzay wants to merge 2 commits intoEmmyLuaLs:mainfrom
NeOzay:fix/recursive-instance-nested-tables
Open

feat(infer): resolve nested table literals as Instance types#987
NeOzay wants to merge 2 commits intoEmmyLuaLs:mainfrom
NeOzay:fix/recursive-instance-nested-tables

Conversation

@NeOzay
Copy link

@NeOzay NeOzay commented Mar 19, 2026

⚠️ ATTENTION: This entire PR was AI-generated (Claude Code). I does not have the expertise to evaluate the code quality. Please review carefully.

Summary

  • When accessing a class field that resolves to a nested table literal (TableConst), wrap the result in Instance(base, range) instead of returning the bare Ref. This preserves the literal context for recursive member access.
  • Enables correct nil-stripping of optional fields at any nesting depth (e.g. test.a.b.c through 3 levels of @class with @field?).
  • Adds Instance-aware rendering in humanize_type so hover displays which optional fields are provided vs absent.

Example

---@class Inner
---@field c integer

---@class Middle
---@field b? Inner

---@class Outer
---@field a? Middle

---@type Outer
local test = { a = { b = { c = 1 } } }

test.a    -- Middle (not Middle?, nil stripped because provided)
test.a.b  -- Inner (not Inner?, recursive Instance resolution)
test.a.b.c -- integer = 1 (resolved through nested literal)

Changes

File Change
infer_index/mod.rs Wrap TableConst fallback in Instance(stripped, nested_range)
humanize_type.rs Render Instance types with per-field nil-strip display
semantic_info/mod.rs Create Instance for LocalName hover when initializer is a non-empty table literal
get_type_at_flow.rs Narrow class types via table literal initializer at flow analysis
member_infer_test.rs Add recursive depth-3 resolution test + update existing tests
hover_test.rs Add recursive hover test (test.a.b.c → integer = 1)

Test plan

  • cargo test -p emmylua_code_analysis — 617 passed
  • cargo test -p emmylua_ls — 178 passed
  • New test: test_recursive_instance_member_resolution (depth-3 test.a.b.c)
  • New test: test_recursive_nested_hover (hover shows integer = 1)
  • Existing tests adapted and passing (no regressions)

🤖 Generated with Claude Code

When a typed class field is provided with a table literal that
is itself a sub-table (TableConst), wrap the result in an
Instance type instead of falling back to the bare class Ref.
This preserves the literal context for recursive member access,
enabling correct nil-stripping on optional fields at any depth.

- infer_index: wrap TableConst fallback in Instance(base, range)
- humanize_type: render Instance with per-field nil-strip display
- semantic_info: create Instance for LocalName hover
- get_type_at_flow: narrow class types via table literal at flow
- tests: add recursive depth-3 member resolution test
- tests: add recursive hover test (test.a.b.c → integer = 1)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 19, 2026 17:27
@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 significantly enhances the type inference system by introducing Instance types for nested table literals. This change allows the language server to accurately track the presence or absence of optional fields within complex, deeply nested data structures, leading to more precise type checking and improved hover information for users. The updates ensure that the type system correctly reflects the runtime state of objects initialized with literals, particularly for optional fields.

Highlights

  • Improved Type Inference for Nested Table Literals: When accessing a class field that resolves to a nested table literal, the result is now wrapped in an Instance type. This preserves the literal context, enabling correct recursive member access and nil-stripping of optional fields at any nesting depth.
  • Enhanced Hover Display for Instance Types: The humanize_type module has been updated to provide Instance-aware rendering. This allows the hover display to accurately show which optional fields are provided versus absent within a narrowed class type.
  • Class Type Narrowing at Flow Analysis: Class types are now narrowed via table literal initializers during flow analysis, improving the precision of type inference for local variables initialized with table literals.

🧠 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 introduces significant improvements to type inference for nested table literals, resolving them as Instance types. This change correctly preserves literal context for recursive member access and enables accurate nil-stripping of optional fields at any nesting depth. The humanize_type function has been updated to render these Instance types with per-field nil-strip display, which is a great enhancement for hover functionality. New test cases have been added to cover these scenarios, demonstrating the effectiveness of the changes. The overall implementation is robust and addresses a key aspect of type narrowing.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances EmmyLua’s type inference so nested table literals used as class instances are preserved as Instance(base, range), enabling recursive member access to keep literal context (including nil-stripping of optional fields) and improving hover rendering to show which optional fields are present vs absent.

Changes:

  • Wrap nested TableConst member results in LuaType::Instance to preserve literal context for deep member inference.
  • Add Instance-aware rendering in humanize_type to display per-field optional narrowing based on literal-provided keys.
  • Extend semantic/flow narrowing and add tests for deep recursive resolution and hover output.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/emmylua_ls/src/handlers/test/hover_test.rs Adds hover tests validating optional-field narrowing and deep nested hover resolution.
crates/emmylua_code_analysis/src/semantic/semantic_info/mod.rs Narrows hovered LocalName class types to Instance when initialized with a non-empty table literal.
crates/emmylua_code_analysis/src/semantic/infer/narrow/get_type_at_flow.rs Narrows class types at flow decl position based on non-empty table literal initializers.
crates/emmylua_code_analysis/src/semantic/infer/infer_index/mod.rs Adjusts Instance member inference to strip nil for literal-provided fields and wrap nested table literals as Instance.
crates/emmylua_code_analysis/src/db_index/type/humanize_type.rs Renders Instance as a narrowed struct view with optional-field presence/absence display.
crates/emmylua_code_analysis/src/compilation/test/member_infer_test.rs Updates existing assertions and adds tests for optional narrowing + recursive instance member resolution.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@NeOzay NeOzay marked this pull request as draft March 19, 2026 17:32
Deduplicate is_class_type into LuaType method, conditionally strip nil
only when literal value is non-nullable (fixes `{ a = nil }` case),
restrict Instance narrowing to LocalName only, strengthen test assertion,
and fix hover display for nil-valued literal fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@NeOzay NeOzay marked this pull request as ready for review March 19, 2026 21:55
@CppCXY
Copy link
Member

CppCXY commented Mar 20, 2026

please fix the check

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.

3 participants