typeprof 0.31.0 → 0.32.0

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -1
  3. data/doc/report_guide.md +88 -0
  4. data/lib/typeprof/cli/cli.rb +9 -3
  5. data/lib/typeprof/code_range.rb +7 -5
  6. data/lib/typeprof/core/ast/base.rb +18 -6
  7. data/lib/typeprof/core/ast/call.rb +96 -32
  8. data/lib/typeprof/core/ast/const.rb +12 -9
  9. data/lib/typeprof/core/ast/control.rb +60 -30
  10. data/lib/typeprof/core/ast/meta.rb +194 -2
  11. data/lib/typeprof/core/ast/method.rb +74 -20
  12. data/lib/typeprof/core/ast/misc.rb +84 -7
  13. data/lib/typeprof/core/ast/module.rb +33 -3
  14. data/lib/typeprof/core/ast/sig_decl.rb +85 -24
  15. data/lib/typeprof/core/ast/sig_type.rb +78 -32
  16. data/lib/typeprof/core/ast/value.rb +14 -6
  17. data/lib/typeprof/core/ast/variable.rb +11 -4
  18. data/lib/typeprof/core/ast.rb +97 -14
  19. data/lib/typeprof/core/builtin.rb +184 -12
  20. data/lib/typeprof/core/env/method.rb +171 -6
  21. data/lib/typeprof/core/env/method_entity.rb +18 -15
  22. data/lib/typeprof/core/env/module_entity.rb +56 -18
  23. data/lib/typeprof/core/env/static_read.rb +4 -4
  24. data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
  25. data/lib/typeprof/core/env/value_entity.rb +25 -3
  26. data/lib/typeprof/core/env.rb +81 -15
  27. data/lib/typeprof/core/graph/box.rb +380 -53
  28. data/lib/typeprof/core/graph/change_set.rb +59 -46
  29. data/lib/typeprof/core/graph/filter.rb +8 -5
  30. data/lib/typeprof/core/graph/vertex.rb +20 -19
  31. data/lib/typeprof/core/service.rb +317 -23
  32. data/lib/typeprof/core/type.rb +43 -8
  33. data/lib/typeprof/core/util.rb +6 -0
  34. data/lib/typeprof/lsp/messages.rb +5 -0
  35. data/lib/typeprof/lsp/server.rb +35 -4
  36. data/lib/typeprof/version.rb +1 -1
  37. metadata +3 -2
@@ -2,7 +2,10 @@ module TypeProf::Core
2
2
  class AST
3
3
  def self.typecheck_for_module(genv, changes, f_mod, f_args, a_vtx, subst)
4
4
  changes.add_edge(genv, a_vtx, changes.target)
5
+ found_any = false
5
6
  a_vtx.each_type do |ty|
7
+ next if ty.is_a?(Type::Bot)
8
+ found_any = true
6
9
  ty = ty.base_type(genv)
7
10
  while ty
8
11
  if ty.mod == f_mod && ty.is_a?(Type::Instance)
@@ -25,7 +28,7 @@ module TypeProf::Core
25
28
  ty = genv.get_superclass_type(ty, changes, {})
26
29
  end
27
30
  end
28
- return false
31
+ return !found_any
29
32
  end
30
33
 
31
34
  def self.typecheck_for_prepended_modules(genv, changes, a_ty, f_mod, f_args, subst)
@@ -33,7 +36,7 @@ module TypeProf::Core
33
36
  if prep_decl.is_a?(AST::SigPrependNode) && prep_mod.type_params
34
37
  prep_ty = genv.get_instance_type(prep_mod, prep_decl.args, changes, {}, a_ty)
35
38
  else
36
- type_params = prep_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
39
+ type_params = prep_mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
37
40
  prep_ty = Type::Instance.new(genv, prep_mod, type_params)
38
41
  end
39
42
  if prep_ty.mod == f_mod
