Class: TypedRb::Types::TyGenericSingletonObject

Inherits:
TySingletonObject show all
Includes:
Polymorphism::GenericComparisons, Polymorphism::GenericObject, Polymorphism::GenericVariables, SingletonObject
Defined in:
lib/typed/types/ty_generic_singleton_object.rb

Instance Attribute Summary collapse

Attributes inherited from TyObject

#classes, #hierarchy, #modules, #ruby_type, #with_ruby_type

Attributes inherited from Type

#node

Instance Method Summary collapse

Methods included from SingletonObject

#actual_arguments_hash, #apply_type_argument, #apply_type_arguments, #apply_type_arguments_recursively, #clone_with_substitutions

Methods included from Polymorphism::GenericVariables

#type_vars, #unbound_vars

Methods included from Polymorphism::GenericComparisons

#!=, #<, #<=, #==, #>, #>=, #add_type_var_constraint, #check_generic_type_relation, #check_inferior_or_equal_binding, #check_type_var_inclusion, #compatible?, #compatible_free_type_vars?, #incompatible_free_type_vars?, #to_ty_object

Methods included from Polymorphism::GenericObject

#ancestor_of_super_type?, #generic?, #generic_singleton_object, #generic_type_var_to_applied_type_var, #materialize_found_function, #materialize_found_function_arg, #materialize_super_type_found_function, #parse_super_type_materialization_arg, #parse_super_type_materialization_args, #to_s

Methods inherited from TySingletonObject

#compatible?, #find_function_type_in_metaclass_hierarchy, #find_var_type, #resolve_ruby_method, #singleton?, #to_s

Methods inherited from TyObject

#<=>, #check_type, #compatible?, #dynamic?, #either?, #find_function_type_in_hierarchy, #find_var_type, #generic?, #join, #max, #resolve_ruby_method, #singleton?, #to_s, #union

Methods included from Comparable

#<=>

Methods inherited from Type

#compatible?, #either?, #stack_jump?

Constructor Details

#initialize(ruby_type, type_vars, super_type = nil, node = nil) ⇒ TyGenericSingletonObject

Returns a new instance of TyGenericSingletonObject.



17
18
19
20
21
22
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 17

def initialize(ruby_type, type_vars, super_type = nil, node = nil)
  super(ruby_type, node)
  @super_type = super_type
  @type_vars = type_vars
  @application_count = 0
end

Instance Attribute Details

#local_typing_contextObject

Returns the value of attribute local_typing_context.



15
16
17
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 15

def local_typing_context
  @local_typing_context
end

#super_typeObject

Returns the value of attribute super_type.



15
16
17
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 15

def super_type
  @super_type
end

Instance Method Details

#apply_bindings(bindings_map) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 98

def apply_bindings(bindings_map)
  type_vars(recursive: false).each_with_index do |var, _i|
    if var.is_a?(Polymorphism::TypeVariable) && var.bound_to_generic?
      var.bind(var.bound.apply_bindings(bindings_map))
    elsif var.is_a?(Polymorphism::TypeVariable)
      var.apply_bindings(bindings_map)
    elsif var.is_a?(TyGenericSingletonObject) || var.is_a?(TyGenericObject)
      var.apply_bindings(bindings_map)
    end
  end
  self
end

#as_object_typeObject



87
88
89
90
91
92
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 87

def as_object_type
  # this should only be used to check the body type of this
  # class. The variables are going to be unbound.
  # This is also used in instantiation of the generic object.
  TyGenericObject.new(ruby_type, @type_vars)
end

#cloneObject



111
112
113
114
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 111

def clone
  cloned_type_vars = type_vars.map(&:clone)
  TyGenericSingletonObject.new(ruby_type, cloned_type_vars, super_type, node)
end

#compute_minimal_typing_contextObject



94
95
96
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 94

def compute_minimal_typing_context
  Model::TmClass.with_fresh_bindings(self, nil, node)
end

#find_function_type(message, num_args, block) ⇒ Object

This object has concrete type parameters The generic Function we retrieve from the registry might be generic If it is generic we apply the bound parameters and we obtain a concrete function type



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 119

