# File typeprof-0.21.1/lib/typeprof/type.rb, line 424
def self.any
Thread.current[:any] ||= Any.new
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 432
def self.bool
Thread.current[:bool] ||= Union.new(Utils::Set[
Instance.new(Type::Builtin[:true]),
Instance.new(Type::Builtin[:false])
], nil)
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 428
def self.bot
Thread.current[:bot] ||= Union.new(Utils::Set[], nil)
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 806
def self.builtin_global_variable_type(var)
case var
when :$_, :$/, :$\, :$,, :$;
Type.optional(Type::Instance.new(Type::Builtin[:str]))
when :$0, :$PROGRAM_NAME
Type::Instance.new(Type::Builtin[:str])
when :$~
Type.optional(Type::Instance.new(Type::Builtin[:matchdata]))
when :$., :$$
Type::Instance.new(Type::Builtin[:int])
when :$?
Type.optional(Type::Instance.new(Type::Builtin[:int]))
when :$!
Type.optional(Type::Instance.new(Type::Builtin[:exc]))
when :$@
str = Type::Instance.new(Type::Builtin[:str])
base_ty = Type::Instance.new(Type::Builtin[:ary])
Type.optional(Type::Array.new(Type::Array::Elements.new([], str), base_ty))
when :$*, :$:, :$LOAD_PATH, :$", :$LOADED_FEATURES
str = Type::Instance.new(Type::Builtin[:str])
base_ty = Type::Instance.new(Type::Builtin[:ary])
Type::Array.new(Type::Array::Elements.new([], str), base_ty)
when :$<
:ARGF
when :$>
:STDOUT
when :$DEBUG
Type.bool
when :$FILENAME
Type::Instance.new(Type::Builtin[:str])
when :$stdin
:STDIN
when :$stdout
:STDOUT
when :$stderr
:STDERR
when :$VERBOSE
Type.bool.union(Type.nil)
else
nil
end
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 747
def self.gen_hash(base_ty = Type::Instance.new(Type::Builtin[:hash]))
hg = HashGenerator.new
yield hg
Type::Hash.new(Type::Hash::Elements.new(hg.map_tys), base_ty)
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 753
def self.guess_literal_type(obj)
case obj
when ::Symbol
Type::Symbol.new(obj, Type::Instance.new(Type::Builtin[:sym]))
when ::Integer
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:int]))
when ::Rational
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:rational]))
when ::Complex
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:complex]))
when ::Float
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:float]))
when ::Class
return Type.any if obj < Exception
case obj
when ::Object
Type::Builtin[:obj]
when ::Array
Type::Builtin[:ary]
else
raise "unknown class: #{ obj.inspect }"
end
when ::TrueClass
Type::Instance.new(Type::Builtin[:true])
when ::FalseClass
Type::Instance.new(Type::Builtin[:false])
when ::Array
base_ty = Type::Instance.new(Type::Builtin[:ary])
lead_tys = obj.map {|arg| guess_literal_type(arg) }
Type::Array.new(Type::Array::Elements.new(lead_tys), base_ty)
when ::Hash
Type.gen_hash do |h|
obj.each do |k, v|
k_ty = guess_literal_type(k).globalize(nil, {}, Config.current.options[:type_depth_limit])
v_ty = guess_literal_type(v)
h[k_ty] = v_ty
end
end
when ::String
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:str]))
when ::Regexp
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:regexp]))
when ::NilClass
Type.nil
when ::Range
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:range]))
when ::Encoding
Type::Literal.new(obj, Type::Instance.new(Type::Builtin[:encoding]))
else
raise "unknown object: #{ obj.inspect }"
end
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 23
def self.match?(ty1, ty2)
# both ty1 and ty2 should be global
# ty1 is always concrete; it should not have type variables
# ty2 might be abstract; it may have type variables
case ty2
when Type::Var
{ ty2 => ty1 }
when Type::Any
{}
when Type::Union
subst = nil
ty2.each_child_global do |ty2|
# this is very conservative to create subst:
# Type.match?( int | str, int | X) creates { X => int | str } but should be { X => str }???
subst2 = Type.match?(ty1, ty2)
next unless subst2
subst = Type.merge_substitution(subst, subst2)
end
subst
else
case ty1
when Type::Var then raise "should not occur"
when Type::Any
subst = {}
ty2.each_free_type_variable do |tyvar|
subst[tyvar] = Type.any
end
subst
when Type::Union
subst = nil
ty1.each_child_global do |ty1|
subst2 = Type.match?(ty1, ty2)
next unless subst2
subst = Type.merge_substitution(subst, subst2)
end
subst
else
if ty2.is_a?(Type::ContainerType)
# ty2 may have type variables
return nil if ty1.class != ty2.class
ty1.match?(ty2)
elsif ty1.is_a?(Type::ContainerType)
nil
else
ty1.consistent?(ty2) ? {} : nil
end
end
end
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 73
def self.merge_substitution(subst1, subst2)
if subst1
subst1 = subst1.dup
subst2.each do |tyvar, ty|
if subst1[tyvar]
subst1[tyvar] = subst1[tyvar].union(ty)
else
subst1[tyvar] = ty
end
end
subst1
else
subst2
end
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 5
def initialize
raise "cannot instantiate abstract type"
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 89
def each_child
yield self
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 93
def each_child_global
yield self
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 97
def each_free_type_variable
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 161
def generate_substitution
{}
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 11
def globalize(_env, _visited, _depth)
self
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 174
def include_untyped?(_scratch)
false
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 19
def limit_size(limit)
self
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 15
def localize(env, _alloc_site, _depth)
return env, self
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 170
def remove_type_vars
substitute(DummySubstitution, Config.current.options[:type_depth_limit])
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 157
def substitute(_subst, _depth)
raise "cannot substitute abstract type: #{ self.class }"
end
# File typeprof-0.21.1/lib/typeprof/type.rb, line 100
def union(other)
return self if self == other # fastpath
ty1, ty2 = self, other
case
when ty1.is_a?(Union)
ty1_types = ty1.types
ty1_elems = ty1.elems
when ty1.is_a?(Array) || ty1.is_a?(Hash)
ty1_types = Utils::Set[]
ty1_elems = {[ty1.class, ty1.base_type] => ty1.elems}
else
ty1_types = ty1_elems = nil
end
case
when ty2.is_a?(Union)
ty2_types = ty2.types
ty2_elems = ty2.elems
when ty2.is_a?(Array) || ty2.is_a?(Hash)
ty2_types = Utils::Set[]
ty2_elems = {[ty2.class, ty2.base_type] => ty2.elems}
else
ty2_types = ty2_elems = nil
end
if ty1_types && ty2_types
ty = ty1_types.sum(ty2_types)
all_elems = ty1_elems.dup || {}
ty2_elems&.each do |key, elems|
all_elems[key] = union_elems(all_elems[key], elems)
end
all_elems = nil if all_elems.empty?
Type::Union.create(ty, all_elems)
elsif ty1_types
Type::Union.create(ty1_types.add(ty2), ty1_elems)
elsif ty2_types
Type::Union.create(ty2_types.add(ty1), ty2_elems)
else
Type::Union.create(Utils::Set[ty1, ty2], nil)
end
end