@@ -58,7 +61,7 @@ module TypeProf::Core
58
61
  if inc_decl.is_a?(AST::SigIncludeNode) && inc_mod.type_params
59
62
  inc_ty = genv.get_instance_type(inc_mod, inc_decl.args, changes, {}, a_ty)
60
63
  else
61
- type_params = inc_mod.type_params.map {|ty_param| Source.new() } # TODO: better support
64
+ type_params = inc_mod.type_params.map {|(_name, _default_ty)| Source.new() } # TODO: better support
62
65
  inc_ty = Type::Instance.new(genv, inc_mod, type_params)
63
66
  end
64
67
  if inc_ty.mod == f_mod
@@ -108,13 +111,19 @@ module TypeProf::Core
108
111
  param = raw_decl.type.rest_positionals
109
112
  @rest_positionals = param ? AST.create_rbs_type(param.type, lenv) : nil
110
113
 
111
- @req_keywords = raw_decl.type.required_keywords.to_h do |key, ty|
114
+ @req_keyword_keys = []
115
+ @req_keyword_values = []
116
+ raw_decl.type.required_keywords.each do |key, ty|
112
117
  raise "unsupported argument type: #{ ty.class }" if !ty.is_a?(RBS::Types::Function::Param)
113
- [key, AST.create_rbs_type(ty.type, lenv)]
118
+ @req_keyword_keys << key
119
+ @req_keyword_values << AST.create_rbs_type(ty.type, lenv)
114
120
  end
115
- @opt_keywords = raw_decl.type.optional_keywords.to_h do |key, ty|
121
+ @opt_keyword_keys = []
122
+ @opt_keyword_values = []
123
+ raw_decl.type.optional_keywords.each do |key, ty|
116
124
  raise "unsupported argument type: #{ ty.class }" if !ty.is_a?(RBS::Types::Function::Param)
117
- [key, AST.create_rbs_type(ty.type, lenv)]
125
+ @opt_keyword_keys << key
126
+ @opt_keyword_values << AST.create_rbs_type(ty.type, lenv)
118
127
  end
119
128
  param = raw_decl.type.rest_keywords
120
129
  @rest_keywords = param ? AST.create_rbs_type(param.type, lenv) : nil
@@ -124,8 +133,10 @@ module TypeProf::Core
124
133
  @post_positionals = []
125
134
  @opt_positionals = []
126
135
  @rest_positionals = SigTyBaseAnyNode.new(raw_decl, lenv)
127
- @req_keywords = {}
128
- @opt_keywords = {}
136
+ @req_keyword_keys = []
137
+ @req_keyword_values = []
138
+ @opt_keyword_keys = []
139
+ @opt_keyword_values = []
129
140
  @rest_keywords = nil
130
141
  end
131
142
 
@@ -137,8 +148,10 @@ module TypeProf::Core
137
148
  attr_reader :post_positionals
138
149
  attr_reader :opt_positionals
139
150
  attr_reader :rest_positionals
140
- attr_reader :req_keywords
141
- attr_reader :opt_keywords
151
+ attr_reader :req_keyword_keys
152
+ attr_reader :req_keyword_values
153
+ attr_reader :opt_keyword_keys
154
+ attr_reader :opt_keyword_values
142
155
  attr_reader :rest_keywords
143
156
  attr_reader :return_type
144
157
 
@@ -148,12 +161,17 @@ module TypeProf::Core
148
161
  post_positionals:,
149
162
  opt_positionals:,
150
163
  rest_positionals:,
151
- req_keywords:,
152
- opt_keywords:,
164
+ req_keyword_values:,
165
+ opt_keyword_values:,
153
166
  rest_keywords:,
154
167
  return_type:,
155
168
  }
156
- def attrs = { type_params:, block_required: }
169
+ def attrs = {
170
+ type_params:,
171
+ req_keyword_keys:,
172
+ opt_keyword_keys:,
173
+ block_required:,
174
+ }
157
175
  end
158
176
 
159
177
  class SigTyNode < Node
