Skip to content

Commit 534d126

Browse files
committed
refactor array_type basic bound check for #var = x
1 parent aa86761 commit 534d126

File tree

20 files changed

+207
-59
lines changed

20 files changed

+207
-59
lines changed

crates/emmylua_code_analysis/src/compilation/analyzer/doc/infer_type.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use crate::{
1414
AnalyzeError, LuaAliasCallType, LuaFunctionType, LuaGenericType, LuaIndexAccessKey,
1515
LuaIntersectionType, LuaObjectType, LuaStringTplType, LuaTupleType, LuaType, LuaUnionType,
1616
},
17-
DiagnosticCode, GenericTpl, InFiled, LuaAliasCallKind, LuaMultiLineUnion, LuaTupleStatus,
18-
LuaTypeDeclId, TypeOps, VariadicType,
17+
DiagnosticCode, GenericTpl, InFiled, LuaAliasCallKind, LuaArrayLen, LuaArrayType,
18+
LuaMultiLineUnion, LuaTupleStatus, LuaTypeDeclId, TypeOps, VariadicType,
1919
};
2020

2121
use super::{preprocess_description, DocAnalyzer};
@@ -47,7 +47,7 @@ pub fn infer_type(analyzer: &mut DocAnalyzer, node: LuaDocType) -> LuaType {
4747
if t.is_unknown() {
4848
return LuaType::Unknown;
4949
}
50-
return LuaType::Array(t.into());
50+
return LuaType::Array(LuaArrayType::new(t, LuaArrayLen::None).into());
5151
}
5252
}
5353
LuaDocType::Literal(literal) => {

crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/find_decl_function.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ fn find_function_type_by_member_key(
145145
find_instance_member_decl_type(db, cache, inst, index_expr, infer_guard, deep_guard)
146146
}
147147
LuaType::Namespace(ns) => infer_namespace_member_decl_type(db, cache, ns, index_expr),
148-
LuaType::Array(array_type) => find_array_function(db, cache, array_type, index_expr),
148+
LuaType::Array(array_type) => {
149+
find_array_function(db, cache, array_type.get_base(), index_expr)
150+
}
149151
_ => Err(InferFailReason::FieldNotFound),
150152
}
151153
}
@@ -471,7 +473,9 @@ fn find_function_type_by_operator(
471473
deep_guard,
472474
),
473475
// LuaType::Module(arc) => todo!(),
474-
LuaType::Array(base) => infer_member_by_index_array(db, cache, base, index_expr),
476+
LuaType::Array(array_type) => {
477+
infer_member_by_index_array(db, cache, array_type.get_base(), index_expr)
478+
}
475479
LuaType::Object(object) => infer_member_by_index_object(db, cache, object, index_expr),
476480
LuaType::Union(union) => {
477481
find_member_by_index_union(db, cache, union, index_expr, deep_guard)

crates/emmylua_code_analysis/src/db_index/type/humanize_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub fn humanize_type(db: &DbIndex, ty: &LuaType, level: RenderLevel) -> String {
7878
id.get_name().to_string()
7979
}
8080
}
81-
LuaType::Array(arr_inner) => humanize_array_type(db, arr_inner, level),
81+
LuaType::Array(arr_inner) => humanize_array_type(db, arr_inner.get_base(), level),
8282
LuaType::Call(alias_call) => humanize_call_type(db, alias_call, level),
8383
LuaType::DocFunction(lua_func) => humanize_doc_function_type(db, lua_func, level),
8484
LuaType::Object(object) => humanize_object_type(db, object, level),

