steep 0.4.0 → 0.5.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE +21 -0
  4. data/bin/smoke_runner.rb +3 -0
  5. data/lib/steep/ast/annotation/collection.rb +120 -43
  6. data/lib/steep/ast/annotation.rb +5 -10
  7. data/lib/steep/ast/location.rb +1 -1
  8. data/lib/steep/ast/method_type.rb +3 -1
  9. data/lib/steep/ast/signature/alias.rb +19 -0
  10. data/lib/steep/ast/signature/env.rb +9 -0
  11. data/lib/steep/ast/signature/members.rb +4 -0
  12. data/lib/steep/ast/types/proc.rb +79 -0
  13. data/lib/steep/ast/types/void.rb +4 -0
  14. data/lib/steep/cli.rb +2 -1
  15. data/lib/steep/drivers/check.rb +4 -1
  16. data/lib/steep/errors.rb +13 -0
  17. data/lib/steep/interface/builder.rb +90 -47
  18. data/lib/steep/interface/instantiated.rb +1 -1
  19. data/lib/steep/interface/method.rb +8 -0
  20. data/lib/steep/interface/method_type.rb +40 -13
  21. data/lib/steep/parser.rb +1098 -1043
  22. data/lib/steep/parser.y +94 -36
  23. data/lib/steep/source.rb +5 -6
  24. data/lib/steep/subtyping/check.rb +162 -47
  25. data/lib/steep/subtyping/variable_occurrence.rb +2 -2
  26. data/lib/steep/subtyping/variable_variance.rb +3 -3
  27. data/lib/steep/type_construction.rb +630 -300
  28. data/lib/steep/type_inference/block_params.rb +186 -35
  29. data/lib/steep/type_inference/send_args.rb +12 -3
  30. data/lib/steep/type_inference/type_env.rb +10 -4
  31. data/lib/steep/type_name.rb +6 -0
  32. data/lib/steep/typing.rb +21 -2
  33. data/lib/steep/version.rb +1 -1
  34. data/lib/steep.rb +2 -0
  35. data/smoke/alias/a.rb +19 -0
  36. data/smoke/alias/a.rbi +10 -0
  37. data/smoke/alias/b.rb +7 -0
  38. data/smoke/alias/c.rb +10 -0
  39. data/smoke/array/c.rb +7 -0
  40. data/smoke/block/c.rb +10 -0
  41. data/smoke/block/c.rbi +3 -0
  42. data/smoke/block/d.rb +15 -0
  43. data/smoke/class/c.rb +1 -1
  44. data/smoke/class/e.rb +1 -1
  45. data/smoke/class/h.rb +15 -0
  46. data/smoke/class/h.rbi +7 -0
  47. data/smoke/class/i.rb +17 -0
  48. data/smoke/class/i.rbi +9 -0
  49. data/smoke/extension/a.rbi +4 -0
  50. data/smoke/extension/d.rb +2 -0
  51. data/smoke/hash/a.rb +17 -0
  52. data/smoke/hash/b.rb +7 -0
  53. data/smoke/implements/a.rb +2 -2
  54. data/smoke/initialize/a.rb +1 -1
  55. data/smoke/lambda/a.rb +11 -0
  56. data/smoke/literal/b.rb +9 -0
  57. data/smoke/literal/literal_methods.rbi +4 -0
  58. data/smoke/method/c.rb +5 -0
  59. data/smoke/regression/array.rb +7 -0
  60. data/smoke/regression/hash.rb +7 -0
  61. data/smoke/regression/set_divide.rb +16 -0
  62. data/smoke/self/a.rb +2 -2
  63. data/stdlib/builtin.rbi +151 -1
  64. data/steep.gemspec +1 -0
  65. metadata +30 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 376c287eb4edd3b191575c4dae0d6f928394ba2a52ee41ed6245c4b73579d3f0
4
- data.tar.gz: ef83cd047a6f35f597e3709f45ee3918c0bad4944c970002827baf2ea012df76
3
+ metadata.gz: 680c21e93b572cec898efc4efe60db2826ed86e06f17be5c3380e84f3884e50b
4
+ data.tar.gz: b638f8968a0bd9e8f05de731059f58dc47da209ccc0430337f32efcfb95fab36
5
5
  SHA512:
