steep 0.30.0 → 0.34.0

Sign up to get free protection for your applications and to get access to all the features.
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