1
- use emmylua_parser:: { LuaAst , LuaAstNode , LuaAstToken , LuaCallExpr , LuaDocTagType } ;
1
+ use std:: ops:: Deref ;
2
+
3
+ use emmylua_parser:: { LuaAst , LuaAstNode , LuaAstToken , LuaCallExpr , LuaDocTagType , LuaExpr } ;
2
4
use rowan:: TextRange ;
3
5
4
6
use crate :: diagnostic:: checker:: generic:: infer_doc_type:: infer_doc_type;
5
7
use crate :: diagnostic:: checker:: param_type_check:: get_call_source_type;
6
8
use crate :: {
7
- humanize_type, DiagnosticCode , GenericTplId , LuaMemberOwner , LuaSemanticDeclId , LuaSignature ,
8
- LuaStringTplType , LuaType , RenderLevel , SemanticDeclLevel , SemanticModel , TypeCheckFailReason ,
9
- TypeCheckResult ,
9
+ humanize_type, DiagnosticCode , GenericTplId , LuaDeclExtra , LuaMemberOwner , LuaSemanticDeclId ,
10
+ LuaSignature , LuaStringTplType , LuaType , RenderLevel , SemanticDeclLevel , SemanticModel ,
11
+ TypeCheckFailReason , TypeCheckResult , TypeOps , VariadicType ,
10
12
} ;
11
13
12
14
use crate :: diagnostic:: checker:: Checker ;
@@ -83,9 +85,8 @@ fn check_call_expr(
83
85
. get_signature_index ( )
84
86
. get ( & signature_id) ?;
85
87
let mut params = signature. get_type_params ( ) ;
88
+ let mut arg_infos = get_arg_infos ( semantic_model, & call_expr) ?;
86
89
87
- let arg_exprs = call_expr. get_args_list ( ) ?. get_args ( ) . collect :: < Vec < _ > > ( ) ;
88
- let mut arg_infos = semantic_model. infer_expr_list_types ( & arg_exprs, None ) ;
89
90
match ( call_expr. is_colon_call ( ) , signature. is_colon_define ) {
90
91
( true , true ) | ( false , false ) => { }
91
92
( false , true ) => {
@@ -102,7 +103,6 @@ fn check_call_expr(
102
103
) ;
103
104
}
104
105
}
105
-
106
106
for ( i, ( _, param_type) ) in params. iter ( ) . enumerate ( ) {
107
107
let param_type = if let Some ( param_type) = param_type {
108
108
param_type
@@ -344,3 +344,139 @@ fn add_type_check_diagnostic(
344
344
}
345
345
}
346
346
}
347
+
348
+ fn get_arg_infos (
349
+ semantic_model : & SemanticModel ,
350
+ call_expr : & LuaCallExpr ,
351
+ ) -> Option < Vec < ( LuaType , TextRange ) > > {
352
+ let arg_exprs = call_expr. get_args_list ( ) ?. get_args ( ) . collect :: < Vec < _ > > ( ) ;
353
+ let mut arg_infos = infer_expr_list_types ( semantic_model, & arg_exprs) ;
354
+ for ( arg_type, arg_expr) in arg_infos. iter_mut ( ) {
355
+ let extend_type = try_instantiate_arg_type ( semantic_model, arg_type, arg_expr, 0 ) ;
356
+ if let Some ( extend_type) = extend_type {
357
+ * arg_type = extend_type;
358
+ }
359
+ }
360
+
361
+ let arg_infos = arg_infos
362
+ . into_iter ( )
363
+ . map ( |( arg_type, arg_expr) | ( arg_type, arg_expr. get_range ( ) ) )
364
+ . collect ( ) ;
365
+
366
+ Some ( arg_infos)
367
+ }
368
+
369
+ fn try_instantiate_arg_type (
370
+ semantic_model : & SemanticModel ,
371
+ arg_type : & LuaType ,
372
+ arg_expr : & LuaExpr ,
373
+ depth : usize ,
374
+ ) -> Option < LuaType > {
375
+ match arg_type {
376
+ LuaType :: TplRef ( tpl_ref) => {
377
+ let node_or_token = arg_expr. syntax ( ) . clone ( ) . into ( ) ;
378
+ let semantic_decl =
379
+ semantic_model. find_decl ( node_or_token, SemanticDeclLevel :: default ( ) ) ?;
380
+ match tpl_ref. get_tpl_id ( ) {
381
+ GenericTplId :: Func ( tpl_id) => {
382
+ if let LuaSemanticDeclId :: LuaDecl ( decl_id) = semantic_decl {
383
+ let decl = semantic_model
384
+ . get_db ( )
385
+ . get_decl_index ( )
386
+ . get_decl ( & decl_id) ?;
387
+ match decl. extra {
388
+ LuaDeclExtra :: Param { signature_id, .. } => {
389
+ let signature = semantic_model
390
+ . get_db ( )
391
+ . get_signature_index ( )
392
+ . get ( & signature_id) ?;
393
+ if let Some ( ( _, param_type) ) =
394
+ signature. generic_params . get ( tpl_id as usize )
395
+ {
396
+ return param_type. clone ( ) ;
397
+ }
398
+ }
399
+ _ => return None ,
400
+ }
401
+ }
402
+ None
403
+ }
404
+ GenericTplId :: Type ( tpl_id) => {
405
+ if let LuaSemanticDeclId :: LuaDecl ( decl_id) = semantic_decl {
406
+ let decl = semantic_model
407
+ . get_db ( )
408
+ . get_decl_index ( )
409
+ . get_decl ( & decl_id) ?;
410
+ match decl. extra {
411
+ LuaDeclExtra :: Param {
412
+ owner_member_id, ..
413
+ } => {
414
+ let owner_member_id = owner_member_id?;
415
+ let parent_owner = semantic_model
416
+ . get_db ( )
417
+ . get_member_index ( )
418
+ . get_current_owner ( & owner_member_id) ?;
419
+ match parent_owner {
420
+ LuaMemberOwner :: Type ( type_id) => {
421
+ let generic_params = semantic_model
422
+ . get_db ( )
423
+ . get_type_index ( )
424
+ . get_generic_params ( & type_id) ?;
425
+ return generic_params. get ( tpl_id as usize ) ?. 1 . clone ( ) ;
426
+ }
427
+ _ => return None ,
428
+ }
429
+ }
430
+ _ => return None ,
431
+ }
432
+ }
433
+ None
434
+ }
435
+ }
436
+ }
437
+ LuaType :: Union ( union_type) => {
438
+ if depth > 1 {
439
+ return None ;
440
+ }
441
+ let mut result = LuaType :: Unknown ;
442
+ for union_member_type in union_type. into_vec ( ) . iter ( ) {
443
+ let extend_type = try_instantiate_arg_type (
444
+ semantic_model,
445
+ union_member_type,
446
+ arg_expr,
447
+ depth + 1 ,
448
+ )
449
+ . unwrap_or ( union_member_type. clone ( ) ) ;
450
+ result = TypeOps :: Union . apply ( semantic_model. get_db ( ) , & result, & extend_type) ;
451
+ }
452
+ Some ( result)
453
+ }
454
+ _ => None ,
455
+ }
456
+ }
457
+
458
+ fn infer_expr_list_types (
459
+ semantic_model : & SemanticModel ,
460
+ exprs : & [ LuaExpr ] ,
461
+ ) -> Vec < ( LuaType , LuaExpr ) > {
462
+ let mut value_types = Vec :: new ( ) ;
463
+ for expr in exprs. iter ( ) {
464
+ let expr_type = semantic_model
465
+ . infer_expr ( expr. clone ( ) )
466
+ . unwrap_or ( LuaType :: Unknown ) ;
467
+ match expr_type {
468
+ LuaType :: Variadic ( variadic) => match variadic. deref ( ) {
469
+ VariadicType :: Base ( base) => {
470
+ value_types. push ( ( base. clone ( ) , expr. clone ( ) ) ) ;
471
+ }
472
+ VariadicType :: Multi ( vecs) => {
473
+ for typ in vecs {
474
+ value_types. push ( ( typ. clone ( ) , expr. clone ( ) ) ) ;
475
+ }
476
+ }
477
+ } ,
478
+ _ => value_types. push ( ( expr_type. clone ( ) , expr. clone ( ) ) ) ,
479
+ }
480
+ }
481
+ value_types
482
+ }
0 commit comments