6
- metadata.gz: 6f350dd1d6043f7389bb97ec1c6526fbc7a62aa86a9fb3b4b4f1c01241d6bd691c9fe51a5e91a242900e4c9528cc50d2ed5638b5b70e6e21645088bd6f85fffc
7
- data.tar.gz: 3df8d10e17edeb6cad99199370f21925681f81cfebf29a471cee4087edb5a1efd13580dae0c9ddc46e2f64b3a6314d18b0a72f0299a42dd597134512fa32593f
6
+ metadata.gz: 013d9357eb3d2710aedecafea03d883486628c62c45bec80abfb761faba4131d2542d1afbbf1151853f729eae0ea13875c860d2ae5390b925649b84b3d4de7de
7
+ data.tar.gz: 7a7ee6ffaf6dc688d4375f5290237aea99262e5ab4cbe18b69458c411596b426037151a2afc7d96153b62a25fa27dde9141c98b32a4d31c6a24f7f17fdd3935d
data/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.5.0 (2018-08-11)
6
+
7
+ * Support *lambda* `->` (#47)
8
+ * Introduce *incompatible* method (#45)
9
+ * Add type alias (#44)
10
+ * Steep is MIT license (#43)
11
+ * Improved block parameter typing (#41)
12
+ * Support optional block
13
+ * Support attributes in module
14
+ * Support `:xstr` node
15
+ * Allow missing method definition with `steep check` without `--strict`
16
+
5
17
  ## 0.4.0 (2018-06-14)
6
18
 
7
19
  * Add *tuple* type (#40)
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Soutaro Matsumoto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/bin/smoke_runner.rb CHANGED
@@ -74,6 +74,9 @@ ARGV.each do |arg|
74
74
  stdout: stdout,
75
75
  stderr: stderr)
76
76
 
77
+ driver.fallback_any_is_error = false
78
+ driver.allow_missing_definitions = false
79
+
77
80
  Rainbow.enabled = false
78
81
  driver.run
79
82
  rescue => exn
@@ -2,78 +2,155 @@ module Steep
2
2
  module AST
3
3
  module Annotation
4
4
  class Collection
5
- attr_reader :var_types
6
- attr_reader :method_types
7
5
  attr_reader :annotations
8
- attr_reader :block_type
9
- attr_reader :return_type
10
- attr_reader :self_type
11
- attr_reader :const_types
12
- attr_reader :instance_type
13
- attr_reader :module_type
14
- attr_reader :implement_module
15
- attr_reader :ivar_types
16
- attr_reader :dynamics
17
- attr_reader :break_type
18
-
19
- def initialize(annotations:)
20
- @var_types = {}
21
- @method_types = {}
22
- @const_types = {}
23
- @ivar_types = {}
24
- @dynamics = {}
25
- @break_type = nil
6
+ attr_reader :builder
7
+ attr_reader :current_module
8
+
9
+ attr_reader :var_type_annotations
10
+ attr_reader :const_type_annotations
11
+ attr_reader :ivar_type_annotations
12
+ attr_reader :method_type_annotations
13
+ attr_reader :block_type_annotation
14
+ attr_reader :return_type_annotation
15
+ attr_reader :self_type_annotation
16
+ attr_reader :instance_type_annotation
17
+ attr_reader :module_type_annotation
18
+ attr_reader :implement_module_annotation
19
+ attr_reader :dynamic_annotations
20
+ attr_reader :break_type_annotation
21
+
22
+ def initialize(annotations:, builder:, current_module:)
23
+ @annotations = annotations
24
+ @builder = builder
25
+ @current_module = current_module
26
+
27
+ @var_type_annotations = {}
28
+ @method_type_annotations = {}
29
+ @const_type_annotations = {}
30
+ @ivar_type_annotations = {}
31
+ @dynamic_annotations = []
26
32
 
27
33
  annotations.each do |annotation|
28
34
  case annotation
29
35
  when VarType
30
- var_types[annotation.name] = annotation
36
+ var_type_annotations[annotation.name] = annotation
31
37
  when MethodType
32
- method_types[annotation.name] = annotation
38
+ method_type_annotations[annotation.name] = annotation
33
39
  when BlockType
34
- @block_type = annotation.type
40
+ @block_type_annotation = annotation
35
41
  when ReturnType
36
- @return_type = annotation.type
42
+ @return_type_annotation = annotation
37
43
  when SelfType
38
- @self_type = annotation.type
44
+ @self_type_annotation = annotation
39
45
  when ConstType
40
- @const_types[annotation.name] = annotation.type
46
+ @const_type_annotations[annotation.name] = annotation
41
47
  when InstanceType
42
- @instance_type = annotation.type
48
+ @instance_type_annotation = annotation
43
49
  when ModuleType
44
- @module_type = annotation.type
50
+ @module_type_annotation = annotation
45
51
  when Implements
46
- @implement_module = annotation
52
+ @implement_module_annotation = annotation
47
53
  when IvarType
48
- ivar_types[annotation.name] = annotation.type
54
+ @ivar_type_annotations[annotation.name] = annotation
49
55
  when Dynamic
50
- annotation.names.each do |name|
51
- dynamics[name.name] = name
52
- end
56
+ @dynamic_annotations << annotation
53
57
  when BreakType
54
- @break_type = annotation.type
58
+ @break_type_annotation = annotation
55
59
  else
56
60
  raise "Unexpected annotation: #{annotation.inspect}"
57
61
  end
58
62
  end
63
+ end
64
+
65
+ def absolute_type(type)
66
+ if type
67
+ builder.absolute_type(type, current: current_module)
68
+ end
69
+ end
59
70
 
60
- @annotations = annotations
71
+ def var_type(lvar: nil, ivar: nil, const: nil)
72
+ case
73
+ when lvar
74
+ absolute_type(var_type_annotations[lvar]&.type)
75
+ when ivar
76
+ absolute_type(ivar_type_annotations[ivar]&.type)
77
+ when const
78
+ absolute_type(const_type_annotations[const]&.type)
79
+ end
80
+ end
81
+
82
+ def method_type(name)
83
+ if (a = method_type_annotations[name])
84
+ builder.method_type_to_method_type(a.type, current: current_module)
85
+ end
86
+ end
87
+
88
+ def block_type
89
+ absolute_type(block_type_annotation&.type)
90
+ end
91
+
92
+ def return_type
93
+ absolute_type(return_type_annotation&.type)
94
+ end
95
+
96
+ def self_type
97
+ absolute_type(self_type_annotation&.type)
61
98
  end
62
99
 
63
- def lookup_var_type(name)
64
- var_types[name]&.type
100
+ def instance_type
101
+ absolute_type(instance_type_annotation&.type)
65
102
  end
66
103
 
67
- def lookup_method_type(name)
68
- method_types[name]&.type
104
+ def module_type
105
+ absolute_type(module_type_annotation&.type)
69
106
  end
70
107
 
71
- def lookup_const_type(node)
72
- const_types[node]
108
+ def break_type
109
+ absolute_type(break_type_annotation&.type)
73
110
  end
74
111
 
75
- def +(other)
76
- self.class.new(annotations: annotations.reject {|a| a.is_a?(BlockType) } + other.annotations)
112
+ def lvar_types
113
+ var_type_annotations.each_key.with_object({}) do |name, hash|
114
+ hash[name] = var_type(lvar: name)
115
+ end
116
+ end
117
+
118
+ def ivar_types
119
+ ivar_type_annotations.each_key.with_object({}) do |name, hash|
120
+ hash[name] = var_type(ivar: name)
121
+ end
122
+ end
123
+
124
+ def const_types
125
+ const_type_annotations.each_key.with_object({}) do |name, hash|
126
+ hash[name] = var_type(const: name)
127
+ end
128
+ end
129
+
130
+ def instance_dynamics
131
+ dynamic_annotations.flat_map do |annot|
132
+ annot.names.select(&:instance_method?).map(&:name)
133
+ end
134
+ end
135
+
136
+ def module_dynamics
137
+ dynamic_annotations.flat_map do |annot|
138
+ annot.names.select(&:module_method?).map(&:name)
139
+ end
140
+ end
141
+
142
+ def merge_block_annotations(annotations)
143
+ if annotations.current_module != current_module || annotations.builder != builder
144
+ raise "Cannot merge another annotation: self=#{self}, other=#{annotations}"
145
+ end
146
+
147
+ retained_annotations = self.annotations.reject do |annotation|
148
+ annotation.is_a?(BlockType) || annotation.is_a?(BreakType)
149
+ end
150
+
151
+ self.class.new(annotations: retained_annotations + annotations.annotations,
152
+ builder: builder,
153
+ current_module: current_module)
77
154
  end
78
155
 
79
156
  def any?(&block)
@@ -15,8 +15,7 @@ module Steep
15
15
  def ==(other)
16
16
  other.is_a?(self.class) &&
17
17
  other.name == name &&
18
- other.type == type &&
19
- (!other.location || !location || other.location == location)
18
+ other.type == type
20
19
  end
21
20
  end
22
21
 
@@ -32,8 +31,7 @@ module Steep
32
31
 
33
32
  def ==(other)
34
33
  other.is_a?(self.class) &&
35
- other.type == type &&
36
- (!other.location || !location || other.location == location)
34
+ other.type == type
37
35
  end
38
36
  end
39
37
 
@@ -73,15 +71,13 @@ module Steep
73
71
  attr_reader :location
74
72
  attr_reader :name
75
73
 
76
- def initialize(name:, location:)
74
+ def initialize(name:, location: nil)
77
75
  @location = location
78
76
  @name = name
79
77
  end
80
78
 
81
79
  def ==(other)
82
- other.is_a?(Implements) &&
83
- other.name == name &&
84
- other.location == location
80
+ other.is_a?(Implements) && other.name == name
85
81
  end
86
82
  end
87
83
 
@@ -122,8 +118,7 @@ module Steep
122
118
 
123
119
  def ==(other)
124
120
  other.is_a?(Dynamic) &&
125
- other.names == names &&
126
- (!other.location || location || other.location == location)
121
+ other.names == names
127
122
  end
128
123
  end
129
124
  end
@@ -12,7 +12,7 @@ module Steep
12
12
  end
13
13
 
14
14
  def inspect
15
- "#<#{self.class}:#{self.__id__} @buffer=..., @start_pos=#{start_pos}, @end_pos=#{end_pos}, source='#{source.lines.first}', start_line=#{start_line}, start_column=#{start_column}>"
15
+ "#<#{self.class}:#{self.__id__} @buffer=#{buffer.name}, @start_pos=#{start_pos}, @end_pos=#{end_pos}, source='#{source.lines.first}', start_line=#{start_line}, start_column=#{start_column}>"
16
16
  end
17
17
 
18
18
  def name
@@ -90,11 +90,13 @@ module Steep
90
90
  attr_reader :location
91
91
  attr_reader :params
92
92
  attr_reader :return_type
93
+ attr_reader :optional
93
94
 
94
- def initialize(location:, params:, return_type:)
95
+ def initialize(location:, params:, return_type:, optional:)
95
96
  @location = location
96
97
  @params = params
97
98
  @return_type = return_type
99
+ @optional = optional
98
100
  end
99
101
  end
100
102
 
@@ -0,0 +1,19 @@
1
+ module Steep
2
+ module AST
3
+ module Signature
4
+ class Alias
5
+ attr_reader :location
6
+ attr_reader :name
7
+ attr_reader :params
8
+ attr_reader :type
9
+
10
+ def initialize(location:, name:, params:, type:)
11
+ @location = location
12
+ @name = name
13
+ @params = params
14
+ @type = type
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -8,6 +8,7 @@ module Steep
8
8
  attr_reader :interfaces
9
9
  attr_reader :constants
10
10
  attr_reader :globals
11
+ attr_reader :aliases
11
12
 
12
13
  def initialize()
13
14
  @modules = {}
@@ -16,6 +17,7 @@ module Steep
16
17
  @interfaces = {}
17
18
  @constants = {}
18
19
  @globals = {}
20
+ @aliases = {}
19
21
  end
20
22
 
21
23
  def add(sig)
@@ -40,6 +42,9 @@ module Steep
40
42
  when Signature::Gvar
41
43
  raise "Duplicated global: #{sig.name}" if globals.key?(sig.name)
42
44
  globals[sig.name] = sig
45
+ when Signature::Alias
46
+ raise "Duplicated alias: #{sig.name}" if aliases.key?(sig.name)
47
+ aliases[sig.name] = sig
43
48
  else
44
49
  raise "Unknown signature:: #{sig}"
45
50
  end
@@ -73,6 +78,10 @@ module Steep
73
78
  globals[name]
74
79
  end
75
80
 
81
+ def find_alias(name)
82
+ aliases[name]
83
+ end
84
+
76
85
  def find_name(hash, name, current_module:)
77
86
  if current_module
78
87
  hash[current_module + name] || find_name(hash, name, current_module: current_module.parent)
@@ -52,6 +52,10 @@ module Steep
52
52
  def constructor?
53
53
  attributes.include?(:constructor)
54
54
  end
55
+
56
+ def incompatible?
57
+ attributes.include?(:incompatible)
58
+ end
55
59
  end
56
60
 
57
61
  class Ivar
@@ -0,0 +1,79 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Proc
5
+ attr_reader :location
6
+ attr_reader :params
7
+ attr_reader :return_type
8
+
9
+ def initialize(params:, return_type:, location: nil)
10
+ @location = location
11
+ @params = params
12
+ @return_type = return_type
13
+ end
14
+
15
+ def ==(other)
16
+ other.is_a?(self.class) &&
17
+ other.params == params &&
18
+ other.return_type == return_type
19
+ end
20
+
21
+ def hash
22
+ self.class.hash && params.hash && return_type.hash
23
+ end
24
+
25
+ alias eql? ==
26
+
27
+ def subst(s)
28
+ self.class.new(
29
+ params: params.subst(s),
30
+ return_type: return_type.subst(s),
31
+ location: location
32
+ )
33
+ end
34
+
35
+ def to_s
36
+ "^#{params} -> #{return_type}"
37
+ end
38
+
39
+ def free_variables
40
+ params.free_variables + return_type.free_variables
41
+ end
42
+
43
+ def level
44
+ children = params.each_type.to_a + [return_type]
45
+ [0] + level_of_children(children)
46
+ end
47
+
48
+ def closed?
49
+ params.closed? && return_type.closed?
50
+ end
51
+
52
+ def with_location(new_location)
53
+ self.class.new(location: new_location)
54
+ end
55
+
56
+ def map_type(&block)
57
+ self.class.new(
58
+ params: params.map_type(&block),
59
+ return_type: yield(return_type),
60
+ location: location
61
+ )
62
+ end
63
+
64
+ def one_arg?
65
+ params.required.size == 1 &&
66
+ params.optional.empty? &&
67
+ !params.rest &&
68
+ params.required_keywords.empty? &&
69
+ params.optional_keywords.empty? &&
70
+ !params.rest_keywords
71
+ end
72
+
73
+ def back_type
74
+ Name.new_instance(name: "::Proc", location: location)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -30,6 +30,10 @@ module Steep
30
30
  Set.new
31
31
  end
32
32
 
33
+ def level
34
+ [0]
35
+ end
36
+
33
37
  def with_location(new_location)
34
38
  self.class.new(location: new_location)
35
39
  end
data/lib/steep/cli.rb CHANGED
@@ -75,6 +75,7 @@ module Steep
75
75
  check.verbose = verbose
76
76
  check.dump_all_types = dump_all_types
77
77
  check.fallback_any_is_error = fallback_any_is_error || strict
78
+ check.allow_missing_definitions = false if strict
78
79
  end.run
79
80
  end
80
81
 
@@ -118,7 +119,7 @@ module Steep
118
119
  OptionParser.new do |opts|
119
120
  opts.on("-I [PATH]") {|path| signature_dirs << Pathname(path) }
120
121
  opts.on("--no-builtin") { no_builtin = true }
121
- end
122
+ end.parse!(argv)
122
123
 
123
124
  unless no_builtin
124
125
  signature_dirs.unshift Pathname(__dir__).join("../../stdlib").realpath
@@ -10,6 +10,7 @@ module Steep
10
10
  attr_accessor :accept_implicit_any
11
11
  attr_accessor :dump_all_types
12
12
  attr_accessor :fallback_any_is_error
13
+ attr_accessor :allow_missing_definitions
13
14
 
14
15
  attr_reader :labeling
15
16
 
@@ -25,6 +26,7 @@ module Steep
25
26
  self.accept_implicit_any = false
26
27
  self.dump_all_types = false
27
28
  self.fallback_any_is_error = false
29
+ self.allow_missing_definitions = true
28
30
 
29
31
  @labeling = ASTUtils::Labeling.new
30
32
  end
@@ -61,7 +63,7 @@ module Steep
61
63
  sources.each do |source|
62
64
  Steep.logger.tagged source.path do
63
65
  Steep.logger.debug "Typechecking..."
64
- annotations = source.annotations(block: source.node) || []
66
+ annotations = source.annotations(block: source.node, builder: check.builder, current_module: nil)
65
67
 
66
68
  pp annotations if verbose
67
69
 
@@ -113,6 +115,7 @@ module Steep
113
115
 
114
116
  typing.errors.each do |error|
115
117
  next if error.is_a?(Errors::FallbackAny) && !fallback_any_is_error
118
+ next if error.is_a?(Errors::MethodDefinitionMissing) && allow_missing_definitions
116
119
  error.print_to stdout
117
120
  end
118
121
  end
data/lib/steep/errors.rb CHANGED
@@ -333,6 +333,19 @@ module Steep
333
333
  end
334
334
  end
335
335
 
336
+ class IncompatibleZuper < Base
337
+ attr_reader :method
338
+
339
+ def initialize(node:, method:)
340
+ super(node: node)
341
+ @method = method
342
+ end
343
+
344
+ def to_s
345
+ "#{location_to_str}: IncompatibleZuper: method=#{method}"
346
+ end
347
+ end
348
+
336
349
  class MethodDefinitionMissing < Base
337
350
  attr_reader :module_name
338
351
  attr_reader :kind