module TypedRb::Types::Polymorphism::TypeOperations
Common operations on types and restrictions.
Public Instance Methods
add_to_send_bubble_constraints(receiver, send_args)
click to toggle source
if the type variable is not bound, we try to find the variable in an upper typing context to satisfy the constraint there. If no container context is found, we fail the unification run unless unbound vars are allowed.
# File lib/typed/types/polymorphism/unification.rb, line 98 def add_to_send_bubble_constraints(receiver, send_args) return check_unbound_receivers(receiver, send_args) if receiver.nil? vars = receiver[:vars].keys.select do |var| Types::TypingContext.include?(var.variable) end return check_unbound_receivers(receiver, send_args) if vars.empty? vars.each do |var| @to_bubble << [var, send_args] end end
can_apply?(fn, arg_types)
click to toggle source
# File lib/typed/types/polymorphism/unification.rb, line 114 def can_apply?(fn, arg_types) if fn.dynamic? true else arg_types.each_with_index do |arg, i| fn_arg = fn.from[i] if arg.is_a?(TypeVariable) if graph[arg][:lower_type] begin type = [graph[arg][:lower_type], fn_arg].min graph[arg][:lower_type] = type rescue TypedRb::Types::Polymorphism::UnificationError value_l = graph[arg][:lower_type] value_r = fn_arg raise TypedRb::Types::UncomparableTypes.new(value_l, value_r, nil, ", #{value_l} cannot be compared to #{value_r}") end else graph[arg][:lower_type] = fn_arg end else compatible_lt_type?(arg, fn_arg) end end end end
check_unbound_receivers(receiver, send_args)
click to toggle source
# File lib/typed/types/polymorphism/unification.rb, line 109 def check_unbound_receivers(receiver, send_args) return if @allow_unbound_receivers fail UnificationError, "Unbound variable #{receiver} type acting as receiver for #{send_args[:message]}" end
compatible_gt_type?(value_l, value_r, join_if_false = true)
click to toggle source
# File lib/typed/types/polymorphism/unification.rb, line 35 def compatible_gt_type?(value_l, value_r, join_if_false = true) value_l > value_r ? value_l : value_r rescue Types::UncomparableTypes, ArgumentError if join_if_false value_l.join(value_r) else raise Types::UncomparableTypes.new(value_l, value_r) end end
compatible_lt_type?(value_l, value_r)
click to toggle source
# File lib/typed/types/polymorphism/unification.rb, line 45 def compatible_lt_type?(value_l, value_r) error_message = "Error checking type, #{value_l} is not a subtype of #{value_r}" begin value_l <= value_r ? value_l : fail(UnificationError, error_message) rescue ArgumentError raise(Types::UncomparableTypes.new(value_l, value_r, nil, ", #{value_l} is not a subtype of #{value_r}")) end end
compatible_send_type?(receiver, send_args)
click to toggle source
This function does not return the infered type. Types
are assigned as a side effect.
# File lib/typed/types/polymorphism/unification.rb, line 56 def compatible_send_type?(receiver, send_args) return_type = send_args[:return] arg_types = send_args[:args] message = send_args[:message] inferred_receiver = infer_receiver(receiver) if inferred_receiver klass, function = inferred_receiver.find_function_type(message, arg_types.size, false) if function.is_a?(Types::TyDynamicFunction) # TODO: should I bind the var to type dynamic in this case? graph[return_type][:upper_type] = Types::TyDynamic.new(Object) graph[return_type][:lower_type] = Types::TyDynamic.new(Object) return true end if function && can_apply?(function, arg_types) if return_type && graph[return_type][:upper_type] compatible_gt_type?(graph[return_type][:upper_type], function.to, false) else graph[return_type][:upper_type] = function.to end else return true if klass != inferred_receiver.ruby_type fail UnificationError, "Message #{message} not found for type variable #{receiver}" end else add_to_send_bubble_constraints(receiver, send_args) end end
compatible_type?(value_l, t, value_r)
click to toggle source
Check if two types are compatible for a certain restriction. If no join type is possible for a particular restriction, a UncomparableTypes
error is raised.
# File lib/typed/types/polymorphism/unification.rb, line 18 def compatible_type?(value_l, t, value_r) if value_l.nil? || value_r.nil? value_l || value_r else case t when :gt # assignations, e.g v = Int, v = Num => Num compatible_gt_type?(value_l, value_r) when :lt # applications, return e.g. return (Int, Num) => Int compatible_lt_type?(value_l, value_r) when :send compatible_send_type?(value_l, value_r) else fail UnificationError, "Unknown type constraint #{t}" end end end
infer_receiver(receiver)
click to toggle source
# File lib/typed/types/polymorphism/unification.rb, line 84 def infer_receiver(receiver) if receiver.is_a?(Hash) receiver[:upper_type] = receiver[:lower_type] if receiver[:upper_type].nil? receiver[:upper_type].as_object_type if receiver[:upper_type] else receiver end end