Skip to content

feat: treat array index as nil-able #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/emmylua_code_analysis/resources/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@
},
"strict": {
"default": {
"arrayIndex": true,
"requirePath": false,
"typeCall": false
},
Expand Down Expand Up @@ -839,6 +840,11 @@
"EmmyrcStrict": {
"type": "object",
"properties": {
"arrayIndex": {
"description": "Whether to enable strict mode array indexing.",
"default": true,
"type": "boolean"
},
"requirePath": {
"description": "Whether to enable strict mode require path.",
"default": false,
Expand Down
14 changes: 9 additions & 5 deletions crates/emmylua_code_analysis/src/config/configs/strict.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

fn default_true() -> bool {
true
}

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct EmmyrcStrict {
/// Whether to enable strict mode require path.
#[serde(default = "default_false")]
#[serde(default)]
pub require_path: bool,
#[serde(default)]
pub type_call: bool,
/// Whether to enable strict mode array indexing.
#[serde(default = "default_true")]
pub array_index: bool,
}

impl Default for EmmyrcStrict {
fn default() -> Self {
Self {
require_path: false,
type_call: false,
array_index: true,
}
}
}

fn default_false() -> bool {
false
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ mod test {
assert(false)

assert(nil and 5)

---@type integer[]
local ints = {1, 2}
assert(ints[3])

---@type [integer, integer]
local enum = {1, 2}
assert(enum[3])
"#
));
}
Expand Down Expand Up @@ -67,5 +75,14 @@ mod test {
assert({}, 'hi')
"#
));

assert!(!ws.check_code_for(
DiagnosticCode::UnnecessaryAssert,
r#"
---@type [integer, integer]
local enum = {1, 2}
assert(enum[2])
"#
));
}
}
22 changes: 15 additions & 7 deletions crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,16 +167,19 @@ fn infer_array_member(
index_expr: LuaIndexMemberExpr,
) -> Result<LuaType, InferFailReason> {
let key = index_expr.get_index_key().ok_or(InferFailReason::None)?;
let expression_type = if db.get_emmyrc().strict.array_index {
TypeOps::Union.apply(array_type, &LuaType::Nil)
} else {
array_type.clone()
};
match key {
LuaIndexKey::Integer(_) => {
return Ok(array_type.clone());
}
LuaIndexKey::Integer(_) => Ok(expression_type),
LuaIndexKey::Expr(expr) => {
let expr_type = infer_expr(db, cache, expr.clone())?;
if expr_type.is_integer() {
return Ok(array_type.clone());
Ok(expression_type)
} else {
return Err(InferFailReason::FieldDotFound);
Err(InferFailReason::FieldDotFound)
}
}
_ => Err(InferFailReason::FieldDotFound),
Expand Down Expand Up @@ -667,13 +670,18 @@ fn infer_member_by_index_array(
index_expr: LuaIndexMemberExpr,
) -> InferResult {
let member_key = index_expr.get_index_key().ok_or(InferFailReason::None)?;
let expression_type = if db.get_emmyrc().strict.array_index {
TypeOps::Union.apply(base, &LuaType::Nil)
} else {
base.clone()
};
if member_key.is_integer() {
return Ok(base.clone());
return Ok(expression_type);
} else if member_key.is_expr() {
let expr = member_key.get_expr().ok_or(InferFailReason::None)?;
let expr_type = infer_expr(db, cache, expr.clone())?;
if check_type_compact(db, &LuaType::Number, &expr_type).is_ok() {
return Ok(base.clone());
return Ok(expression_type);
}
}

Expand Down
5 changes: 3 additions & 2 deletions docs/config/emmyrc_json_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ https://github.com/CppCXY/emmylua-analyzer-rust/blob/main/crates/emmylua_code_an
## strict

- `requirePath`: 是否启用require严格模式, 默认为 `false`. 严格模式时, require必须从指定的根目录开始, 否则无法跳转
- `typeCall`: 是否启用类型调用时严格模式, 默认为 `true`. 严格模式时, 类型调用必须手动写好重载, 否则返回unknown, 非严格模式时, 类型调用会返回自身
- `typeCall`: 是否启用类型调用时严格模式, 默认为 `false`. 严格模式时, 类型调用必须手动写好重载, 否则返回unknown, 非严格模式时, 类型调用会返回自身
- `arrayIndex`:是否启用数组索引的严格模式. 默认为 `true`. 严格模式下,索引必须遵循严格规则(如适用)

## hover

Expand All @@ -158,4 +159,4 @@ https://github.com/CppCXY/emmylua-analyzer-rust/blob/main/crates/emmylua_code_an
## references

- `enable`: 是否启用references功能, 默认为 `true`.
- `fuzzy_search`: 是否启用模糊搜索, 默认为 `true`.
- `fuzzy_search`: 是否启用模糊搜索, 默认为 `true`.
10 changes: 6 additions & 4 deletions docs/config/emmyrc_json_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ It primarily follows this format:
},
"strict": {
"requirePath": false,
"typeCall": true
"typeCall": false,
"arrayIndex": true
},
"hover": {
"enable": true
Expand Down Expand Up @@ -135,12 +136,13 @@ This feature is mainly to make `require` work correctly. If you need to map modu
- `enable`: Whether or not to enable CodeLens. Default is `true`.

## strict
- `requirePath`: Whether or not to enable strict mode for require. Default is `true`.
- `typeCall`: Whether or not to enable strict type calls. Default is `true`.
- `requirePath`: Whether or not to enable strict mode for require. Default is `false`.
- `typeCall`: Whether or not to enable strict type calls. Default is `false`.
- `arrayIndex`: Whether or not to enable strict mode for array indexing. Default is `true`.

## hover
- `enable`: Whether or not to enable hover support. Default is `true`.

## references
- `enable`: Whether or not to enable references. Default is `true`.
- `fuzzy_search`: Whether or not to enable fuzzy search in references. Default is `true`.
- `fuzzy_search`: Whether or not to enable fuzzy search in references. Default is `true`.