[](idx)
click to toggle source
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
def append(ty)
if @rest_ty == Type.bot
if @lead_tys.size < 5
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
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
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
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
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
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
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
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
def screen_name(scratch)
if @rest_ty == Type.bot
if @lead_tys.empty?
return "Array[bot]"
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) }]"
end
squash()
click to toggle source
def squash
@lead_tys.inject(@rest_ty) {|ty1, ty2| ty1.union(ty2) }
end
squash_or_any()
click to toggle source
def squash_or_any
ty = squash
ty == Type.bot ? Type.any : ty
end
substitute(subst, depth)
click to toggle source
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
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
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
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
def to_local_type(id, base_ty)
Type::Local.new(Array, id, base_ty)
end
union(other)
click to toggle source
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
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
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