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.
- checksums.yaml +7 -0
- data/Rakefile +26 -0
- data/bin/typed.rb +110 -0
- data/lib/typed/language.rb +131 -0
- data/lib/typed/model/tm_abs.rb +104 -0
- data/lib/typed/model/tm_array_literal.rb +25 -0
- data/lib/typed/model/tm_boolean.rb +15 -0
- data/lib/typed/model/tm_boolean_operator.rb +34 -0
- data/lib/typed/model/tm_break.rb +24 -0
- data/lib/typed/model/tm_case_when.rb +38 -0
- data/lib/typed/model/tm_class.rb +63 -0
- data/lib/typed/model/tm_const.rb +29 -0
- data/lib/typed/model/tm_defined.rb +19 -0
- data/lib/typed/model/tm_error.rb +16 -0
- data/lib/typed/model/tm_float.rb +15 -0
- data/lib/typed/model/tm_for.rb +42 -0
- data/lib/typed/model/tm_fun.rb +165 -0
- data/lib/typed/model/tm_global_var.rb +22 -0
- data/lib/typed/model/tm_global_var_assignment.rb +20 -0
- data/lib/typed/model/tm_hash_literal.rb +32 -0
- data/lib/typed/model/tm_if_else.rb +24 -0
- data/lib/typed/model/tm_instance_var.rb +23 -0
- data/lib/typed/model/tm_instance_var_assignment.rb +32 -0
- data/lib/typed/model/tm_int.rb +15 -0
- data/lib/typed/model/tm_local_var_asgn.rb +35 -0
- data/lib/typed/model/tm_mass_asgn.rb +60 -0
- data/lib/typed/model/tm_mlhs.rb +87 -0
- data/lib/typed/model/tm_module.rb +51 -0
- data/lib/typed/model/tm_next.rb +24 -0
- data/lib/typed/model/tm_nil.rb +14 -0
- data/lib/typed/model/tm_range_literal.rb +30 -0
- data/lib/typed/model/tm_regexp.rb +27 -0
- data/lib/typed/model/tm_rescue.rb +27 -0
- data/lib/typed/model/tm_return.rb +24 -0
- data/lib/typed/model/tm_s_class.rb +30 -0
- data/lib/typed/model/tm_self.rb +22 -0
- data/lib/typed/model/tm_send.rb +300 -0
- data/lib/typed/model/tm_sequencing.rb +53 -0
- data/lib/typed/model/tm_string.rb +15 -0
- data/lib/typed/model/tm_string_interpolation.rb +21 -0
- data/lib/typed/model/tm_super.rb +27 -0
- data/lib/typed/model/tm_symbol.rb +15 -0
- data/lib/typed/model/tm_symbol_interpolation.rb +21 -0
- data/lib/typed/model/tm_try.rb +29 -0
- data/lib/typed/model/tm_var.rb +28 -0
- data/lib/typed/model/tm_while.rb +43 -0
- data/lib/typed/model.rb +48 -0
- data/lib/typed/prelude.rb +939 -0
- data/lib/typed/prelude_existential_registry.bin +0 -0
- data/lib/typed/prelude_generic_registry.bin +0 -0
- data/lib/typed/prelude_registry.bin +0 -0
- data/lib/typed/runtime/ast_parser.rb +589 -0
- data/lib/typed/runtime/method_signature_processor.rb +72 -0
- data/lib/typed/runtime/normalization/validations.rb +47 -0
- data/lib/typed/runtime/normalization.rb +196 -0
- data/lib/typed/runtime/parser_context.rb +36 -0
- data/lib/typed/runtime/type_parser.rb +215 -0
- data/lib/typed/runtime/type_registry.rb +170 -0
- data/lib/typed/runtime/type_signature_processor.rb +34 -0
- data/lib/typed/runtime.rb +33 -0
- data/lib/typed/type_signature/parser.rb +240 -0
- data/lib/typed/types/polymorphism/existential_type_variable.rb +13 -0
- data/lib/typed/types/polymorphism/generic_comparisons.rb +134 -0
- data/lib/typed/types/polymorphism/generic_variables.rb +24 -0
- data/lib/typed/types/polymorphism/type_variable.rb +138 -0
- data/lib/typed/types/polymorphism/type_variable_register.rb +298 -0
- data/lib/typed/types/polymorphism/unification.rb +579 -0
- data/lib/typed/types/ty_boolean.rb +15 -0
- data/lib/typed/types/ty_dynamic.rb +39 -0
- data/lib/typed/types/ty_either.rb +168 -0
- data/lib/typed/types/ty_error.rb +18 -0
- data/lib/typed/types/ty_existential_type.rb +22 -0
- data/lib/typed/types/ty_function.rb +144 -0
- data/lib/typed/types/ty_generic_function.rb +115 -0
- data/lib/typed/types/ty_generic_object.rb +180 -0
- data/lib/typed/types/ty_generic_singleton_object.rb +238 -0
- data/lib/typed/types/ty_object.rb +256 -0
- data/lib/typed/types/ty_singleton_object.rb +78 -0
- data/lib/typed/types/ty_stack_jump.rb +44 -0
- data/lib/typed/types/ty_top_level_object.rb +38 -0
- data/lib/typed/types.rb +60 -0
- data/lib/typed/typing_context.rb +206 -0
- data/lib/typed/version.rb +3 -0
- data/lib/typed.rb +161 -0
- data/spec/lib/ast_parser_spec.rb +101 -0
- data/spec/lib/examples/animals.rb +44 -0
- data/spec/lib/examples/counter.rb +16 -0
- data/spec/lib/examples/if.rb +31 -0
- data/spec/lib/language_spec.rb +36 -0
- data/spec/lib/model/tm_abs_spec.rb +66 -0
- data/spec/lib/model/tm_array_literal_spec.rb +36 -0
- data/spec/lib/model/tm_case_when_spec.rb +39 -0
- data/spec/lib/model/tm_class_spec.rb +67 -0
- data/spec/lib/model/tm_defined_spec.rb +10 -0
- data/spec/lib/model/tm_for_spec.rb +150 -0
- data/spec/lib/model/tm_fun_spec.rb +11 -0
- data/spec/lib/model/tm_hash_literal_spec.rb +40 -0
- data/spec/lib/model/tm_mass_asgn_spec.rb +104 -0
- data/spec/lib/model/tm_module_spec.rb +42 -0
- data/spec/lib/model/tm_regexp_spec.rb +9 -0
- data/spec/lib/model/tm_return_spec.rb +47 -0
- data/spec/lib/model/tm_s_class_spec.rb +27 -0
- data/spec/lib/model/tm_self_spec.rb +19 -0
- data/spec/lib/model/tm_string_interpolation_spec.rb +10 -0
- data/spec/lib/model/tm_symbol_interpolation_spec.rb +10 -0
- data/spec/lib/model/tm_symbol_spec.rb +9 -0
- data/spec/lib/model/tm_while_spec.rb +141 -0
- data/spec/lib/polymorphism/type_variable_spec.rb +14 -0
- data/spec/lib/polymorphism/unification_spec.rb +328 -0
- data/spec/lib/prelude/array_spec.rb +263 -0
- data/spec/lib/prelude/class_spec.rb +12 -0
- data/spec/lib/prelude/enumerable_spec.rb +278 -0
- data/spec/lib/prelude/enumerator_spec.rb +101 -0
- data/spec/lib/prelude/hash_spec.rb +361 -0
- data/spec/lib/prelude/kernel_spec.rb +23 -0
- data/spec/lib/prelude/object_spec.rb +22 -0
- data/spec/lib/prelude/pair_spec.rb +16 -0
- data/spec/lib/prelude/showable_spec.rb +31 -0
- data/spec/lib/prelude/string_spec.rb +98 -0
- data/spec/lib/runtime/normalization_spec.rb +29 -0
- data/spec/lib/runtime/validations_spec.rb +56 -0
- data/spec/lib/runtime_spec.rb +503 -0
- data/spec/lib/type_signature/parser_spec.rb +239 -0
- data/spec/lib/types/comparisons_spec.rb +35 -0
- data/spec/lib/types/polymorphism/generic_comparisons_spec.rb +492 -0
- data/spec/lib/types/polymorphism/type_variable_register_spec.rb +128 -0
- data/spec/lib/types/ty_dynamic_spec.rb +103 -0
- data/spec/lib/types/ty_either_spec.rb +288 -0
- data/spec/lib/types/ty_error_spec.rb +18 -0
- data/spec/lib/types/ty_generic_object_spec.rb +78 -0
- data/spec/lib/types/ty_generic_singleton_object_spec.rb +288 -0
- data/spec/lib/types/typing_context_spec.rb +86 -0
- data/spec/lib/types_spec.rb +174 -0
- data/spec/lib/typing/boolean_asgn_spec.rb +134 -0
- data/spec/lib/typing/break_spec.rb +79 -0
- data/spec/lib/typing/generics_spec.rb +191 -0
- data/spec/lib/typing/instance_vars_spec.rb +103 -0
- data/spec/lib/typing/next_spec.rb +29 -0
- data/spec/lib/typing/op_asgn_spec.rb +104 -0
- data/spec/lib/typing/overriden_methods_spec.rb +31 -0
- data/spec/lib/typing/subtyping_spec.rb +112 -0
- data/spec/lib/typing/tm_boolean_operator_spec.rb +100 -0
- data/spec/lib/typing/tm_boolean_spec.rb +61 -0
- data/spec/lib/typing/tm_const_spec.rb +28 -0
- data/spec/lib/typing/tm_defined_spec.rb +12 -0
- data/spec/lib/typing/tm_fun_spec.rb +347 -0
- data/spec/lib/typing/tm_global_var_spec.rb +33 -0
- data/spec/lib/typing/tm_if_else_spec.rb +104 -0
- data/spec/lib/typing/tm_ignore_spec.rb +24 -0
- data/spec/lib/typing/tm_instance_vars_spec.rb +117 -0
- data/spec/lib/typing/tm_local_var_asgn_spec.rb +134 -0
- data/spec/lib/typing/tm_mlhs_spec.rb +164 -0
- data/spec/lib/typing/tm_module_spec.rb +89 -0
- data/spec/lib/typing/tm_raise_spec.rb +31 -0
- data/spec/lib/typing/tm_range_literal_spec.rb +25 -0
- data/spec/lib/typing/tm_regexp_spec.rb +14 -0
- data/spec/lib/typing/tm_return_spec.rb +45 -0
- data/spec/lib/typing/tm_send_casting_spec.rb +26 -0
- data/spec/lib/typing/tm_send_class_methods_spec.rb +42 -0
- data/spec/lib/typing/tm_send_generic_apply_spec.rb +103 -0
- data/spec/lib/typing/tm_send_generic_methods_spec.rb +77 -0
- data/spec/lib/typing/tm_send_initialize_spec.rb +68 -0
- data/spec/lib/typing/tm_send_lambda_spec.rb +135 -0
- data/spec/lib/typing/tm_send_spec.rb +217 -0
- data/spec/lib/typing/tm_send_yield_block_spec.rb +308 -0
- data/spec/lib/typing/tm_sequencing_spec.rb +174 -0
- data/spec/lib/typing/tm_string_interpolation_spec.rb +19 -0
- data/spec/lib/typing/tm_super_spec.rb +63 -0
- data/spec/lib/typing/tm_symbol_interpolation_spec.rb +19 -0
- data/spec/lib/typing/tm_symbol_spec.rb +14 -0
- data/spec/lib/typing/tm_try_spec.rb +73 -0
- data/spec/spec_helper.rb +140 -0
- 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
|