typeprof 0.30.1 → 0.31.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/lib/typeprof/cli/cli.rb +27 -7
  4. data/lib/typeprof/code_range.rb +9 -7
  5. data/lib/typeprof/core/ast/base.rb +27 -10
  6. data/lib/typeprof/core/ast/call.rb +85 -24
  7. data/lib/typeprof/core/ast/const.rb +7 -12
  8. data/lib/typeprof/core/ast/control.rb +345 -71
  9. data/lib/typeprof/core/ast/meta.rb +5 -5
  10. data/lib/typeprof/core/ast/method.rb +15 -5
  11. data/lib/typeprof/core/ast/misc.rb +21 -2
  12. data/lib/typeprof/core/ast/module.rb +10 -7
  13. data/lib/typeprof/core/ast/pattern.rb +9 -1
  14. data/lib/typeprof/core/ast/sig_decl.rb +163 -42
  15. data/lib/typeprof/core/ast/sig_type.rb +394 -24
  16. data/lib/typeprof/core/ast/value.rb +10 -2
  17. data/lib/typeprof/core/ast/variable.rb +32 -2
  18. data/lib/typeprof/core/ast.rb +15 -4
  19. data/lib/typeprof/core/builtin.rb +15 -9
  20. data/lib/typeprof/core/env/method.rb +21 -16
  21. data/lib/typeprof/core/env/method_entity.rb +11 -2
  22. data/lib/typeprof/core/env/module_entity.rb +57 -0
  23. data/lib/typeprof/core/env/narrowing.rb +131 -0
  24. data/lib/typeprof/core/env/static_read.rb +9 -8
  25. data/lib/typeprof/core/env.rb +37 -12
  26. data/lib/typeprof/core/graph/box.rb +207 -97
  27. data/lib/typeprof/core/graph/change_set.rb +44 -37
  28. data/lib/typeprof/core/graph/vertex.rb +4 -21
  29. data/lib/typeprof/core/service.rb +30 -1
  30. data/lib/typeprof/core/type.rb +48 -123
  31. data/lib/typeprof/core.rb +1 -0
  32. data/lib/typeprof/diagnostic.rb +5 -6
  33. data/lib/typeprof/lsp/messages.rb +21 -15
  34. data/lib/typeprof/lsp/server.rb +132 -39
  35. data/lib/typeprof/lsp/text.rb +1 -0
  36. data/lib/typeprof/version.rb +1 -1
  37. data/typeprof.conf.jsonc +22 -0
  38. data/typeprof.gemspec +1 -0
  39. metadata +19 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f42086b6df655b0df5ea0e11633500c15735fc81713833c477536138de6cd70
4
- data.tar.gz: 8e2c1bbd37db3e87fea65136cdbb78c31853ed0db434aeee76e9066cb15c125a
3
+ metadata.gz: af1ca7b849fb94f4a39e31b3e1b2c45b557936f68099002d69a25d09e2c76b51
4
+ data.tar.gz: cf3d5e1e88614b53a354f874ed0560e6b6bd965468e3be5f024594cf633e4b8d
5
5
  SHA512:
6
- metadata.gz: 89feb1071cf88fb006b7c04312d2ef576e940023e096b0fed10178b1b89f70301cf50f8d53343983e33760f258d96e2c9244de44bec55e1437bf0857951d4b91
7
- data.tar.gz: 4f63149902b7b926df8159a1d2dc18a7472d15e07df9a441483b1e401a313c9b0ddf201ffdaa8eaccda4115bf3ae88d1ec282e8c66a11230b342275842809ba4
6
+ metadata.gz: 84eec1b1d33b57ba5022bacab1f194a5942789282c3e19fcb32f2b4d3168f4ff826b5d176982a5ba36b7bbe3bba9f0fef5a0cb927811cba89b759ef337ab72f6
7
+ data.tar.gz: b196e236660ab1814456fd9586e122e135e7773e27c3f49151e6c7a18a015b8ac0562a08c1b740a1d8bcfcd0005c27aefa2dabbaf98085230fcff73933f8028b
data/README.md CHANGED
@@ -2,12 +2,31 @@
2
2
 
3
3
  An experimental type-level Ruby interpreter for testing and understanding Ruby code.
4
4
 
