Class: Steep::TypeInference::LocalVariableTypeEnv

Inherits:
Object
  • Object
show all
Defined in:
lib/steep/type_inference/local_variable_type_env.rb

Defined Under Namespace

Classes: Entry

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(subtyping:, declared_types:, assigned_types:, self_type:) ⇒ LocalVariableTypeEnv

Returns a new instance of LocalVariableTypeEnv.



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 49

def initialize(subtyping:, declared_types:, assigned_types:, self_type:)
  @subtyping = subtyping
  @self_type = self_type

  @declared_types = declared_types
  @assigned_types = assigned_types

  unless (intersection = Set.new(declared_types.keys) & Set.new(assigned_types.keys)).empty?
    raise "Declared types and assigned types should be disjoint: #{intersection}"
  end
end

Instance Attribute Details

#assigned_typesObject (readonly)

Returns the value of attribute assigned_types.



43
44
45
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 43

def assigned_types
  @assigned_types
end

#declared_typesObject (readonly)

Returns the value of attribute declared_types.



42
43
44
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 42

def declared_types
  @declared_types
end

#self_typeObject (readonly)

Returns the value of attribute self_type.



5
6
7
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 5

def self_type
  @self_type
end

#subtypingObject (readonly)

Returns the value of attribute subtyping.



4
5
6
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 4

def subtyping
  @subtyping
end

Class Method Details

.empty(subtyping:, self_type:) ⇒ Object



45
46
47
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 45

def self.empty(subtyping:, self_type:)
  new(subtyping: subtyping, declared_types: {}, assigned_types: {}, self_type: self_type)
end

Instance Method Details

#[](var) ⇒ Object



128
129
130
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 128

def [](var)
  entry(var)&.type
end

#annotate(collection) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 103

def annotate(collection)
  decls = collection.var_type_annotations.each.with_object({}) do |(var, annotation), hash|
    type = collection.var_type(lvar: var)
    hash[var] = Entry.new(type: type, annotations: [annotation])
  end

  decls.each do |var, annot|
    inner_type = annot.type
    outer_type = self[var]

    if outer_type
      relation = Subtyping::Relation.new(sub_type: inner_type, super_type: outer_type)
      constraints = Subtyping::Constraints.new(unknowns: Set.new)
      subtyping.check(relation, constraints: constraints, self_type: self_type).else do |result|
        yield var, outer_type, inner_type, result
      end
    end
  end

  new_decls = declared_types.merge(decls)
  new_assigns = assigned_types.reject {|var, _| new_decls.key?(var) }

  update(declared_types: new_decls, assigned_types: new_assigns)
end

#assign(var, node:, type:) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 86

def assign(var, node:, type:)
  declared_type = declared_types[var]&.type

  if declared_type
    relation = Subtyping::Relation.new(sub_type: type, super_type: declared_type)
    constraints = Subtyping::Constraints.new(unknowns: Set.new)
    subtyping.check(relation, constraints: constraints, self_type: self_type).else do |result|
      yield declared_type, type, result
    end

    self
  else
    assignments = { var => Entry.new(type: type, nodes: [node]) }
    update(assigned_types: assigned_types.merge(assignments))
  end
end

#assign!(var, node:, type:) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 70

def assign!(var, node:, type:)
  declared_type = declared_types[var]&.type

  if declared_type
    relation = Subtyping::Relation.new(sub_type: type, super_type: declared_type)
    constraints = Subtyping::Constraints.new(unknowns: Set.new)
    subtyping.check(relation, constraints: constraints, self_type: self_type).else do |result|
      yield declared_type, type, result
    end
  end

  assignments = { var => Entry.new(type: type, nodes: [node]) }
  update(assigned_types: assigned_types.merge(assignments),
         declared_types: declared_types.reject {|k, _| k == var })
end

#eachObject



150
151
152
153
154
155
156
157
158
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 150

def each
  if block_given?
    vars.each do |var|
      yield var, self[var]
    end
  else
    enum_for :each
  end
end

#entry(var) ⇒ Object



132
133
134
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 132

def entry(var)
  declared_types[var] || assigned_types[var]
end

#except(variables) ⇒ Object



143
144
145
146
147
148
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 143

def except(variables)
  update(
    declared_types: declared_types.reject {|var, _| variables.include?(var) },
    assigned_types: assigned_types.reject {|var, _| variables.include?(var) }
  )
end

#join(*envs) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 164

def join(*envs)
  if envs.empty?
    self
  else
    env = envs.inject do |env1, env2|
      assigned_types = {}
      declared_types = {}

      (env1.vars + env2.vars).each do |var|
        e1 = env1.entry(var)
        e2 = env2.entry(var)
        je = join_entry(e1, e2)

        if env1.declared_types.key?(var) || env2.declared_types.key?(var)
          declared_types[var] = je
        else
          assigned_types[var] = je
        end
      end

      LocalVariableTypeEnv.new(
        subtyping: subtyping,
        self_type: self_type,
        declared_types: declared_types,
        assigned_types: assigned_types
      )
    end

    decls = env.declared_types.merge(declared_types)
    assignments = env.assigned_types.reject {|var, _| decls.key?(var) }

    update(
      declared_types: decls,
      assigned_types: assignments,
    )
  end
end

#join_entry(e1, e2) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 202

def join_entry(e1, e2)
  case
  when e1 && e2
    e1 + e2
  when e1
    e1.optional
  when e2
    e2.optional
  else
    raise
  end
end

#pin_assignmentsObject



136
137
138
139
140
141
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 136

def pin_assignments
  update(
    declared_types: assigned_types.merge(declared_types),
    assigned_types: {}
  )
end

#to_sObject



215
216
217
218
219
220
221
222
223
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 215

def to_s
  ss = []

  vars.each do |var|
    ss << "#{var}: #{self[var].to_s}"
  end

  "{#{ss.join(", ")}}"
end

#update(declared_types: self.declared_types, assigned_types: self.assigned_types, self_type: self.self_type) ⇒ Object



61
62
63
64
65
66
67
68
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 61

def update(declared_types: self.declared_types, assigned_types: self.assigned_types, self_type: self.self_type)
  self.class.new(
    subtyping: subtyping,
    declared_types: declared_types,
    assigned_types: assigned_types,
    self_type: self_type
  )
end

#varsObject



160
161
162
# File 'lib/steep/type_inference/local_variable_type_env.rb', line 160

def vars
  @vars ||= Set.new(declared_types.keys + assigned_types.keys)
end