crates/emmylua_code_analysis/src/db_index/type/types.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub enum LuaType {
4040
TableConst(InFiled<TextRange>),
4141
Ref(LuaTypeDeclId),
4242
Def(LuaTypeDeclId),
43-
Array(Arc<LuaType>),
43+
Array(Arc<LuaArrayType>),
4444
Tuple(Arc<LuaTupleType>),
4545
DocFunction(Arc<LuaFunctionType>),
4646
Object(Arc<LuaObjectType>),
@@ -1187,3 +1187,40 @@ impl LuaMultiLineUnion {
11871187
self.unions.iter().any(|(t, _)| t.contain_tpl())
11881188
}
11891189
}
1190+
1191+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1192+
pub struct LuaArrayType {
1193+
base: LuaType,
1194+
len: LuaArrayLen,
1195+
}
1196+
1197+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1198+
pub enum LuaArrayLen {
1199+
None,
1200+
Max(i64),
1201+
}
1202+
1203+
impl LuaArrayType {
1204+
pub fn new(base: LuaType, len: LuaArrayLen) -> Self {
1205+
Self { base, len }
1206+
}
1207+
1208+
pub fn from_base_type(base: LuaType) -> Self {
1209+
Self {
1210+
base,
1211+
len: LuaArrayLen::None,
1212+
}
1213+
}
1214+
1215+
pub fn get_base(&self) -> &LuaType {
1216+
&self.base
1217+
}
1218+
1219+
pub fn get_len(&self) -> &LuaArrayLen {
1220+
&self.len
1221+
}
1222+
1223+
pub fn contain_tpl(&self) -> bool {
1224+
self.base.contain_tpl()
1225+
}
1226+
}