5
+ ## Installation
6
+
7
+ Install via RubyGems.
8
+
9
+ ```sh
10
+ $ gem install typeprof
11
+ ```
12
+
13
+ ### Requirements
14
+
15
+ TypeProf supports Ruby 3.3 or later.
16
+
17
+ ## Quick start
18
+
19
+ 1. Install VSCode [Ruby TypeProf](https://marketplace.visualstudio.com/items?itemName=mame.ruby-typeprof) extension: `code --install-extension mame.ruby-typeprof`
20
+ 2. Run `typeprof --init` in your project root to create `typeprof.conf.jsonc` file.
21
+ Other options are available. See [typeprof.conf.jsonc](typeprof.conf.jsonc) for details.
22
+
23
+ 3. Reopen your project in VSCode.
24
+
5
25
  ## Development
6
26
 
7
- 1. Install Ruby 3.3 or later.
8
- 2. Git clone this repository: `git clone https://github.com/ruby/typeprof.git`
9
- 3. Install VSCode extension: `code --install-extension mame.ruby-typeprof`
10
- 4. Open the repository in VSCode: `code typeprof`
27
+ 1. Git clone this repository: `git clone https://github.com/ruby/typeprof.git`
28
+ 2. Install VSCode [Ruby TypeProf](https://marketplace.visualstudio.com/items?itemName=mame.ruby-typeprof) extension: `code --install-extension mame.ruby-typeprof`
29
+ 3. Open the repository in VSCode: `code typeprof`
11
30
 
12
31
  ### Testing
13
32
 
@@ -11,6 +11,7 @@ module TypeProf::CLI
11
11
 
12
12
  output = nil
13
13
  rbs_collection_path = nil
14
+ initialize_config_file = false
14
15
 
15
16
  opt.separator ""
16
17
  opt.separator "Options:"
@@ -39,6 +40,7 @@ module TypeProf::CLI
39
40
  opt.separator ""
40
41
  opt.separator "Advanced options:"
41
42
  opt.on("--[no-]stackprof MODE", /\Acpu|wall|object\z/, "Enable stackprof (for debugging purpose)") {|v| cli_options[:stackprof] = v.to_sym }
43
+ opt.on("--init", 'Generate TypeProf configuration file') {|v| initialize_config_file = true}
42
44
 
43
45
  opt.separator ""
44
46
  opt.separator "LSP options:"
@@ -47,6 +49,11 @@ module TypeProf::CLI
47
49
 
48
50
  opt.parse!(argv)
49
51
 
52
+ if initialize_config_file
53
+ generate_config_file
54
+ exit 0
55
+ end
56
+
50
57
  if !cli_options[:lsp] && !lsp_options.empty?
51
58
  raise OptionParser::InvalidOption.new("lsp options with non-lsp mode")
52
59
  end
@@ -101,27 +108,28 @@ module TypeProf::CLI
101
108
  attr_reader :core_options, :lsp_options, :cli_options
102
109
 
103
110
  def run
104
- core = TypeProf::Core::Service.new(@core_options)
105
111
 
106
112
  if @cli_options[:lsp]
107
- run_lsp(core)
113
+ run_lsp
108
114
  else
109
- run_cli(core)
115
+ run_cli
110
116
  end
111
117
  end
112
118
 
113
- def run_lsp(core)
119
+ def run_lsp
114
120
  if @lsp_options[:stdio]
115
- TypeProf::LSP::Server.start_stdio(core)
121
+ TypeProf::LSP::Server.start_stdio(@core_options)
116
122
  else
117
- TypeProf::LSP::Server.start_socket(core)
123
+ TypeProf::LSP::Server.start_socket(@core_options)
118
124
  end
119
125
  rescue Exception
120
126
  puts $!.detailed_message(highlight: false).gsub(/^/, "---")
121
127
  raise
122
128
  end
123
129
 
124
- def run_cli(core)
130
+ def run_cli
131
+ core = TypeProf::Core::Service.new(@core_options)
132
+
125
133
  puts "typeprof #{ TypeProf::VERSION }" if @cli_options[:display_version]
126
134
 
127
135
  files = find_files
@@ -174,5 +182,17 @@ module TypeProf::CLI
174
182
  StackProf.results
175
183
  end
176
184
  end
185
+
186
+ def generate_config_file
187
+ exist_dirs = ["app", "lib"].select { |dir| File.exist?(File.join(Dir.pwd, dir)) }
188
+ File.write('typeprof.conf.jsonc', <<~JSONC, mode: "wx")
189
+ {
190
+ "typeprof_version": "experimental",
191
+ "rbs_dir": "sig/",
192
+ "analysis_unit_dirs": #{exist_dirs.inspect}
193
+ // "diagnostic_severity": "warning"
194
+ }
195
+ JSONC
196
+ end
177
197
  end
178
198
  end
@@ -56,16 +56,13 @@ module TypeProf
56
56
  end
57
57
 
58
58
  def self.from_node(node, encoding = Encoding::UTF_16LE)
59
- node = node.location if node.is_a?(Prism::Node)
59
+ node = node.location if node.respond_to?(:location)
60
60
  if node.is_a?(Prism::Location)
61
61
  pos1 = CodePosition.new(node.start_line, node.start_code_units_column(encoding))
62
62
  pos2 = CodePosition.new(node.end_line, node.end_code_units_column(encoding))
63
- elsif node.respond_to?(:location)
64
- loc = node.location
65
- row, col = loc.start_loc
66
- pos1 = CodePosition.new(row, col) # TODO: use SPLAT
67
- row, col = loc.end_loc
68
- pos2 = CodePosition.new(row, col)
63
+ elsif node.is_a?(RBS::Location)
64
+ pos1 = CodePosition.new(*node.start_loc)
65
+ pos2 = CodePosition.new(*node.end_loc)
69
66
  else
70
67
  p node.class.ancestors
71
68
  raise "unknown type: #{ node.class }"
@@ -108,5 +105,10 @@ module TypeProf
108
105
  def ==(other)
109
106
  @first == other.first && @last == other.last
110
107
  end
108
+
109
+ def <=>(other)
110
+ cmp = @first <=> other.first
111
+ cmp == 0 ? @last <=> other.last : cmp
112
+ end
111
113
  end
112
114
  end
@@ -9,6 +9,7 @@ module TypeProf::Core
9
9
  @ret = nil
10
10
 
11
11
  @changes = ChangeSet.new(self, nil)
12
+ @diagnostics = Set[]
12
13
  end
13
14
 
14
15
  attr_reader :lenv
@@ -16,6 +17,7 @@ module TypeProf::Core
16
17
  attr_reader :static_ret
17
18
  attr_reader :ret
18
19
  attr_reader :changes
20
+ attr_reader :diagnostics
19
21
 
20
22
  def subnodes = {}
21
23
  def attrs = {}
@@ -63,12 +65,12 @@ module TypeProf::Core
63
65
  end
64
66
 
65
67
  def define_copy(genv)
66
- @lenv = @prev_node.lenv
68
+ @lenv = (@prev_node || raise).lenv
67
69
  each_subnode do |subnode|
68
70
  subnode.define_copy(genv)
69
71
  end
70
72
  @prev_node.instance_variable_set(:@reused, true)
71
- @static_ret = @prev_node.static_ret
73
+ @static_ret = (@prev_node || raise).static_ret
72
74
  end
73
75
 
74
76
  def define0(genv)
@@ -90,6 +92,7 @@ module TypeProf::Core
90
92
  end
91
93
  end
92
94
 
95
+ #: (TypeProf::Core::GlobalEnv) -> TypeProf::Core::BasicVertex
93
96
  def install(genv)
94
97
  @ret = install0(genv)
95
98
  @changes.reinstall(genv)
@@ -97,14 +100,19 @@ module TypeProf::Core
97
100
  end
98
101
 
99
102
  def install_copy(genv)
100
- @changes.copy_from(@prev_node.changes)
103
+ @changes.copy_from((@prev_node || raise).changes)
101
104
  @changes.reuse(self)
105
+ (@prev_node || raise).diagnostics.each do |diag|
106
+ diag.reuse(self)
107
+ @diagnostics << diag
108
+ end
102
109
  each_subnode do |subnode|
103
110
  subnode.install_copy(genv)
104
111
  end
105
- @ret = @prev_node.ret
112
+ @ret = (@prev_node || raise).ret
106
113
  end
107
114
 
115
+ #: (TypeProf::Core::GlobalEnv) -> untyped
108
116
  def install0(_)
109
117
  raise "should override"
110
118
  end
@@ -116,6 +124,18 @@ module TypeProf::Core
116
124
  end
117
125
  end
118
126
 
127
+ def narrowings
128
+ Narrowing::EmptyNarrowings
129
+ end
130
+
131
+ def add_diagnostic(diag)
132
+ @diagnostics << diag
133
+ end
134
+
135
+ def remove_diagnostic(diag)
136
+ @diagnostics.delete(diag)
137
+ end
138
+
119
139
  def diff(prev_node)
120
140
  if prev_node.is_a?(self.class) && attrs.all? {|key, attr| attr == prev_node.send(key) }
121
141
  raise unless prev_node # annotation
@@ -159,13 +179,10 @@ module TypeProf::Core
159
179
  end
160
180
  end
161
181
 
162
- def diagnostics(genv, &blk)
163
- @changes.diagnostics.each(&blk)
164
- @changes.boxes.each_value do |box|
165
- box.diagnostics(genv, &blk)
166
- end
182
+ def each_diagnostic(genv, &blk)
183
+ @diagnostics.each(&blk)
167
184
  each_subnode do |subnode|
168
- subnode.diagnostics(genv, &blk)
185
+ subnode.each_diagnostic(genv, &blk)
169
186
  end
170
187
  end
171
188
 
@@ -17,22 +17,28 @@ module TypeProf::Core
17
17
  @block_tbl = nil
18
18
  @block_f_args = nil
19
19
  @block_body = nil
20
+ @safe_navigation = raw_node.respond_to?(:safe_navigation?) && raw_node.safe_navigation?
21
+ @anonymous_block_forwarding = false
20
22
 
21
23
  if raw_args
22
24
  args = []
23
25
  @splat_flags = []
24
26
  raw_args.arguments.each do |raw_arg|
25
- if raw_arg.is_a?(Prism::SplatNode)
27
+ case raw_arg
28
+ when Prism::SplatNode
26
29
  args << raw_arg.expression
27
30
  @splat_flags << true
31
+ when Prism::ForwardingArgumentsNode
32
+ # TODO: Support forwarding arguments
28
33
  else
29
34
  args << raw_arg
30
35
  @splat_flags << false
31
36
  end
32
37
  end
33
- @positional_args = args.map {|arg| AST.create_node(arg, lenv) }
38
+ @positional_args = args.map {|arg| arg ? AST.create_node(arg, lenv) : DummyNilNode.new(code_range, lenv) }
34
39
 
35
- if @positional_args.last.is_a?(TypeProf::Core::AST::HashNode) && @positional_args.last.keywords
40
+ kw = @positional_args.last
41
+ if kw.is_a?(TypeProf::Core::AST::HashNode) && kw.keywords
36
42
  @keyword_args = @positional_args.pop
37
43
  end
38
44
  end
@@ -41,7 +47,11 @@ module TypeProf::Core
41
47
 
42
48
  if raw_block
43
49
  if raw_block.type == :block_argument_node
44
- @block_pass = AST.create_node(raw_block.expression, lenv)
50
+ if raw_block.expression
51
+ @block_pass = AST.create_node(raw_block.expression, lenv)
52
+ else
53
+ @anonymous_block_forwarding = true
54
+ end
45
55
  else
46
56
  @block_pass = nil
47
57
  @block_tbl = raw_block.locals
@@ -51,6 +61,8 @@ module TypeProf::Core
51
61
  raw_block.parameters.parameters.requireds.map {|n| n.is_a?(Prism::MultiTargetNode) ? nil : n.name }
52
62
  when Prism::NumberedParametersNode
53
63
  1.upto(raw_block.parameters.maximum).map { |n| :"_#{n}" }
64
+ when Prism::ItParametersNode
65
+ [:it]
54
66
  when nil
55
67
  []
56
68
  else
@@ -67,51 +79,63 @@ module TypeProf::Core
67
79
 
68
80
  attr_reader :recv, :mid, :mid_code_range, :yield
69
81
  attr_reader :positional_args, :splat_flags, :keyword_args
70
- attr_reader :block_tbl, :block_f_args, :block_body, :block_pass
82
+ attr_reader :block_tbl, :block_f_args, :block_body, :block_pass, :anonymous_block_forwarding
83
+ attr_reader :safe_navigation
71
84
 
72
85
  def subnodes = { recv:, positional_args:, keyword_args:, block_body:, block_pass: }
73
- def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield: }
86
+ def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield:, safe_navigation:, anonymous_block_forwarding: }
74
87
 
