steep 0.4.0 → 0.5.0

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