@@ -182,6 +200,7 @@ module TypeProf::Core
182
200
  def typecheck(genv, changes, vtx, subst)
183
201
  changes.add_edge(genv, vtx, changes.target)
184
202
  vtx.each_type do |ty|
203
+ next if ty.is_a?(Type::Bot)
185
204
  return false unless ty == genv.true_type || ty == genv.false_type
186
205
  end
187
206
  true
@@ -204,6 +223,7 @@ module TypeProf::Core
204
223
  def typecheck(genv, changes, vtx, subst)
205
224
  changes.add_edge(genv, vtx, changes.target)
206
225
  vtx.each_type do |ty|
226
+ next if ty.is_a?(Type::Bot)
207
227
  return false unless ty == genv.nil_type
208
228
  end
209
229
  true
@@ -287,11 +307,11 @@ module TypeProf::Core
287
307
 
288
308
  class SigTyBaseBottomNode < SigTyNode
289
309
  def covariant_vertex0(genv, changes, vtx, subst)
290
- changes.add_edge(genv, Source.new(Type::Bot.new(genv)), vtx)
310
+ changes.add_edge(genv, Source.new(genv.bot_type), vtx)
291
311
  end
292
312
 
293
313
  def contravariant_vertex0(genv, changes, vtx, subst)
294
- changes.add_edge(genv, Source.new(Type::Bot.new(genv)), vtx)
314
+ changes.add_edge(genv, Source.new(genv.bot_type), vtx)
295
315
  end
296
316
 
297
317
  def typecheck(genv, changes, vtx, subst)
@@ -530,6 +550,8 @@ module TypeProf::Core
530
550
  name = raw_decl.name
531
551
  @cpath = name.namespace.path + [name.name]
532
552
  @toplevel = name.namespace.absolute?
553
+ # RBS::Types::ClassSingleton#args was added in RBS 4.0
554
+ @args = raw_decl.respond_to?(:args) ? raw_decl.args.map {|arg| AST.create_rbs_type(arg, lenv) } : []
533
555
  end
534
556
 
535
557
  attr_reader :cpath, :toplevel
@@ -578,7 +600,10 @@ module TypeProf::Core
578
600
  return unless cpath
579
601
  f_mod = genv.resolve_cpath(cpath)
580
602
  changes.add_edge(genv, vtx, changes.target)
603
+ found_any = false
581
604
  vtx.each_type do |ty|
605
+ next if ty.is_a?(Type::Bot)
606
+ found_any = true
582
607
  case ty
583
608
  when Type::Singleton
584
609
  if f_mod.module?
@@ -593,7 +618,7 @@ module TypeProf::Core
593
618
  end
594
619
  end
595
620
  end
596
- false
621
+ !found_any
597
622
  end
598
623
 
599
624
  def show
@@ -714,7 +739,10 @@ module TypeProf::Core
714
739
 
715
740
  def typecheck(genv, changes, vtx, subst)
716
741
  changes.add_edge(genv, vtx, changes.target)
742
+ found_any = false
717
743
  vtx.each_type do |ty|
744
+ next if ty.is_a?(Type::Bot)
745
+ found_any = true
718
746
  case ty
719
747
  when Type::Array
720
748
  next if ty.elems.size != @types.size
@@ -729,7 +757,7 @@ module TypeProf::Core
729
757
  return true
730
758
  end
731
759
  end
732
- false
760
+ !found_any
733
761
  end
734
762
 
735
763
  def show
@@ -740,16 +768,18 @@ module TypeProf::Core
740
768
  class SigTyRecordNode < SigTyNode
741
769
  def initialize(raw_decl, lenv)
742
770
  super(raw_decl, lenv)
743
- @fields = raw_decl.fields.transform_values { |val| AST.create_rbs_type(val, lenv) }
771
+ @keys = raw_decl.fields.keys
772
+ @vals = raw_decl.fields.values.map { |val| AST.create_rbs_type(val, lenv) }
744
773
  end
