Class: TypeProf::Core::ModuleEntity

Inherits:
Object
  • Object
show all
Defined in:
lib/typeprof/core/env/module_entity.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(cpath, outer_module = self) ⇒ ModuleEntity

Returns a new instance of ModuleEntity.



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/typeprof/core/env/module_entity.rb', line 3

def initialize(cpath, outer_module = self)
  @cpath = cpath

  @module_decls = Set[]
  @module_defs = Set[]
  @include_decls = Set[]
  @include_defs = Set[]
  @prepend_decls = []
  @prepend_defs = []

  @inner_modules = {}
  @outer_module = outer_module

  # parent modules (superclass and all modules that I include)
  @superclass = nil
  @self_types = {}
  @included_modules = {}
  @prepended_modules = {}
  @basic_object = @cpath == [:BasicObject]

  # child modules (subclasses and all modules that include me)
  @child_modules = {}

  # class Foo[X, Y, Z] < Bar[A, B, C]
  @superclass_type_args = nil # A, B, C
  @type_params = [] # X, Y, Z

  @consts = {}
  @methods = { true => {}, false => {} }
  @ivars = { true => {}, false => {} }
  @cvars = {}
  @type_aliases = {}

  @static_reads = {}
  @subclass_checks = Set[]
  @ivar_reads = Set[] # should be handled in @ivars ??
  @cvar_reads = Set[]
end

Instance Attribute Details

#child_modulesObject (readonly)

Returns the value of attribute child_modules.



53
54
55
# File 'lib/typeprof/core/env/module_entity.rb', line 53

def child_modules
  @child_modules
end

#constsObject (readonly)

Returns the value of attribute consts.



58
59
60
# File 'lib/typeprof/core/env/module_entity.rb', line 58

def consts
  @consts
end

#cpathObject (readonly)

Returns the value of attribute cpath.



42
43
44
# File 'lib/typeprof/core/env/module_entity.rb', line 42

def cpath
  @cpath
end

#cvar_readsObject (readonly)

Returns the value of attribute cvar_reads.



67
68
69
# File 'lib/typeprof/core/env/module_entity.rb', line 67

def cvar_reads
  @cvar_reads
end

#cvarsObject (readonly)

Returns the value of attribute cvars.



61
62
63
# File 'lib/typeprof/core/env/module_entity.rb', line 61

def cvars
  @cvars
end

#included_modulesObject (readonly)

Returns the value of attribute included_modules.



51
52
53
# File 'lib/typeprof/core/env/module_entity.rb', line 51

def included_modules
  @included_modules
end

#inner_modulesObject (readonly)

Returns the value of attribute inner_modules.



46
47
48
# File 'lib/typeprof/core/env/module_entity.rb', line 46

def inner_modules
  @inner_modules
end

#ivar_readsObject (readonly)

Returns the value of attribute ivar_reads.



66
67
68
# File 'lib/typeprof/core/env/module_entity.rb', line 66

def ivar_reads
  @ivar_reads
end

#ivarsObject (readonly)

Returns the value of attribute ivars.



60
61
62
# File 'lib/typeprof/core/env/module_entity.rb', line 60

def ivars
  @ivars
end

#methodsObject (readonly)

Returns the value of attribute methods.



59
60
61
# File 'lib/typeprof/core/env/module_entity.rb', line 59

def methods
  @methods
end

#module_declsObject (readonly)

Returns the value of attribute module_decls.



43
44
45
# File 'lib/typeprof/core/env/module_entity.rb', line 43

def module_decls
  @module_decls
end

#module_defsObject (readonly)

Returns the value of attribute module_defs.



44
45
46
# File 'lib/typeprof/core/env/module_entity.rb', line 44

def module_defs
  @module_defs
end

#outer_moduleObject (readonly)

Returns the value of attribute outer_module.



47
48
49
# File 'lib/typeprof/core/env/module_entity.rb', line 47

def outer_module
  @outer_module
end

#prepended_modulesObject (readonly)

