steep 0.30.0 → 0.34.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5293cbc87834cee36e50cb66bab84e466a5182c1e868732b7bd3e685b2bd954
4
- data.tar.gz: 7794e42573b5ac04c74780824213cfbe1ca255f1feaa4465a1066377d2647e0b
3
+ metadata.gz: 0ec77465913e4b2146e068c58f63b7ae8b5c51fd2391f6eb2776dba8372a81c2
4
+ data.tar.gz: 7528dbaf4873d9eb77728521837ecb0fe43a2010036572be2c3dc017c5b903cc
5
5
  SHA512:
6
- metadata.gz: e723bf77a7452e0696c38d6d1797e71f246fb97d1b1f18082ba21b8eadb8174d6bcc4deda872898b5f39d162b91173c413cacfa28175018517170f8f2568bd70
7
- data.tar.gz: 38dbe78df43706fe33d5350ad04524c25606955bcba5397ad18690717a60c59d361485ad2d5d3077787336d23902bd91ba9fa5b31e1933a93d1fe32747837688
6
+ metadata.gz: b0426373f8fb9e48ccec48d0676d70d5a674a389a83624df78dc3deacaba23840b02cc94becba92304de35f98c8d8bb3af12ef185161e4e6a6c37600cb61a82d
7
+ data.tar.gz: 5f3a32240541f116b6299c354fada0c8de398b6139b9d5e275e7b05490ccc401aa1b4f70978af5561e2ce9c6c7bb2587c1c8e43801276c0875000496ed332a5b
@@ -2,6 +2,32 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.34.0 (2020-10-27)
6
+
7
+ * Add `steep stats` command to show method call typing stats ([#246](https://github.com/soutaro/steep/pull/246))
8
+ * Fix attribute assignment typing ([#243](https://github.com/soutaro/steep/pull/243))
9
+ * Let `Range[T]` be covariant ([#242](https://github.com/soutaro/steep/pull/242))
10
+ * Fix constant typing ([#247](https://github.com/soutaro/steep/pull/247), [#248](https://github.com/soutaro/steep/pull/248))
11
+
12
+ ## 0.33.0 (2020-10-13)
13
+
14
+ * Make `!` typing flow sensitive ([#240](https://github.com/soutaro/steep/pull/240))
15
+
16
+ ## 0.32.0 (2020-10-09)
17
+
18
+ * Let type-case support interface types ([#237](https://github.com/soutaro/steep/pull/237))
19
+
20
+ ## 0.31.1 (2020-10-07)
21
+
22
+ * Fix `if-then-else` parsing ([#236](https://github.com/soutaro/steep/pull/236))
23
+
24
+ ## 0.31.0 (2020-10-04)
25
+
26
+ * Fix type checking performance ([#230](https://github.com/soutaro/steep/pull/230))
27
+ * Improve LSP completion/hover performance ([#232](https://github.com/soutaro/steep/pull/232))
28
+ * Fix instance variable completion ([#234](https://github.com/soutaro/steep/pull/234))
29
+ * Relax version requirements on Listen to allow installing on Ruby 3 ([#235](https://github.com/soutaro/steep/pull/235))
30
+
5
31
  ## 0.30.0 (2020-10-03)
6
32
 
7
33
  * Let top-level defs be methods of Object ([#227](https://github.com/soutaro/steep/pull/227))
@@ -9,8 +9,7 @@ def exit(*)
9
9
 
10
10
  end
11
11
 
12
-
13
12
  STDERR.puts "Running profiler: mode=#{mode}, out=#{out}"
14
- StackProf.run(mode: mode, out: out) do
13
+ StackProf.run(mode: mode, out: out, raw: true) do
15
14
  load File.join(__dir__, "../exe/steep")
16
15
  end
@@ -16,7 +16,7 @@ require 'uri'
16
16
 
17
17
  require "rbs"
18
18
 
19
- require "steep/ast/location"
19
+ require "steep/method_name"
20
20
  require "steep/ast/types/helper"
21
21
  require "steep/ast/types/any"
22
22
  require "steep/ast/types/instance"
@@ -39,7 +39,6 @@ require "steep/ast/types/logic"
39
39
  require "steep/ast/type_params"
40
40
  require "steep/ast/annotation"
41
41
  require "steep/ast/annotation/collection"
42
- require "steep/ast/buffer"
43
42
  require "steep/ast/builtin"
44
43
  require "steep/ast/types/factory"
45
44
 
@@ -72,6 +71,7 @@ require "steep/type_inference/type_env"
72
71
  require "steep/type_inference/local_variable_type_env"
73
72
  require "steep/type_inference/logic"
74
73
  require "steep/type_inference/logic_type_interpreter"
74
+ require "steep/type_inference/method_call"
75
75
  require "steep/ast/types"
76
76
 
77
77
  require "steep/server/utils"
@@ -93,6 +93,7 @@ require "steep/project/hover_content"
93
93
  require "steep/project/completion_provider"
94
94
  require "steep/drivers/utils/driver_helper"
95
95
  require "steep/drivers/check"
96
+ require "steep/drivers/stats"
96
97
  require "steep/drivers/validate"
97
98
  require "steep/drivers/annotations"
98
99
  require "steep/drivers/watch"
@@ -68,7 +68,7 @@ module Steep
68
68
  name = match[:name]
69
69
  type = match[:type]
70
70
 
71
- method_type = factory.method_type(RBS::Parser.parse_method_type(type), self_type: AST::Types::Self.new)
71
+ method_type = factory.method_type(RBS::Parser.parse_method_type(type), self_type: AST::Types::Self.new, method_decls: Set[])
72
72
 
73
73
  AST::Annotation::MethodType.new(name: name.to_sym,
74
74
  type: method_type,
@@ -7,11 +7,14 @@ module Steep
7
7
  attr_reader :type_name_cache
8
8
  attr_reader :type_cache
9
9
 
10
+ attr_reader :type_interface_cache
11
+
10
12
  def initialize(builder:)
11
13
  @definition_builder = builder
12
14
 
13
15
  @type_name_cache = {}
14
16
  @type_cache = {}
17
+ @type_interface_cache = {}
15
18
  end
16
19
 
17
20
  def type_name_resolver
@@ -146,6 +149,8 @@ module Steep
146
149
  type: function_1(type.params, type.return_type),
147
150
  location: nil
148
151
  )
152
+ when Logic::Base
153
+ RBS::Types::Bases::Bool.new(location: nil)
149
154
  else
150
155
  raise "Unexpected type given: #{type} (#{type.class})"
151
156
  end
@@ -175,7 +180,7 @@ module Steep
175
180
  )
176
181
  end
177
182
 
178
- def method_type(method_type, self_type:, subst2: nil, method_def: nil)
183
+ def method_type(method_type, self_type:, subst2: nil, method_decls:)
179
184
  fvs = self_type.free_variables()
180
185
 
181
186
  type_params = []
@@ -206,8 +211,7 @@ module Steep
206
211
  return_type: type(block.type.return_type).subst(subst), location: nil)
207
212
  )
208
213
  end,
209
- method_def: method_def,
210
- location: method_def&.member&.location
214
+ method_decls: method_decls
211
215
  )
212
216
 
213
217
  if block_given?
@@ -339,48 +343,46 @@ module Steep
339
343
  end
340
344
  end
341
345
 
342
- def setup_primitives(method_name, method_type)
343
- if method_def = method_type.method_def
344
- defined_in = method_def.defined_in
345
- member = method_def.member
346
-
347
- if member.is_a?(RBS::AST::Members::MethodDefinition)
348
- case
349
- when defined_in == RBS::BuiltinNames::Object.name && member.instance?
350
- case method_name
351
- when :is_a?, :kind_of?, :instance_of?
352
- return method_type.with(
353
- return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
354
- )
355
- when :nil?
356
- return method_type.with(
357
- return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
358
- )
359
- end
346
+ NilClassName = TypeName("::NilClass")
360
347
 
361
- when defined_in == AST::Builtin::NilClass.module_name && member.instance?
362
- case method_name
363
- when :nil?
364
- return method_type.with(
365
- return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
366
- )
367
- end
348
+ def setup_primitives(method_name, method_def, method_type)
349
+ defined_in = method_def.defined_in
350
+ member = method_def.member
368
351
 
369
- when defined_in == RBS::BuiltinNames::BasicObject.name && member.instance?
370
- case method_name
371
- when :!
372
- return method_type.with(
373
- return_type: AST::Types::Logic::Not.new(location: method_type.return_type.location)
374
- )
375
- end
352
+ if member.is_a?(RBS::AST::Members::MethodDefinition)
353
+ case method_name
354
+ when :is_a?, :kind_of?, :instance_of?
355
+ if defined_in == RBS::BuiltinNames::Object.name && member.instance?
356
+ return method_type.with(
357
+ return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
358
+ )
359
+ end
376
360
 
377
- when defined_in == RBS::BuiltinNames::Module.name && member.instance?
378
- case method_name
379
- when :===
380
- return method_type.with(
381
- return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.return_type.location)
382
- )
383
- end
361
+ when :nil?
362
+ case defined_in
363
+ when RBS::BuiltinNames::Object.name,
364
+ NilClassName
365
+ return method_type.with(
366
+ return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
367
+ )
368
+ end
369
+
370
+ when :!
371
+ case defined_in
372
+ when RBS::BuiltinNames::BasicObject.name,
373
+ RBS::BuiltinNames::TrueClass.name,
374
+ RBS::BuiltinNames::FalseClass.name
375
+ return method_type.with(
376
+ return_type: AST::Types::Logic::Not.new(location: method_type.return_type.location)
377
+ )
378
+ end
379
+
380
+ when :===
381
+ case defined_in
382
+ when RBS::BuiltinNames::Module.name
383
+ return method_type.with(
384
+ return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.return_type.location)
385
+ )
384
386
  end
385
387
  end
386
388
  end
@@ -390,15 +392,23 @@ module Steep
390
392
 
391
393
  def interface(type, private:, self_type: type)
392
394
  Steep.logger.debug { "Factory#interface: #{type}, private=#{private}, self_type=#{self_type}" }
393
- type = expand_alias(type)
395
+
396
+ cache_key = [type, self_type, private]
397
+ if type_interface_cache.key?(cache_key)
398
+ return type_interface_cache[cache_key]
399
+ end
394
400
 
395
401
  case type
402
+ when Name::Alias
403
+ interface(expand_alias(type), private: private, self_type: self_type)
404
+
396
405
  when Self
397
406
  if self_type != type
398
407
  interface self_type, private: private, self_type: Self.new
399
408
  else
400
409
  raise "Unexpected `self` type interface"
401
410
  end
411
+
402
412
  when Name::Instance
403
413
  Interface::Interface.new(type: self_type, private: private).tap do |interface|
404
414
  definition = definition_builder.build_instance(type.name)
@@ -422,10 +432,13 @@ module Steep
422
432
 
423
433
  interface.methods[name] = Interface::Interface::Entry.new(
424
434
  method_types: method.defs.map do |type_def|
435
+ method_name = InstanceMethodName.new(type_name: type_def.implemented_in || type_def.defined_in, method_name: name)
436
+ decl = TypeInference::MethodCall::MethodDecl.new(method_name: method_name, method_def: type_def)
425
437
  setup_primitives(
426
438
  name,
439
+ type_def,
427
440
  method_type(type_def.type,
428
- method_def: type_def,
441
+ method_decls: Set[decl],
429
442
  self_type: self_type,
430
443
  subst2: subst)
431
444
  )
@@ -449,7 +462,11 @@ module Steep
449
462
  definition.methods.each do |name, method|
450
463
  interface.methods[name] = Interface::Interface::Entry.new(
451
464
  method_types: method.defs.map do |type_def|
452
- method_type(type_def.type, method_def: type_def, self_type: self_type, subst2: subst)
465
+ decls = Set[TypeInference::MethodCall::MethodDecl.new(
466
+ method_name: InstanceMethodName.new(type_name: type_def.implemented_in || type_def.defined_in, method_name: name),
467
+ method_def: type_def
468
+ )]
469
+ method_type(type_def.type, method_decls: decls, self_type: self_type, subst2: subst)
453
470
  end
454
471
  )
455
472
  end
@@ -474,10 +491,16 @@ module Steep
474
491
 
475
492
  interface.methods[name] = Interface::Interface::Entry.new(
476
493
  method_types: method.defs.map do |type_def|
494
+ decl = TypeInference::MethodCall::MethodDecl.new(
495
+ method_name: SingletonMethodName.new(type_name: type_def.implemented_in || type_def.defined_in,
496
+ method_name: name),
497
+ method_def: type_def
498
+ )
477
499
  setup_primitives(
478
500
  name,
501
+ type_def,
479
502
  method_type(type_def.type,
480
- method_def: type_def,
503
+ method_decls: Set[decl],
481
504
  self_type: self_type,
482
505
  subst2: subst)
483
506
  )
@@ -557,8 +580,7 @@ module Steep
557
580
  rest_keywords: nil),
558
581
  block: nil,
559
582
  return_type: elem_type,
560
- method_def: nil,
561
- location: nil
583
+ method_decls: Set[]
562
584
  )
563
585
  } + aref.method_types
564
586
  )
@@ -577,8 +599,7 @@ module Steep
577
599
  rest_keywords: nil),
578
600
  block: nil,
579
601
  return_type: elem_type,
580
- method_def: nil,
581
- location: nil
602
+ method_decls: Set[]
582
603
  )
583
604
  } + update.method_types
584
605
  )
@@ -592,8 +613,7 @@ module Steep
592
613
  params: Interface::Params.empty,
593
614
  block: nil,
594
615
  return_type: type.types[0] || AST::Builtin.nil_type,
595
- method_def: nil,
596
- location: nil
616
+ method_decls: Set[]
597
617
  )
598
618
  ]
599
619
  )
@@ -607,8 +627,7 @@ module Steep
607
627
  params: Interface::Params.empty,
608
628
  block: nil,
609
629
  return_type: type.types.last || AST::Builtin.nil_type,
610
- method_def: nil,
611
- location: nil
630
+ method_decls: Set[]
612
631
  )
613
632
  ]
614
633
  )
@@ -629,6 +648,7 @@ module Steep
629
648
  Interface::Interface::Entry.new(
630
649
  method_types: type.elements.map {|key_value, value_type|
631
650
  key_type = Literal.new(value: key_value, location: nil)
651
+
632
652
  Interface::MethodType.new(
633
653
  type_params: [],
634
654
  params: Interface::Params.new(required: [key_type],
@@ -639,8 +659,7 @@ module Steep
639
659
  rest_keywords: nil),
640
660
  block: nil,
641
661
  return_type: value_type,
642
- method_def: nil,
643
- location: nil
662
+ method_decls: Set[]
644
663
  )
645
664
  } + ref.method_types
646
665
  )
@@ -660,8 +679,7 @@ module Steep
660
679
  rest_keywords: nil),
661
680
  block: nil,
662
681
  return_type: value_type,
663
- method_def: nil,
664
- location: nil
682
+ method_decls: Set[]
665
683
  )
666
684
  } + update.method_types
667
685
  )
@@ -676,8 +694,7 @@ module Steep
676
694
  params: type.params,
677
695
  return_type: type.return_type,
678
696
  block: nil,
679
- method_def: nil,
680
- location: nil
697
+ method_decls: Set[]
681
698
  )
682
699
 
683
700
  interface.methods[:[]] = Interface::Interface::Entry.new(method_types: [method_type])
@@ -689,6 +706,8 @@ module Steep
689
706
 
690
707
  else
691
708
  raise "Unexpected type for interface: #{type}"
709
+ end.tap do |interface|
710
+ type_interface_cache[cache_key] = interface
692
711
  end
693
712
  end
694
713
 
@@ -16,7 +16,7 @@ module Steep
16
16
  end
17
17
 
18
18
  def self.available_commands
19
- [:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :vendor]
19
+ [:init, :check, :validate, :annotations, :version, :project, :watch, :langserver, :vendor, :stats]
20
20
  end
21
21
 
22
22
  def process_global_options
@@ -91,6 +91,19 @@ module Steep
91
91
  end.run
92
92
  end
93
93
 
94
+ def process_stats
95
+ Drivers::Stats.new(stdout: stdout, stderr: stderr).tap do |check|
96
+ OptionParser.new do |opts|
97
+ opts.banner = "Usage: steep stats [options] [sources]"
98
+
99
+ opts.on("--steepfile=PATH") {|path| check.steepfile = Pathname(path) }
100
+ handle_logging_options opts
101
+ end.parse!(argv)
102
+
103
+ check.command_line_patterns.push *argv
104
+ end.run
105
+ end
106
+
94
107
  def process_validate
95
108
  Drivers::Validate.new(stdout: stdout, stderr: stderr).tap do |command|
96
109
  OptionParser.new do |opts|
@@ -0,0 +1,85 @@
1
+ require "csv"
2
+
3
+ module Steep
4
+ module Drivers
5
+ class Stats
6
+ attr_reader :stdout
7
+ attr_reader :stderr
8
+ attr_reader :command_line_patterns
9
+
10
+ include Utils::DriverHelper
11
+
12
+ def initialize(stdout:, stderr:)
13
+ @stdout = stdout
14
+ @stderr = stderr
15
+ @command_line_patterns = []
16
+ end
17
+
18
+ def run
19
+ project = load_config()
20
+
21
+ loader = Project::FileLoader.new(project: project)
22
+ loader.load_sources(command_line_patterns)
23
+ loader.load_signatures()
24
+
25
+ type_check(project)
26
+
27
+ stdout.puts(
28
+ CSV.generate do |csv|
29
+ csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
30
+
31
+ project.targets.each do |target|
32
+ case (status = target.status)
33
+ when Project::Target::TypeCheckStatus
34
+ status.type_check_sources.each do |source_file|
35
+ case source_file.status
36
+ when Project::SourceFile::TypeCheckStatus
37
+ typing = source_file.status.typing
38
+
39
+ typed = 0
40
+ untyped = 0
41
+ total = 0
42
+ typing.method_calls.each_value do |call|
43
+ case call
44
+ when TypeInference::MethodCall::Typed
45
+ typed += 1
46
+ when TypeInference::MethodCall::Untyped
47
+ untyped += 1
48
+ end
49
+
50
+ total += 1
51
+ end
52
+
53
+ csv << format_stats(target, source_file.path, "success", typed, untyped, total)
54
+ when Project::SourceFile::TypeCheckErrorStatus
55
+ csv << format_stats(target, source_file.path, "error", 0, 0, 0)
56
+ else
57
+ csv << format_stats(target, source_file.path, "unknown (#{source_file.status.class.to_s.split(/::/).last})", 0, 0, 0)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ )
64
+
65
+ 0
66
+ end
67
+
68
+ def format_stats(target, path, status, typed, untyped, total)
69
+ [
70
+ target.name,
71
+ path.to_s,
72
+ status,
73
+ typed,
74
+ untyped,
75
+ total,
76
+ if total.nonzero?
77
+ format("%.2f", (typed.to_f/total)*100)
78
+ else
79
+ 0
80
+ end
81
+ ]
82
+ end
83
+ end
84
+ end
85
+ end