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.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/doc/report_guide.md +88 -0
- data/lib/typeprof/cli/cli.rb +9 -3
- data/lib/typeprof/code_range.rb +7 -5
- data/lib/typeprof/core/ast/base.rb +18 -6
- data/lib/typeprof/core/ast/call.rb +96 -32
- data/lib/typeprof/core/ast/const.rb +12 -9
- data/lib/typeprof/core/ast/control.rb +60 -30
- data/lib/typeprof/core/ast/meta.rb +194 -2
- data/lib/typeprof/core/ast/method.rb +74 -20
- data/lib/typeprof/core/ast/misc.rb +84 -7
- data/lib/typeprof/core/ast/module.rb +33 -3
- data/lib/typeprof/core/ast/sig_decl.rb +85 -24
- data/lib/typeprof/core/ast/sig_type.rb +78 -32
- data/lib/typeprof/core/ast/value.rb +14 -6
- data/lib/typeprof/core/ast/variable.rb +11 -4
- data/lib/typeprof/core/ast.rb +97 -14
- data/lib/typeprof/core/builtin.rb +184 -12
- data/lib/typeprof/core/env/method.rb +171 -6
- data/lib/typeprof/core/env/method_entity.rb +18 -15
- data/lib/typeprof/core/env/module_entity.rb +56 -18
- data/lib/typeprof/core/env/static_read.rb +4 -4
- data/lib/typeprof/core/env/type_alias_entity.rb +1 -1
- data/lib/typeprof/core/env/value_entity.rb +25 -3
- data/lib/typeprof/core/env.rb +81 -15
- data/lib/typeprof/core/graph/box.rb +380 -53
- data/lib/typeprof/core/graph/change_set.rb +59 -46
- data/lib/typeprof/core/graph/filter.rb +8 -5
- data/lib/typeprof/core/graph/vertex.rb +20 -19
- data/lib/typeprof/core/service.rb +317 -23
- data/lib/typeprof/core/type.rb +43 -8
- data/lib/typeprof/core/util.rb +6 -0
- data/lib/typeprof/lsp/messages.rb +5 -0
- data/lib/typeprof/lsp/server.rb +35 -4
- data/lib/typeprof/version.rb +1 -1
- 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
|
|
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 {|
|
|
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 {|
|
|
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
|
-
@
|
|
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
|
-
|
|
118
|
+
@req_keyword_keys << key
|
|
119
|
+
@req_keyword_values << AST.create_rbs_type(ty.type, lenv)
|
|
114
120
|
end
|
|
115
|
-
@
|
|
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
|
-
|
|
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
|
-
@
|
|
128
|
-
@
|
|
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 :
|
|
141
|
-
attr_reader :
|
|
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
|
-
|
|
152
|
-
|
|
164
|
+
req_keyword_values:,
|
|
165
|
+
opt_keyword_values:,
|
|
153
166
|
rest_keywords:,
|
|
154
167
|
return_type:,
|
|
155
168
|
}
|
|
156
|
-
def attrs = {
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
@
|
|
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 :
|
|
747
|
-
def subnodes = {
|
|
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
|
-
@
|
|
752
|
-
field_vertices[key] =
|
|
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
|
-
@
|
|
770
|
-
field_vertices[key] =
|
|
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
|
-
@
|
|
823
|
+
@keys.zip(@vals) do |key, val_node|
|
|
791
824
|
val_vtx = ty.get_value(key)
|
|
792
|
-
return false unless
|
|
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
|
-
|
|
830
|
+
!found_any
|
|
798
831
|
end
|
|
799
832
|
|
|
800
833
|
def show
|
|
801
|
-
field_strs = @
|
|
802
|
-
"#{ key }: #{
|
|
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
|
|
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(
|
|
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 <<
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
data/lib/typeprof/core/ast.rb
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
17
|
+
lenv = LocalEnv.new(file_context, cref, {}, [])
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
ignore_ranges = collect_ignore_ranges(result)
|
|
20
|
+
ProgramNode.new(raw_scope, lenv, ignore_ranges: ignore_ranges)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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::
|
|
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
|