typed.rb 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +26 -0
  3. data/bin/typed.rb +110 -0
  4. data/lib/typed/language.rb +131 -0
  5. data/lib/typed/model/tm_abs.rb +104 -0
  6. data/lib/typed/model/tm_array_literal.rb +25 -0
  7. data/lib/typed/model/tm_boolean.rb +15 -0
  8. data/lib/typed/model/tm_boolean_operator.rb +34 -0
  9. data/lib/typed/model/tm_break.rb +24 -0
  10. data/lib/typed/model/tm_case_when.rb +38 -0
  11. data/lib/typed/model/tm_class.rb +63 -0
  12. data/lib/typed/model/tm_const.rb +29 -0
  13. data/lib/typed/model/tm_defined.rb +19 -0
  14. data/lib/typed/model/tm_error.rb +16 -0
  15. data/lib/typed/model/tm_float.rb +15 -0
  16. data/lib/typed/model/tm_for.rb +42 -0
  17. data/lib/typed/model/tm_fun.rb +165 -0
  18. data/lib/typed/model/tm_global_var.rb +22 -0
  19. data/lib/typed/model/tm_global_var_assignment.rb +20 -0
  20. data/lib/typed/model/tm_hash_literal.rb +32 -0
  21. data/lib/typed/model/tm_if_else.rb +24 -0
  22. data/lib/typed/model/tm_instance_var.rb +23 -0
  23. data/lib/typed/model/tm_instance_var_assignment.rb +32 -0
  24. data/lib/typed/model/tm_int.rb +15 -0
  25. data/lib/typed/model/tm_local_var_asgn.rb +35 -0
  26. data/lib/typed/model/tm_mass_asgn.rb +60 -0
  27. data/lib/typed/model/tm_mlhs.rb +87 -0
  28. data/lib/typed/model/tm_module.rb +51 -0
  29. data/lib/typed/model/tm_next.rb +24 -0
  30. data/lib/typed/model/tm_nil.rb +14 -0
  31. data/lib/typed/model/tm_range_literal.rb +30 -0
  32. data/lib/typed/model/tm_regexp.rb +27 -0
  33. data/lib/typed/model/tm_rescue.rb +27 -0
  34. data/lib/typed/model/tm_return.rb +24 -0
  35. data/lib/typed/model/tm_s_class.rb +30 -0
  36. data/lib/typed/model/tm_self.rb +22 -0
  37. data/lib/typed/model/tm_send.rb +300 -0
  38. data/lib/typed/model/tm_sequencing.rb +53 -0
  39. data/lib/typed/model/tm_string.rb +15 -0
  40. data/lib/typed/model/tm_string_interpolation.rb +21 -0
  41. data/lib/typed/model/tm_super.rb +27 -0
  42. data/lib/typed/model/tm_symbol.rb +15 -0
  43. data/lib/typed/model/tm_symbol_interpolation.rb +21 -0
  44. data/lib/typed/model/tm_try.rb +29 -0
  45. data/lib/typed/model/tm_var.rb +28 -0
  46. data/lib/typed/model/tm_while.rb +43 -0
  47. data/lib/typed/model.rb +48 -0
  48. data/lib/typed/prelude.rb +939 -0
  49. data/lib/typed/prelude_existential_registry.bin +0 -0
  50. data/lib/typed/prelude_generic_registry.bin +0 -0
  51. data/lib/typed/prelude_registry.bin +0 -0
  52. data/lib/typed/runtime/ast_parser.rb +589 -0
  53. data/lib/typed/runtime/method_signature_processor.rb +72 -0
  54. data/lib/typed/runtime/normalization/validations.rb +47 -0
  55. data/lib/typed/runtime/normalization.rb +196 -0
  56. data/lib/typed/runtime/parser_context.rb +36 -0
  57. data/lib/typed/runtime/type_parser.rb +215 -0
  58. data/lib/typed/runtime/type_registry.rb +170 -0
  59. data/lib/typed/runtime/type_signature_processor.rb +34 -0
  60. data/lib/typed/runtime.rb +33 -0
  61. data/lib/typed/type_signature/parser.rb +240 -0
  62. data/lib/typed/types/polymorphism/existential_type_variable.rb +13 -0
  63. data/lib/typed/types/polymorphism/generic_comparisons.rb +134 -0
  64. data/lib/typed/types/polymorphism/generic_variables.rb +24 -0
  65. data/lib/typed/types/polymorphism/type_variable.rb +138 -0
  66. data/lib/typed/types/polymorphism/type_variable_register.rb +298 -0
  67. data/lib/typed/types/polymorphism/unification.rb +579 -0
  68. data/lib/typed/types/ty_boolean.rb +15 -0
  69. data/lib/typed/types/ty_dynamic.rb +39 -0
  70. data/lib/typed/types/ty_either.rb +168 -0
  71. data/lib/typed/types/ty_error.rb +18 -0
  72. data/lib/typed/types/ty_existential_type.rb +22 -0
  73. data/lib/typed/types/ty_function.rb +144 -0
  74. data/lib/typed/types/ty_generic_function.rb +115 -0
  75. data/lib/typed/types/ty_generic_object.rb +180 -0
  76. data/lib/typed/types/ty_generic_singleton_object.rb +238 -0
  77. data/lib/typed/types/ty_object.rb +256 -0
  78. data/lib/typed/types/ty_singleton_object.rb +78 -0
  79. data/lib/typed/types/ty_stack_jump.rb +44 -0
  80. data/lib/typed/types/ty_top_level_object.rb +38 -0
  81. data/lib/typed/types.rb +60 -0
  82. data/lib/typed/typing_context.rb +206 -0
  83. data/lib/typed/version.rb +3 -0
  84. data/lib/typed.rb +161 -0
  85. data/spec/lib/ast_parser_spec.rb +101 -0
  86. data/spec/lib/examples/animals.rb +44 -0
  87. data/spec/lib/examples/counter.rb +16 -0
  88. data/spec/lib/examples/if.rb +31 -0
  89. data/spec/lib/language_spec.rb +36 -0
  90. data/spec/lib/model/tm_abs_spec.rb +66 -0
  91. data/spec/lib/model/tm_array_literal_spec.rb +36 -0
  92. data/spec/lib/model/tm_case_when_spec.rb +39 -0
  93. data/spec/lib/model/tm_class_spec.rb +67 -0
  94. data/spec/lib/model/tm_defined_spec.rb +10 -0
  95. data/spec/lib/model/tm_for_spec.rb +150 -0
  96. data/spec/lib/model/tm_fun_spec.rb +11 -0
  97. data/spec/lib/model/tm_hash_literal_spec.rb +40 -0
  98. data/spec/lib/model/tm_mass_asgn_spec.rb +104 -0
  99. data/spec/lib/model/tm_module_spec.rb +42 -0
  100. data/spec/lib/model/tm_regexp_spec.rb +9 -0
  101. data/spec/lib/model/tm_return_spec.rb +47 -0
  102. data/spec/lib/model/tm_s_class_spec.rb +27 -0
  103. data/spec/lib/model/tm_self_spec.rb +19 -0
  104. data/spec/lib/model/tm_string_interpolation_spec.rb +10 -0
  105. data/spec/lib/model/tm_symbol_interpolation_spec.rb +10 -0
  106. data/spec/lib/model/tm_symbol_spec.rb +9 -0
  107. data/spec/lib/model/tm_while_spec.rb +141 -0
  108. data/spec/lib/polymorphism/type_variable_spec.rb +14 -0
  109. data/spec/lib/polymorphism/unification_spec.rb +328 -0
  110. data/spec/lib/prelude/array_spec.rb +263 -0
  111. data/spec/lib/prelude/class_spec.rb +12 -0
  112. data/spec/lib/prelude/enumerable_spec.rb +278 -0
  113. data/spec/lib/prelude/enumerator_spec.rb +101 -0
  114. data/spec/lib/prelude/hash_spec.rb +361 -0
  115. data/spec/lib/prelude/kernel_spec.rb +23 -0
  116. data/spec/lib/prelude/object_spec.rb +22 -0
  117. data/spec/lib/prelude/pair_spec.rb +16 -0
  118. data/spec/lib/prelude/showable_spec.rb +31 -0
  119. data/spec/lib/prelude/string_spec.rb +98 -0
  120. data/spec/lib/runtime/normalization_spec.rb +29 -0
  121. data/spec/lib/runtime/validations_spec.rb +56 -0
  122. data/spec/lib/runtime_spec.rb +503 -0
  123. data/spec/lib/type_signature/parser_spec.rb +239 -0
  124. data/spec/lib/types/comparisons_spec.rb +35 -0
  125. data/spec/lib/types/polymorphism/generic_comparisons_spec.rb +492 -0
  126. data/spec/lib/types/polymorphism/type_variable_register_spec.rb +128 -0
  127. data/spec/lib/types/ty_dynamic_spec.rb +103 -0
  128. data/spec/lib/types/ty_either_spec.rb +288 -0
  129. data/spec/lib/types/ty_error_spec.rb +18 -0
  130. data/spec/lib/types/ty_generic_object_spec.rb +78 -0
  131. data/spec/lib/types/ty_generic_singleton_object_spec.rb +288 -0
  132. data/spec/lib/types/typing_context_spec.rb +86 -0
  133. data/spec/lib/types_spec.rb +174 -0
  134. data/spec/lib/typing/boolean_asgn_spec.rb +134 -0
  135. data/spec/lib/typing/break_spec.rb +79 -0
  136. data/spec/lib/typing/generics_spec.rb +191 -0
  137. data/spec/lib/typing/instance_vars_spec.rb +103 -0
  138. data/spec/lib/typing/next_spec.rb +29 -0
  139. data/spec/lib/typing/op_asgn_spec.rb +104 -0
  140. data/spec/lib/typing/overriden_methods_spec.rb +31 -0
  141. data/spec/lib/typing/subtyping_spec.rb +112 -0
  142. data/spec/lib/typing/tm_boolean_operator_spec.rb +100 -0
  143. data/spec/lib/typing/tm_boolean_spec.rb +61 -0
  144. data/spec/lib/typing/tm_const_spec.rb +28 -0
  145. data/spec/lib/typing/tm_defined_spec.rb +12 -0
  146. data/spec/lib/typing/tm_fun_spec.rb +347 -0
  147. data/spec/lib/typing/tm_global_var_spec.rb +33 -0
  148. data/spec/lib/typing/tm_if_else_spec.rb +104 -0
  149. data/spec/lib/typing/tm_ignore_spec.rb +24 -0
  150. data/spec/lib/typing/tm_instance_vars_spec.rb +117 -0
  151. data/spec/lib/typing/tm_local_var_asgn_spec.rb +134 -0
  152. data/spec/lib/typing/tm_mlhs_spec.rb +164 -0
  153. data/spec/lib/typing/tm_module_spec.rb +89 -0
  154. data/spec/lib/typing/tm_raise_spec.rb +31 -0
  155. data/spec/lib/typing/tm_range_literal_spec.rb +25 -0
  156. data/spec/lib/typing/tm_regexp_spec.rb +14 -0
  157. data/spec/lib/typing/tm_return_spec.rb +45 -0
  158. data/spec/lib/typing/tm_send_casting_spec.rb +26 -0
  159. data/spec/lib/typing/tm_send_class_methods_spec.rb +42 -0
  160. data/spec/lib/typing/tm_send_generic_apply_spec.rb +103 -0
  161. data/spec/lib/typing/tm_send_generic_methods_spec.rb +77 -0
  162. data/spec/lib/typing/tm_send_initialize_spec.rb +68 -0
  163. data/spec/lib/typing/tm_send_lambda_spec.rb +135 -0
  164. data/spec/lib/typing/tm_send_spec.rb +217 -0
  165. data/spec/lib/typing/tm_send_yield_block_spec.rb +308 -0
  166. data/spec/lib/typing/tm_sequencing_spec.rb +174 -0
  167. data/spec/lib/typing/tm_string_interpolation_spec.rb +19 -0
  168. data/spec/lib/typing/tm_super_spec.rb +63 -0
  169. data/spec/lib/typing/tm_symbol_interpolation_spec.rb +19 -0
  170. data/spec/lib/typing/tm_symbol_spec.rb +14 -0
  171. data/spec/lib/typing/tm_try_spec.rb +73 -0
  172. data/spec/spec_helper.rb +140 -0
  173. metadata +216 -0