75
88
  def install0(genv)
76
89
  recv = @recv ? @recv.install(genv) : @yield ? @lenv.get_var(:"*given_block") : @lenv.get_var(:"*self")
77
90
 
91
+ if @safe_navigation
92
+ allow_nil = NilFilter.new(genv, self, recv, true).next_vtx
93
+ recv = NilFilter.new(genv, self, recv, false).next_vtx
94
+ end
95
+
78
96
  positional_args = @positional_args.map do |arg|
79
- arg.install(genv)
97
+ if arg.is_a?(DummyNilNode)
98
+ @lenv.get_var(:"*anonymous_rest")
99
+ else
100
+ arg.install(genv)
101
+ end
80
102
  end
81
103
 
82
104
  keyword_args = @keyword_args ? @keyword_args.install(genv) : nil
83
105
 
84
106
  if @block_body
85
- @lenv.locals.each {|var, vtx| @block_body.lenv.locals[var] = vtx }
86
- @block_tbl.each {|var| @block_body.lenv.locals[var] = Source.new(genv.nil_type) }
107
+ block_body = @block_body # kinda type annotationty
108
+ block_tbl = @block_tbl || raise
109
+ @lenv.locals.each {|var, vtx| block_body.lenv.locals[var] = vtx }
110
+ block_tbl.each {|var| block_body.lenv.locals[var] = Source.new(genv.nil_type) }
87
111
  @block_body.lenv.locals[:"*self"] = @block_body.lenv.cref.get_self(genv)
