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,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# range literals
|
7
|
+
class TmRangeLiteral < Expr
|
8
|
+
attr_reader :start_range, :end_range
|
9
|
+
def initialize(start_range, end_range, node)
|
10
|
+
super(node)
|
11
|
+
@start_range = start_range
|
12
|
+
@end_range = end_range
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_type(context)
|
16
|
+
start_range_type = start_range.check_type(context)
|
17
|
+
end_range_type = end_range.check_type(context)
|
18
|
+
max_type = [start_range_type, end_range_type].max
|
19
|
+
|
20
|
+
type_var = Types::Polymorphism::TypeVariable.new('Range:T',
|
21
|
+
:node => node,
|
22
|
+
:gen_name => false,
|
23
|
+
:upper_bound => max_type,
|
24
|
+
:lower_bound => max_type)
|
25
|
+
type_var.bind(max_type)
|
26
|
+
Types::TyGenericObject.new(Range, [type_var], node)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# Regular expresssion
|
7
|
+
class TmRegexp < Expr
|
8
|
+
attr_reader :exp, :options
|
9
|
+
def initialize(exp, options, node)
|
10
|
+
super(node)
|
11
|
+
@exp = exp
|
12
|
+
@ptions = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_type(context)
|
16
|
+
options.check_type(context) if options
|
17
|
+
exp_type = exp.check_type(context)
|
18
|
+
if exp_type.compatible?(Types::TyString.new(node), :lt)
|
19
|
+
Types::TyRegexp.new(node)
|
20
|
+
else
|
21
|
+
error_message = "Error type checking Regexp: Expected String type for expression, found #{exp_type}"
|
22
|
+
fail Types::TypeCheckError.new(error_message, node)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../model'
|
2
|
+
|
3
|
+
module TypedRb
|
4
|
+
module Model
|
5
|
+
class TmRescue < Expr
|
6
|
+
|
7
|
+
attr_reader :exceptions, :catch_var, :rescue_body
|
8
|
+
def initialize(exceptions, catch_var, rescue_body)
|
9
|
+
@exceptions = exceptions
|
10
|
+
@catch_var = catch_var
|
11
|
+
@rescue_body = rescue_body
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_type(context)
|
15
|
+
if catch_var
|
16
|
+
exception_type = exceptions.map{|e| e.check_type(context) }.max
|
17
|
+
context.add_binding!(catch_var, exception_type)
|
18
|
+
end
|
19
|
+
if rescue_body
|
20
|
+
rescue_body.check_type(context)
|
21
|
+
else
|
22
|
+
Types::TyUnit.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative '../model'
|
2
|
+
|
3
|
+
module TypedRb
|
4
|
+
module Model
|
5
|
+
class TmReturn < 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.return(returned_type, node)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# Class expression
|
7
|
+
class TmSClass < Expr
|
8
|
+
attr_reader :class_name, :super_class_name, :body
|
9
|
+
|
10
|
+
def initialize(class_name, body, node)
|
11
|
+
super(node)
|
12
|
+
@class_name = class_name
|
13
|
+
@body = body
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_type(context)
|
17
|
+
if class_name != :self
|
18
|
+
class_ruby_type = Types::TypingContext.find_namespace(class_name)
|
19
|
+
class_type = Runtime::TypeParser.parse_singleton_object_type(class_ruby_type.name)
|
20
|
+
class_type.node = node
|
21
|
+
context = context.add_binding(:self, class_type)
|
22
|
+
end
|
23
|
+
Types::TypingContext.push_context(:sclass)
|
24
|
+
res = body.check_type(context)
|
25
|
+
Types::TypingContext.pop_context
|
26
|
+
res
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# booleans
|
7
|
+
class TmSelf < Expr
|
8
|
+
def initialize(node)
|
9
|
+
super(node)
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_type(context)
|
13
|
+
self_type = context.get_type_for(:self)
|
14
|
+
if self_type.nil?
|
15
|
+
fail TypeCheckError.new.new('Error type checking self reference: Cannot find self reference in typing context', node)
|
16
|
+
else
|
17
|
+
self_type
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,300 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# message send
|
7
|
+
class TmSend < Expr
|
8
|
+
attr_accessor :receiver, :message, :args, :block
|
9
|
+
def initialize(receiver, message, args, node)
|
10
|
+
super(node)
|
11
|
+
@receiver = receiver
|
12
|
+
@message = message
|
13
|
+
@args = args
|
14
|
+
@block = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def with_block(block)
|
18
|
+
@block = block
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_type(context)
|
22
|
+
@context = context
|
23
|
+
TypedRb.log(binding, :debug, "Type checking message sent: #{message} at line #{node.loc.line}")
|
24
|
+
if receiver.nil? && message == :ts
|
25
|
+
# ignore, => type annotation
|
26
|
+
Types::TyUnit.new(node)
|
27
|
+
elsif message == :new && !singleton_object_type(receiver, context).nil? # clean this!
|
28
|
+
check_instantiation(context)
|
29
|
+
elsif receiver == :self || receiver.nil?
|
30
|
+
# self.m(args), m(args), m
|
31
|
+
check_type_no_explicit_receiver(context)
|
32
|
+
else
|
33
|
+
# x.m(args)
|
34
|
+
check_type_explicit_receiver(context)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def singleton_object_type(receiver, context)
|
39
|
+
parsed_receiver_type = if receiver.nil? || receiver == :self
|
40
|
+
context.get_type_for(:self)
|
41
|
+
else
|
42
|
+
receiver_type
|
43
|
+
end
|
44
|
+
return parsed_receiver_type if parsed_receiver_type.is_a?(Types::TySingletonObject)
|
45
|
+
end
|
46
|
+
|
47
|
+
# we received new, but we look for initialize in the class,
|
48
|
+
# not the singleton class.
|
49
|
+
# we then run the regular application,
|
50
|
+
# but we return the class type instead of the return type
|
51
|
+
# for the constructor application (should be unit/nil).
|
52
|
+
def check_instantiation(context)
|
53
|
+
self_type = singleton_object_type(receiver, context).as_object_type
|
54
|
+
function_klass_type, function_type = self_type.find_function_type(:initialize, args.size, @block)
|
55
|
+
# function application
|
56
|
+
@message = :initialize
|
57
|
+
begin
|
58
|
+
check_application(self_type, function_type, context)
|
59
|
+
rescue TypeCheckError => error
|
60
|
+
raise error if function_klass_type == self_type.ruby_type
|
61
|
+
end
|
62
|
+
self_type
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_type_no_explicit_receiver(context)
|
66
|
+
if message == :yield
|
67
|
+
check_yield_application(context)
|
68
|
+
else
|
69
|
+
@receiver_type = context.get_type_for(:self) # check message in self type -> application
|
70
|
+
check_type_explicit_receiver(context)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def check_yield_application(context)
|
75
|
+
yield_abs_type = context.get_type_for(:yield)
|
76
|
+
if yield_abs_type
|
77
|
+
check_lambda_application(yield_abs_type, context)
|
78
|
+
else
|
79
|
+
fail TypeCheckError.new("Error type checking message sent '#{message}': Cannot find yield function defined in typing context", node)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def check_type_explicit_receiver(context)
|
84
|
+
if receiver_type.is_a?(Types::Polymorphism::TypeVariable)
|
85
|
+
# Existential type (Module) if receiver_type is self
|
86
|
+
# TODO: what can we do if this is the inclusion of a module?
|
87
|
+
arg_types = args.map { |arg| arg.check_type(context) }
|
88
|
+
receiver_type.add_message_constraint(message, arg_types)
|
89
|
+
elsif receiver_type.is_a?(Types::TyGenericSingletonObject) && (message == :call)
|
90
|
+
# Application of types accept a type class or a string with a type description
|
91
|
+
arg_types = parse_type_application_arguments(args, context)
|
92
|
+
check_type_application_to_generic(receiver_type, arg_types)
|
93
|
+
elsif receiver_type.is_a?(Types::TyFunction) && (message == :[] || message == :call)
|
94
|
+
check_lambda_application(receiver_type, context)
|
95
|
+
else
|
96
|
+
function_klass_type, function_type = receiver_type.find_function_type(message, args.size, @block)
|
97
|
+
# begin
|
98
|
+
if function_type.nil?
|
99
|
+
error_message = "Error type checking message sent '#{message}': Type information for #{receiver_type}:#{message} not found."
|
100
|
+
fail TypeCheckError.new(error_message, node)
|
101
|
+
elsif cast?(function_klass_type)
|
102
|
+
check_casting(context)
|
103
|
+
elsif module_include_implementation?(function_klass_type)
|
104
|
+
check_module_inclusions(receiver_type, context)
|
105
|
+
else
|
106
|
+
# function application
|
107
|
+
check_application(receiver_type, function_type, context)
|
108
|
+
end
|
109
|
+
# rescue TypeCheckError => error
|
110
|
+
# if function_klass_type != receiver_type.ruby_type
|
111
|
+
# Types::TyDynamic.new(Object, node)
|
112
|
+
# else
|
113
|
+
# raise error
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def parse_type_application_arguments(arguments, context)
|
120
|
+
arguments.map do |argument|
|
121
|
+
if argument.is_a?(Model::TmString)
|
122
|
+
type_var_signature = argument.node.children.first
|
123
|
+
maybe_generic_method_var = Types::TypingContext.vars_info(:method)[type_var_signature]
|
124
|
+
maybe_generic_class_var = Types::TypingContext.vars_info(:class)[type_var_signature]
|
125
|
+
if maybe_generic_method_var || maybe_generic_class_var
|
126
|
+
maybe_generic_method_var || maybe_generic_class_var
|
127
|
+
else
|
128
|
+
parsed_types = TypeSignature::Parser.parse(type_var_signature)
|
129
|
+
if parsed_types.is_a?(Array)
|
130
|
+
parsed_types.map { |parsed_type| parse_type_application_argument(parsed_type) }
|
131
|
+
else
|
132
|
+
parse_type_application_argument(parsed_types)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
else
|
136
|
+
argument.check_type(context)
|
137
|
+
end
|
138
|
+
end.flatten
|
139
|
+
end
|
140
|
+
|
141
|
+
def parse_type_application_argument(type)
|
142
|
+
# TODO: do this recursively in the case of nested generic type
|
143
|
+
# TODO: do we need it at all?
|
144
|
+
klass = if type.is_a?(Hash) && type[:kind] == :generic_type
|
145
|
+
Class.for_name(type[:type])
|
146
|
+
end
|
147
|
+
Runtime::TypeParser.parse(type, klass)
|
148
|
+
end
|
149
|
+
|
150
|
+
def type_application_counter
|
151
|
+
@type_application_counter ||= 0
|
152
|
+
@type_application_counter += 1
|
153
|
+
end
|
154
|
+
|
155
|
+
def check_type_application_to_generic(generic_type, args)
|
156
|
+
generic_type.materialize(args)
|
157
|
+
end
|
158
|
+
|
159
|
+
def check_application(receiver_type, function_type, context)
|
160
|
+
if function_type.is_a?(Types::TyDynamicFunction)
|
161
|
+
function_type.to
|
162
|
+
else
|
163
|
+
if function_type.generic?
|
164
|
+
function_type.local_typing_context.parent = Types::TypingContext.type_variables_register
|
165
|
+
return_type = function_type.materialize do |materialized_function|
|
166
|
+
check_application(receiver_type, materialized_function, context)
|
167
|
+
end.to
|
168
|
+
return_type.respond_to?(:as_object_type) ? return_type.as_object_type : return_type
|
169
|
+
else
|
170
|
+
formal_parameters = function_type.from
|
171
|
+
parameters_info = function_type.parameters_info
|
172
|
+
TypedRb.log(binding, :debug, "Checking function application #{receiver_type}::#{message}( #{parameters_info} )")
|
173
|
+
check_args_application(parameters_info, formal_parameters, args, context)
|
174
|
+
if @block
|
175
|
+
block_type = @block.check_type(context)
|
176
|
+
# TODO:
|
177
|
+
# Unification is run here
|
178
|
+
# Algorithm is failing:
|
179
|
+
# G > String,
|
180
|
+
# G < E
|
181
|
+
# ========
|
182
|
+
# G = [String, ?]
|
183
|
+
# -----
|
184
|
+
# G = [String, E]
|
185
|
+
# E = [String, ?]
|
186
|
+
block_return_type = if function_type.block_type
|
187
|
+
# materialization and unification will happen in this invocation
|
188
|
+
block_type.compatible?(function_type.block_type, :lt)
|
189
|
+
else
|
190
|
+
block_type.to
|
191
|
+
end
|
192
|
+
if block_return_type.to.stack_jump?
|
193
|
+
break_type = block_return_type.to.wrapped_type.check_type(context)
|
194
|
+
unless break_type.compatible?(function_type.to, :lt)
|
195
|
+
error_message = "Incompatible 'break' type, expected #{function_type.to}, found #{break_type}"
|
196
|
+
fail error_message, block_return_type.to.node
|
197
|
+
end
|
198
|
+
elsif block_return_type.to.either?
|
199
|
+
max_type = block_return_type.check_type(context, [:return, :break, :normal])
|
200
|
+
unless max_type.compatible?(function_type.to, :lt)
|
201
|
+
error_message = "Incompatible either max type, expected #{function_type.to}, found #{max_type}"
|
202
|
+
fail error_message, block_return_type.to.node
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
return_type = function_type.to
|
207
|
+
return_type.respond_to?(:as_object_type) ? return_type.as_object_type : return_type
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def check_lambda_application(lambda_type, context)
|
213
|
+
lambda_type.check_args_application(args, context).to
|
214
|
+
end
|
215
|
+
|
216
|
+
def check_args_application(parameters_info, formal_parameters, actual_arguments, context)
|
217
|
+
#binding.pry if actual_arguments.size == 1 && actual_arguments.first.class == TypedRb::Model::TmVar && actual_arguments.first.val == "klass" && actual_arguments.first.col == 36
|
218
|
+
parameters_info.each_with_index do |(require_info, arg_name), index|
|
219
|
+
actual_argument = actual_arguments[index]
|
220
|
+
formal_parameter_type = formal_parameters[index]
|
221
|
+
if formal_parameter_type.nil? && !require_info == :block
|
222
|
+
fail TypeCheckError.new("Error type checking message sent '#{message}': Missing information about argument #{arg_name} in #{receiver}##{message}", node)
|
223
|
+
end
|
224
|
+
if actual_argument.nil? && require_info != :opt && require_info != :rest && require_info != :block
|
225
|
+
fail TypeCheckError.new("Error type checking message sent '#{message}': Missing mandatory argument #{arg_name} in #{receiver}##{message}", node)
|
226
|
+
else
|
227
|
+
if require_info == :rest
|
228
|
+
break if actual_argument.nil? # invocation without any of the optional arguments
|
229
|
+
rest_type = formal_parameter_type.type_vars.first
|
230
|
+
formal_parameter_type = if rest_type.respond_to?(:bound)
|
231
|
+
rest_type.bound
|
232
|
+
else
|
233
|
+
rest_type
|
234
|
+
end
|
235
|
+
actual_arguments[index..-1].each do |actual_argument|
|
236
|
+
unless actual_argument.check_type(context).compatible?(formal_parameter_type, :lt)
|
237
|
+
error_message = "Error type checking message sent '#{message}': #{formal_parameter_type} expected, #{actual_argument_type} found"
|
238
|
+
fail TypeCheckError.new(error_message, node)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
break
|
242
|
+
else
|
243
|
+
unless actual_argument.nil? # opt or block if this is nil
|
244
|
+
actual_argument_type = actual_argument.check_type(context)
|
245
|
+
fail TypeCheckError.new("Error type checking message sent '#{message}': Missing type information for argument '#{arg_name}'", node) if formal_parameter_type.nil?
|
246
|
+
begin
|
247
|
+
unless actual_argument_type.compatible?(formal_parameter_type, :lt)
|
248
|
+
error_message = "Error type checking message sent '#{message}': #{formal_parameter_type} expected, #{actual_argument_type} found"
|
249
|
+
fail TypeCheckError.new(error_message, node)
|
250
|
+
end
|
251
|
+
rescue Types::UncomparableTypes, ArgumentError
|
252
|
+
raise Types::UncomparableTypes.new(actual_argument_type, formal_parameter_type, node)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def cast?(function_klass_type)
|
261
|
+
function_klass_type == BasicObject && message == :cast
|
262
|
+
end
|
263
|
+
|
264
|
+
def check_casting(context)
|
265
|
+
from_type = args[0].check_type(context)
|
266
|
+
to = parse_type_application_arguments([args[1]], context).first
|
267
|
+
to_type = to.is_a?(Types::TyObject) ? to.as_object_type : to
|
268
|
+
TypedRb.log(binding, :info, "Casting #{from_type} into #{to_type}")
|
269
|
+
to_type
|
270
|
+
end
|
271
|
+
|
272
|
+
def module_include_implementation?(function_klass_type)
|
273
|
+
function_klass_type == Module && message == :include
|
274
|
+
end
|
275
|
+
|
276
|
+
def check_module_inclusions(self_type, context)
|
277
|
+
args.map do |arg|
|
278
|
+
arg.check_type(context)
|
279
|
+
end.each do |module_type|
|
280
|
+
if module_type.is_a?(Types::TyExistentialType)
|
281
|
+
if module_type.local_typing_context
|
282
|
+
module_type.check_inclusion(self_type)
|
283
|
+
else
|
284
|
+
# TODO: report warning about missing module information
|
285
|
+
TypedRb.log(binding, :debug, "Not type checking module #{module_type.ruby_type} inclusion due to lack of module information")
|
286
|
+
end
|
287
|
+
else
|
288
|
+
error_message = "Error type checking message sent '#{message}': Module type expected for inclusion in #{self_type}, #{module_type} found"
|
289
|
+
fail TypeCheckError.new(error_message, node)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
self_type
|
293
|
+
end
|
294
|
+
|
295
|
+
def receiver_type
|
296
|
+
@receiver_type ||= receiver.check_type(@context)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
class TmSequencing < Expr
|
7
|
+
attr_accessor :terms
|
8
|
+
def initialize(terms, node)
|
9
|
+
super(node)
|
10
|
+
@terms = terms.reject(&:nil?)
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_type(context)
|
14
|
+
process_terms_before_return(@terms, context)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def process_terms_before_return(terms, context, processed_terms=[], potential_return=nil)
|
20
|
+
if terms.empty?
|
21
|
+
make_final_return(processed_terms.last, potential_return)
|
22
|
+
else
|
23
|
+
term_type = terms.first.check_type(context)
|
24
|
+
if term_type.stack_jump?
|
25
|
+
process_terms_after_return(terms.drop(1), context)
|
26
|
+
make_final_return(term_type, potential_return)
|
27
|
+
elsif term_type.either?
|
28
|
+
process_terms_before_return(terms.drop(1), context, processed_terms << nil, make_final_return(term_type, potential_return))
|
29
|
+
else
|
30
|
+
process_terms_before_return(terms.drop(1), context, processed_terms << term_type, potential_return)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_terms_after_return(terms, context)
|
36
|
+
terms.each { |term| term.check_type(context) }
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def make_final_return(type_a, type_b)
|
41
|
+
return (type_a || type_b) if type_a.nil? || type_b.nil?
|
42
|
+
either_types = [type_a, type_b].map{ |type| Types::TyEither.wrap(type) }
|
43
|
+
reduced_final_type = either_types.reduce { |a,b| a.compatible_either?(b) }.unwrap
|
44
|
+
if type_a.stack_jump? || type_b.stack_jump?
|
45
|
+
jump_kind = [type_a, type_b].detect {|type| type.stack_jump? }.jump_kind
|
46
|
+
reduced_final_type[jump_kind]
|
47
|
+
else
|
48
|
+
reduced_final_type
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# strings
|
7
|
+
class TmString < Expr
|
8
|
+
attr_accessor :val
|
9
|
+
def initialize(node)
|
10
|
+
super(node, Types::TyString.new(node))
|
11
|
+
@val = node.children.first
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative '../model'
|
2
|
+
|
3
|
+
module TypedRb
|
4
|
+
module Model
|
5
|
+
# String interpolation
|
6
|
+
class TmStringInterpolation < Expr
|
7
|
+
attr_reader :units
|
8
|
+
def initialize(units, node)
|
9
|
+
super(node)
|
10
|
+
@units = units
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_type(context)
|
14
|
+
units.each do |unit|
|
15
|
+
unit.check_type(context)
|
16
|
+
end
|
17
|
+
Types::TyString.new(node)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# super keyword invocations
|
7
|
+
class TmSuper < Expr
|
8
|
+
attr_reader :args
|
9
|
+
def initialize(args, node)
|
10
|
+
super(node)
|
11
|
+
@args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_type(context)
|
15
|
+
if Types::TypingContext.function_context
|
16
|
+
self_type, message, args = Types::TypingContext.function_context
|
17
|
+
parent_self_type = Types::TyObject.new(self_type.hierarchy.first, node)
|
18
|
+
args = @args || args
|
19
|
+
args = args.map { |arg| arg.check_type(context) }
|
20
|
+
TmSend.new(parent_self_type, message, args, node).check_type(context)
|
21
|
+
else
|
22
|
+
fail TypeCheckError.new("Error type checking 'super' invocation without function context.", node)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# floats
|
7
|
+
class TmSymbol < Expr
|
8
|
+
attr_accessor :val
|
9
|
+
def initialize(node)
|
10
|
+
super(node, Types::TySymbol.new(node))
|
11
|
+
@val = node.children.first
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative '../model'
|
2
|
+
|
3
|
+
module TypedRb
|
4
|
+
module Model
|
5
|
+
# Symbol interpolation
|
6
|
+
class TmSymbolInterpolation < Expr
|
7
|
+
attr_reader :units
|
8
|
+
def initialize(units, node)
|
9
|
+
super(node)
|
10
|
+
@units = units
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_type(context)
|
14
|
+
units.each do |unit|
|
15
|
+
unit.check_type(context)
|
16
|
+
end
|
17
|
+
Types::TySymbol.new(node)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
class TmTry < Expr
|
7
|
+
def initialize(try_term, rescue_terms, node)
|
8
|
+
super(node)
|
9
|
+
@try_term = try_term
|
10
|
+
@rescue_terms = rescue_terms
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_type(context)
|
14
|
+
try_term_type = @try_term.check_type(context)
|
15
|
+
rescue_term_types = @rescue_terms.map do |term|
|
16
|
+
term.check_type(context)
|
17
|
+
end.reject do |type|
|
18
|
+
type.is_a?(Types::TyUnit)
|
19
|
+
end
|
20
|
+
incompatible_type = rescue_term_types.detect { |term_type| !try_term_type.compatible?(term_type) }
|
21
|
+
if incompatible_type
|
22
|
+
fail TypeCheckError.new("Type error checking try statement: Error in rescue clause, expected type #{try_term_type} got #{incompatible_type}", node)
|
23
|
+
else
|
24
|
+
try_term_type
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '../model'
|
3
|
+
|
4
|
+
module TypedRb
|
5
|
+
module Model
|
6
|
+
# variable
|
7
|
+
class TmVar < Expr
|
8
|
+
attr_accessor :val
|
9
|
+
|
10
|
+
def initialize(val, node)
|
11
|
+
super(node)
|
12
|
+
@val = val.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"#{GenSym.resolve(@val)}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_type(context)
|
20
|
+
type = context.get_type_for(@val)
|
21
|
+
if type.nil?
|
22
|
+
fail TypeCheckError.new("Type error checking local var #{@val}: Cannot find binding local var in the typing context", node)
|
23
|
+
end
|
24
|
+
type
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|