typed.rb 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
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