def find_function_type(message, num_args, block)
  function_klass_type, function_type = super(message, num_args, block)
  if function_klass_type != ruby_type && ancestor_of_super_type?(generic_singleton_object.super_type, function_klass_type)
    target_class = ancestor_of_super_type?(generic_singleton_object.super_type, function_klass_type)
    TypedRb.log binding, :debug, "Found message '#{message}', generic function: #{function_type}, explicit super type #{target_class}"
    target_type_vars = target_class.type_vars
    materialize_super_type_found_function(message, num_args, block, target_class, target_type_vars)
  elsif function_klass_type != ruby_type && BasicObject::TypeRegistry.find_generic_type(function_klass_type)
    TypedRb.log binding, :debug, "Found message '#{message}', generic function: #{function_type}, implict super type #{function_klass_type}"
    target_class = BasicObject::TypeRegistry.find_generic_type(function_klass_type)
    materialize_super_type_found_function(message, num_args, block, target_class, type_vars)
  else
    TypedRb.log binding, :debug, "Found message '#{message}', generic function: #{function_type}"
    materialized_function = materialize_found_function(function_type)
    TypedRb.log binding, :debug, "Found message '#{message}', materialized generic function: #{materialized_function}"
    [function_klass_type, materialized_function]
  end
end

#materialize(actual_arguments) ⇒ Object

materialize will be invoked by the logic handling invocations like: ts ‘MyClass[Y]’ class MyClass

...

end MyClass.(TypeArg1, TypeArg2) -> make X<TypeArg1, Y<TypeArg2, X>TypeArg1, X>TypeArg2 MyClass.(TypeArg1, TypeArg2) -> Materialize here > make X<TypeArg1, Y<TypeArg2 > Unification



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 54

def materialize(actual_arguments)
  TypedRb.log binding, :debug, "Materialising generic singleton object '#{self}' with args [#{actual_arguments.map(&:to_s).join(',')}]"
  # This can happen when we're dealing with a generic singleton object that has only been
  # annotated but we don't have the annotated implementation. e.g. Array[T]
  # We need to provide a default local_type_context based on the upper bounds provided in the
  # type annotation.
  compute_minimal_typing_context if @local_typing_context.nil?

  applied_typing_context, substitutions = @local_typing_context.clone(:class)
  fresh_vars_generic_type = clone_with_substitutions(substitutions)
  TypingContext.with_context(applied_typing_context) do
    # Appy constraints for application of Type args
    apply_type_arguments(fresh_vars_generic_type, actual_arguments)
  end
  # got all the constraints here
  # do something with the context -> unification? merge context?
  # applied_typing_context.all_constraints.each{|(l,t,r)| puts "#{l} #{t} #{r}" }
  unification = Polymorphism::Unification.new(applied_typing_context.all_constraints).run
  applied_typing_context.unlink # these constraints have already been satisfied
  # - Create a new ty_generic_object for the  unified types
  # - Apply the unified types to all the methods in the class/instance
  #   - this can be dynamically done with the right implementation of find_function_type
  # - Make the class available for the type checking system, so it can be found when
  #   - this can be done, just returning the new ty_singleton_object with the unified types
  #   - messages will be redirected to that instance and find_function_type/ find_var_type / as_object
  #     will handle the mesage
  # - looking for messages at the instance level
  #   - this can be accomplished with the overloading version of as_object_type, that will return
  #     an instance of a new class ty_generic_object with overloaded versions of find_function_type /find_var_type
  ########################
  fresh_vars_generic_type.apply_bindings(unification.bindings_map)
end

#materialize_with_type_vars(type_vars, bound_type) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 24

def materialize_with_type_vars(type_vars, bound_type)
  TypedRb.log binding, :debug, "Materialising generic singleton object with type vars '#{self}' <= #{type_vars.map(&:to_s).join(',')} :: #{bound_type}"
  bound_type_vars = self.type_vars.map do |type_var|
    maybe_class_bound = type_vars.detect do |bound_type_var|
      type_var.variable == bound_type_var.variable
    end
    if maybe_class_bound.nil?
      # it has to be method generic variable
      type_var
    else
      maybe_class_bound
    end
  end
  materialize(bound_type_vars.map { |bound_type_var| bound_type_var.send(bound_type) })
end

#self_materializeObject



40
41
42
43
44
45
# File 'lib/typed/types/ty_generic_singleton_object.rb', line 40

def self_materialize
  TypedRb.log binding, :debug, "Materialising self for generic singleton object '#{self}'"
  generic_type = BasicObject::TypeRegistry.find_generic_type(ruby_type)
  fail TypeCheckError.new("Missing generic type annotation for #{ruby_type}", node) if generic_type.nil?
  generic_type.materialize(type_vars)
end