88
112
 
89
113
  blk_f_args = []
90
114
  if @block_f_args
91
115
  @block_f_args.each do |arg|
92
- blk_f_args << @block_body.lenv.new_var(arg, self)
116
+ blk_f_args << block_body.lenv.new_var(arg, self)
93
117
  end
94
118
  end
95
119
 
96
120
  @lenv.locals.each do |var, vtx|
97
- @block_body.lenv.set_var(var, vtx)
121
+ block_body.lenv.set_var(var, vtx)
98
122
  end
99
123
  vars = []
100
- @block_body.modified_vars(@lenv.locals.keys - @block_tbl, vars)
124
+ @block_body.modified_vars(@lenv.locals.keys - block_tbl, vars)
101
125
  vars.uniq!
102
126
  vars.each do |var|
103
127
  vtx = @lenv.get_var(var)
104
128
  nvtx = vtx.new_vertex(genv, self)
105
129
  @lenv.set_var(var, nvtx)
106
- @block_body.lenv.set_var(var, nvtx)
130
+ block_body.lenv.set_var(var, nvtx)
107
131
  end
108
132
 
109
- e_ret = @block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
133
+ @block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
110
134
  @block_body.install(genv)
111
- @block_body.lenv.add_next_box(@changes.add_escape_box(genv, @block_body.ret, e_ret))
135
+ @block_body.lenv.add_next_box(@changes.add_escape_box(genv, @block_body.ret))
112
136
 
