steep 0.31.0 → 0.35.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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/lib/steep.rb +3 -2
  4. data/lib/steep/annotation_parser.rb +1 -1
  5. data/lib/steep/ast/types/factory.rb +66 -60
  6. data/lib/steep/cli.rb +15 -2
  7. data/lib/steep/drivers/print_project.rb +11 -0
  8. data/lib/steep/drivers/stats.rb +85 -0
  9. data/lib/steep/drivers/vendor.rb +1 -20
  10. data/lib/steep/errors.rb +19 -15
  11. data/lib/steep/interface/method_type.rb +12 -23
  12. data/lib/steep/method_name.rb +28 -0
  13. data/lib/steep/project/completion_provider.rb +24 -15
  14. data/lib/steep/project/dsl.rb +13 -17
  15. data/lib/steep/project/options.rb +4 -4
  16. data/lib/steep/project/source_file.rb +2 -1
  17. data/lib/steep/project/target.rb +19 -10
  18. data/lib/steep/server/interaction_worker.rb +1 -1
  19. data/lib/steep/server/utils.rb +1 -1
  20. data/lib/steep/source.rb +3 -3
  21. data/lib/steep/subtyping/check.rb +30 -16
  22. data/lib/steep/subtyping/variable_occurrence.rb +2 -0
  23. data/lib/steep/type_construction.rb +585 -416
  24. data/lib/steep/type_inference/context.rb +7 -3
  25. data/lib/steep/type_inference/context_array.rb +1 -1
  26. data/lib/steep/type_inference/local_variable_type_env.rb +10 -1
  27. data/lib/steep/type_inference/logic_type_interpreter.rb +6 -0
  28. data/lib/steep/type_inference/method_call.rb +116 -0
  29. data/lib/steep/typing.rb +38 -8
  30. data/lib/steep/version.rb +1 -1
  31. data/smoke/regression/fun.rb +8 -0
  32. data/smoke/regression/fun.rbs +4 -0
  33. data/smoke/regression/range.rb +5 -0
  34. data/steep.gemspec +1 -1
  35. metadata +10 -6
  36. data/lib/steep/ast/buffer.rb +0 -51
  37. data/lib/steep/ast/location.rb +0 -86
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e315b0a9541b0289ae3c9dd3acb19c2112e990a321176f94ed44f25d4190acb4
4
- data.tar.gz: 9ce6e2024e81e5a2452fc5d7ca381decd1d91ed917d385dc280133652af51e06
3
+ metadata.gz: 5ddd53798b724f6fd1a93d869b03a3864db04bed448552a75dadeabe8d1bc51e
4
+ data.tar.gz: c85f6c58a010ed11dfc1041f8ba98007e0f557d7bda133222b94915dfed0d6ca
5
5
  SHA512:
