class TypedRb::Model::TmFun
A instance/class function definition expression
Attributes
args[RW]
body[RW]
name[RW]
owner[RW]
owner_type[R]
Public Class Methods
new(owner, name, args, body, node)
click to toggle source
Calls superclass method
TypedRb::Model::Expr::new
# File lib/typed/model/tm_fun.rb, line 11 def initialize(owner, name, args, body, node) super(node) @owner = parse_owner(owner) @name = name @args = args @body = body @arg_count = args.count { |arg| arg.first != :blockarg } @has_block = args.detect { |arg| arg.first == :blockarg } end
with_fresh_bindings(klass, function_type) { || ... }
click to toggle source
TODO: 1 Find free type variables for the generic function. 2 Create a new local typing context for the generic function 3 Add free type variables to the typing context
# File lib/typed/model/tm_fun.rb, line 44 def self.with_fresh_bindings(klass, function_type) if function_type.generic? Types::TypingContext.push_context(:method) function_type.free_type_variables(klass).each do |type_var| # This will add the variable to the context Types::TypingContext.type_variable_for_function_type(type_var) end yield if block_given? # # Since every single time we find the generic type the same instance # # will be returned, the local_typing_context will still be associated. # # This is the reason we need to build a new typing context cloning this # # one while type materialization. function_type.local_typing_context = Types::TypingContext.pop_context else yield if block_given? end function_type end
Public Instance Methods
check_type(context)
click to toggle source
# File lib/typed/model/tm_fun.rb, line 21 def check_type(context) compute_owner_type(context) function_klass_type, function_type = owner_type.find_function_type(name, @arg_count, @has_block) if function_type.nil? || function_type.dynamic? TypedRb.log_dynamic_warning(node, owner_type, name) return Types::TyUnit.new(node) end context = setup_context(context, function_type) # check the body with the new bindings for the args TmFun.with_fresh_bindings(function_klass_type, function_type) do body_return_type = body.check_type(context) TypedRb::Types::TypingContext.function_context_pop check_return_type(context, function_type, body_return_type) end end
Private Instance Methods
check_return_type(context, function_type, body_return_type)
click to toggle source
# File lib/typed/model/tm_fun.rb, line 132 def check_return_type(context, function_type, body_return_type) return function_type.to if function_type.to.instance_of?(Types::TyUnit) # Same as before but for the return type function_type_to = function_type.to.is_a?(Types::TyGenericSingletonObject) ? function_type.to.clone : function_type.to if body_return_type.either? compatible_body = body_return_type[:normal].compatible?(function_type_to, :lt) compatible_return = if body_return_type.return? body_return_type[:return].wrapped_type.compatible?(function_type_to, :lt) else true end if compatible_body && compatible_return return function_type_to else if compatible_body == false fail Types::UncomparableTypes.new(function_type_to, body_return_type[:normal], node) else fail Types::UncomparableTypes.new(function_type_to, body_return_type[:return], node) end end else body_return_type = body_return_type.wrapped_type.check_type(context) if body_return_type.stack_jump? return function_type if body_return_type.compatible?(function_type_to, :lt) end # TODO: # A TyObject(Symbol) should be returned not the function type # x = def id(x); x; end / => x == :id error_message = ". Wrong return type, expected #{function_type.to}, found #{body_return_type}." body_return_type.compatible?(function_type_to, :lt) fail Types::UncomparableTypes.new(function_type.to, body_return_type, node, error_message) end
compute_owner_type(context)
click to toggle source
# File lib/typed/model/tm_fun.rb, line 74 def compute_owner_type(context) @owner_type = if owner == :self context.get_self elsif owner.nil? context.get_self.as_object_type else owner.check_type(context) end end
parse_owner(owner)
click to toggle source
# File lib/typed/model/tm_fun.rb, line 67 def parse_owner(owner) return nil if owner.nil? return :self if owner == :self || owner.type == :self # must be a class or other expression we can check the type owner end
process_arguments(context, function_type)
click to toggle source
# File lib/typed/model/tm_fun.rb, line 84 def process_arguments(context, function_type) args.each_with_index do |arg, i| function_arg_type = function_type.from[i] # Generic arguments are parsed by runtime without checking constraints since they are not available at parsing type. # We need to run unification in them before using the type to detect invalid type argument applications. function_arg_type = function_arg_type.self_materialize.as_object_type if function_arg_type.is_a?(Types::TyGenericSingletonObject) context = case arg.first when :arg, :restarg context.add_binding(arg[1], function_arg_type) when :optarg declared_arg_type = arg.last.check_type(context) context.add_binding(arg[1], function_arg_type) if declared_arg_type.compatible?(function_arg_type) when :blockarg if function_type.block_type context.add_binding(arg[1], function_type.block_type) else fail TypeCheckError.new("Error type checking function #{owner}##{name}: Missing block type for block argument #{arg[1]}", node) end when :mlhs tm_mlhs = arg[1] tm_mlhs.check_type(function_arg_type, context) else fail TypeCheckError.new("Error type checking function #{owner}##{name}: Unknown type of arg #{arg.first}", node) end end context end
setup_context(context, function_type)
click to toggle source
# File lib/typed/model/tm_fun.rb, line 112 def setup_context(context, function_type) context = process_arguments(context, function_type) # pointing self to the right type self_type = if owner_type.is_a?(Types::TyExistentialType) owner_type.self_variable else owner_type end context = context.add_binding(:self, self_type) # adding yield binding if present context = context.add_binding(:yield, function_type.block_type) if function_type.block_type # set the current function context TypedRb::Types::TypingContext.function_context_push(self_type, name, function_type.from) context end