113
137
  vars.each do |var|
114
- @changes.add_edge(genv, @block_body.lenv.get_var(var), @lenv.get_var(var))
138
+ @changes.add_edge(genv, block_body.lenv.get_var(var), @lenv.get_var(var))
115
139
  end
116
140
 
117
141
  blk_f_ary_arg = Vertex.new(self)
@@ -120,19 +144,27 @@ module TypeProf::Core
120
144
  blk_ty = Source.new(Type::Proc.new(genv, block))
121
145
  elsif @block_pass
122
146
  blk_ty = @block_pass.install(genv)
147
+ elsif @anonymous_block_forwarding
148
+ blk_ty = @lenv.get_var(:"*anonymous_block")
123
149
  end
124
150
 
125
151
  a_args = ActualArguments.new(positional_args, @splat_flags, keyword_args, blk_ty)
126
152
  box = @changes.add_method_call_box(genv, recv, @mid, a_args, !@recv)
127
153
 
128
- if @block_body && @block_body.lenv.break_vtx
154
+ block_body = @block_body
155
+ if block_body && block_body.lenv.break_vtx
129
156
  ret = Vertex.new(self)
130
157
  @changes.add_edge(genv, box.ret, ret)
131
- @changes.add_edge(genv, @block_body.lenv.break_vtx, ret)
132
- ret
158
+ @changes.add_edge(genv, block_body.lenv.break_vtx, ret)
133
159
  else