Returns the value of attribute prepended_modules.



52
53
54
# File 'lib/typeprof/core/env/module_entity.rb', line 52

def prepended_modules
  @prepended_modules
end

#self_typesObject (readonly)

Returns the value of attribute self_types.



50
51
52
# File 'lib/typeprof/core/env/module_entity.rb', line 50

def self_types
  @self_types
end

#static_readsObject (readonly)

Returns the value of attribute static_reads.



64
65
66
# File 'lib/typeprof/core/env/module_entity.rb', line 64

def static_reads
  @static_reads
end

#subclass_checksObject (readonly)

Returns the value of attribute subclass_checks.



65
66
67
# File 'lib/typeprof/core/env/module_entity.rb', line 65

def subclass_checks
  @subclass_checks
end

#superclassObject (readonly)

Returns the value of attribute superclass.



49
50
51
# File 'lib/typeprof/core/env/module_entity.rb', line 49

def superclass
  @superclass
end

#superclass_type_argsObject (readonly)

Returns the value of attribute superclass_type_args.



55
56
57
# File 'lib/typeprof/core/env/module_entity.rb', line 55

def superclass_type_args
  @superclass_type_args
end

#type_aliasesObject (readonly)

Returns the value of attribute type_aliases.



62
63
64
# File 'lib/typeprof/core/env/module_entity.rb', line 62

def type_aliases
  @type_aliases
end

#type_paramsObject (readonly)

Returns the value of attribute type_params.



56
57
58
# File 'lib/typeprof/core/env/module_entity.rb', line 56

def type_params
  @type_params
end

Instance Method Details

#add_include_decl(genv, node) ⇒ Object



179
180
181
182
# File 'lib/typeprof/core/env/module_entity.rb', line 179

def add_include_decl(genv, node)
  @include_decls << node
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#add_include_def(genv, node) ⇒ Object



189
190
191
192
# File 'lib/typeprof/core/env/module_entity.rb', line 189

def add_include_def(genv, node)
  @include_defs << node
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#add_module_decl(genv, decl) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/typeprof/core/env/module_entity.rb', line 112

def add_module_decl(genv, decl)
  on_module_added(genv)

  @module_decls << decl

  if @type_params
    update_type_params if @type_params != decl.params
  else
    @type_params = decl.params
  end

  if decl.is_a?(AST::SigClassNode) && !@superclass_type_args
    @superclass_type_args = decl.superclass_args
  end

  ce = @outer_module.get_const(get_cname)
  ce.add_decl(decl)
  ce
end

#add_module_def(genv, node) ⇒ Object



165
166
167
168
169
170
171
# File 'lib/typeprof/core/env/module_entity.rb', line 165

def add_module_def(genv, node)
  on_module_added(genv)
  @module_defs << node
  ce = @outer_module.get_const(get_cname)
  ce.add_def(node)
  ce
end

#add_prepend_decl(genv, node) ⇒ Object



199
200
201
202
# File 'lib/typeprof/core/env/module_entity.rb', line 199

def add_prepend_decl(genv, node)
  @prepend_decls << node
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#add_prepend_def(genv, node) ⇒ Object



209
210
211
212
# File 'lib/typeprof/core/env/module_entity.rb', line 209

def add_prepend_def(genv, node)
  @prepend_defs << node
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#each_descendant(base_mod = nil) {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:



419
420
421
422
423
424
425
# File 'lib/typeprof/core/env/module_entity.rb', line 419

def each_descendant(base_mod = nil, &blk)
  return if base_mod == self
  yield self
  @child_modules.each_key do |child_mod|
    child_mod.each_descendant(base_mod || self, &blk)
  end
end

#exist?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/typeprof/core/env/module_entity.rb', line 81

def exist?
  !@module_decls.empty? || !@module_defs.empty?
end

#find_superclass_const_readObject



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/typeprof/core/env/module_entity.rb', line 249