745
774
 
746
- attr_reader :fields
747
- def subnodes = { fields: }
775
+ attr_reader :keys, :vals
776
+ def subnodes = { vals: }
777
+ def attrs = { keys: }
748
778
 
749
779
  def covariant_vertex0(genv, changes, vtx, subst)
750
780
  field_vertices = {}
751
- @fields.each do |key, field_node|
752
- field_vertices[key] = field_node.covariant_vertex(genv, changes, subst)
781
+ @keys.zip(@vals) do |key, val_node|
782
+ field_vertices[key] = val_node.covariant_vertex(genv, changes, subst)
753
783
  end
754
784
 
755
785
  # Create base Hash type for Record
@@ -766,8 +796,8 @@ module TypeProf::Core
766
796
 
767
797
  def contravariant_vertex0(genv, changes, vtx, subst)
768
798
  field_vertices = {}
769
- @fields.each do |key, field_node|
770
- field_vertices[key] = field_node.contravariant_vertex(genv, changes, subst)
799
+ @keys.zip(@vals) do |key, val_node|
800
+ field_vertices[key] = val_node.contravariant_vertex(genv, changes, subst)
771
801
  end
772
802
 
773
803
  # Create base Hash type for Record
@@ -784,22 +814,25 @@ module TypeProf::Core
784
814
 
785
815
  def typecheck(genv, changes, vtx, subst)
786
816
  changes.add_edge(genv, vtx, changes.target)
817
+ found_any = false
787
818
  vtx.each_type do |ty|
819
+ next if ty.is_a?(Type::Bot)
820
+ found_any = true
788
821
  case ty
789
822
  when Type::Hash
790
- @fields.each do |key, field_node|
823
+ @keys.zip(@vals) do |key, val_node|
791
824
  val_vtx = ty.get_value(key)
792
- return false unless field_node.typecheck(genv, changes, val_vtx, subst)
825
+ return false unless val_node.typecheck(genv, changes, val_vtx, subst)
793
826
  end
794
827
  return true
795
828
  end
796
829
  end
797
- false
830
+ !found_any
798
831
  end
799
832
 
800
833
  def show
801
- field_strs = @fields.map do |key, field_node|
802
- "#{ key }: #{ field_node.show }"
834
+ field_strs = @keys.zip(@vals).map do |key, val_node|
835
+ "#{ key }: #{ val_node.show }"
803
836
  end
804
837
  "{ #{ field_strs.join(", ") } }"
805
838
  end
@@ -826,7 +859,7 @@ module TypeProf::Core
826
859
  end
827
860
 
828
861
  def typecheck(genv, changes, vtx, subst)
829
- changes.add_edge(genv, vtx, subst[@var]) unless vtx == subst[@var]
862
+ changes.add_edge(genv, vtx.new_vertex(genv, self), subst[@var]) unless vtx == subst[@var]
830
863
  true
831
864
  end
832
865
 
@@ -855,6 +888,16 @@ module TypeProf::Core
855
888
  end
856
889
 
857
890
  def typecheck(genv, changes, vtx, subst)
891
+ # For optional type T?, check if all non-nil types match T.
892
+ # nil is always acceptable.
893
+ changes.add_edge(genv, vtx, changes.target)
894
+ has_non_nil = false
895
+ vtx.each_type do |ty|
896
+ next if ty.is_a?(Type::Bot)
897
+ next if ty == genv.nil_type
898
+ has_non_nil = true
899
+ end
900
+ return true unless has_non_nil
858
901
  @type.typecheck(genv, changes, vtx, subst)
859
902
  end
860
903
 
@@ -900,13 +943,16 @@ module TypeProf::Core
900
943
  def typecheck(genv, changes, vtx, subst)
901
944
  if @lit.is_a?(::Symbol)
902
945
  changes.add_edge(genv, vtx, changes.target)
946
+ found_any = false
903
947
  vtx.each_type do |ty|