@@ -0,0 +1,42 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ class TmFor < Expr
7
+ attr_reader :condition, :body
8
+ def initialize(condition, body, node)
9
+ super(node)
10
+ @condition = condition
11
+ @body = body
12
+ end
13
+
14
+ def check_type(context)
15
+ condition.check_type(context)
16
+ result_type = body.check_type(context)
17
+ if result_type.stack_jump? && (result_type.next? || result_type.break?)
18
+ result_type.wrapped_type.check_type(context)
19
+ elsif result_type.either?
20
+ process_either_type(result_type, context)
21
+ else
22
+ result_type
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def process_either_type(either_type, context)
29
+ return_type = either_type[:return]
30
+ final_type = either_type.check_type(context, [:normal, :next, :break])
31
+ if return_type.nil?
32
+ final_type
33
+ else
34
+ new_either_type = Types::TyEither.new(node)
35
+ new_either_type[:return] = return_type
36
+ new_either_type[:normal] = final_type
37
+ new_either_type
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,165 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+ require_relative 'tm_mlhs'
4
+
5
+ module TypedRb
6
+ module Model
7
+ # A instance/class function definition expression
8
+ class TmFun < Expr
9
+ attr_accessor :name, :args, :body, :owner
10
+ attr_reader :owner_type
11
+
12
+ def initialize(owner, name, args, body, node)
13
+ super(node)
14
+ @owner = parse_owner(owner)
15
+ @name = name
16
+ @args = args
17
+ @body = body
18
+ @arg_count = args.count { |arg| arg.first != :blockarg }
19
+ @has_block = args.detect { |arg| arg.first == :blockarg }
20
+ end
21
+
22
+ def check_type(context)
23
+ compute_owner_type(context)
24
+
25
+ function_klass_type, function_type = owner_type.find_function_type(name, @arg_count, @has_block)
26
+
27
+ # fail TypeCheckError.new("Error type checking function #{owner}##{name}: Cannot find function type information for owner.", node)
28
+ # Missing type information stops the type checking process
29
+ # TODO: raise a warning here about the previous fact
30
+ return Types::TyUnit.new(node) if function_type.nil? || function_type.dynamic?
31
+
32
+ context = setup_context(context, function_type)
33
+ # check the body with the new bindings for the args
34
+ TmFun.with_fresh_bindings(function_klass_type, function_type) do
35
+ body_return_type = body.check_type(context)
36
+ TypedRb::Types::TypingContext.function_context_pop
37
+ check_return_type(context, function_type, body_return_type)
38
+ end
39
+ end
40
+
41
+ # TODO:
42
+ # 1 Find free type variables for the generic function.
43
+ # 2 Create a new local typing context for the generic function
44
+ # 3 Add free type variables to the typing context
45
+ def self.with_fresh_bindings(klass, function_type)
46
+ if function_type.generic?
47
+ Types::TypingContext.push_context(:method)
48
+ function_type.free_type_variables(klass).each do |type_var|
49
+ # This will add the variable to the context
50
+ Types::TypingContext.type_variable_for_function_type(type_var)
51
+ end
52
+
53
+ yield if block_given?
54
+
55
+ # # Since every single time we find the generic type the same instance
56
+ # # will be returned, the local_typing_context will still be associated.
57
+ # # This is the reason we need to build a new typing context cloning this
58
+ # # one while type materialization.
59
+ function_type.local_typing_context = Types::TypingContext.pop_context
60
+ else
61
+ yield if block_given?
62
+ end
63
+ function_type
64
+ end
65
+
66
+ private
67
+
68
+ def parse_owner(owner)
69
+ return nil if owner.nil?
70
+ return :self if owner == :self || owner.type == :self
71
+ # must be a class or other expression we can check the type
72
+ owner
73
+ end
74
+
75
+ def compute_owner_type(context)
76
+ @owner_type = if owner == :self
77
+ context.get_self
78
+ elsif owner.nil?
79
+ context.get_self.as_object_type
80
+ else
81
+ owner.check_type(context)
82
+ end
83
+ end
84
+
85
+ def process_arguments(context, function_type)
86
+ args.each_with_index do |arg, i|
87
+ function_arg_type = function_type.from[i]
88
+ # Generic arguments are parsed by runtime without checking constraints since they are not available at parsing type.
89
+ # We need to run unification in them before using the type to detect invalid type argument applications.
90
+ function_arg_type = function_arg_type.self_materialize if function_arg_type.is_a?(Types::TyGenericSingletonObject)
91
+ context = case arg.first
92
+ when :arg, :restarg
93
+ context.add_binding(arg[1], function_arg_type)
94
+ when :optarg
95
+ declared_arg_type = arg.last.check_type(context)
96
+ context.add_binding(arg[1], function_arg_type) if declared_arg_type.compatible?(function_arg_type)
97
+ when :blockarg
98
+ if function_type.block_type
99
+ context.add_binding(arg[1], function_type.block_type)
100
+ else
101
+ fail TypeCheckError.new("Error type checking function #{owner}##{name}: Missing block type for block argument #{arg[1]}", node)
102
+ end
103
+ when :mlhs
104
+ tm_mlhs = arg[1]
105
+ tm_mlhs.check_type(function_arg_type, context)
106
+ else
107
+ fail TypeCheckError.new("Error type checking function #{owner}##{name}: Unknown type of arg #{arg.first}", node)
108
+ end
109
+ end
110
+ context
111
+ end
112
+
113
+ def setup_context(context, function_type)
114
+ context = process_arguments(context, function_type)
115
+
116
+ # pointing self to the right type
117
+ self_type = if owner_type.is_a?(Types::TyExistentialType)
118
+ owner_type.self_variable
119
+ else
120
+ owner_type
121
+ end
122
+ context = context.add_binding(:self, self_type)
123
+
124
+ # adding yield binding if present
125
+ context = context.add_binding(:yield, function_type.block_type) if function_type.block_type
126
+
127
+ # set the current function context
128
+ TypedRb::Types::TypingContext.function_context_push(self_type, name, function_type.from)
129
+
130
+ context
131
+ end
132
+
133
+ def check_return_type(context, function_type, body_return_type)
134
+ return function_type.to if function_type.to.instance_of?(Types::TyUnit)
135
+ # Same as before but for the return type
136
+ function_type_to = function_type.to.is_a?(Types::TyGenericSingletonObject) ? function_type.to.clone : function_type.to
137
+ if body_return_type.either?
138
+ compatible_body = body_return_type[:normal].compatible?(function_type_to, :lt)
139
+ compatible_return = if body_return_type.return?
140
+ body_return_type[:return].wrapped_type.compatible?(function_type_to, :lt)
141
+ else
142
+ true
143
+ end
144
+ if compatible_body && compatible_return
145
+ return function_type_to
146
+ else
147
+ if compatible_body == false
148
+ fail Types::UncomparableTypes.new(function_type_to, body_return_type[:normal], node)
149
+ else
150
+ fail Types::UncomparableTypes.new(function_type_to, body_return_type[:return], node)
151
+ end
152
+ end
153
+ else
154
+ body_return_type = body_return_type.wrapped_type.check_type(context) if body_return_type.stack_jump?
155
+ return function_type if body_return_type.compatible?(function_type_to, :lt)
156
+ end
157
+ # TODO:
158
+ # A TyObject(Symbol) should be returned not the function type
159
+ # x = def id(x); x; end / => x == :id
160
+ error_message = "Error type checking function type #{owner}##{name}: Wrong return type, expected #{function_type.to}, found #{body_return_type}."
161
+ fail Types::UncomparableTypes.new(function_type.to, body_return_type, node)
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # instance variable
7
+ class TmGlobalVar < Expr
8
+ attr_accessor :val
9
+
10
+ def initialize(val, node)
11
+ super(node)
12
+ @val = val
13
+ end
14
+
15
+ def check_type(_context)
16
+ type = Types::TypingContext.type_variable_for_global(val)
17
+ type.node = node
18
+ type
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+ require_relative './tm_instance_var_assignment'
4
+
5
+ module TypedRb
6
+ module Model
7
+ # global variable assignation
8
+ class TmGlobalVarAssignment < TmInstanceVarAssignment
9
+ def check_type(context)
10
+ rvalue_type = rvalue.check_type(context)
11
+ lvalue_type = Types::TypingContext.type_variable_for_global(lvalue.val)
12
+ # This is always going to add just another constraint to the var that will
13
+ # be resolved in the unification process.
14
+ # No need to check the compatible value.
15
+ lvalue_type.compatible?(rvalue_type, :gt)
16
+ rvalue_type
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../model'
2
+
3
+ module TypedRb
4
+ module Model
5
+ class TmHashLiteral < Expr
6
+ attr_reader :pairs
7
+ def initialize(pairs, node)
8
+ super(node)
9
+ @pairs = pairs
10
+ end
11
+
12
+ def check_type(context)
13
+ pair_types = pairs.map { |key, element| [key.check_type(context), element.check_type(context)] }
14
+ max_key_type = pair_types.map(&:first).max rescue Types::TyObject.new(Object, node)
15
+ max_value_type = pair_types.map(&:last).max rescue Types::TyObject.new(Object, node)
16
+ type_var_key = Types::Polymorphism::TypeVariable.new('Hash:T',
17
+ :node => node,
18
+ :gen_name => false,
19
+ :upper_bound => max_key_type,
20
+ :lower_bound => max_key_type)
21
+ type_var_key.bind(max_key_type)
22
+ type_var_value = Types::Polymorphism::TypeVariable.new('Hash:U',
23
+ :node => node,
24
+ :gen_name => false,
25
+ :upper_bound => max_value_type,
26
+ :lower_bound => max_value_type)
27
+ type_var_value.bind(max_value_type)
28
+ Types::TyGenericObject.new(Hash, [type_var_key, type_var_value], node)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ class TmIfElse < Expr
7
+ attr_reader :condition_expr, :then_expr
8
+ attr_accessor :else_expr
9
+ def initialize(node, condition_expr, then_expr, else_expr)
10
+ super(node, nil)
11
+ @condition_expr = condition_expr
12
+ @then_expr = then_expr || Types::TyUnit.new
13
+ @else_expr = else_expr || Types::TyUnit.new
14
+ end
15
+
16
+ def check_type(context)
17
+ either_type = Types::TyEither.new(node)
18
+ either_type.compatible_either?(then_expr.check_type(context))
19
+ either_type.compatible_either?(else_expr.check_type(context))
20
+ either_type.has_jump? ? either_type : either_type[:normal]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # instance variable
7
+ class TmInstanceVar < Expr
8
+ attr_accessor :val
9
+
10
+ def initialize(val, node)
11
+ super(node)
12
+ @val = val
13
+ end
14
+
15
+ def check_type(context)
16
+ self_type = context.get_type_for(:self)
17
+ type = self_type.find_var_type(val)
18
+ fail TypeCheckError.new("Error type checking instance variable #{val}: Cannot find type for variable.", node) if type.nil?
19
+ type
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # instance variable assignation
7
+ class TmInstanceVarAssignment < Expr
8
+ attr_accessor :lvalue, :rvalue
9
+
10
+ def initialize(lvalue, rvalue, node)
11
+ super(node)
12
+ @lvalue = lvalue
13
+ @rvalue = rvalue
14
+ end
15
+
16
+ def check_type(context)
17
+ rvalue_type = rvalue.check_type(context)
18
+ self_type = context.get_type_for(:self)
19
+ lvalue_type = self_type.find_var_type(lvalue.val)
20
+ if lvalue_type.nil?
21
+ fail TypeCheckError.new("Error type checking instance variable #{lvalue} assignment: Cannot find type for variable", node)
22
+ end
23
+ if lvalue_type.compatible?(rvalue_type, :gt)
24
+ rvalue_type
25
+ else
26
+ error_message = "Error type checking instance variable #{lvalue} assignment: Error finding compatible instance variable, expected #{lvalue_type} found #{rvalue_type}"
27
+ fail TypeCheckError.new(error_message, node)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # integers
7
+ class TmInt < Expr
8
+ attr_accessor :val
9
+ def initialize(node)
10
+ super(node, Types::TyInteger.new(node))
11
+ @val = node.children.first
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ class TmLocalVarAsgn < Expr
7
+ attr_accessor :lhs, :rhs
8
+ # ts '#initialize / String -> Node -> Node -> unit'
9
+ def initialize(lhs, rhs, node)
10
+ super(node)
11
+ @lhs = lhs
12
+ @rhs = rhs
13
+ end
14
+
15
+ def check_type(context)
16
+ binding_type = rhs.check_type(context)
17
+ maybe_binding = context.get_type_for(lhs)
18
+ if maybe_binding
19
+ begin
20
+ if maybe_binding.compatible?(binding_type, :gt)
21
+ maybe_binding
22
+ else
23
+ fail Types::UncomparableTypes.new(maybe_binding, binding_type, node)
24
+ end
25
+ rescue Types::UncomparableTypes
26
+ raise Types::UncomparableTypes.new(maybe_binding, binding_type, node)
27
+ end
28
+ else
29
+ context.add_binding!(lhs, binding_type)
30
+ binding_type
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ require_relative '../model'
2
+
3
+ module TypedRb
4
+ module Model
5
+ class TmMassAsgn < Expr
6
+ attr_reader :lhs, :rhs
7
+
8
+ def initialize(lhs, rhs, node)
9
+ super(node)
10
+ @lhs = lhs.map { |lhs_node| lhs_node.children.first }
11
+ @lhs_children = lhs
12
+ @rhs = rhs
13
+ end
14
+
15
+ def check_type(context)
16
+ rhs_type = rhs.check_type(context)
17
+ if rhs_type.ruby_type == Array
18
+ lhs.each_with_index do |node, i|
19
+ local_asgn = TmLocalVarAsgn.new(node,
20
+ rhs_type.type_vars.first,
21
+ @lhs_children[i])
22
+ local_asgn.check_type(context)
23
+ end
24
+ elsif rhs_type.ruby_type == Pair
25
+ process_pair(rhs_type, context)
26
+ else
27
+ local_asgn = TmLocalVarAsgn.new(lhs.first,
28
+ rhs_type,
29
+ @lhs_children.first)
30
+ local_asgn.check_type(context)
31
+ lhs.drop(1).each_with_index do |node, i|
32
+ local_asgn = TmLocalVarAsgn.new(node,
33
+ Types::TyUnit.new,
34
+ @lhs_children[i + 1])
35
+ local_asgn.check_type(context)
36
+ end
37
+ end
38
+ rhs_type
39
+ end
40
+
41
+ protected
42
+
43
+ def process_pair(actual_argument, context)
44
+ lhs.each_with_index do |node, i|
45
+ type = case i
46
+ when 0
47
+ actual_argument.type_vars[0]
48
+ when 1
49
+ actual_argument.type_vars[1]
50
+ else
51
+ Types::TyUnit.new(node)
52
+ end
53
+ local_asgn = TmLocalVarAsgn.new(node, type, @lhs_children[i])
54
+ local_asgn.check_type(context)
55
+ end
56
+ context
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,87 @@
1
+ require_relative '../model'
2
+ require_relative '../types/ty_generic_object'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # Deconstructing arg variables
7
+ class TmMlhs < Expr
8
+ attr_accessor :args, :lambda_args
9
+ def initialize(args, node)
10
+ super(node)
11
+ @args = args
12
+ end
13
+
14
+ def check_type(actual_argument, context)
15
+ return process_lambda_args(context) if actual_argument == :lambda
16
+ if pair_argument?(actual_argument)
17
+ process_pair(actual_argument, context)
18
+ elsif array_argument?(actual_argument)
19
+ process_array(actual_argument, context)
20
+ else
21
+ fail TypeCheckError.new("Error type checking function MLHS term: Type is not subtype of Array: #{actual_argument}", node)
22
+ end
23
+ end
24
+
25
+ def compatible?(other_type, relation = :lt)
26
+ if other_type.generic? && other_type.ruby_type.ancestors.include?(Array)
27
+ if other_type.type_vars.size == 1
28
+ @lambda_args.each do |lambda_arg|
29
+ lambda_arg.compatible?(other_type.type_vars.first, relation)
30
+ end
31
+ elsif other_type.type_vars.size == @lambda_args.size
32
+ @lambda_args.each_with_index do |lambda_arg, i|
33
+ lambda_arg.compatible?(other_type.type_vars[i], relation)
34
+ end
35
+ else
36
+ false
37
+ end
38
+ else
39
+ false
40
+ end
41
+ end
42
+
43
+ protected
44
+
45
+ def process_lambda_args(context)
46
+ @lambda_args = args.map do |arg|
47
+ type_var = Types::TypingContext.type_variable_for_abstraction(:lambda, arg.to_s, context)
48
+ type_var.node = node
49
+ context = context.add_binding(arg, type_var)
50
+ type_var
51
+ end
52
+ context
53
+ end
54
+
55
+ def process_array(actual_argument, context)
56
+ type_var = actual_argument.type_vars[0]
57
+ args.each { |arg| context = context.add_binding(arg, type_var) }
58
+ context
59
+ end
60
+
61
+ def process_pair(actual_argument, context)
62
+ args.each_with_index do |arg, i|
63
+ type = case i
64
+ when 0
65
+ actual_argument.type_vars[0]
66
+ when 1
67
+ actual_argument.type_vars[1]
68
+ else
69
+ Types::TyUnit.new(node)
70
+ end
71
+ context = context.add_binding(arg, type)
72
+ end
73
+ context
74
+ end
75
+
76
+ def array_argument?(argument)
77
+ argument.is_a?(Types::TyGenericObject) &&
78
+ argument.ruby_type.ancestors.include?(Array)
79
+ end
80
+
81
+ def pair_argument?(argument)
82
+ argument.is_a?(Types::TyGenericObject) &&
83
+ argument.ruby_type.ancestors.include?(Pair)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # Module expression
7
+ class TmModule < Expr
8
+ attr_reader :module_name, :body
9
+
10
+ def initialize(module_name, body, node)
11
+ super(node)
12
+ @module_name = module_name
13
+ @body = body
14
+ end
15
+
16
+ def check_type(context)
17
+ module_ruby_type = Types::TypingContext.find_namespace(module_name)
18
+ module_type = Runtime::TypeParser.parse_existential_object_type(module_ruby_type.name)
19
+ Types::TypingContext.namespace_push(module_name)
20
+ module_type.node = node
21
+ module_typing_context = TmModule.with_local_context(module_type, node) do |_module_self_variable|
22
+ context = context.add_binding(:self, module_type)
23
+ body.check_type(context) if body
24
+ end
25
+ Types::TypingContext.namespace_pop
26
+ module_type.local_typing_context = module_typing_context
27
+ unification = Types::Polymorphism::Unification.new(module_type.local_typing_context.all_constraints,
28
+ :allow_unbound_receivers => true)
29
+ unification.run
30
+
31
+ module_type
32
+ end
33
+
34
+ def self.with_local_context(module_type, node)
35
+ Types::TypingContext.push_context(:module)
36
+ # Deal with upper/lower bounds here if required
37
+ module_self_variable = Types::TypingContext.type_variable_for(module_type.ruby_type, :module_self, [module_type.ruby_type])
38
+ module_self_variable.node = node
39
+ module_self_variable.module_type = module_type
40
+ module_type.self_variable = module_self_variable
41
+ yield(module_self_variable)
42
+
43
+ # Since every single time we find the generic type the same instance
44
+ # will be returned, the local_typing_context will still be associated.
45
+ # This is the reason we need to build a new typing context cloning this
46
+ # one while type materialization.
47
+ Types::TypingContext.pop_context
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ require_relative '../model'
2
+
3
+ module TypedRb
4
+ module Model
5
+ class TmNext < Expr
6
+ attr_reader :elements
7
+ def initialize(elements, node)
8
+ super(node)
9
+ @elements = elements
10
+ end
11
+
12
+ def check_type(context)
13
+ returned_type = if elements.size == 0
14
+ Types::TyUnit.new(node)
15
+ elsif elements.size == 1
16
+ elements.first.check_type(context)
17
+ else
18
+ TmArrayLiteral.new(elements, node).check_type(context)
19
+ end
20
+ Types::TyStackJump.next(returned_type, node)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ require_relative '../model'
3
+
4
+ module TypedRb
5
+ module Model
6
+ # Nil values
7
+ class TmNil < Expr
8
+ attr_accessor :val
9
+ def initialize(node)
10
+ super(node, Types::TyUnit.new(node))
11
+ end
12
+ end
13
+ end
14
+ end