class TypeProf::Type::Array::Elements
Attributes
lead_tys[R]
rest_ty[R]
Public Class Methods
dummy_elements()
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 274 def self.dummy_elements Elements.new([], Type.any) end
new(lead_tys, rest_ty = Type.bot)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 268 def initialize(lead_tys, rest_ty = Type.bot) raise unless lead_tys.all? {|ty| ty.is_a?(Type) } raise unless rest_ty.is_a?(Type) @lead_tys, @rest_ty = lead_tys, rest_ty end
Public Instance Methods
[](idx)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 373 def [](idx) if idx.is_a?(Range) if @rest_ty == Type.bot lead_tys = @lead_tys[idx] if lead_tys rest_ty = Type.bot else return Type.nil end else b, e = idx.begin, idx.end b = 0 if !b if !e lead_tys = @lead_tys[idx] || [] rest_ty = @rest_ty elsif b >= 0 if e >= 0 if b <= e if e < @lead_tys.size lead_tys = @lead_tys[idx] rest_ty = Type.bot else lead_tys = @lead_tys[idx] || [] rest_ty = @rest_ty end else return Type.nil end else lead_tys = @lead_tys[idx] || [] e = idx.exclude_end? ? e : e == -1 ? @lead_tys.size : e + 1 rest_ty = (@lead_tys[e + 1..] || []).inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) } end else lead_tys = [] if e >= 0 rest_ty = e < @lead_tys.size ? Type.bot : @rest_ty range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e) rest_ty = @lead_tys[range].inject(rest_ty) {|ty0, ty1| ty0.union(ty1) } else if b <= e range = [0, @lead_tys.size + b].max .. (idx.exclude_end? ? e - 1 : e) rest_ty = @lead_tys[range].inject(@rest_ty) {|ty0, ty1| ty0.union(ty1) } else return Type.nil end end end end base_ty = Type::Instance.new(Type::Builtin[:ary]) Array.new(Elements.new(lead_tys, rest_ty), base_ty) elsif idx >= 0 if idx < @lead_tys.size @lead_tys[idx] elsif @rest_ty == Type.bot Type.nil else @rest_ty end else i = @lead_tys.size + idx i = [i, 0].max ty = @rest_ty @lead_tys[i..].each do |ty2| ty = ty.union(ty2) end ty end end
append(ty)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 477 def append(ty) if @rest_ty == Type.bot if @lead_tys.size < 5 # XXX: should be configurable, or ...? lead_tys = @lead_tys + [ty] Elements.new(lead_tys, @rest_ty) else Elements.new(@lead_tys, ty) end else Elements.new(@lead_tys, @rest_ty.union(ty)) end end
each_free_type_variable(&blk)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 351 def each_free_type_variable(&blk) @lead_tys.each do |ty| ty.each_free_type_variable(&blk) end @rest_ty&.each_free_type_variable(&blk) end
globalize(env, visited, depth)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 284 def globalize(env, visited, depth) lead_tys = [] @lead_tys.each do |ty| lead_tys << ty.globalize(env, visited, depth) end rest_ty = @rest_ty&.globalize(env, visited, depth) Elements.new(lead_tys, rest_ty) end
include_untyped?(scratch)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 553 def include_untyped?(scratch) return true if @lead_tys.any? {|ty| ty.include_untyped?(scratch) } return true if @rest_ty.include_untyped?(scratch) false end
limit_size(limit)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 304 def limit_size(limit) Elements.new(@lead_tys.map {|ty| ty.limit_size(limit) }, @rest_ty.limit_size(limit)) end
localize(env, alloc_site, depth)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 293 def localize(env, alloc_site, depth) lead_tys = @lead_tys.map.with_index do |ty, i| alloc_site2 = alloc_site.add_id(i) env, ty = ty.localize(env, alloc_site2, depth) ty end alloc_site_rest = alloc_site.add_id(:rest) env, rest_ty = @rest_ty.localize(env, alloc_site_rest, depth) return env, Elements.new(lead_tys, rest_ty) end
match?(other)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 338 def match?(other) n = [@lead_tys.size, other.lead_tys.size].min rest_ty1 = @lead_tys[n..].inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) } rest_ty2 = other.lead_tys[n..].inject(other.rest_ty) {|ty1, ty2| ty1.union(ty2) } subst = nil (@lead_tys[0, n] + [rest_ty1]).zip(other.lead_tys[0, n] + [rest_ty2]) do |ty0, ty1| subst2 = Type.match?(ty0, ty1) return nil unless subst2 subst = Type.merge_substitution(subst, subst2) end subst end
pretty_print(q)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 330 def pretty_print(q) q.group(9, "Elements[", "]") do q.seplist(@lead_tys + [@rest_ty]) do |elem| q.pp elem end end end
screen_name(scratch)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 308 def screen_name(scratch) if @rest_ty == Type.bot if @lead_tys.empty? # This is heuristic: in general, an empty array is a wrong guess. # Note that an empty array is representable as "[ ]" in RBS, but # users often have to modify it to "Array[something]". # In this term, "Array[untyped]" is considered more useful than "[ ]". return "Array[untyped]" end s = @lead_tys.map do |ty| ty.screen_name(scratch) end s << "*" + @rest_ty.screen_name(scratch) if @rest_ty != Type.bot return "[#{ s.join(", ") }]" end "*[#{ squash.screen_name(scratch) }]" rescue SystemStackError p squash exit! end
squash()
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 364 def squash @lead_tys.inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) } #.union(Type.nil) # is this needed? end
squash_or_any()
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 368 def squash_or_any ty = squash ty == Type.bot ? Type.any : ty end
substitute(subst, depth)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 358 def substitute(subst, depth) lead_tys = @lead_tys.map {|ty| ty.substitute(subst, depth) } rest_ty = @rest_ty.substitute(subst, depth) Elements.new(lead_tys, rest_ty) end
take_first(num)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 507 def take_first(num) base_ty = Type::Instance.new(Type::Builtin[:ary]) if @lead_tys.size >= num lead_tys = @lead_tys[0, num] rest_ary_ty = Array.new(Elements.new(@lead_tys[num..-1], @rest_ty), base_ty) return lead_tys, rest_ary_ty else lead_tys = @lead_tys.dup until lead_tys.size == num # .union(Type.nil) is needed for `a, b, c = [42]` to assign nil to b and c lead_tys << @rest_ty.union(Type.nil) end rest_ary_ty = Array.new(Elements.new([], @rest_ty), base_ty) return lead_tys, rest_ary_ty end end
take_last(num)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 524 def take_last(num) base_ty = Type::Instance.new(Type::Builtin[:ary]) if @rest_ty == Type.bot if @lead_tys.size >= num following_tys = @lead_tys[-num, num] rest_ary_ty = Array.new(Elements.new(@lead_tys[0...-num], Type.bot), base_ty) return rest_ary_ty, following_tys else following_tys = @lead_tys[-num, num] || [] until following_tys.size == num following_tys.unshift(Type.nil) end rest_ary_ty = Array.new(Elements.new([], Type.bot), base_ty) return rest_ary_ty, following_tys end else lead_tys = @lead_tys.dup last_ty = rest_ty following_tys = [] until following_tys.size == num last_ty = last_ty.union(lead_tys.pop) unless lead_tys.empty? following_tys.unshift(last_ty) end rest_ty = lead_tys.inject(last_ty) {|ty1, ty2| ty1.union(ty2) } rest_ary_ty = Array.new(Elements.new([], rest_ty), base_ty) return rest_ary_ty, following_tys end end
to_local_type(id, base_ty)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 280 def to_local_type(id, base_ty) Type::Local.new(Array, id, base_ty) end
union(other)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 490 def union(other) return self if self == other raise "Hash::Elements merge Array::Elements" if other.is_a?(Hash::Elements) lead_count = [@lead_tys.size, other.lead_tys.size].min lead_tys = (0...lead_count).map do |i| @lead_tys[i].union(other.lead_tys[i]) end rest_ty = @rest_ty.union(other.rest_ty) (@lead_tys[lead_count..-1] + other.lead_tys[lead_count..-1]).each do |ty| rest_ty = rest_ty.union(ty) end Elements.new(lead_tys, rest_ty) end
update(idx, ty)
click to toggle source
# File typeprof-0.21.11/lib/typeprof/container-type.rb, line 443 def update(idx, ty) if idx if idx >= 0 if idx < @lead_tys.size lead_tys = Utils.array_update(@lead_tys, idx, ty) Elements.new(lead_tys, @rest_ty) else rest_ty = @rest_ty.union(ty) Elements.new(@lead_tys, rest_ty) end else i = @lead_tys.size + idx if @rest_ty == Type.bot if i >= 0 lead_tys = Utils.array_update(@lead_tys, i, ty) Elements.new(lead_tys, Type.bot) else # TODO: out of bound? should we emit an error? Elements.new(@lead_tys, Type.bot) end else i = [i, 0].max lead_tys = @lead_tys[0, i] + @lead_tys[i..].map {|ty2| ty2.union(ty) } rest_ty = @rest_ty.union(ty) Elements.new(@lead_tys, rest_ty) end end else lead_tys = @lead_tys.map {|ty1| ty1.union(ty) } rest_ty = @rest_ty.union(ty) Elements.new(lead_tys, rest_ty) end end