Class: Steep::TypeInference::SendArgs::KeywordArgs

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

Defined Under Namespace

Classes: ArgTypePairs, MissingKeyword, SplatArg, UnexpectedKeyword

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(kwarg_nodes:, keyword_params:, index: 0, consumed_keywords: ) ⇒ KeywordArgs

Returns a new instance of KeywordArgs.



258
259
260
261
262
263
# File 'lib/steep/type_inference/send_args.rb', line 258

def initialize(kwarg_nodes:, keyword_params:, index: 0, consumed_keywords: Set[])
  @kwarg_nodes = kwarg_nodes
  @keyword_params = keyword_params
  @index = index
  @consumed_keywords = consumed_keywords
end

Instance Attribute Details

#consumed_keywordsObject (readonly)

Returns the value of attribute consumed_keywords.



256
257
258
# File 'lib/steep/type_inference/send_args.rb', line 256

def consumed_keywords
  @consumed_keywords
end

#indexObject (readonly)

Returns the value of attribute index.



255
256
257
# File 'lib/steep/type_inference/send_args.rb', line 255

def index
  @index
end

#keyword_paramsObject (readonly)

Returns the value of attribute keyword_params.



254
255
256
# File 'lib/steep/type_inference/send_args.rb', line 254

def keyword_params
  @keyword_params
end

#kwarg_nodesObject (readonly)

Returns the value of attribute kwarg_nodes.



253
254
255
# File 'lib/steep/type_inference/send_args.rb', line 253

def kwarg_nodes
  @kwarg_nodes
end

Instance Method Details

#all_keysObject



294
295
296
297
298
299
# File 'lib/steep/type_inference/send_args.rb', line 294

def all_keys
  keys = Set.new
  keys.merge(required_keywords.each_key)
  keys.merge(optional_keywords.each_key)
  keys.sort_by(&:to_s).to_a
end

#all_valuesObject



301
302
303
304
305
306
# File 'lib/steep/type_inference/send_args.rb', line 301

def all_values
  keys = Set.new
  keys.merge(required_keywords.each_value)
  keys.merge(optional_keywords.each_value)
  keys.sort_by(&:to_s).to_a
end

#consume_keys(keys, node:) ⇒ Object



402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/steep/type_inference/send_args.rb', line 402

def consume_keys(keys, node:)
  # @type var consumed_keys: Array[Symbol]
  consumed_keys = []
  # @type var types: Array[AST::Types::t]
  types = []

  # @type var unexpected_keyword: Symbol?
  unexpected_keyword = nil

  keys.each do |key|
    case
    when type = keyword_type(key)
      consumed_keys << key
      types << type
    when type = rest_type()
      types << type
    else
      unexpected_keyword = key
    end
  end

  [
    if unexpected_keyword
      UnexpectedKeyword.new(keyword: unexpected_keyword, node: node)
    else
      types
    end,
    update(index: index + 1, consumed_keywords: consumed_keywords + consumed_keys)
  ]
end

#keyword_pairObject



274
275
276
# File 'lib/steep/type_inference/send_args.rb', line 274

def keyword_pair
  kwarg_nodes[index]
end

#keyword_type(key) ⇒ Object



290
291
292
# File 'lib/steep/type_inference/send_args.rb', line 290

def keyword_type(key)
  required_keywords[key] || optional_keywords[key]
end

#nextObject



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/steep/type_inference/send_args.rb', line 323

def next()
  node = keyword_pair

  if node
    case node.type
    when :pair
      key_node, value_node = node.children

      if key_node.type == :sym
        key = key_node.children[0]

        case
        when value_type = keyword_type(key)
          [
            ArgTypePairs.new(
              pairs: [
                [key_node, AST::Types::Literal.new(value: key)],
                [value_node, value_type]
              ]
            ),
            update(
              index: index+1,
              consumed_keywords: consumed_keywords + [key]
            )
          ]
        when value_type = rest_type
          [
            ArgTypePairs.new(
              pairs: [
                [key_node, AST::Builtin::Symbol.instance_type],
                [value_node, value_type]
              ]
            ),
            update(
              index: index+1,
              consumed_keywords: consumed_keywords + [key]
            )
          ]
        else
          [
            UnexpectedKeyword.new(keyword: key, node: node),
            update(index: index+1)
          ]
        end
      else
        if !all_keys.empty? || rest_type
          [
            ArgTypePairs.new(
              pairs: [
                [key_node, possible_key_type],
                [value_node, possible_value_type]
              ]
            ),
            update(index: index+1)
          ]
        else
          [
            UnexpectedKeyword.new(keyword: nil, node: node),
            update(index: index+1)
          ]
        end
      end
    when :kwsplat
      [
        SplatArg.new(node: node),
        self
      ]
    end
  else
    left = Set.new(required_keywords.keys) - consumed_keywords
    unless left.empty?
      [
        MissingKeyword.new(keywords: left),
        update(consumed_keywords: consumed_keywords + left)
      ]
    end
  end
end

#optional_keywordsObject



282
283
284
# File 'lib/steep/type_inference/send_args.rb', line 282

def optional_keywords
  keyword_params.optionals
end

#possible_key_typeObject



308
309
310
311
312
313
314
# File 'lib/steep/type_inference/send_args.rb', line 308

def possible_key_type
  # @type var key_types: Array[AST::Types::t]
  key_types = all_keys.map {|key| AST::Types::Literal.new(value: key) }
  key_types << AST::Builtin::Symbol.instance_type if rest_type

  AST::Types::Union.build(types: key_types)
end

#possible_value_typeObject



316
317
318
319
320
321
# File 'lib/steep/type_inference/send_args.rb', line 316

def possible_value_type
  value_types = all_values
  value_types << rest_type if rest_type

  AST::Types::Intersection.build(types: value_types)
end

#required_keywordsObject



278
279
280
# File 'lib/steep/type_inference/send_args.rb', line 278

def required_keywords
  keyword_params.requireds
end

#rest_typeObject



286
287
288
# File 'lib/steep/type_inference/send_args.rb', line 286

def rest_type
  keyword_params.rest
end

#update(index: self.index, consumed_keywords: self.consumed_keywords) ⇒ Object



265
266
267
268
269
270
271
272
# File 'lib/steep/type_inference/send_args.rb', line 265

def update(index: self.index, consumed_keywords: self.consumed_keywords)
  KeywordArgs.new(
    kwarg_nodes: kwarg_nodes,
    keyword_params: keyword_params,
    index: index,
    consumed_keywords: consumed_keywords
  )
end