def find_superclass_const_read
  return nil if @basic_object

  if @module_decls.empty?
    @module_defs.each do |mdef|
      case mdef
      when AST::ClassNode
        if mdef.superclass_cpath
          const_read = mdef.superclass_cpath.static_ret
          return const_read ? const_read.cpath : []
        end
      when AST::SingletonClassNode
        next
      when AST::ModuleNode
        return nil
      else
        raise
      end
    end
  else
    @module_decls.each do |mdecl|
      case mdecl
      when AST::SigClassNode
        if mdecl.superclass_cpath
          const_read = mdecl.static_ret[:superclass_cpath].last
          return const_read ? const_read.cpath : []
        end
      when AST::SigModuleNode, AST::SigInterfaceNode
        return nil
      end
    end
  end

  return []
end

#get_cnameObject



77
78
79
# File 'lib/typeprof/core/env/module_entity.rb', line 77

def get_cname
  @cpath.empty? ? :Object : @cpath.last
end

#get_const(cname) ⇒ Object



427
428
429
# File 'lib/typeprof/core/env/module_entity.rb', line 427

def get_const(cname)
  @consts[cname] ||= ValueEntity.new
end

#get_cvar(name) ⇒ Object



439
440
441
# File 'lib/typeprof/core/env/module_entity.rb', line 439

def get_cvar(name)
  @cvars[name] ||= ValueEntity.new
end

#get_ivar(singleton, name) ⇒ Object



435
436
437
# File 'lib/typeprof/core/env/module_entity.rb', line 435

def get_ivar(singleton, name)
  @ivars[singleton][name] ||= ValueEntity.new
end

#get_method(singleton, mid) ⇒ Object



431
432
433
# File 'lib/typeprof/core/env/module_entity.rb', line 431

def get_method(singleton, mid)
  @methods[singleton][mid] ||= MethodEntity.new
end

#get_type_alias(name) ⇒ Object



443
444
445
# File 'lib/typeprof/core/env/module_entity.rb', line 443

def get_type_alias(name)
  @type_aliases[name] ||= TypeAliasEntity.new
end

#get_vertexes(vtxs) ⇒ Object



447
448
449
450
451
452
453
454
455
# File 'lib/typeprof/core/env/module_entity.rb', line 447

def get_vertexes(vtxs)
  @inner_modules.each_value do |mod|
    next if self.equal?(mod) # for Object
    mod.get_vertexes(vtxs)
  end
  @consts.each_value do |cdef|
    vtxs << cdef.vtx
  end
end

#interface?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/typeprof/core/env/module_entity.rb', line 73

def interface?
  @cpath.last && @cpath.last.start_with?("_")
end

#module?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/typeprof/core/env/module_entity.rb', line 69

def module?
  !@superclass && !@basic_object
end

#on_ancestors_updated(genv, base_mod) ⇒ Object



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/typeprof/core/env/module_entity.rb', line 401

def on_ancestors_updated(genv, base_mod)
  @child_modules.each_key {|child_mod| child_mod.on_ancestors_updated(genv, base_mod || self) }
  @static_reads.each_value do |static_reads|
    static_reads.each do |static_read|
      genv.add_static_eval_queue(:static_read_changed, static_read)
    end
  end
  @methods.each do |_, methods|
    methods.each_value do |me|
      me.method_call_boxes.each do |box|
        genv.add_run(box)
      end
    end
  end
  @ivar_reads.each {|ivar_read| genv.add_run(ivar_read) }
  @cvar_reads.each {|cvar_read| genv.add_run(cvar_read) }
end

#on_inner_modules_changed(genv, changed_cname) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'lib/typeprof/core/env/module_entity.rb', line 85

def on_inner_modules_changed(genv, changed_cname)
  @child_modules.each_key do |child_mod|
    child_mod.on_inner_modules_changed(genv, changed_cname)
  end
  if @static_reads[changed_cname]
    @static_reads[changed_cname].each do |static_read|
      genv.add_static_eval_queue(:static_read_changed, static_read)
    end
  end
end

#on_module_added(genv) ⇒ Object