948
+ next if ty.is_a?(Type::Bot)
949
+ found_any = true
904
950
  case ty
905
951
  when Type::Symbol
906
952
  return true if ty.sym == @lit
907
953
  end
908
954
  end
909
- return false
955
+ return !found_any
910
956
  end
911
957
  f_mod = get_type(genv).mod
912
958
  AST.typecheck_for_module(genv, changes, f_mod, [], vtx, subst)
@@ -5,7 +5,7 @@ module TypeProf::Core
5
5
  when :string_node
6
6
  AST.create_node(raw_part, lenv)
7
7
  when :embedded_statements_node
8
- raw_part.statements ? AST.create_node(raw_part.statements, lenv) : DummyNilNode.new(TypeProf::CodeRange.from_node(raw_part), lenv)
8
+ raw_part.statements ? AST.create_node(raw_part.statements, lenv) : DummyNilNode.new(lenv.code_range_from_node(raw_part), lenv)
9
9
  when :embedded_variable_node
10
10
  AST.create_node(raw_part.variable, lenv)
11
11
  else
@@ -275,7 +275,7 @@ module TypeProf::Core
275
275
  if raw_elem.value
276
276
  @vals << AST.create_node(raw_elem.value, lenv)
277
277
  else
278
- @vals << DummyNilNode.new(code_range, lenv)
278
+ @vals << nil
279
279
  end
280
280
  @splat = true
281
281
  else
@@ -293,15 +293,20 @@ module TypeProf::Core
293
293
  unified_key = Vertex.new(self)
294
294
  unified_val = Vertex.new(self)
295
295
  literal_pairs = {}
296
+ all_symbol_keys = true
296
297
  @keys.zip(@vals) do |key, val|
297
298
  if key
298
299
  k = key.install(genv).new_vertex(genv, self)
299
300
  v = val.install(genv).new_vertex(genv, self)
300
301
  @changes.add_edge(genv, k, unified_key)
301
302
  @changes.add_edge(genv, v, unified_val)
302
- literal_pairs[key.lit] = v if key.is_a?(SymbolNode)
303
+ if key.is_a?(SymbolNode)
304
+ literal_pairs[key.lit] = v
305
+ else
306
+ all_symbol_keys = false
307
+ end
303
308
  else
304
- if val.is_a?(DummyNilNode)
309
+ if val.nil?
305
310
  h = @lenv.get_var(:"**anonymous_keyword")
306
311
  else
307
312
  h = val.install(genv)
@@ -310,10 +315,13 @@ module TypeProf::Core
310
315
  @changes.add_hash_splat_box(genv, h, unified_key, unified_val)
311
316
  end
312
317
  end
318
+ base_hash_type = genv.gen_hash_type(unified_key, unified_val)
313
319
  if @splat
314
- Source.new(genv.gen_hash_type(unified_key, unified_val))
320
+ Source.new(base_hash_type)
321
+ elsif all_symbol_keys
322
+ Source.new(Type::Record.new(genv, literal_pairs, base_hash_type))
315
323
  else
316
- Source.new(Type::Hash.new(genv, literal_pairs, genv.gen_hash_type(unified_key, unified_val)))
324
+ Source.new(Type::Hash.new(genv, literal_pairs, base_hash_type))
317
325
  end
318
326
  end
319
327
  end
@@ -46,7 +46,7 @@ module TypeProf::Core
46
46
  def initialize(raw_node, rhs, lenv)
47
47
  super(raw_node, lenv)
48
48
  @var = raw_node.name
49
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
49
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
50
50
  @rhs = rhs
51
51
  end
52
52
 
@@ -68,6 +68,13 @@ module TypeProf::Core
68
68
  super(pos, &blk)
69
69
  end
70
70
 
71
+ def narrowings
72
+ @narrowings ||= [
73
+ Narrowing.new({ @var => Narrowing::NilConstraint.new(false) }),
74
+ Narrowing.new({ @var => Narrowing::NilConstraint.new(true) }),
75
+ ]
76
+ end
77
+
71
78
  def modified_vars(tbl, vars)
