jaclang 0.8.9__py3-none-any.whl → 0.8.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

Files changed (103) hide show
  1. jaclang/cli/cli.py +147 -25
  2. jaclang/cli/cmdreg.py +144 -8
  3. jaclang/compiler/__init__.py +6 -1
  4. jaclang/compiler/codeinfo.py +16 -1
  5. jaclang/compiler/constant.py +33 -13
  6. jaclang/compiler/jac.lark +130 -31
  7. jaclang/compiler/larkparse/jac_parser.py +2 -2
  8. jaclang/compiler/parser.py +567 -176
  9. jaclang/compiler/passes/__init__.py +2 -1
  10. jaclang/compiler/passes/ast_gen/__init__.py +5 -0
  11. jaclang/compiler/passes/ast_gen/base_ast_gen_pass.py +54 -0
  12. jaclang/compiler/passes/ast_gen/jsx_processor.py +344 -0
  13. jaclang/compiler/passes/ecmascript/__init__.py +25 -0
  14. jaclang/compiler/passes/ecmascript/es_unparse.py +576 -0
  15. jaclang/compiler/passes/ecmascript/esast_gen_pass.py +2068 -0
  16. jaclang/compiler/passes/ecmascript/estree.py +972 -0
  17. jaclang/compiler/passes/ecmascript/tests/__init__.py +1 -0
  18. jaclang/compiler/passes/ecmascript/tests/fixtures/advanced_language_features.jac +170 -0
  19. jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.impl.jac +30 -0
  20. jaclang/compiler/passes/ecmascript/tests/fixtures/class_separate_impl.jac +14 -0
  21. jaclang/compiler/passes/ecmascript/tests/fixtures/client_jsx.jac +89 -0
  22. jaclang/compiler/passes/ecmascript/tests/fixtures/core_language_features.jac +195 -0
  23. jaclang/compiler/passes/ecmascript/tests/test_esast_gen_pass.py +167 -0
  24. jaclang/compiler/passes/ecmascript/tests/test_js_generation.py +239 -0
  25. jaclang/compiler/passes/main/__init__.py +0 -3
  26. jaclang/compiler/passes/main/annex_pass.py +23 -1
  27. jaclang/compiler/passes/main/pyast_gen_pass.py +324 -234
  28. jaclang/compiler/passes/main/pyast_load_pass.py +46 -11
  29. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +2 -0
  30. jaclang/compiler/passes/main/sym_tab_build_pass.py +18 -1
  31. jaclang/compiler/passes/main/tests/fixtures/autoimpl.cl.jac +7 -0
  32. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +3 -0
  33. jaclang/compiler/passes/main/tests/fixtures/checker_class_construct.jac +33 -0
  34. jaclang/compiler/passes/main/tests/fixtures/defuse_modpath.jac +7 -0
  35. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +2 -1
  36. jaclang/compiler/passes/main/tests/test_checker_pass.py +31 -2
  37. jaclang/compiler/passes/main/tests/test_def_use_pass.py +12 -0
  38. jaclang/compiler/passes/main/tests/test_import_pass.py +23 -4
  39. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +25 -0
  40. jaclang/compiler/passes/main/type_checker_pass.py +7 -0
  41. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +115 -0
  42. jaclang/compiler/passes/tool/fuse_comments_pass.py +1 -10
  43. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +4 -1
  44. jaclang/compiler/passes/transform.py +9 -1
  45. jaclang/compiler/passes/uni_pass.py +5 -7
  46. jaclang/compiler/program.py +22 -25
  47. jaclang/compiler/tests/test_client_codegen.py +113 -0
  48. jaclang/compiler/tests/test_importer.py +12 -10
  49. jaclang/compiler/tests/test_parser.py +249 -3
  50. jaclang/compiler/type_system/type_evaluator.jac +169 -50
  51. jaclang/compiler/type_system/type_utils.py +1 -1
  52. jaclang/compiler/type_system/types.py +6 -0
  53. jaclang/compiler/unitree.py +430 -84
  54. jaclang/langserve/engine.jac +224 -288
  55. jaclang/langserve/sem_manager.jac +12 -8
  56. jaclang/langserve/server.jac +48 -48
  57. jaclang/langserve/tests/fixtures/greet.py +17 -0
  58. jaclang/langserve/tests/fixtures/md_path.jac +22 -0
  59. jaclang/langserve/tests/fixtures/user.jac +15 -0
  60. jaclang/langserve/tests/test_server.py +66 -371
  61. jaclang/lib.py +1 -1
  62. jaclang/runtimelib/client_bundle.py +169 -0
  63. jaclang/runtimelib/client_runtime.jac +586 -0
  64. jaclang/runtimelib/constructs.py +2 -0
  65. jaclang/runtimelib/machine.py +259 -100
  66. jaclang/runtimelib/meta_importer.py +111 -22
  67. jaclang/runtimelib/mtp.py +15 -0
  68. jaclang/runtimelib/server.py +1089 -0
  69. jaclang/runtimelib/tests/fixtures/client_app.jac +18 -0
  70. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  71. jaclang/runtimelib/tests/fixtures/savable_object.jac +4 -5
  72. jaclang/runtimelib/tests/fixtures/serve_api.jac +75 -0
  73. jaclang/runtimelib/tests/test_client_bundle.py +55 -0
  74. jaclang/runtimelib/tests/test_client_render.py +63 -0
  75. jaclang/runtimelib/tests/test_serve.py +1069 -0
  76. jaclang/settings.py +0 -2
  77. jaclang/tests/fixtures/iife_functions.jac +142 -0
  78. jaclang/tests/fixtures/iife_functions_client.jac +143 -0
  79. jaclang/tests/fixtures/multistatement_lambda.jac +116 -0
  80. jaclang/tests/fixtures/multistatement_lambda_client.jac +113 -0
  81. jaclang/tests/fixtures/needs_import_dup.jac +6 -4
  82. jaclang/tests/fixtures/py_run.py +7 -5
  83. jaclang/tests/fixtures/pyfunc_fstr.py +2 -2
  84. jaclang/tests/fixtures/simple_lambda_test.jac +12 -0
  85. jaclang/tests/test_cli.py +1 -1
  86. jaclang/tests/test_language.py +10 -39
  87. jaclang/tests/test_reference.py +17 -2
  88. jaclang/utils/NonGPT.py +375 -0
  89. jaclang/utils/helpers.py +44 -16
  90. jaclang/utils/lang_tools.py +31 -4
  91. jaclang/utils/tests/test_lang_tools.py +1 -1
  92. jaclang/utils/treeprinter.py +8 -3
  93. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/METADATA +3 -3
  94. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/RECORD +96 -66
  95. jaclang/compiler/passes/main/binder_pass.py +0 -594
  96. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +0 -47
  97. jaclang/compiler/passes/main/tests/test_binder_pass.py +0 -111
  98. jaclang/langserve/tests/session.jac +0 -294
  99. jaclang/langserve/tests/test_dev_server.py +0 -80
  100. jaclang/runtimelib/importer.py +0 -351
  101. jaclang/tests/test_typecheck.py +0 -542
  102. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/WHEEL +0 -0
  103. {jaclang-0.8.9.dist-info → jaclang-0.8.10.dist-info}/entry_points.txt +0 -0
