Skip to content

Commit a837bf2

Browse files
committed
support Select Type
1 parent 4a33e15 commit a837bf2

File tree

5 files changed

+139
-37
lines changed

5 files changed

+139
-37
lines changed

crates/emmylua_code_analysis/resources/std/builtin.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,9 @@
109109
---@alias NotNull<T> T - ?
110110

111111
---@alias Nullable<T> T + ?
112+
113+
--- built-in type
114+
---@alias Select<T, StartOrLen> unkonwn
115+
116+
--- built-in type
117+
---@alias Unpack<T, Start, End> unknown

crates/emmylua_code_analysis/resources/std/global.lua

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,10 @@ function require(modname) end
309309
--- `index`. a negative number indexes from the end (-1 is the last argument).
310310
--- Otherwise, `index` must be the string "#", and `select` returns
311311
--- the total number of extra arguments it received.
312-
---@generic T
313-
---@param index number
314-
---@param ... T...
315-
---@return T...
316-
---@overload fun(index: '#', ...): int
312+
---@generic T, Num: integer | '#'
313+
---@param index Num
314+
---@param ... T
315+
---@return Select<T, Num>
317316
function select(index, ...) end
318317

319318
---

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,17 @@ fn infer_special_generic_type(
213213
return Some(LuaType::Namespace(ns_str));
214214
}
215215
}
216+
"Select" => {
217+
let mut params = Vec::new();
218+
for param in generic_type.get_generic_types()?.get_types() {
219+
let param_type = infer_type(analyzer, param);
220+
params.push(param_type);
221+
}
222+
return Some(LuaType::Call(
223+
LuaAliasCallType::new(LuaAliasCallKind::Select, params).into(),
224+
));
225+
}
226+
"Unpack" => {}
216227
_ => {}
217228
}
218229