72
79
  vars << self.var if tbl.include?(self.var)
73
80
  end
@@ -109,7 +116,7 @@ module TypeProf::Core
109
116
  def initialize(raw_node, rhs, lenv)
110
117
  super(raw_node, lenv)
111
118
  @var = raw_node.name
112
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
119
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
113
120
  @rhs = rhs
114
121
  end
115
122
 
@@ -191,7 +198,7 @@ module TypeProf::Core
191
198
  def initialize(raw_node, rhs, lenv)
192
199
  super(raw_node, lenv)
193
200
  @var = raw_node.name
194
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
201
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
195
202
  @rhs = rhs
196
203
  end
197
204
 
@@ -264,7 +271,7 @@ module TypeProf::Core
264
271
  def initialize(raw_node, rhs, lenv)
265
272
  super(raw_node, lenv)
266
273
  @var = raw_node.name
267
- @var_code_range = TypeProf::CodeRange.from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
274
+ @var_code_range = lenv.code_range_from_node(raw_node.respond_to?(:name_loc) ? raw_node.name_loc : raw_node)
268
275
  @rhs = rhs
269
276
  end
270
277
 
@@ -1,6 +1,6 @@
1
1
  module TypeProf::Core
2
2
  class AST
3
- def self.parse_rb(path, src)
3
+ def self.parse_rb(path, src, position_encoding)
4
4
  result = Prism.parse(src)
5
5
 
6
6
  return nil unless result.errors.empty?
@@ -10,19 +10,58 @@ module TypeProf::Core
10
10
 
11
11
  raise unless raw_scope.type == :program_node
12
12
 
13
- Fiber[:comments] = result.comments
13
+ prism_source = result.source
14
+ file_context = FileContext.new(path, position_encoding, prism_source, result.comments)
14
15
 
15
16
  cref = CRef::Toplevel
16
- lenv = LocalEnv.new(path, cref, {}, [])
17
+ lenv = LocalEnv.new(file_context, cref, {}, [])
17
18
 
18
- ProgramNode.new(raw_scope, lenv)
19
+ ignore_ranges = collect_ignore_ranges(result)
20
+ ProgramNode.new(raw_scope, lenv, ignore_ranges: ignore_ranges)
19
21
  end
20
22
 
21
- #: (untyped, TypeProf::Core::LocalEnv, ?bool) -> TypeProf::Core::AST::Node
22
- def self.create_node(raw_node, lenv, use_result = true)
23
+ # Collect line ranges marked with `# typeprof:ignore` comments.
24
+ # Each range is suppressed in ProgramNode#each_diagnostic.
25
+ #
26
+ # Inline form (suppresses the line containing the comment):
27
+ # foo(1, 2) # typeprof:ignore
28
+ #
29
+ # Block form (suppresses lines between :start and :end):
30
+ # # typeprof:ignore:start
31
+ # foo(1, 2)
32
+ # # typeprof:ignore:end
33
+ #
34
+ # An unmatched `:start` extends to the end of the file.
35
+ IGNORE_RE = /\A#\s*typeprof:ignore\s*\z/
36
+ IGNORE_START_RE = /\A#\s*typeprof:ignore:start\s*\z/
37
+ IGNORE_END_RE = /\A#\s*typeprof:ignore:end\s*\z/
38
+ def self.collect_ignore_ranges(prism_result)
39
+ ranges = []
40
+ start_line = nil
41
+ prism_result.comments.each do |c|
42
+ text = c.location.slice
43
+ line = c.location.start_line
44
+ if text.match?(IGNORE_START_RE)
45
+ start_line ||= line
46
+ elsif text.match?(IGNORE_END_RE)
47
+ if start_line
48
+ ranges << (start_line..line)
49
+ start_line = nil
50
+ end
51
+ elsif text.match?(IGNORE_RE)
52
+ ranges << (line..line)
53
+ end
54
+ end
55
+ ranges << (start_line..Float::INFINITY) if start_line
56
+ ranges
57
+ end
58
+
59
+ #: (untyped, TypeProf::Core::LocalEnv, ?bool, ?bool) -> TypeProf::Core::AST::Node
60
+ def self.create_node(raw_node, lenv, use_result = true, allow_meta = false)
23
61
  while true