6
- metadata.gz: bd8db01573d1a2e31b362fb893bfad1325969b8343415d1bfd82428a76f0a6c8f8fe2875f7e474ab94244476e9901b1dda186f57cb90a49602638453826534a8
7
- data.tar.gz: f1f30e2afc48265917468a4c5dd040fff3e226f92cb17441c3f3fcbba7f95aaa1002172ece399410d567358d9caf7bd80c1f1c27b9083c81a39e1abe61b74a68
6
+ metadata.gz: 79a7742bdef0d368aa2dceaa528cf3e4bc74bccefafc0d6c366aa94994917e7d5560c8d4fd6f03adf0d50c3b8536d80d7e998bba3a9dc5cb872c7047c0079cba
7
+ data.tar.gz: 512b5bdf6efd6e465d5e3147de2df6cafb549fe68e05890efc13fffcc763b0cec1c48005a1734b6ade2cd120fa48059c435c20bad4b9998b1d15a0b4f557f615
@@ -2,6 +2,31 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.35.0 (2020-11-14)
6
+
7
+ * Support third party RBS repository ([#231](https://github.com/soutaro/steep/pull/231), [#254](https://github.com/soutaro/steep/pull/254), [#255](https://github.com/soutaro/steep/pull/255))
8
+ * Boolean type semantics update ([#252](https://github.com/soutaro/steep/pull/252))
9
+ * More flexible record typing ([#256](https://github.com/soutaro/steep/pull/256))
10
+
11
+ ## 0.34.0 (2020-10-27)
12
+
13
+ * Add `steep stats` command to show method call typing stats ([#246](https://github.com/soutaro/steep/pull/246))
14
+ * Fix attribute assignment typing ([#243](https://github.com/soutaro/steep/pull/243))
15
+ * Let `Range[T]` be covariant ([#242](https://github.com/soutaro/steep/pull/242))
16
+ * Fix constant typing ([#247](https://github.com/soutaro/steep/pull/247), [#248](https://github.com/soutaro/steep/pull/248))
17
+
18
+ ## 0.33.0 (2020-10-13)
19
+
20
+ * Make `!` typing flow sensitive ([#240](https://github.com/soutaro/steep/pull/240))
21
+
22
+ ## 0.32.0 (2020-10-09)
23
+
24
+ * Let type-case support interface types ([#237](https://github.com/soutaro/steep/pull/237))
25
+
26
+ ## 0.31.1 (2020-10-07)
27
+
28
+ * Fix `if-then-else` parsing ([#236](https://github.com/soutaro/steep/pull/236))
29
+
5
30
  ## 0.31.0 (2020-10-04)
6
31
 
7
32
  * Fix type checking performance ([#230](https://github.com/soutaro/steep/pull/230))
@@ -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,
@@ -149,6 +149,8 @@ module Steep
149
149
  type: function_1(type.params, type.return_type),
150
150
  location: nil
151
151
  )
152
+ when Logic::Base
153
+ RBS::Types::Bases::Bool.new(location: nil)
152
154
  else
153
155
  raise "Unexpected type given: #{type} (#{type.class})"
154
156
  end
@@ -178,7 +180,7 @@ module Steep
178
180
  )
179
181
  end
180
182
 
181
- def method_type(method_type, self_type:, subst2: nil, method_def: nil)
183
+ def method_type(method_type, self_type:, subst2: nil, method_decls:)
182
184
  fvs = self_type.free_variables()
183
185
 
184
186
  type_params = []
@@ -209,8 +211,7 @@ module Steep
209
211
  return_type: type(block.type.return_type).subst(subst), location: nil)
210
212
  )
211
213
  end,
212
- method_def: method_def,
213
- location: method_def&.member&.location
214
+ method_decls: method_decls
214
215
  )
215
216
 
216
217
  if block_given?
@@ -342,48 +343,46 @@ module Steep
342
343
  end
343
344
  end
344
345
 
345
- def setup_primitives(method_name, method_type)
346
- if method_def = method_type.method_def
347
- defined_in = method_def.defined_in
348
- member = method_def.member
349
-
350
- if member.is_a?(RBS::AST::Members::MethodDefinition)
351
- case
352
- when defined_in == RBS::BuiltinNames::Object.name && member.instance?
353
- case method_name
354
- when :is_a?, :kind_of?, :instance_of?
355
- return method_type.with(
356
- return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
357
- )
358
- when :nil?
359
- return method_type.with(
360
- return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
361
- )
362
- end
346
+ NilClassName = TypeName("::NilClass")
363
347
 
364
- when defined_in == AST::Builtin::NilClass.module_name && member.instance?
365
- case method_name
366
- when :nil?
367
- return method_type.with(
368
- return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
369
- )
370
- end
348
+ def setup_primitives(method_name, method_def, method_type)
349
+ defined_in = method_def.defined_in
350
+ member = method_def.member
371
351
 
372
- when defined_in == RBS::BuiltinNames::BasicObject.name && member.instance?
373
- case method_name
374
- when :!
375
- return method_type.with(
376
- return_type: AST::Types::Logic::Not.new(location: method_type.return_type.location)
377
- )
378
- 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
379
360
 
380
- when defined_in == RBS::BuiltinNames::Module.name && member.instance?
381
- case method_name
382
- when :===
383
- return method_type.with(
384
- return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.return_type.location)
385
- )
386
- 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
+ )
387
386
  end
388
387
  end
389
388
  end
@@ -409,7 +408,7 @@ module Steep
409
408
  else
410
409
  raise "Unexpected `self` type interface"
411
410
  end
412
-
411
+
413
412
  when Name::Instance
414
413
  Interface::Interface.new(type: self_type, private: private).tap do |interface|
415
414
  definition = definition_builder.build_instance(type.name)
@@ -433,10 +432,13 @@ module Steep
433
432
 
434
433
  interface.methods[name] = Interface::Interface::Entry.new(
435
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)
436
437
  setup_primitives(
437
438
  name,
439
+ type_def,
438
440
  method_type(type_def.type,
439
- method_def: type_def,
441
+ method_decls: Set[decl],
440
442
  self_type: self_type,
441
443
  subst2: subst)
442
444
  )
@@ -460,7 +462,11 @@ module Steep
460
462
  definition.methods.each do |name, method|
461
463
  interface.methods[name] = Interface::Interface::Entry.new(
462
464
  method_types: method.defs.map do |type_def|
463
- 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)
464
470
  end
465
471
  )
466
472
  end
@@ -485,10 +491,16 @@ module Steep
485
491
 
486
492
  interface.methods[name] = Interface::Interface::Entry.new(
487
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
+ )
488
499
  setup_primitives(
489
500
  name,
501
+ type_def,
490
502
  method_type(type_def.type,
491
- method_def: type_def,
503
+ method_decls: Set[decl],
492
504
  self_type: self_type,
493
505
  subst2: subst)
494
506
  )
@@ -568,8 +580,7 @@ module Steep
568
580
  rest_keywords: nil),
569
581
  block: nil,
570
582
  return_type: elem_type,
571
- method_def: nil,
572
- location: nil
583
+ method_decls: Set[]
573
584
  )
574
585
  } + aref.method_types
575
586
  )
@@ -588,8 +599,7 @@ module Steep
588
599
  rest_keywords: nil),
589
600
  block: nil,
590
601
  return_type: elem_type,
591
- method_def: nil,
592
- location: nil
602
+ method_decls: Set[]
593
603
  )
594
604
  } + update.method_types
595
605
  )
@@ -603,8 +613,7 @@ module Steep
603
613
  params: Interface::Params.empty,
604
614
  block: nil,
605
615
  return_type: type.types[0] || AST::Builtin.nil_type,
606
- method_def: nil,
607
- location: nil
616
+ method_decls: Set[]
608
617
  )
609
618
  ]
610
619
  )
@@ -618,8 +627,7 @@ module Steep
618
627
  params: Interface::Params.empty,
619
628
  block: nil,
620
629
  return_type: type.types.last || AST::Builtin.nil_type,
621
- method_def: nil,
622
- location: nil
630
+ method_decls: Set[]
623
631
  )
624
632
  ]
625
633
  )
