Skip to content

fix(type-check): accept exhaustive boolean unions - #1228

Open
lewis6991 wants to merge 1 commit into
EmmyLuaLs:mainfrom
lewis6991:issue1226
Open

fix(type-check): accept exhaustive boolean unions#1228
lewis6991 wants to merge 1 commit into
EmmyLuaLs:mainfrom
lewis6991:issue1226

Conversation

@lewis6991

Copy link
Copy Markdown
Collaborator

Problem

boolean values were rejected where the equivalent true | false literal
union was expected.

Solution

  • Treat unions containing both boolean literals as exhaustive during type
    checking.
  • Reuse structural union construction in both document type inference paths.

Tests

  • cargo test -p emmylua_code_analysis
  • cargo fmt --all -- --check
  • cargo clippy -p emmylua_code_analysis --all-targets --all-features --locked -- -D warnings

Fixes #1226

Treat the true | false literal union as covering boolean values during
assignability checks, while preserving structural annotation unions.

Reuse LuaType::from_vec in both document type inference paths to remove
duplicate union flattening logic.

Fixes EmmyLuaLs#1226

Assisted-by: Codex

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'll review the code changes for potential issues:

Issues Found:

1. Loss of Union Type Flattening (Critical)

Files: infer_type.rs and infer_doc_type.rs

The original code flattened nested union types, e.g., (A | B) | (C | D) would become [A, B, C, D]. The new code creates nested unions like [Union(A, B), Union(C, D)]. This can cause:

  • Performance degradation: Nested unions require recursive traversal during type checking
  • Type equality issues: (A | B) | C may not be considered equal to A | B | C in all code paths
  • Potential bugs in type display and serialization

Recommendation: Keep the flattening logic but consider using a helper function to reduce duplication between the two files.

2. Boolean Literal Check Inconsistency (Potential Bug)

File: complex_type/mod.rs

if matches!(compact_type, LuaType::Boolean) {
    let contains_literal = |value| {
        sub_types.contains(&LuaType::BooleanConst(value))
            || sub_types.contains(&LuaType::DocBooleanConst(value))
    };

Issues:

  • Mixed literal types: The check requires both true and false to be present, but doesn't handle mixed cases like BooleanConst(true) | DocBooleanConst(false)
  • Missing Boolean type: If the union contains LuaType::Boolean (the general boolean type), it should also cover both literals, but this isn't checked
  • Early return skips other checks: Returning Ok(()) immediately bypasses any additional type checking that might be needed

Recommendation:

if matches!(compact_type, LuaType::Boolean) {
    let has_true = sub_types.iter().any(|t| matches!(t, 
        LuaType::BooleanConst(true) | LuaType::DocBooleanConst(true) | LuaType::Boolean));
    let has_false = sub_types.iter().any(|t| matches!(t, 
        LuaType::BooleanConst(false) | LuaType::DocBooleanConst(false) | LuaType::Boolean));
    
    if has_true && has_false {
        return Ok(());
    }
}

3. Test Coverage Gap

File: return_type_mismatch_test.rs

The test only covers the case where the annotation is boolean and the return is true | false. It doesn't test:

  • The reverse case (annotation is true | false, return is boolean)
  • Nested union types like (true | false) | boolean
  • The case where only one boolean literal is present

4. Code Duplication

The union flattening logic was duplicated in two files (infer_type.rs and infer_doc_type.rs). While the new code reduces duplication, it introduces the same logic in both places. Consider extracting a shared helper function.

Summary of Recommendations:

  1. Critical: Restore union flattening to avoid nested union types
  2. Important: Fix the boolean literal check to handle all cases (mixed literal types, general Boolean type)
  3. Moderate: Add more comprehensive tests for boolean type checking
  4. Minor: Extract shared union handling logic to a common utility function

The changes appear to be addressing issue #1226 about boolean type mismatches, but the implementation has some edge cases that need attention.

@xuhuanzy

Copy link
Copy Markdown
Member

I’m refactoring the type-checking system, and it’s nearly complete. I think it would be better for me to handle this issue.

@lewis6991

Copy link
Copy Markdown
Collaborator Author

Doesn't it matter? AI can trivially resolve any conflicts.

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.

true | false is assignalbe to boolean, but boolean isn't assignable to true | false

2 participants