24
62
  case raw_node.type
25
63
  when :parentheses_node
64
+ return DummyNilNode.new(lenv.code_range_from_node(raw_node), lenv) if raw_node.body.nil?
26
65
  raw_node = raw_node.body
27
66
  when :implicit_node
28
67
  raw_node = raw_node.value
@@ -64,7 +103,13 @@ module TypeProf::Core
64
103
  when :constant_read_node, :constant_path_node
65
104
  ConstantReadNode.new(raw_node, lenv)
66
105
  when :constant_write_node, :constant_path_write_node
67
- ConstantWriteNode.new(raw_node, AST.create_node(raw_node.value, lenv), lenv)
106
+ if (members = detect_struct_new(raw_node.value))
107
+ StructNewNode.new(raw_node, members, :struct, lenv)
108
+ elsif (members = detect_data_define(raw_node.value))
109
+ StructNewNode.new(raw_node, members, :data, lenv)
110
+ else
111
+ ConstantWriteNode.new(raw_node, AST.create_node(raw_node.value, lenv), lenv)
112
+ end
68
113
  when :constant_operator_write_node
69
114
  read = ConstantReadNode.new(raw_node, lenv)
70
115
  rhs = OperatorNode.new(raw_node, read, lenv)
@@ -132,6 +177,7 @@ module TypeProf::Core
132
177
  when :class_variable_operator_write_node
133
178
  read = ClassVariableReadNode.new(raw_node, lenv)
134
179
  rhs = OperatorNode.new(raw_node, read, lenv)
180
+ ClassVariableWriteNode.new(raw_node, rhs, lenv)
135
181
  when :class_variable_or_write_node
136
182
  read = ClassVariableReadNode.new(raw_node, lenv)
137
183
  rhs = OrNode.new(raw_node, read, raw_node.value, lenv)
@@ -233,15 +279,20 @@ module TypeProf::Core
233
279
  when :forwarding_super_node then ForwardingSuperNode.new(raw_node, lenv)
234
280
  when :yield_node then YieldNode.new(raw_node, lenv)
235
281
  when :call_node
236
- if !raw_node.receiver
237
- # TODO: handle them only when it is directly under class or module
282
+ if allow_meta && !raw_node.receiver && !lenv.cref.mid && [:class, :metaclass].include?(lenv.cref.scope_level)
238
283
  case raw_node.name
239
284
  when :include
240
285
  return IncludeMetaNode.new(raw_node, lenv)
241
286
  when :attr_reader
242
287
  return AttrReaderMetaNode.new(raw_node, lenv)
288
+ when :attr_writer
289
+ return AttrWriterMetaNode.new(raw_node, lenv)
243
290
  when :attr_accessor
244
291
  return AttrAccessorMetaNode.new(raw_node, lenv)
292
+ when :module_function
293
+ if raw_node.arguments.nil?
294
+ return ModuleFunctionMetaNode.new(raw_node, lenv)
295
+ end
245
296
  end
246
297
  end
247
298
  CallNode.new(raw_node, lenv)
@@ -252,7 +303,7 @@ module TypeProf::Core
252
303
  end
253
304
 
254
305
  def self.create_target_node(raw_node, lenv)
255
- dummy_node = DummyRHSNode.new(TypeProf::CodeRange.from_node(raw_node.location), lenv)
306
+ dummy_node = DummyRHSNode.new(lenv.code_range_from_node(raw_node.location), lenv)
256
307
  case raw_node.type
257
308
  when :local_variable_target_node
