Class: Audition::Static::Checks::RactorIsolation::CaptureScanner

Inherits:
Prism::Visitor
  • Object
show all
Defined in:
lib/audition/static/checks/ractor_isolation.rb

Overview

Walks a block's body tracking how many block scopes deep we are; a local reference with depth greater than that resolves outside the block, depth - level scopes above it.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ CaptureScanner

Returns a new instance of CaptureScanner.



260
261
262
263
264
# File 'lib/audition/static/checks/ractor_isolation.rb', line 260

def initialize
  @captures = []
  @level = 0
  super
end

Instance Attribute Details

#captures ⇒ Object (readonly)

Returns the value of attribute captures.



258
259
260
# File 'lib/audition/static/checks/ractor_isolation.rb', line 258

def captures
  @captures
end

Class Method Details

.captures(body) ⇒ Array<Array(String, Integer)>

Returns each captured name once, with how many scopes above the block it lives.

Returns:

  • (Array<Array(String, Integer)>) —

    each captured name once, with how many scopes above the block it lives



252
253
254
255
256
# File 'lib/audition/static/checks/ractor_isolation.rb', line 252

def self.captures(body)
  scanner = new
  scanner.visit(body)
  scanner.captures.uniq(&:first)
end

.scan(body) ⇒ Object



245
246
247
# File 'lib/audition/static/checks/ractor_isolation.rb', line 245

def self.scan(body)
  captures(body).map(&:first)
end

Instance Method Details

#visit_block_node(node) ⇒ Object



266
267
268
269
270
271
# File 'lib/audition/static/checks/ractor_isolation.rb', line 266

def visit_block_node(node)
  @level += 1
  super
ensure
  @level -= 1
end

#visit_def_node(node) ⇒ Object

Method definitions open fresh scopes; nothing inside them can capture the surrounding locals. A def opens a fresh scope, but its receiver expression (def x.foo) evaluates in the enclosing one and can capture an outer local.



285
286
287
# File 'lib/audition/static/checks/ractor_isolation.rb', line 285

def visit_def_node(node)
  visit(node.receiver) if node.receiver
end

#visit_lambda_node(node) ⇒ Object



273
274
275
276
277
278
# File 'lib/audition/static/checks/ractor_isolation.rb', line 273

def visit_lambda_node(node)
  @level += 1
  super
ensure
  @level -= 1
end

#visit_local_variable_and_write_node(node) ⇒ Object



313
314
315
316
# File 'lib/audition/static/checks/ractor_isolation.rb', line 313

def visit_local_variable_and_write_node(node)
  note(node)
  super
end

#visit_local_variable_operator_write_node(node) ⇒ Object



303
304
305
306
# File 'lib/audition/static/checks/ractor_isolation.rb', line 303

def visit_local_variable_operator_write_node(node)
  note(node)
  super
end

#visit_local_variable_or_write_node(node) ⇒ Object



308
309
310
311
# File 'lib/audition/static/checks/ractor_isolation.rb', line 308

def visit_local_variable_or_write_node(node)
  note(node)
  super
end

#visit_local_variable_read_node(node) ⇒ Object

Plain defs, not a define_method loop: the parallel scan calls these from worker Ractors, and a method born from define_method carries an un-shareable Proc that raises when dispatched from another Ractor.



293
294
295
296
# File 'lib/audition/static/checks/ractor_isolation.rb', line 293

def visit_local_variable_read_node(node)
  note(node)
  super
end

#visit_local_variable_target_node(node) ⇒ Object



318
319
320
321
# File 'lib/audition/static/checks/ractor_isolation.rb', line 318

def visit_local_variable_target_node(node)
  note(node)
  super
end

#visit_local_variable_write_node(node) ⇒ Object



298
299
300
301
# File 'lib/audition/static/checks/ractor_isolation.rb', line 298

def visit_local_variable_write_node(node)
  note(node)
  super
end