crates/emmylua_code_analysis/src/diagnostic/checker/check_field.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ fn is_valid_member(
151151
match prefix_typ {
152152
LuaType::Global | LuaType::Userdata => return Some(()),
153153
LuaType::Array(typ) => {
154-
if typ.is_unknown() {
154+
if typ.get_base().is_unknown() {
155155
return Some(());
156156
}
157157
}

crates/emmylua_code_analysis/src/diagnostic/checker/generic/infer_doc_type.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use emmylua_parser::{
24
LuaAstNode, LuaDocBinaryType, LuaDocDescriptionOwner, LuaDocFuncType, LuaDocGenericType,
35
LuaDocMultiLineUnionType, LuaDocObjectFieldKey, LuaDocObjectType, LuaDocStrTplType, LuaDocType,
@@ -8,10 +10,10 @@ use rowan::TextRange;
810
use smol_str::SmolStr;
911

1012
use crate::{
11-
InFiled, LuaAliasCallKind, LuaAliasCallType, LuaFunctionType, LuaGenericType,
12-
LuaIndexAccessKey, LuaIntersectionType, LuaMultiLineUnion, LuaObjectType, LuaStringTplType,
13-
LuaTupleStatus, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType, SemanticModel, TypeOps,
14-
VariadicType,
13+
InFiled, LuaAliasCallKind, LuaAliasCallType, LuaArrayLen, LuaArrayType, LuaFunctionType,
14+
LuaGenericType, LuaIndexAccessKey, LuaIntersectionType, LuaMultiLineUnion, LuaObjectType,
15+
LuaStringTplType, LuaTupleStatus, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType,
16+
SemanticModel, TypeOps, VariadicType,
1517
};
1618

1719
pub fn infer_doc_type(semantic_model: &SemanticModel, node: &LuaDocType) -> LuaType {
@@ -46,7 +48,7 @@ pub fn infer_doc_type(semantic_model: &SemanticModel, node: &LuaDocType) -> LuaT
4648
if t.is_unknown() {
4749
return LuaType::Unknown;
4850
}
49-
return LuaType::Array(t.into());
51+
return LuaType::Array(Arc::new(LuaArrayType::new(t.into(), LuaArrayLen::None)));
5052
}
5153
}
5254
LuaDocType::Literal(literal) => {

crates/emmylua_code_analysis/src/semantic/generic/instantiate_special_generic.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,9 @@ fn instantiate_unpack_call(db: &DbIndex, operands: &[LuaType]) -> LuaType {
201201

202202
LuaType::Variadic(VariadicType::Multi(types).into())
203203
}
204-
LuaType::Array(base) => LuaType::Variadic(
205-
VariadicType::Base(TypeOps::Union.apply(db, base, &LuaType::Nil)).into(),
204+
LuaType::Array(array_type) => LuaType::Variadic(
205+
VariadicType::Base(TypeOps::Union.apply(db, array_type.get_base(), &LuaType::Nil))
206+
.into(),
206207
),
207208
LuaType::TableGeneric(table) => {
208209
if table.len() != 2 {

crates/emmylua_code_analysis/src/semantic/generic/instantiate_type_generic.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88
LuaFunctionType, LuaGenericType, LuaIntersectionType, LuaObjectType, LuaTupleType, LuaType,
99
LuaUnionType, VariadicType,
1010
},
11-
DbIndex, GenericTpl, LuaSignatureId,
11+
DbIndex, GenericTpl, LuaArrayType, LuaSignatureId,
1212
};
1313

1414
use super::{
@@ -22,7 +22,7 @@ pub fn instantiate_type_generic(
2222
substitutor: &TypeSubstitutor,
2323
) -> LuaType {
2424
match ty {
25-
LuaType::Array(base) => instantiate_array(db, base, substitutor),
25+
LuaType::Array(array_type) => instantiate_array(db, array_type.get_base(), substitutor),
2626
LuaType::Tuple(tuple) => instantiate_tuple(db, tuple, substitutor),
2727
LuaType::DocFunction(doc_func) => instantiate_doc_function(db, doc_func, substitutor),
2828
LuaType::Object(object) => instantiate_object(db, object, substitutor),
@@ -55,7 +55,7 @@ pub fn instantiate_type_generic(
5555

5656
fn instantiate_array(db: &DbIndex, base: &LuaType, substitutor: &TypeSubstitutor) -> LuaType {
5757
let base = instantiate_type_generic(db, base, substitutor);
58-
LuaType::Array(base.into())
58+
LuaType::Array(LuaArrayType::from_base_type(base).into())
5959
}
6060

6161
fn instantiate_tuple(db: &DbIndex, tuple: &LuaTupleType, substitutor: &TypeSubstitutor) -> LuaType {

crates/emmylua_code_analysis/src/semantic/generic/tpl_pattern.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ fn tpl_pattern_match(
145145
}
146146
_ => {}
147147
},
148-
LuaType::Array(base) => {
149-
array_tpl_pattern_match(db, cache, root, base, &target, substitutor)?;
148+
LuaType::Array(array_type) => {
149+
array_tpl_pattern_match(db, cache, root, array_type.get_base(), &target, substitutor)?;
150150
}
151151
LuaType::TableGeneric(table_generic_params) => {
152152
table_generic_tpl_pattern_match(
@@ -287,8 +287,15 @@ fn array_tpl_pattern_match(
287287
substitutor: &mut TypeSubstitutor,
288288
) -> TplPatternMatchResult {
289289
match target {
290-
LuaType::Array(target_base) => {
291-
tpl_pattern_match(db, cache, root, base, target_base, substitutor)?;
290+
LuaType::Array(target_array_type) => {
291+
tpl_pattern_match(
292+
db,
293+
cache,
294+
root,
295+
base,
296+
target_array_type.get_base(),
297+
substitutor,
298+
)?;
292299
}
293300
LuaType::Tuple(target_tuple) => {
294301
let target_base = target_tuple.cast_down_array_base(db);
@@ -348,7 +355,7 @@ fn table_generic_tpl_pattern_match(
348355
cache,
349356
root,
350357
&table_generic_params[1],
351-
target_array_base,
358+
target_array_base.get_base(),
352359
substitutor,
353360
)?;
354361
}
@@ -949,7 +956,7 @@ fn tuple_tpl_pattern_match(
949956
if let LuaType::TplRef(tpl_ref) = base {
950957
let tpl_id = tpl_ref.get_tpl_id();
951958
substitutor
952-
.insert_multi_base(tpl_id, target_array_base.deref().clone());
959+
.insert_multi_base(tpl_id, target_array_base.get_base().clone());
953960
}
954961
}
955962
VariadicType::Multi(_) => {}

crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ use crate::{
1818
type_check::{self, check_type_compact},
1919
InferGuard,
2020
},
21-
CacheEntry, InFiled, LuaDeclOrMemberId, LuaInferCache, LuaInstanceType, LuaMemberOwner,
22-
LuaOperatorOwner, TypeOps,
21+
CacheEntry, InFiled, LuaArrayLen, LuaArrayType, LuaDeclOrMemberId, LuaInferCache,
22+
LuaInstanceType, LuaMemberOwner, LuaOperatorOwner, TypeOps,
2323
};
2424

2525
use super::{infer_expr, infer_name::infer_global_type, InferFailReason, InferResult};
@@ -181,24 +181,56 @@ pub fn infer_member_by_member_key(
181181
fn infer_array_member(
182182
db: &DbIndex,
183183
cache: &mut LuaInferCache,
184-
array_type: &LuaType,
184+
array_type: &LuaArrayType,
185185
index_expr: LuaIndexMemberExpr,
186186
) -> Result<LuaType, InferFailReason> {
187187
let key = index_expr.get_index_key().ok_or(InferFailReason::None)?;
188-
let expression_type = if db.get_emmyrc().strict.array_index {
189-
match &array_type {
190-
LuaType::Any | LuaType::Unknown => array_type.clone(),
191-
_ => TypeOps::Union.apply(db, array_type, &LuaType::Nil),
192-
}
193-
} else {
194-
array_type.clone()
195-
};
196188
match key {
197-
LuaIndexKey::Integer(_) => Ok(expression_type),
189+
LuaIndexKey::Integer(i) => {
190+
if !db.get_emmyrc().strict.array_index {
191+
return Ok(array_type.get_base().clone());
192+
}
193+
194+
let base_type = array_type.get_base();
195+
match array_type.get_len() {
196+
LuaArrayLen::None => {}
197+
LuaArrayLen::Max(max_len) => {
198+
let index_value = i.get_int_value();
199+
if index_value > 0 && index_value <= *max_len {
200+
return Ok(base_type.clone());
201+
}
202+
}
203+
}
204+
205+
let result_type = match &base_type {
206+
LuaType::Any | LuaType::Unknown => base_type.clone(),
207+
_ => TypeOps::Union.apply(db, base_type, &LuaType::Nil),
208+
};
209+
210+
Ok(result_type)
211+
}
198212
LuaIndexKey::Expr(expr) => {
199213
let expr_type = infer_expr(db, cache, expr.clone())?;
200214
if expr_type.is_integer() {
201-
Ok(expression_type)
215+
let base_type = array_type.get_base();
216+
match (array_type.get_len(), expr_type) {
217+
(
218+
LuaArrayLen::Max(max_len),
219+
LuaType::IntegerConst(index_value) | LuaType::DocIntegerConst(index_value),
220+
) => {
221+
if index_value > 0 && index_value <= *max_len {
222+
return Ok(base_type.clone());
223+
}
224+
}
225+
_ => {}
226+
}
227+
228+
let result_type = match &base_type {
229+
LuaType::Any | LuaType::Unknown => base_type.clone(),
230+
_ => TypeOps::Union.apply(db, base_type, &LuaType::Nil),
231+
};
232+
233+
Ok(result_type)
202234
} else {
203235
Err(InferFailReason::FieldNotFound)
204236
}
@@ -680,7 +712,9 @@ pub fn infer_member_by_operator(
680712
infer_member_by_index_custom_type(db, cache, decl_id, index_expr, infer_guard)
681713
}
682714
// LuaType::Module(arc) => todo!(),
683-
LuaType::Array(base) => infer_member_by_index_array(db, cache, base, index_expr),
715+
LuaType::Array(array_type) => {
716+
infer_member_by_index_array(db, cache, array_type.get_base(), index_expr)
717+
}
684718
LuaType::Object(object) => infer_member_by_index_object(db, cache, object, index_expr),
685719
LuaType::Union(union) => infer_member_by_index_union(db, cache, union, index_expr),
686720
LuaType::Intersection(intersection) => {

0 commit comments

Comments
 (0)