@@ -282,22 +293,21 @@ fn infer_binary_type(analyzer: &mut DocAnalyzer, binary_type: LuaDocBinaryType)
282293
LuaTypeBinaryOperator::Extends => {
283294
return LuaType::Call(
284295
LuaAliasCallType::new(
285-
left_type,
286296
LuaAliasCallKind::Extends,
287-
Some(right_type),
297+
vec![left_type, right_type],
288298
)
289299
.into(),
290300
);
291301
}
292302
LuaTypeBinaryOperator::Add => {
293303
return LuaType::Call(
294-
LuaAliasCallType::new(left_type, LuaAliasCallKind::Add, Some(right_type))
304+
LuaAliasCallType::new(LuaAliasCallKind::Add, vec![left_type, right_type])
295305
.into(),
296306
);
297307
}
298308
LuaTypeBinaryOperator::Sub => {
299309
return LuaType::Call(
300-
LuaAliasCallType::new(left_type, LuaAliasCallKind::Sub, Some(right_type))
310+
LuaAliasCallType::new(LuaAliasCallKind::Sub, vec![left_type, right_type])
301311
.into(),
302312
);
303313
}
@@ -320,7 +330,7 @@ fn infer_unary_type(analyzer: &mut DocAnalyzer, unary_type: LuaDocUnaryType) ->
320330
match op.get_op() {
321331
LuaTypeUnaryOperator::Keyof => {
322332
return LuaType::Call(
323-
LuaAliasCallType::new(base, LuaAliasCallKind::KeyOf, None).into(),
333+
LuaAliasCallType::new(LuaAliasCallKind::KeyOf, vec![base]).into(),
324334
);
325335
}
326336
_ => {}

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

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -563,10 +563,7 @@ impl LuaObjectType {
563563

564564
let mut ty = LuaType::Unknown;
565565
let mut count = 1;
566-
let mut fields = self
567-
.fields
568-
.iter()
569-
.collect::<Vec<_>>();
566+
let mut fields = self.fields.iter().collect::<Vec<_>>();
570567

571568
fields.sort_by(|(a, _), (b, _)| a.cmp(b));
572569

@@ -662,38 +659,31 @@ pub enum LuaAliasCallKind {
662659
Extends,
663660
Add,
664661
Sub,
662+
Select,
663+
Unpack,
665664
}
666665

667666
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
668667
pub struct LuaAliasCallType {
669-
source: LuaType,
670668
call_kind: LuaAliasCallKind,
671-
operand: Option<LuaType>,
669+
operand: Vec<LuaType>,
672670
}
673671

674672
impl LuaAliasCallType {
675-
pub fn new(source: LuaType, call_kind: LuaAliasCallKind, operand: Option<LuaType>) -> Self {
676-
Self {
677-
source,
678-
call_kind,
679-
operand,
680-
}
681-
}
682-
683-
pub fn get_source(&self) -> &LuaType {
684-
&self.source
673+
pub fn new(call_kind: LuaAliasCallKind, operand: Vec<LuaType>) -> Self {
674+
Self { call_kind, operand }
685675
}
686676

687-
pub fn get_operand(&self) -> Option<&LuaType> {
688-
self.operand.as_ref()
677+
pub fn get_operands(&self) -> &Vec<LuaType> {
678+
&self.operand
689679
}
690680

691681
pub fn get_call_kind(&self) -> LuaAliasCallKind {
692682
self.call_kind
693683
}
694684

695685
pub fn contain_tpl(&self) -> bool {
696-
self.source.contain_tpl() || self.operand.as_ref().map_or(false, |o| o.contain_tpl())
686+
self.operand.iter().any(|t| t.contain_tpl())
697687
}
698688
}
699689

crates/emmylua_code_analysis/src/semantic/instantiate/instantiate_class_generic.rs

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -339,15 +339,33 @@ fn instantiate_alias_call(
339339
alias_call: &LuaAliasCallType,
340340
substitutor: &TypeSubstitutor,
341341
) -> LuaType {
342-
let left = alias_call.get_source();
343-
let right = alias_call.get_operand().unwrap_or(&LuaType::Unknown);
344-
let left_inst = instantiate_type(db, left, substitutor);
345-
let right_inst = instantiate_type(db, right, substitutor);
342+
let operands = alias_call
343+
.get_operands()
344+
.iter()
345+
.map(|it| instantiate_type(db, it, substitutor))
346+
.collect::<Vec<_>>();
347+
346348
match alias_call.get_call_kind() {
347-
LuaAliasCallKind::Sub => return TypeOps::Remove.apply(&left_inst, &right_inst),
348-
LuaAliasCallKind::Add => return TypeOps::Union.apply(&left_inst, &right_inst),
349+
LuaAliasCallKind::Sub => {
350+
if operands.len() != 2 {
351+
return LuaType::Unknown;
352+
}
353+
354+
return TypeOps::Remove.apply(&operands[0], &operands[1]);
355+
}
356+
LuaAliasCallKind::Add => {
357+
if operands.len() != 2 {
358+
return LuaType::Unknown;
359+
}
360+
361+
return TypeOps::Union.apply(&operands[0], &operands[1]);
362+
}
349363
LuaAliasCallKind::KeyOf => {
350-
let members = infer_members(db, &left_inst).unwrap_or(Vec::new());
364+
if operands.len() != 1 {
365+
return LuaType::Unknown;
366+
}
367+
368+
let members = infer_members(db, &operands[0]).unwrap_or(Vec::new());
351369
let member_key_types = members
352370
.iter()
353371
.filter_map(|m| match &m.key {
@@ -360,15 +378,94 @@ fn instantiate_alias_call(
360378
return LuaType::Union(LuaUnionType::new(member_key_types).into());
361379
}
362380
LuaAliasCallKind::Extends => {
363-
let compact = type_check::check_type_compact(db, &right_inst, &left_inst).is_ok();
381+
if operands.len() != 2 {
382+
return LuaType::Unknown;
383+
}
384+
385+
let compact = type_check::check_type_compact(db, &operands[0], &operands[1]).is_ok();
364386
return LuaType::BooleanConst(compact);
365387
}
388+
LuaAliasCallKind::Select => {
389+
if operands.len() != 2 {
390+
return LuaType::Unknown;
391+
}
392+
393+
return instantiate_select_call(&operands[0], &operands[1]);
394+
}
366395
_ => {}
367396
}
368397

369398
LuaType::Unknown
370399
}
371400

401+
enum NumOrLen {
402+
Num(i64),
403+
Len,
404+
LenUnknown,
405+
}
406+
407+
fn instantiate_select_call(source: &LuaType, index: &LuaType) -> LuaType {
408+
let num_or_len = match index {
409+
LuaType::DocIntegerConst(i) => {
410+
if *i == 0 {
411+
return LuaType::Unknown;
412+
}
413+
NumOrLen::Num(*i)
414+
}
415+
LuaType::IntegerConst(i) => {
416+
if *i == 0 {
417+
return LuaType::Unknown;
418+
}
419+
NumOrLen::Num(*i)
420+
}
421+
LuaType::DocStringConst(s) => {
422+
if s.as_str() == "#" {
423+
NumOrLen::Len
424+
} else {
425+
NumOrLen::LenUnknown
426+
}
427+
}
428+
LuaType::StringConst(s) => {
429+
if s.as_str() == "#" {
430+
NumOrLen::Len
431+
} else {
432+
NumOrLen::LenUnknown
433+
}
434+
}
435+
_ => return LuaType::Unknown,
436+
};
437+
let multi_return = if let LuaType::MuliReturn(multi) = source {
438+
multi.deref()
439+
} else {
440+
&LuaMultiReturn::Base(source.clone())
441+
};
442+
443+
match num_or_len {
444+
NumOrLen::Num(i) => match multi_return {
445+
LuaMultiReturn::Base(_) => LuaType::MuliReturn(multi_return.clone().into()),
446+
LuaMultiReturn::Multi(types) => {
447+
let start = if i < 0 { types.len() as i64 + i } else { i - 1 };
448+
if start < 0 || start as usize >= types.len() {
449+
return LuaType::Unknown;
450+
}
451+
452+
let new_types = types
453+
.iter()
454+
.skip(start as usize)
455+
.cloned()
456+
.collect::<Vec<_>>();
457+
458+
LuaType::MuliReturn(LuaMultiReturn::Multi(new_types).into())
459+
}
460+
},
461+
NumOrLen::Len => match multi_return {
462+
LuaMultiReturn::Base(_) => LuaType::Integer,
463+
LuaMultiReturn::Multi(types) => LuaType::DocIntegerConst(types.len() as i64),
464+
},
465+
NumOrLen::LenUnknown => LuaType::Integer,
466+
}
467+
}
468+
372469
fn instantiate_variadic_type(
373470
db: &DbIndex,
374471
inner: &LuaType,

0 commit comments

Comments
 (0)