@@ -15,7 +15,7 @@ import from typing { Callable, TYPE_CHECKING, cast }
15
15
 
16
16
  import jaclang.compiler.unitree as uni;
17
17
  import from jaclang.compiler { TOKEN_MAP }
18
- import from jaclang.compiler.constant { Tokens as Tok }
18
+ import from jaclang.compiler.constant { SymbolType, Tokens as Tok }
19
19
  import from jaclang.compiler.passes.main.pyast_load_pass { PyastBuildPass }
20
20
  import from jaclang.compiler.passes.main.sym_tab_build_pass { SymTabBuildPass }
21
21
  import from jaclang.compiler.type_system { types }
@@ -112,9 +112,11 @@ class TypeEvaluator {
112
112
  def __init__(self: TypeEvaluator, program: "JacProgram") -> None {
113
113
  self.program = program;
114
114
  self.symbol_resolution_stack: list[SymbolResolutionStackEntry] = [];
115
+ self.prefetch: PrefetchedTypes | None = None;
115
116
  self.builtins_module = self._load_builtins_stub_module();
116
- self.prefetch = self._prefetch_types();
117
117
  self.diagnostic_callback: DiagnosticCallback | None = None;
118
+
119
+ self._prefetch_types();
118
120
  }
119
121
 
120
122
  """Load and return the builtins stub module."""
@@ -147,7 +149,7 @@ class TypeEvaluator {
147
149
 
148
150
  """Return the prefetched types for the type evaluator."""
149
151
  def _prefetch_types(self: TypeEvaluator) -> "PrefetchedTypes" {
150
- return PrefetchedTypes(
152
+ self.prefetch = PrefetchedTypes(
151
153
  # TODO: Pyright first try load NoneType from typeshed and if it cannot
152
154
  # then it set to unknown type.
153
155
  none_type_class=types.UnknownType(),
@@ -267,23 +269,41 @@ class TypeEvaluator {
267
269
 
268
270
  """Return the effective type of the module."""
269
271
  def get_type_of_module(self: TypeEvaluator, node_: uni.ModulePath) -> types.TypeBase {
270
- if node_.name_spec.type is not None {
271
- return cast(types.ModuleType, node_.name_spec.type);
272
- }
273
- if not Path(node_.resolve_relative_path()).exists() {
274
- node_.name_spec.type = types.UnknownType();
275
- return node_.name_spec.type;
276
- }
272
+ if node_.path {
273
+ # If the type is already computed, return it.
274
+ if node_.path[-1].type {
275
+ return node_.path[-1].type;
276
+ }
277
277
 
278
- mod: uni.Module = self._import_module_from_path(node_.resolve_relative_path());
279
- mod_type = types.ModuleType(
280
- mod_name=node_.name_spec.sym_name,
281
- file_uri=Path(node_.resolve_relative_path()).resolve(),
282
- symbol_table=mod,
283
- );
278
+ for (idx, npath) in enumerate(node_.path) {
279
+ mod_path = node_.resolve_relative_path_list()[idx];
280
+
281
+ # If the path doesn't exist, return unknown type.
282
+ # eg: import from ..mod { item } # <-- Here ..mod might not exist.
283
+ if not Path(mod_path).exists() {
284
+ npath.type = types.UnknownType();
285
+ npath._sym_category = SymbolType.MODULE;
286
+ self.add_diagnostic(npath, 'Module not found', warning=True);
287
+ return npath.type;
288
+ }
289
+
290
+ mod: uni.Module = self._import_module_from_path(mod_path);
291
+ mod_type = types.ModuleType(
292
+ mod_name=npath.value,
293
+ file_uri=Path(mod_path).resolve(),
294
+ symbol_table=mod
295
+ );
296
+ npath.type = mod_type;
297
+ npath._sym_category = SymbolType.MODULE;
298
+ }
299
+ if node_.alias {
300
+ node_.alias.type = node_.path[-1].type;
301
+ node_.alias._sym_category = SymbolType.MODULE;
302
+ }
303
+ return node_.path[-1].type;
304
+ }
305
+ return types.UnknownType();
284
306
 
285
- node_.name_spec.type = mod_type;
286
- return mod_type;
287
307
  }
288
308
 
289
309
  """Return the effective type of the module item."""
@@ -291,12 +311,13 @@ class TypeEvaluator {
291
311
  # Module item can be both a module or a member of a module.
292
312
  # import from .. { mod } # <-- Here mod is not a member but a module itself.
293
313
  # import from mod { item } # <-- Here item is not a module but a member of mod.
294
- if node_.name_spec.type is not None {
295
- return node_.name_spec.type;
314
+ if node_.name.type is not None {
315
+ return node_.name.type;
296
316
  }
297
317
 
298
318
  import_node = node_.parent_of_type(uni.Import);
299
- if import_node.from_loc {
319
+ assert import_node.from_loc is not None;
320
+ if isinstance(self.get_type_of_module(import_node.from_loc), types.ModuleType){
300
321
 
301
322
  from_path = Path(import_node.from_loc.resolve_relative_path());
302
323
  is_dir = from_path.is_dir() or (from_path.stem == "__init__");
@@ -309,12 +330,12 @@ class TypeEvaluator {
309
330
  if (path := (mod_dir / (node_.name.value + ext)).resolve()).exists() {
310
331
  mod = self._import_module_from_path(str(path));
311
332
  mod_type = types.ModuleType(
312
- mod_name=node_.name_spec.sym_name,
333
+ mod_name=node_.name.sym_name,
313
334
  file_uri=path,
314
335
  symbol_table=mod,
315
336
  );
316
337
  # Cache the type.
317
- node_.name_spec.type = mod_type;
338
+ node_.name.type = mod_type;
318
339
 
319
340
  # FIXME: goto definition works on imported symbol by checking if it's a MODULE
320
341
  # type and in that case it'll call resolve_relative_path on the parent node of
@@ -323,8 +344,8 @@ class TypeEvaluator {
323
344
  # below should work but because of the above assumption (should be a mod path)
324
345
  # it won't, This needs to be discussed.
325
346
  #
326
- # node.name_spec._sym_category = uni.SymbolType.MODULE
327
- return node_.name_spec.type;
347
+ node_.name._sym_category = SymbolType.MODULE;
348
+ return mod_type;
328
349
  }
329
350
  }
330
351
  }
@@ -333,18 +354,18 @@ class TypeEvaluator {
333
354
  else {
334
355
  mod_type = self.get_type_of_module(import_node.from_loc);
335
356
  if not isinstance(mod_type, types.ModuleType) {
336
- node_.name_spec.type = types.UnknownType();
357
+ node_.name.type = types.UnknownType();
337
358
  # TODO: Add diagnostic that from_loc is not accessible.
338
359
  # Eg: 'Import "scipy" could not be resolved'
339
- return node_.name_spec.type;
360
+ return node_.name.type;
340
361
  }
341
362
  if sym := mod_type.symbol_table.lookup(node_.name.value, deep=True) {
342
363
  node_.name.sym = sym;
343
364
  if node_.alias {
344
365
  node_.alias.sym = sym;
345
366
  }
346
- node_.name_spec.type = self.get_type_of_symbol(sym);
347
- return node_.name_spec.type;
367
+ node_.name.type = self.get_type_of_symbol(sym);
368
+ return node_.name.type;
348
369
  }
349
370
  }
350
371
  }
@@ -366,12 +387,18 @@ class TypeEvaluator {
366
387
  }
367
388
  is_builtin_class = node_.find_parent_of_type(uni.Module) == self.builtins_module;
368
389
 
390
+ # NOTE: obj, walker, node, edge are dataclass with symbol type as such but
391
+ # other classes are with symbol type TYPE.
392
+ # TODO: We need to handle @dataclass decorator as well.
393
+ is_data_class = node_.sym_category != SymbolType.TYPE;
394
+
369
395
  cls_type = types.ClassType(
370
396
  types.ClassType.ClassDetailsShared(
371
397
  class_name=node_.name_spec.sym_name,
372
398
  symbol_table=node_,
373
399
  base_classes=base_classes,
374
400
  is_builtin_class=is_builtin_class,
401
+ is_data_class=is_data_class,
375
402
  ),
376
403
  flags=types.TypeFlags.Instantiable,
377
404
  );
@@ -600,12 +627,6 @@ class TypeEvaluator {
600
627
  def _get_type_of_symbol(self: TypeEvaluator, symbol: uni.Symbol) -> TypeBase {
601
628
  node_ = symbol.decl.name_of;
602
629
  match node_ {
603
- case uni.ModulePath():
604
- return self.get_type_of_module(node_);
605
-
606
- case uni.ModuleItem():
607
- return self.get_type_of_module_item(node_);
608
-
609
630
  case uni.Archetype():
610
631
  return self.get_type_of_class(node_);
611
632
 
@@ -635,6 +656,12 @@ class TypeEvaluator {
635
656
  }
636
657
  }
637
658
  }
659
+ if isinstance(node_.parent, uni.ModulePath) {
660
+ return self.get_type_of_module(node_.parent);
661
+ }
662
+ if isinstance(node_.parent, uni.ModuleItem) {
663
+ return self.get_type_of_module_item(node_.parent);
664
+ }
638
665
 
639
666
  case uni.HasVar():
640
667
  if node_.type_tag is not None {
@@ -657,14 +684,30 @@ class TypeEvaluator {
657
684
  def _get_type_of_expression_core(self: TypeEvaluator, expr: uni.Expr) -> TypeBase {
658
685
  match expr {
659
686
 
687
+ # ----------------------------------------------------------------------
688
+ # Prefetched types: These types may not have prefetched and we need to
689
+ # check if they are available, if the're not, we're inside builtins or
690
+ # typeshed module itself and in that case we can just return unknown type.
691
+ # ----------------------------------------------------------------------
692
+
660
693
  case uni.String() | uni.MultiString():
661
- return self._convert_to_instance(self.get_type_of_string(expr));
694
+ if self.prefetch {
695
+ return self._convert_to_instance(self.get_type_of_string(expr));
696
+ }
662
697
 
663
698
  case uni.Int():
664
- return self._convert_to_instance(self.get_type_of_int(expr));
699
+ if self.prefetch {
700
+ return self._convert_to_instance(self.get_type_of_int(expr));
701
+ }
665
702
 
666
703
  case uni.Float():
667
- return self._convert_to_instance(self.get_type_of_float(expr));
704
+ if self.prefetch {
705
+ return self._convert_to_instance(self.get_type_of_float(expr));
706
+ }
707
+
708
+ # ----------------------------------------------------------------------
709
+ # End of prefetched types
710
+ # ----------------------------------------------------------------------
668
711
 
669
712
  case uni.AtomTrailer():
670
713
  # NOTE: Pyright is using CFG to figure out the member type by narrowing the base
@@ -679,8 +722,7 @@ class TypeEvaluator {
679
722
  if sym := base_type.symbol_table.lookup(
680
723
  expr.right.value, deep=True
681
724
  ) {
682
- expr.right.sym = sym;
683
- return self.get_type_of_symbol(sym);
725
+ return self._set_symbol_to_expr(expr.right, sym);
684
726
  }
685
727
  return types.UnknownType();
686
728
  }
@@ -690,8 +732,7 @@ class TypeEvaluator {
690
732
  if member := self._lookup_class_member(
691
733
  base_type, expr.right.value
692
734
  ) {
693
- expr.right.sym = member.symbol;
694
- return self.get_type_of_symbol(member.symbol);
735
+ return self._set_symbol_to_expr(expr.right, member.symbol);
695
736
  }
696
737
  return types.UnknownType();
697
738
  }
@@ -701,8 +742,7 @@ class TypeEvaluator {
701
742
  if member := self._lookup_object_member(
702
743
  base_type, expr.right.value
703
744
  ) {
704
- expr.right.sym = member.symbol;
705
- return self.get_type_of_symbol(member.symbol);
745
+ return self._set_symbol_to_expr(expr.right, member.symbol);
706
746
  }
707
747
  return types.UnknownType();
708
748
  }
@@ -734,7 +774,7 @@ class TypeEvaluator {
734
774
  }
735
775
 
736
776
  if symbol := expr.sym_tab.lookup(expr.value, deep=True) {
737
- expr.sym = symbol;
777
+ expr.sym = self.resolve_imported_symbols(symbol);
738
778
  return self.get_type_of_symbol(symbol);
739
779
  }
740
780
  }
@@ -747,6 +787,26 @@ class TypeEvaluator {
747
787
  # Helper functions
748
788
  # -----------------------------------------------------------------------------
749
789
 
790
+ """Resolve the imported symbols to the actual symbol."""
791
+ def resolve_imported_symbols(self: TypeEvaluator, sym: uni.Symbol) -> uni.Symbol {
792
+ if (
793
+ isinstance(sym.decl, uni.Name) and sym.decl.find_parent_of_type(uni.ModuleItem)
794
+ ) {
795
+ # If the symbol is from a module item, we need to resolve it to the actual symbol.
796
+ mod_item = sym.decl.find_parent_of_type(uni.ModuleItem);
797
+ assert (mod_item is not None);
798
+ self.get_type_of_module(mod_item.from_mod_path);
799
+ return (mod_item.name.sym or sym);
800
+ }
801
+ return sym;
802
+ }
803
+
804
+ def _set_symbol_to_expr(self: TypeEvaluator, expr: uni.Expr, sym: uni.Symbol) -> TypeBase {
805
+ expr.sym = sym;
806
+ expr.type = self.get_type_of_symbol(sym);
807
+ return expr.type;
808
+ }
809
+
750
810
  """Check if the expression is Name that is 'self' and in the method context."""
751
811
  def _is_expr_self(self: TypeEvaluator, expr: uni.Expr) -> bool {
752
812
  if (
@@ -812,7 +872,6 @@ class TypeEvaluator {
812
872
 
813
873
  """Lookup the class member type."""
814
874
  def _lookup_class_member(self: TypeEvaluator, base_type: types.ClassType, member: str) -> type_utils.ClassMember | None {
815
- assert self.prefetch.int_class is not None;
816
875
  # FIXME: Pyright's way: Implement class member iterator (based on mro and the multiple inheritance)
817
876
  # return the first found member from the iterator.
818
877
 
@@ -908,6 +967,8 @@ class TypeEvaluator {
908
967
  """
909
968
  def validate_call_args(self: TypeEvaluator, expr: uni.FuncCall) -> TypeBase {
910
969
  caller_type = self.get_type_of_expression(expr.target);
970
+
971
+ # 1. Call to a function.
911
972
  if isinstance(caller_type, types.FunctionType) {
912
973
  arg_param_match = self.match_args_to_params(expr, caller_type);
913
974
  if not arg_param_match.argument_errors {
@@ -916,14 +977,34 @@ class TypeEvaluator {
916
977
  return caller_type.return_type or types.UnknownType();
917
978
  }
918
979
 
919
- if (
920
- isinstance(caller_type, types.ClassType)
921
- and caller_type.is_instantiable_class()
922
- ) {
980
+ # 2. Call to an instantiable class.
981
+ if (isinstance(caller_type, types.ClassType) and caller_type.is_instantiable_class()) {
923
982
  # TODO: validate args for __init__()
983
+
984
+ # If it has __init__ method, try to call it.
985
+ if init_method := self._lookup_class_member(caller_type, "__init__") {
986
+ init_fn_type = self.get_type_of_symbol(init_method.symbol);
987
+ if isinstance(init_fn_type, types.FunctionType) {
988
+ arg_param_match = self.match_args_to_params(expr, init_fn_type);
989
+ if not arg_param_match.argument_errors {
990
+ self.validate_arg_types(arg_param_match);
991
+ }
992
+ }
993
+ }
994
+
995
+ # If it's a data class, create the __init__ method and validate.
996
+ elif caller_type.is_data_class() {
997
+ init_fn_type = self._create_dataclass_init_method(caller_type);
998
+ arg_param_match = self.match_args_to_params(expr, init_fn_type);
999
+ if not arg_param_match.argument_errors {
1000
+ self.validate_arg_types(arg_param_match);
1001
+ }
1002
+ }
1003
+
924
1004
  return caller_type.clone_as_instance();
925
1005
  }
926
1006
 
1007
+ # 3. Call to a callable object (__call__).
927
1008
  if caller_type.is_class_instance() {
928
1009
  # TODO: validate args.
929
1010
  magic_call_ret = self.get_type_of_magic_method_call(caller_type, "__call__");
@@ -956,4 +1037,42 @@ class TypeEvaluator {
956
1037
  }
957
1038
  }
958
1039
 
1040
+ def _create_dataclass_init_method(self: TypeEvaluator, class_type: types.ClassType) -> types.FunctionType {
1041
+
1042
+ parameters: list[types.Parameter] = [];
1043
+
1044
+ # Iterate over the has vars and create parameters.
1045
+ for has_var in class_type.shared.symbol_table.get_has_vars() {
1046
+
1047
+ # Get parameter type.
1048
+ param_type: TypeBase | None = None;
1049
+ if has_var.type_tag {
1050
+ var_type_expr = has_var.type_tag.tag;
1051
+ type_cls = self.get_type_of_expression(var_type_expr);
1052
+ param_type = self._convert_to_instance(type_cls);
1053
+ }
1054
+
1055
+ # Create parameter.
1056
+ parameters.append(
1057
+ types.Parameter(
1058
+ name=has_var.name.value,
1059
+ category=types.ParameterCategory.Positional,
1060
+ param_type=param_type,
1061
+ default_value=has_var.value,
1062
+ is_self=False,
1063
+ param_kind=types.ParamKind.NORMAL,
1064
+ )
1065
+ );
1066
+ }
1067
+
1068
+ # Create and return the __init__ method type.
1069
+ return types.FunctionType(
1070
+ func_name="__init__",
1071
+ return_type=types.UnknownType(),
1072
+ parameters=parameters,
1073
+ );
1074
+
1075
+ }
1076
+
1077
+
959
1078
  }
@@ -167,7 +167,7 @@ class ParamAssignmentTracker:
167
167
  if self.curr_param_idx == -1:
168
168
  return self.varargs
169
169
 
170
- if isinstance(arg, uni.UnaryExpr) and arg.op.value == Tok.STAR_MUL:
170
+ if isinstance(arg, uni.UnaryExpr) and arg.op.name == Tok.STAR_MUL:
171
171
  self._mark_all_positional_params_as_matched()
172
172
  return None
173
173
  else:
@@ -164,6 +164,7 @@ class ClassType(TypeBase):
164
164
  symbol_table: SymbolTable,
165
165
  base_classes: list[TypeBase] | None = None,
166
166
  is_builtin_class: bool = False,
167
+ is_data_class: bool = False,
167
168
  ) -> None:
168
169
  """Initialize obviously."""
169
170
  self.class_name = class_name
@@ -182,6 +183,7 @@ class ClassType(TypeBase):
182
183
  # ...
183
184
  #
184
185
  self.is_builtin_class = is_builtin_class
186
+ self.is_data_class = is_data_class
185
187
 
186
188
  def __init__(
187
189
  self,
@@ -226,6 +228,10 @@ class ClassType(TypeBase):
226
228
  return self.shared.class_name == class_name
227
229
  return True
228
230
 
231
+ def is_data_class(self) -> bool:
232
+ """Return true if this class is a data class."""
233
+ return self.shared.is_data_class
234
+
229
235
 
230
236
  class ParamKind(IntEnum):
231
237
  """Enumeration of parameter kinds."""