@@ -640,6 +648,7 @@ module Steep
640
648
  Interface::Interface::Entry.new(
641
649
  method_types: type.elements.map {|key_value, value_type|
642
650
  key_type = Literal.new(value: key_value, location: nil)
651
+
643
652
  Interface::MethodType.new(
644
653
  type_params: [],
645
654
  params: Interface::Params.new(required: [key_type],
@@ -650,8 +659,7 @@ module Steep
650
659
  rest_keywords: nil),
651
660
  block: nil,
652
661
  return_type: value_type,
653
- method_def: nil,
654
- location: nil
662
+ method_decls: Set[]
655
663
  )
656
664
  } + ref.method_types
657
665
  )
@@ -671,8 +679,7 @@ module Steep
671
679
  rest_keywords: nil),
672
680
  block: nil,
673
681
  return_type: value_type,
674
- method_def: nil,
675
- location: nil
682
+ method_decls: Set[]
676
683
  )
677
684
  } + update.method_types
678
685
  )
@@ -687,8 +694,7 @@ module Steep
687
694
  params: type.params,
688
695
  return_type: type.return_type,
689
696
  block: nil,
690
- method_def: nil,
691
- location: nil
697
+ method_decls: Set[]
692
698
  )
693
699
 
694
700
  interface.methods[:[]] = Interface::Interface::Entry.new(method_types: [method_type])
@@ -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, :stats]
20
20
  end
21
21
 
22
22
  def process_global_options
@@ -34,7 +34,7 @@ module Steep
34
34
 
35
35
  def setup_command
36
36
  @command = argv.shift&.to_sym
37
- if CLI.available_commands.include?(@command) || @command == :worker
37
+ if CLI.available_commands.include?(@command) || @command == :worker || @command == :vendor
38
38
  true
39
39
  else
40
40
  stderr.puts "Unknown command: #{command}"
@@ -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|
@@ -47,6 +47,17 @@ module Steep
47
47
  target.options.libraries.each do |lib|
48
48
  stdout.puts " - #{lib}"
49
49
  end
50
+ stdout.puts " library dirs:"
51
+ Project::Target.construct_env_loader(options: target.options).tap do |loader|
52
+ loader.each_dir do |lib, path|
53
+ case lib
54
+ when :core
55
+ stdout.puts " - core: #{path}"
56
+ else
57
+ stdout.puts " - #{lib.name}: #{path}"
58
+ end
59
+ end
60
+ end
50
61
  end
51
62
 
52
63
  0
@@ -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