96
97
98
99
100
101
102
# File 'lib/typeprof/core/env/module_entity.rb', line 96

def on_module_added(genv)
  return if @cpath.empty?
  unless exist?
    genv.add_static_eval_queue(:inner_modules_changed, [@outer_module, get_cname])
  end
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#on_module_removed(genv) ⇒ Object



104
105
106
107
108
109
110
# File 'lib/typeprof/core/env/module_entity.rb', line 104

def on_module_removed(genv)
  return if @cpath.empty?
  genv.add_static_eval_queue(:parent_modules_changed, self)
  unless exist?
    genv.add_static_eval_queue(:inner_modules_changed, [@outer_module, get_cname])
  end
end

#on_parent_modules_changed(genv) ⇒ Object



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/typeprof/core/env/module_entity.rb', line 285

def on_parent_modules_changed(genv)
  any_updated = false

  unless @basic_object
    new_superclass_cpath = find_superclass_const_read

    new_superclass, updated = update_parent(genv, :superclass, @superclass, new_superclass_cpath)
    if updated
      @superclass = new_superclass
      any_updated = true
    end
  end

  @module_decls.each do |mdecl|
    case mdecl
    when AST::SigModuleNode
      mdecl.static_ret[:self_types].each_with_index do |const_reads, i|
        key = [mdecl, i]
        new_parent_cpath = const_reads.last.cpath
        new_self_type, updated = update_parent(genv, key, @self_types[key], new_parent_cpath)
        if updated
          if new_self_type
            @self_types[key] = new_self_type
          else
            @self_types.delete(key) || raise
          end
          any_updated = true
        end
      end
    end
  end
  @self_types.delete_if do |(origin_mdecl, origin_idx), old_mod|
    if @module_decls.include?(origin_mdecl)
      false
    else
      _new_self_type, updated = update_parent(genv, [origin_mdecl, origin_idx], old_mod, nil)
      any_updated ||= updated
      true
    end
  end

  @include_decls.each do |idecl|
    new_parent_cpath = idecl.static_ret.last.cpath
    new_parent, updated = update_parent(genv, idecl, @included_modules[idecl], new_parent_cpath)
    if updated
      if new_parent
        @included_modules[idecl] = new_parent
      else
        @included_modules.delete(idecl) || raise
      end
      any_updated = true
    end
  end
  @include_defs.each do |idef|
    new_parent_cpath = idef.static_ret ? idef.static_ret.cpath : nil
    new_parent, updated = update_parent(genv, idef, @included_modules[idef], new_parent_cpath)
    if updated
      if new_parent
        @included_modules[idef] = new_parent
      else
        @included_modules.delete(idef) || raise
      end
      any_updated = true
    end
  end
  @prepend_decls.each do |pdecl|
    new_parent_cpath = pdecl.static_ret.last.cpath
    new_parent, updated = update_parent(genv, pdecl, @prepended_modules[pdecl], new_parent_cpath)
    if updated
      if new_parent
        @prepended_modules[pdecl] = new_parent
      else
        @prepended_modules.delete(pdecl) || raise
      end
      any_updated = true
    end
  end
  @prepend_defs.each do |pdef|
    new_parent_cpath = pdef.static_ret ? pdef.static_ret.cpath : nil
    new_parent, updated = update_parent(genv, pdef, @prepended_modules[pdef], new_parent_cpath)
    if updated
      if new_parent
        @prepended_modules[pdef] = new_parent
      else
        @prepended_modules.delete(pdef) || raise
      end
      any_updated = true
    end
  end
  @included_modules.delete_if do |origin, old_mod|
    if @include_decls.include?(origin) || @include_defs.include?(origin)
      false
    else
      _new_parent, updated = update_parent(genv, origin, old_mod, nil)
      any_updated ||= updated
      true
    end
  end
  @prepended_modules.delete_if do |origin, old_mod|
    if @prepend_decls.include?(origin) || @prepend_defs.include?(origin)
      false
    else
      _new_parent, updated = update_parent(genv, origin, old_mod, nil)
      any_updated ||= updated
      true
    end
  end

  if any_updated
    @subclass_checks.each do |mcall_box|
      genv.add_run(mcall_box)
    end
    on_ancestors_updated(genv, nil)
  end
