Class: TypedRb::Types::TyFunction

Inherits:
Type show all
Includes:
Comparable
Defined in:
lib/typed/types/ty_function.rb

Direct Known Subclasses

TyDynamicFunction, TyGenericFunction

Instance Attribute Summary collapse

Attributes inherited from Type

#node

Instance Method Summary collapse

Methods inherited from Type

#either?, #stack_jump?

Constructor Details

#initialize(from, to, parameters_info = nil, node = nil) ⇒ TyFunction

Returns a new instance of TyFunction.



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/typed/types/ty_function.rb', line 9

def initialize(from, to, parameters_info = nil, node = nil)
  super(node)
  @from            = from.is_a?(Array) ? from : [from]
  @to              = to
  @parameters_info = parameters_info
  if @parameters_info.nil?
    @parameters_info = @from.map { |type| [:req, type] }
  end
  @arity           = parse_function_arity
  @min_arity       = parse_min_function_arity
  @block_type      = nil
end

Instance Attribute Details

#arityObject

Returns the value of attribute arity.



6
7
8
# File 'lib/typed/types/ty_function.rb', line 6

def arity
  @arity
end

#block_typeObject

Returns the value of attribute block_type.



6
7
8
# File 'lib/typed/types/ty_function.rb', line 6

def block_type
  @block_type
end

#fromObject

Returns the value of attribute from.



6
7
8
# File 'lib/typed/types/ty_function.rb', line 6

def from
  @from
end

#min_arityObject

Returns the value of attribute min_arity.



6
7
8
# File 'lib/typed/types/ty_function.rb', line 6

def min_arity
  @min_arity
end

#nameObject



45
46
47
# File 'lib/typed/types/ty_function.rb', line 45

def name
  @name || 'lambda'
end

#parameters_infoObject

Returns the value of attribute parameters_info.



6
7
8
# File 'lib/typed/types/ty_function.rb', line 6

def parameters_info
  @parameters_info
end

#toObject

Returns the value of attribute to.



6
7
8
# File 'lib/typed/types/ty_function.rb', line 6

def to
  @to
end

Instance Method Details

#<=>(other) ⇒ Object



120
121
122
123
124
125
126
127
# File 'lib/typed/types/ty_function.rb', line 120

def <=>(other)
  if other.is_a?(TyFunction)
    # TODO: implement!
    raise 'Non implemented yet'
  else
    TyObject.new(Method, node) <=> other
  end
end

#apply_bindings(bindings_map) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/typed/types/ty_function.rb', line 99

def apply_bindings(bindings_map)
  from.each_with_index do |from_type, i|
    if from_type.is_a?(Polymorphism::TypeVariable)
      from_type.apply_bindings(bindings_map)
      from[i] = from_type.bound if from_type.bound
    elsif from_type.is_a?(TyGenericSingletonObject) || from_type.is_a?(TyGenericObject)
      from_type.apply_bindings(bindings_map)
    end
  end

  if to.is_a?(Polymorphism::TypeVariable)
    @to = to.apply_bindings(bindings_map)
    @to = to.bound if to.bound
  elsif to.respond_to?(:apply_bindings)
    @to = to.apply_bindings(bindings_map)
  end

  block_type.apply_bindings(bindings_map) if block_type && block_type.generic?
  self
end

#arg_compatible?(num_args) ⇒ Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/typed/types/ty_function.rb', line 27

def arg_compatible?(num_args)
  num_args >= min_arity && (arity == Float::INFINITY || arity == num_args)
end

#check_args_application(actual_arguments, context) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/typed/types/ty_function.rb', line 49

def check_args_application(actual_arguments, context)
  parameters_info.each_with_index do |(require_info, arg_name), index|
    actual_argument = actual_arguments[index]
    from_type = from[index]
    if actual_argument.nil? && require_info != :opt
      error_msg = "Type error checking function '#{name}': Missing mandatory argument #{arg_name} in #{receiver_type}##{message}"
      fail TypeCheckError.new(error_msg, node)
    else
      unless actual_argument.nil? # opt if this is nil
        actual_argument_type = actual_argument.check_type(context)
        unless actual_argument_type.compatible?(from_type, :lt)
          error_message = "Type error checking function '#{name}': #{error_message} #{from_type} expected, #{argument_type} found"
          fail TypeCheckError.new(error_message, node)
        end
      end
    end
  end
  self
end

#compatible?(other_type, relation = :lt) ⇒ Boolean

(S1 -> S2) < (T1 -> T2) => T1 < S1 && S2 < T2 Contravariant in the input, covariant in the output

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/typed/types/ty_function.rb', line 71

def compatible?(other_type, relation = :lt)
  if other_type.is_a?(TyGenericFunction)
    other_type.compatible?(self, relation == :lt ? :gt : :lt)
  elsif other_type.is_a?(TyFunction)
    other_from = deconstruct_from_arguments(other_type)
    from.each_with_index do |arg, i|
      other_arg = other_from[i]
      return false unless arg.compatible?(other_arg, :gt)
    end
    return false unless to.compatible?(other_type.to, :lt)
  else
    fail TypeCheckError.new("Type error checking function '#{name}': Comparing function type with no function type")
  end
  true
end

#deconstruct_from_arguments(other_type) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/typed/types/ty_function.rb', line 87

def deconstruct_from_arguments(other_type)
  if from.size == other_type.from.size
    other_type.from
  elsif from.size > 1 && other_type.from.size == 1 && other_type.from.first.ruby_type.ancestors.include?(Pair)
    other_type.from.first.type_vars(recursive: false)
  elsif from.size > 1 && other_type.from.size == 1 && other_type.from.first.ruby_type.ancestors.include?(Array)
    other_type.from.first.type_vars(recursive: false) * from.size
  else
    other_type.from
  end
end

#dynamic?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/typed/types/ty_function.rb', line 35

def dynamic?
  false
end

#generic?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/typed/types/ty_function.rb', line 31

def generic?
  false
end

#to_sObject



39
40
41
42
43
# File 'lib/typed/types/ty_function.rb', line 39

def to_s
  args = @from.map(&:to_s).join(', ')
  args = "#{args}, &#{block_type}" if block_type
  "(#{args} -> #{@to})"
end

#with_block_type(type) ⇒ Object



22
23
24
25
# File 'lib/typed/types/ty_function.rb', line 22

def with_block_type(type)
  @block_type = type
  self
end