11use std:: sync:: Arc ;
22
33use emmylua_parser:: {
4- LuaAst , LuaAstNode , LuaDocAttributeType , LuaDocBinaryType , LuaDocDescriptionOwner ,
5- LuaDocFuncType , LuaDocGenericType , LuaDocMultiLineUnionType , LuaDocObjectFieldKey ,
6- LuaDocObjectType , LuaDocStrTplType , LuaDocType , LuaDocUnaryType , LuaDocVariadicType ,
7- LuaLiteralToken , LuaSyntaxKind , LuaTypeBinaryOperator , LuaTypeUnaryOperator , LuaVarExpr ,
4+ LuaAst , LuaAstNode , LuaDocAttributeType , LuaDocBinaryType , LuaDocConditionalType ,
5+ LuaDocDescriptionOwner , LuaDocFuncType , LuaDocGenericDecl , LuaDocGenericType ,
6+ LuaDocIndexAccessType , LuaDocInferType , LuaDocMappedType , LuaDocMultiLineUnionType ,
7+ LuaDocObjectFieldKey , LuaDocObjectType , LuaDocStrTplType , LuaDocType , LuaDocUnaryType ,
8+ LuaDocVariadicType , LuaLiteralToken , LuaSyntaxKind , LuaTypeBinaryOperator ,
9+ LuaTypeUnaryOperator , LuaVarExpr ,
810} ;
11+ use internment:: ArcIntern ;
912use rowan:: TextRange ;
1013use smol_str:: SmolStr ;
1114
1215use crate :: {
13- AsyncState , DiagnosticCode , GenericTpl , InFiled , LuaAliasCallKind , LuaArrayLen , LuaArrayType ,
14- LuaAttributeType , LuaMultiLineUnion , LuaTupleStatus , LuaTypeDeclId , TypeOps , VariadicType ,
16+ AsyncState , DiagnosticCode , GenericParam , GenericTpl , InFiled , LuaAliasCallKind , LuaArrayLen ,
17+ LuaArrayType , LuaAttributeType , LuaMultiLineUnion , LuaTupleStatus , LuaTypeDeclId , TypeOps ,
18+ VariadicType ,
1519 db_index:: {
16- AnalyzeError , LuaAliasCallType , LuaFunctionType , LuaGenericType , LuaIndexAccessKey ,
17- LuaIntersectionType , LuaObjectType , LuaStringTplType , LuaTupleType , LuaType ,
20+ AnalyzeError , LuaAliasCallType , LuaConditionalType , LuaFunctionType , LuaGenericType ,
21+ LuaIndexAccessKey , LuaIntersectionType , LuaMappedType , LuaObjectType , LuaStringTplType ,
22+ LuaTupleType , LuaType ,
1823 } ,
1924} ;
2025
@@ -111,7 +116,20 @@ pub fn infer_type(analyzer: &mut DocAnalyzer, node: LuaDocType) -> LuaType {
111116 LuaDocType :: Attribute ( attribute_type) => {
112117 return infer_attribute_type ( analyzer, attribute_type) ;
113118 }
114- _ => { } // LuaDocType::Conditional(lua_doc_conditional_type) => todo!(),
119+ LuaDocType :: Conditional ( cond_type) => {
120+ return infer_conditional_type ( analyzer, cond_type) ;
121+ }
122+ LuaDocType :: Infer ( infer_type) => {
123+ if let Some ( name) = infer_type. get_generic_decl_name_text ( ) {
124+ return LuaType :: ConditionalInfer ( ArcIntern :: new ( SmolStr :: new ( & name) ) ) ;
125+ }
126+ }
127+ LuaDocType :: Mapped ( mapped_type) => {
128+ return infer_mapped_type ( analyzer, mapped_type) . unwrap_or ( LuaType :: Unknown ) ;
129+ }
130+ LuaDocType :: IndexAccess ( index_access) => {
131+ return infer_index_access_type ( analyzer, index_access) ;
132+ }
115133 }
116134 LuaType :: Unknown
117135}
@@ -125,6 +143,7 @@ fn infer_buildin_or_ref_type(
125143 let position = range. start ( ) ;
126144 match name {
127145 "unknown" => LuaType :: Unknown ,
146+ "never" => LuaType :: Never ,
128147 "nil" | "void" => LuaType :: Nil ,
129148 "any" => LuaType :: Any ,
130149 "userdata" => LuaType :: Userdata ,
@@ -145,12 +164,10 @@ fn infer_buildin_or_ref_type(
145164 LuaType :: Table
146165 }
147166 _ => {
148- if let Some ( ( tpl_id, is_variadic) ) = analyzer. generic_index . find_generic ( position, name)
149- {
167+ if let Some ( tpl_id) = analyzer. generic_index . find_generic ( position, name) {
150168 return LuaType :: TplRef ( Arc :: new ( GenericTpl :: new (
151169 tpl_id,
152170 SmolStr :: new ( name) . into ( ) ,
153- is_variadic,
154171 ) ) ) ;
155172 }
156173
@@ -672,3 +689,104 @@ fn infer_attribute_type(
672689
673690 LuaType :: DocAttribute ( LuaAttributeType :: new ( params_result) . into ( ) )
674691}
692+
693+ fn infer_conditional_type (
694+ analyzer : & mut DocAnalyzer ,
695+ cond_type : & LuaDocConditionalType ,
696+ ) -> LuaType {
697+ if let Some ( ( condition, when_true, when_false) ) = cond_type. get_types ( ) {
698+ // 收集条件中的所有 infer 声明
699+ let infer_params = collect_cond_infer_params ( & condition) ;
700+ if !infer_params. is_empty ( ) {
701+ // 条件表达式中 infer 声明的类型参数只允许在`true`分支中使用
702+ let true_range = when_true. get_range ( ) ;
703+ analyzer
704+ . generic_index
705+ . add_generic_scope ( vec ! [ true_range] , infer_params. clone ( ) , false ) ;
706+ }
707+
708+ // 处理条件和分支类型
709+ let condition_type = infer_type ( analyzer, condition) ;
710+ let true_type = infer_type ( analyzer, when_true) ;
711+ let false_type = infer_type ( analyzer, when_false) ;
712+
713+ return LuaConditionalType :: new (
714+ condition_type,
715+ true_type,
716+ false_type,
717+ infer_params,
718+ cond_type. has_new ( ) . unwrap_or ( false ) ,
719+ )
720+ . into ( ) ;
721+ }
722+
723+ LuaType :: Unknown
724+ }
725+
726+ /// 收集条件类型中的条件表达式中所有 infer 声明
727+ fn collect_cond_infer_params ( doc_type : & LuaDocType ) -> Vec < GenericParam > {
728+ let mut params = Vec :: new ( ) ;
729+ let doc_infer_types = doc_type. descendants :: < LuaDocInferType > ( ) ;
730+ for infer_type in doc_infer_types {
731+ if let Some ( name) = infer_type. get_generic_decl_name_text ( ) {
732+ params. push ( GenericParam :: new ( SmolStr :: new ( & name) , None , None ) ) ;
733+ }
734+ }
735+ params
736+ }
737+
738+ fn infer_mapped_type (
739+ analyzer : & mut DocAnalyzer ,
740+ mapped_type : & LuaDocMappedType ,
741+ ) -> Option < LuaType > {
742+ // [P in K]
743+ let mapped_key = mapped_type. get_key ( ) ?;
744+ let generic_decl = mapped_key. child :: < LuaDocGenericDecl > ( ) ?;
745+ let name_token = generic_decl. get_name_token ( ) ?;
746+ let name = name_token. get_name_text ( ) ;
747+ let constraint = generic_decl
748+ . get_type ( )
749+ . map ( |constraint| infer_type ( analyzer, constraint) ) ;
750+ let param = GenericParam :: new ( SmolStr :: new ( name) , constraint, None ) ;
751+
752+ analyzer. generic_index . add_generic_scope (
753+ vec ! [ mapped_type. get_range( ) ] ,
754+ vec ! [ param. clone( ) ] ,
755+ false ,
756+ ) ;
757+ let position = mapped_type. get_range ( ) . start ( ) ;
758+ let id = analyzer. generic_index . find_generic ( position, name) ?;
759+
760+ let doc_type = mapped_type. get_value_type ( ) ?;
761+ let value_type = infer_type ( analyzer, doc_type) ;
762+
763+ Some ( LuaType :: Mapped (
764+ LuaMappedType :: new (
765+ ( id, param) ,
766+ value_type,
767+ mapped_type. is_readonly ( ) ,
768+ mapped_type. is_optional ( ) ,
769+ )
770+ . into ( ) ,
771+ ) )
772+ }
773+
774+ fn infer_index_access_type (
775+ analyzer : & mut DocAnalyzer ,
776+ index_access : & LuaDocIndexAccessType ,
777+ ) -> LuaType {
778+ let mut types_iter = index_access. children :: < LuaDocType > ( ) ;
779+ let Some ( source_doc) = types_iter. next ( ) else {
780+ return LuaType :: Unknown ;
781+ } ;
782+ let Some ( key_doc) = types_iter. next ( ) else {
783+ return LuaType :: Unknown ;
784+ } ;
785+
786+ let source_type = infer_type ( analyzer, source_doc) ;
787+ let key_type = infer_type ( analyzer, key_doc) ;
788+
789+ LuaType :: Call (
790+ LuaAliasCallType :: new ( LuaAliasCallKind :: Index , vec ! [ source_type, key_type] ) . into ( ) ,
791+ )
792+ }
0 commit comments