Class: RaaP::MethodType

Inherits:
Object
  • Object
show all
Defined in:
lib/raap/method_type.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(method, type_params_decl: [], type_args: [], self_type: nil, instance_type: nil, class_type: nil) ⇒ MethodType

Returns a new instance of MethodType.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/raap/method_type.rb', line 7

def initialize(method, type_params_decl: [], type_args: [], self_type: nil, instance_type: nil, class_type: nil)
  rbs =
    case method
    when ""
      raise ArgumentError, "method type is empty"
    when String
      ::RBS::Parser.parse_method_type(method, require_eof: true) or raise
    when ::RBS::MethodType
      method
    else
      raise "bad method #{method}"
    end

  params = (type_params_decl + rbs.type_params).uniq
  ts = TypeSubstitution.new(params, type_args)
  @rbs = ts.method_type_sub(rbs, self_type: self_type, instance_type: instance_type, class_type: class_type)
  function_or_untypedfunction = __skip__ = @rbs.type
  @fun_type = FunctionType.new(function_or_untypedfunction)
  @type_check = ::RBS::Test::TypeCheck.new(
    self_class: (_ = self_type),
    instance_class: (_ = instance_type),
    class_class: (_ = class_type),
    builder: RBS.builder,
    sample_size: 100,
    unchecked_classes: []
  )
end

Instance Attribute Details

#rbsObject (readonly)

Returns the value of attribute rbs.



5
6
7
# File 'lib/raap/method_type.rb', line 5

def rbs
  @rbs
end

Instance Method Details

#arguments_to_symbolic_call(size: 10) ⇒ Object



39
40
41
42
43
44
# File 'lib/raap/method_type.rb', line 39

def arguments_to_symbolic_call(size: 10)
  args, kwargs = @fun_type.arguments_to_symbolic_call(size: size)
  block = pick_block(size: size)

  [args, kwargs, block]
end

#check_return(return_value) ⇒ Object



106
107
108
# File 'lib/raap/method_type.rb', line 106

def check_return(return_value)
  @type_check.value(return_value, rbs.type.return_type)
end

#pick_arguments(size: 10) ⇒ Object



35
36
37
# File 'lib/raap/method_type.rb', line 35

def pick_arguments(size: 10)
  SymbolicCaller.new(arguments_to_symbolic_call(size: size)).eval
end

#pick_block(size: 10) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/raap/method_type.rb', line 46

def pick_block(size: 10)
  block = @rbs.block
  return nil if block.nil?
  return nil if (block.required == false) && [true, false].sample

  args_name = []
  args_source = []
  resource = [*'a'..'z']
  case fun = block.type
  when ::RBS::Types::Function
    # FIXME: Support keyword types
    fun.required_positionals.each do
      resource.shift.tap do |name|
        args_name << name
        args_source << name
      end
    end
    fun.optional_positionals.each do |param|
      resource.shift.tap do |name|
        default = Type.new(param.type).pick(size: size)
        args_name << name
        # FIXME: Support any object
        args_source << "#{name} = #{default.inspect}"
      end
    end
    fun.rest_positionals&.yield_self do |_|
      resource.shift.tap do |name|
        args_name << "*#{name}"
        args_source << "*#{name}"
      end
    end
    fun.trailing_positionals.each do
      resource.shift.tap do |name|
        args_name << name
        args_source << name
      end
    end
  end
  # Hack: Use local variable in eval
  fixed_return_value = Type.new(block.type.return_type).pick(size: size)
  _ = fixed_return_value
  type_check = @type_check
  _ = type_check
  eval(<<~RUBY) # rubocop:disable Security/Eval
    -> (#{args_source.join(', ')}) do
      i = 0
      type_check.zip_args([#{args_name.join(', ')}], block.type) do |val, param|
        unless type_check.value(val, param.type)
          raise TypeError, "block argument type mismatch: expected `(\#{fun.param_to_s})`, got \#{BindCall.inspect([#{args_name.join(', ')}])}"
        end

        Coverage.log_with_type("block_param_\#{i}", param.type)
        i += 1
      end
      Coverage.log_with_type("block_return", block.type.return_type)
      fixed_return_value
    end
  RUBY
end