258
309
  LocalVariableWriteNode.new(raw_node, dummy_node, lenv)
@@ -270,6 +321,8 @@ module TypeProf::Core
270
321
  IndexWriteNode.new(raw_node, dummy_node, lenv)
271
322
  when :call_target_node
272
323
  CallWriteNode.new(raw_node, dummy_node, lenv)
324
+ when :multi_target_node
325
+ MultiTargetNode.new(raw_node, dummy_node, lenv)
273
326
  else
274
327
  pp raw_node
275
328
  raise "not supported yet: #{ raw_node.type }"
@@ -303,7 +356,7 @@ module TypeProf::Core
303
356
  when :pinned_expression_node then PinnedPatternNode.new(raw_node, lenv)
304
357
 
305
358
  when :local_variable_target_node
306
- dummy_node = DummyRHSNode.new(TypeProf::CodeRange.from_node(raw_node.location), lenv)
359
+ dummy_node = DummyRHSNode.new(lenv.code_range_from_node(raw_node.location), lenv)
307
360
  LocalVariableWriteNode.new(raw_node, dummy_node, lenv)
308
361
 
309
362
  when :constant_read_node, :constant_path_node
@@ -362,11 +415,12 @@ module TypeProf::Core
362
415
  return cpath + names.reverse if cpath
363
416
  end
364
417
 
365
- def self.parse_rbs(path, src)
418
+ def self.parse_rbs(path, src, position_encoding)
366
419
  _buffer, _directives, raw_decls = RBS::Parser.parse_signature(src)
367
420
 
368
421
  cref = CRef::Toplevel
369
- lenv = LocalEnv.new(path, cref, {}, [])
422
+ file_context = FileContext.new(path, position_encoding)
423
+ lenv = LocalEnv.new(file_context, cref, {}, [])
370
424
 
371
425
  raw_decls.map do |raw_decl|
372
426
  AST.create_rbs_decl(raw_decl, lenv)
@@ -383,7 +437,10 @@ module TypeProf::Core
383
437
  SigInterfaceNode.new(raw_decl, lenv)
384
438
  when RBS::AST::Declarations::Constant
385
439
  SigConstNode.new(raw_decl, lenv)
386
- when RBS::AST::Declarations::AliasDecl
440
+ when RBS::AST::Declarations::ClassAlias
441
+ SigClassAliasNode.new(raw_decl, lenv)
442
+ when RBS::AST::Declarations::ModuleAlias
443
+ SigModuleAliasNode.new(raw_decl, lenv)
387
444
  when RBS::AST::Declarations::TypeAlias
388
445
  SigTypeAliasNode.new(raw_decl, lenv)
389
446
  # TODO: check
@@ -479,5 +536,31 @@ module TypeProf::Core
479
536
  raise "unknown RBS type: #{ raw_decl.class }"
480
537
  end
481
538
  end
539
+
540
+ def self.detect_struct_new(raw_value)
541
+ return nil unless raw_value.type == :call_node
542
+ return nil unless raw_value.name == :new
543
+ recv = raw_value.receiver
544
+ return nil unless recv&.type == :constant_read_node && recv.name == :Struct
545
+ extract_symbol_args(raw_value)
546
+ end
547
+
548
+ def self.detect_data_define(raw_value)
549
+ return nil unless raw_value.type == :call_node
550
+ return nil unless raw_value.name == :define
551
+ recv = raw_value.receiver
552
+ return nil unless recv&.type == :constant_read_node && recv.name == :Data
553
+ extract_symbol_args(raw_value)
554
+ end
555
+
556
+ def self.extract_symbol_args(raw_call)
557
+ return nil unless raw_call.arguments
558
+ members = []
559
+ raw_call.arguments.arguments.each do |arg|
560
+ return nil unless arg.type == :symbol_node
561
+ members << arg.value.to_sym
562
+ end
563
+ members
564
+ end
482
565
  end
483
566
  end