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