Class: Yadriggy::RubyTypeInferer
- Inherits:
-
RubyTypeChecker
- Object
- Checker
- TypeChecker
- RubyTypeChecker
- Yadriggy::RubyTypeInferer
- Defined in:
- lib/yadriggy/ruby_typeinfer.rb
Overview
Type checker for Ruby with type inference.
Direct Known Subclasses
Constant Summary
Constants included from Yadriggy
Instance Method Summary collapse
- #binary_type(bin_expr, right_t, left_t) ⇒ Object
-
#bind_local_var(env, ast, var_type, is_def = true) ⇒ Object
Binds a local variable name to a type.
-
#get_instance_variable_type(key, ivar, is_valid_type, value_type) ⇒ Type
Obtains the type of the given instance variable ‘ivar` declared in the given class (i.e. module) or the instance object `key`.
-
#get_return_type(an_ast, mthd, new_tenv, arg_types) ⇒ Object
Overrides Yadriggy::RubyTypeChecker#get_return_type.
- #is_attr_accessor?(expr, tenv, name) ⇒ Boolean
-
#to_non_instance_type(t) ⇒ Object
When the initial value of a variable is an InstanceType, the type of the variable has to be a RubyCass type corresponding to that instance type.
Methods inherited from RubyTypeChecker
#clear_references, #get_call_expr_type, #get_name_type, #initialize, #lookup_builtin, #lookup_ruby_classes, #references, #type_assert_params, #type_assert_subsume, #type_parameters
Methods inherited from TypeChecker
#add_typedef, #check, #error_group, #initialize, #make_base_env, #type, #type_as, #type_assert, #type_assert_false, #type_assert_later, #type_env, #typecheck, #typedef
Methods inherited from Checker
all_rules, #apply_typing_rule, #ast, #ast_env, #check, #check_all, check_init_class, #check_later, #error, #error_found!, #error_group, find_rule_entry, #initialize, #make_base_env, #proceed, rule
Methods included from Yadriggy
debug, debug=, define_syntax, reify
Constructor Details
This class inherits a constructor from Yadriggy::RubyTypeChecker
Instance Method Details
#binary_type(bin_expr, right_t, left_t) ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/yadriggy/ruby_typeinfer.rb', line 195 def binary_type(bin_expr, right_t, left_t) op = bin_expr.op case op when :'&&', :'||', :and, :or # not overridable return UnionType.new([right_t, left_t]) when :>, :>=, :<, :<=, :==, :===, :!= if left_t <= RubyClass::Numeric return RubyClass::Boolean end when :**, :*, :/, :%, :+, :- if left_t <= RubyClass::Numeric if left_t <= RubyClass::Float || right_t <= RubyClass::Float return RubyClass::Float else return RubyClass::Integer end end when :<<, :>>, :&, :|, :^ return RubyClass::Integer if left_t <= RubyClass::Integer # when :=~, :!~, :<=> end if left_t <= RubyClass::String if op == :% || op == :+ || op == :<< return RubyClass::String elsif op == :=~ || op == :<=> return UnionType.new(RubyClass::Integer, RubyClass::NilClass) elsif op == :!~ return RubyClass::Boolean end end call_expr = Call.make(receiver: bin_expr.left, name: op, args: [bin_expr.right], parent: bin_expr.parent) return get_call_expr_type(call_expr, type_env, op) end |
#bind_local_var(env, ast, var_type, is_def = true) ⇒ Object
Binds a local variable name to a type.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/yadriggy/ruby_typeinfer.rb', line 17 def bind_local_var(env, ast, var_type, is_def=true) unless var_type.nil? t = if UnionType.role(var_type) ts = UnionType.role(var_type).types UnionType.new(ts.map {|t| to_non_instance_type(t) }) else ins_t = InstanceType.role(var_type) to_non_instance_type(var_type) end lvt = LocalVarType.new(t.copy(OptionalRole), is_def ? ast : nil) env.bind_name(ast, lvt) @typetable[ast] = lvt end end |
#get_instance_variable_type(key, ivar, is_valid_type, value_type) ⇒ Type
Obtains the type of the given instance variable ‘ivar` declared in the given class (i.e. module) or the instance object `key`. If the type of `ivar` is not defined, `value_type` is recorded as its type.
158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/yadriggy/ruby_typeinfer.rb', line 158 def get_instance_variable_type(key, ivar, is_valid_type, value_type) td = add_typedef(key) ivar_t = td[ivar] if ivar_t.nil? td[ivar] = value_type else type_assert_subsume(ivar_t, value_type, "bad type value for #{ivar.name}") if is_valid_type ivar_t end end |
#get_return_type(an_ast, mthd, new_tenv, arg_types) ⇒ Object
Overrides Yadriggy::RubyTypeChecker#get_return_type.
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/yadriggy/ruby_typeinfer.rb', line 269 def get_return_type(an_ast, mthd, new_tenv, arg_types) m_ast = an_ast.root.reify(mthd) type_assert_false(m_ast.nil?, "no source code: for #{mthd}") (@syntax.check(m_ast.tree) || @syntax.raise_error) if @syntax m_ast.tree.params.each_with_index do |p, i| bind_local_var(new_tenv, p, arg_types[i]) end nparams = m_ast.tree.params.length m_ast.tree.optionals.each_with_index do |p, i| bind_local_var(new_tenv, p, arg_types[nparams + i]) end mtype = MethodType.role(type(m_ast.tree, new_tenv)) type_assert(mtype, 'not a method type') type_assert_params(mtype.params, arg_types, 'argument type mismatch') mtype.result end |
#is_attr_accessor?(expr, tenv, name) ⇒ Boolean
90 91 92 93 94 95 |
# File 'lib/yadriggy/ruby_typeinfer.rb', line 90 def is_attr_accessor?(expr, tenv, name) self_t = type_env.context !self_t.nil? && (self_t.method_defined?(name) || self_t.private_method_defined?(name)) end |
#to_non_instance_type(t) ⇒ Object
When the initial value of a variable is an InstanceType, the type of the variable has to be a RubyCass type corresponding to that instance type. The variable type can be set to that InstanceType only when it is guaranteed that the value of the variable is never changed later.
39 40 41 42 43 44 45 46 |
# File 'lib/yadriggy/ruby_typeinfer.rb', line 39 def to_non_instance_type(t) ins_t = InstanceType.role(t) if ins_t.nil? t else ins_t.supertype end end |