134
- box.ret
160
+ ret = box.ret
161
+ end
162
+
163
+ if @safe_navigation
164
+ @changes.add_edge(genv, allow_nil, ret)
135
165
  end
166
+
167
+ ret
136
168
  end
137
169
 
138
170
  def block_last_stmt_code_range
@@ -158,10 +190,12 @@ module TypeProf::Core
158
190
  def modified_vars(tbl, vars)
159
191
  subnodes.each do |key, subnode|
160
192
  next unless subnode
161
- if key == :block_body
162
- subnode.modified_vars(tbl - self.block_tbl, vars)
163
- elsif subnode.is_a?(AST::Node)
164
- subnode.modified_vars(tbl, vars)
193
+ if subnode.is_a?(AST::Node)
194
+ if key == :block_body
195
+ subnode.modified_vars(tbl - self.block_tbl, vars)
196
+ else
197
+ subnode.modified_vars(tbl, vars)
198
+ end
165
199
  else
166
200
  subnode.each {|n| n.modified_vars(tbl, vars) }
167
201
  end
@@ -178,6 +212,33 @@ module TypeProf::Core
178
212
  raw_block = raw_node.block
179
213
  super(raw_node, recv, mid, mid_code_range, raw_args, nil, raw_block, lenv)
180
214
  end
215
+
216
+ def narrowings
217
+ @narrowings ||= begin
218
+ args = @positional_args
219
+ case @mid
220
+ when :is_a?
221
+ if @recv.is_a?(LocalVariableReadNode) && args && args.size == 1
222
+ [
223
+ Narrowing.new({ @recv.var => Narrowing::IsAConstraint.new(args[0], false) }),
224
+ Narrowing.new({ @recv.var => Narrowing::IsAConstraint.new(args[0], true) })
225
+ ]
226
+ elsif @recv.is_a?(InstanceVariableReadNode) && args && args.size == 1
227
+ [
228
+ Narrowing.new({ @recv.var => Narrowing::IsAConstraint.new(args[0], false) }),
229
+ Narrowing.new({ @recv.var => Narrowing::IsAConstraint.new(args[0], true) })
230
+ ]
231
+ else
232
+ super
233
+ end
234
+ when :!
235
+ then_narrowing, else_narrowing = @recv.narrowings
236
+ [else_narrowing, then_narrowing]
237
+ else
238
+ super
239
+ end
240
+ end
241
+ end
181
242
  end
182
243
 
183
244
  class SuperNode < CallBaseNode
@@ -17,29 +17,24 @@ module TypeProf::Core
17
17
  @cbase = nil
18
18
  @toplevel = true
19
19
  end
20
- # temporarily support old Prism https://bugs.ruby-lang.org/issues/20467
21
- if raw_node.respond_to?(:name)
22
- @cname = raw_node.name
23
- @cname_code_range = TypeProf::CodeRange.from_node(raw_node.name_loc)
24
- else
25
- @cname = raw_node.child.name
26
- @cname_code_range = TypeProf::CodeRange.from_node(raw_node.child.location)
27
- end
20
+ @cname = raw_node.name
21
+ @cname_code_range = TypeProf::CodeRange.from_node(raw_node.name_loc)
28
22
  else
29
23
  raise raw_node.type.to_s
30
24
  end
25
+ @strict_const_scope = lenv.strict_const_scope
31
26
  end
32
27
 
33
- attr_reader :cname, :cbase, :toplevel, :cname_code_range
28
+ attr_reader :cname, :cbase, :toplevel, :cname_code_range, :strict_const_scope
34
29
 
35
- def attrs = { cname:, toplevel: }
30
+ def attrs = { cname:, toplevel:, strict_const_scope: }
36
31
  def subnodes = { cbase: }
37
32
 
38
33
  def define0(genv)
39
34
  if @cbase
40
- ScopedConstRead.new(@cname, @cbase.define(genv))
35
+ ScopedConstRead.new(@cname, @cbase.define(genv), @strict_const_scope)
41
36
  else
42
- BaseConstRead.new(genv, @cname, @toplevel ? CRef::Toplevel : @lenv.cref)
37
+ BaseConstRead.new(genv, @cname, @toplevel ? CRef::Toplevel : @lenv.cref, @strict_const_scope)
43
38
  end
44
39
  end
45
40