end

#pretty_print(q) ⇒ Object



461
462
463
# File 'lib/typeprof/core/env/module_entity.rb', line 461

def pretty_print(q)
  q.text "#<ModuleEntity[::#{ @cpath.empty? ? "Object" : @cpath.join("::") }]>"
end

#remove_include_decl(genv, node) ⇒ Object



184
185
186
187
# File 'lib/typeprof/core/env/module_entity.rb', line 184

def remove_include_decl(genv, node)
  @include_decls.delete(node) || raise
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#remove_include_def(genv, node) ⇒ Object



194
195
196
197
# File 'lib/typeprof/core/env/module_entity.rb', line 194

def remove_include_def(genv, node)
  @include_defs.delete(node) || raise
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#remove_module_decl(genv, decl) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/typeprof/core/env/module_entity.rb', line 132

def remove_module_decl(genv, decl)
  @outer_module.get_const(get_cname).remove_decl(decl)
  @module_decls.delete(decl) || raise

  update_type_params if @type_params == decl.params
  if decl.is_a?(AST::SigClassNode) && @superclass_type_args == decl.superclass_args
    @superclass_type_args = nil
    @module_decls.each do |decl|
      if decl.superclass_args
        @superclass_type_args = decl.superclass_args
        break
      end
    end
  end

  on_module_removed(genv)
end

#remove_module_def(genv, node) ⇒ Object



173
174
175
176
177
# File 'lib/typeprof/core/env/module_entity.rb', line 173

def remove_module_def(genv, node)
  @outer_module.get_const(get_cname).remove_def(node)
  @module_defs.delete(node) || raise
  on_module_removed(genv)
end

#remove_prepend_decl(genv, node) ⇒ Object



204
205
206
207
# File 'lib/typeprof/core/env/module_entity.rb', line 204

def remove_prepend_decl(genv, node)
  @prepend_decls.delete(node) || raise
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#remove_prepend_def(genv, node) ⇒ Object



214
215
216
217
# File 'lib/typeprof/core/env/module_entity.rb', line 214

def remove_prepend_def(genv, node)
  @prepend_defs.delete(node) || raise
  genv.add_static_eval_queue(:parent_modules_changed, self)
end

#show_cpathObject



457
458
459
# File 'lib/typeprof/core/env/module_entity.rb', line 457

def show_cpath
  @cpath.empty? ? "Object" : @cpath.join("::" )
end

#update_parent(genv, origin, old_parent, new_parent_cpath) ⇒ Object



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/typeprof/core/env/module_entity.rb', line 219

def update_parent(genv, origin, old_parent, new_parent_cpath)
  new_parent = new_parent_cpath ? genv.resolve_cpath(new_parent_cpath) : nil
  if old_parent != new_parent
    # check circular inheritance
    mod = new_parent
    while mod
      if mod == self
        # TODO: report an "circular inheritance" error
        new_parent = nil
        break
      end
      mod = mod.superclass
    end

    if old_parent != new_parent
      if old_parent
        set = old_parent.child_modules[self]
        set.delete(origin)
        old_parent.child_modules.delete(self) if set.empty?
      end
      if new_parent
        set = new_parent.child_modules[self] ||= Set[]
        set << origin
      end
      return [new_parent, true]
    end
  end
  return [new_parent, false]
end

#update_type_paramsObject



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/typeprof/core/env/module_entity.rb', line 150

def update_type_params
  @type_params = nil
  @module_decls.each do |decl|
    params = decl.params
    next unless params
    if @type_params
      @type_params = params if (@type_params <=> params) > 0
    else
      @type_params = params
    end
  end
  @type_params ||= []
  # TODO: report an error if there are multiple inconsistent declarations
end