steep 0.9.0 → 0.10.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: 05a765d5cdc7792406c32f581e041ee9e47b41c1b70dfb0d43e8db5400fbe172
4
- data.tar.gz: 71e35e1516a261d82082e1278774ff0a8d36c5ffecdd8511ba8de312b93a16f8
3
+ metadata.gz: 63ee9143e226c595a96dd859109327d66f97ab2c428601c30f771a12a21a1603
4
+ data.tar.gz: ec8d8d3cdcde5c0e37c73fdb70faeb0887b5b36ae1590d57dbab1feea95f86ad
5
5
  SHA512:
6
- metadata.gz: b721b3ac5bb01d3296071025ef72a7e2ab76f4900bdfb0909ee8a715642d371812185c4adc74585344a156c43af742e0e35782b8dc9f89966da6d558e7f87f83
7
- data.tar.gz: 3849077a1ea0d7109eb3b148be3dc2e8260f9cc63df17cb1864235fa2137faa984947a64d95343524c1b34d75fcf4ff9ada215488e15977bcc657359da3cac4c
6
+ metadata.gz: 5297a41597af66524e848e02f2c6f6b33d53d9fc52aac03280ec438845414e306dc3ce6a86b643608d34e89e1cabacfc75262013f7f78970661af88d4679f624
7
+ data.tar.gz: 610747408983f5e98ee292b5a3795e7b61c8dd74b6d255e3768f5c3658676f63c7dd8157cf7cbba492c98d36806e9c08482dcf5d58474e7ffaaaf78ea93c1157
data/CHANGELOG.md CHANGED
@@ -2,7 +2,14 @@
2
2
 
3
3
  ## master
4
4
 
5
- ## 0.8.3 (2018-11-11)
5
+ ## 0.10.0 (2019-03-05)
6
+
7
+ * Add `watch` subcommand (#77)
8
+ * Automatically `@implements` super class if the class definition inherits
9
+ * Fix tuple typing
10
+ * Fix `or` typing
11
+
12
+ ## 0.9.0 (2018-11-11)
6
13
 
7
14
  * Private methods (#72)
8
15
  * `__skip__` to skip type checking (#73)
@@ -50,7 +50,7 @@ module Steep
50
50
  end
51
51
 
52
52
  def with_location(new_location)
53
- self.class.new(location: new_location)
53
+ self.class.new(location: new_location, params: params, return_type: return_type)
54
54
  end
55
55
 
56
56
  def map_type(&block)
data/lib/steep/cli.rb CHANGED
@@ -89,7 +89,7 @@ module Steep
89
89
  end
90
90
 
91
91
  def paths
92
- options = if @options.none? {|option| option.is_a?(Pathname) }
92
+ options = if @options.none? {|option| option.is_a?(Pathname) } && Pathname("sig").directory?
93
93
  @options + [Pathname("sig")]
94
94
  else
95
95
  @options
@@ -132,7 +132,7 @@ module Steep
132
132
  end
133
133
 
134
134
  def self.available_commands
135
- [:check, :validate, :annotations, :scaffold, :interface, :version, :paths]
135
+ [:check, :validate, :annotations, :scaffold, :interface, :version, :paths, :watch]
136
136
  end
137
137
 
138
138
  def process_global_options
@@ -228,13 +228,11 @@ module Steep
228
228
  def process_annotations
229
229
  source_paths = argv.map {|file| Pathname(file) }
230
230
  Drivers::Annotations.new(source_paths: source_paths, stdout: stdout, stderr: stderr).run
231
- 0
232
231
  end
233
232
 
234
233
  def process_scaffold
235
234
  source_paths = argv.map {|file| Pathname(file) }
236
235
  Drivers::Scaffold.new(source_paths: source_paths, stdout: stdout, stderr: stderr).run
237
- 0
238
236
  end
239
237
 
240
238
  def process_interface
@@ -244,6 +242,29 @@ module Steep
244
242
  end.parse!(argv)
245
243
 
246
244
  Drivers::PrintInterface.new(type_name: argv.first, signature_dirs: signature_options.paths, stdout: stdout, stderr: stderr).run
245
+ end
246
+ end
247
+
248
+ def process_watch
249
+ with_signature_options do |signature_options|
250
+ strict = false
251
+ fallback_any_is_error = false
252
+
253
+ OptionParser.new do |opts|
254
+ handle_dir_options opts, signature_options
255
+ opts.on("--strict") { strict = true }
256
+ opts.on("--fallback-any-is-error") { fallback_any_is_error = true }
257
+ end.parse!(argv)
258
+
259
+ source_dirs = argv.map {|path| Pathname(path) }
260
+ if source_dirs.empty?
261
+ source_dirs << Pathname(".")
262
+ end
263
+
264
+ Drivers::Watch.new(source_dirs: source_dirs, signature_dirs: signature_options.paths, stdout: stdout, stderr: stderr).tap do |driver|
265
+ driver.options.fallback_any_is_error = fallback_any_is_error || strict
266
+ driver.options.allow_missing_definitions = false if strict
267
+ end.run
247
268
 
248
269
  0
249
270
  end
@@ -17,10 +17,21 @@ module Steep
17
17
  end
18
18
 
19
19
  def run
20
- each_ruby_source(source_paths, false) do |source|
21
- source.each_annotation.sort_by {|node, _| [node.loc.expression.begin_pos, node.loc.expression.end_pos] }.each do |node, annotations|
20
+ project = Project.new()
21
+
22
+ source_paths.each do |path|
23
+ each_file_in_path(".rb", path) do |file_path|
24
+ file = Project::SourceFile.new(path: file_path, options: Project::Options.new)
25
+ file.content = file_path.read
26
+ project.source_files[file_path] = file
27
+ end
28
+ end
29
+
30
+ project.source_files.each_value do |file|
31
+ file.parse
32
+ file.source.each_annotation.sort_by {|node, _| [node.loc.expression.begin_pos, node.loc.expression.end_pos] }.each do |node, annotations|
22
33
  loc = node.loc
23
- stdout.puts "#{source.path}:#{loc.line}:#{loc.column}:#{node.type}:\t#{node.loc.expression.source.lines.first}"
34
+ stdout.puts "#{file.path}:#{loc.line}:#{loc.column}:#{node.type}:\t#{node.loc.expression.source.lines.first}"
24
35
  annotations.each do |annotation|
25
36
  stdout.puts " #{annotation.location.source}"
26
37
  end
@@ -27,106 +27,102 @@ module Steep
27
27
  self.dump_all_types = false
28
28
  self.fallback_any_is_error = false
29
29
  self.allow_missing_definitions = true
30
+ end
30
31
 
31
- @labeling = ASTUtils::Labeling.new
32
+ def options
33
+ Project::Options.new.tap do |opt|
34
+ opt.allow_missing_definitions = allow_missing_definitions
35
+ opt.fallback_any_is_error = fallback_any_is_error
36
+ end
32
37
  end
33
38
 
34
39
  def run
35
40
  Steep.logger.level = Logger::DEBUG if verbose
36
41
 
37
- env = AST::Signature::Env.new
42
+ project = Project.new(Project::SyntaxErrorRaisingListener.new)
38
43
 
39
- each_signature(signature_dirs, verbose) do |signature|
40
- env.add signature
44
+ source_paths.each do |path|
45
+ each_file_in_path(".rb", path) do |file_path|
46
+ file = Project::SourceFile.new(path: file_path, options: options)
47
+ file.content = file_path.read
48
+ project.source_files[file_path] = file
49
+ end
41
50
  end
42
51
 
43
- builder = Interface::Builder.new(signatures: env)
44
- check = Subtyping::Check.new(builder: builder)
45
-
46
- validator = Utils::Validator.new(stdout: stdout, stderr: stderr, verbose: verbose)
47
-
48
- validated = validator.run(env: env, builder: builder, check: check) do |sig|
49
- stderr.puts "Validating #{sig.name} (#{sig.location.name}:#{sig.location.start_line})..." if verbose
52
+ signature_dirs.each do |path|
53
+ each_file_in_path(".rbi", path) do |file_path|
54
+ file = Project::SignatureFile.new(path: file_path)
55
+ file.content = file_path.read
56
+ project.signature_files[file_path] = file
57
+ end
50
58
  end
51
59
 
52
- unless validated
53
- return 1
54
- end
60
+ project.type_check
55
61
 
56
- sources = []
57
- each_ruby_source(source_paths, verbose) do |source|
58
- sources << source
62
+ case signature = project.signature
63
+ when Project::SignatureLoaded
64
+ output_type_check_result(project)
65
+ project.has_type_error? ? 1 : 0
66
+ when Project::SignatureHasError
67
+ output_signature_errors(project)
68
+ 1
59
69
  end
70
+ end
60
71
 
61
- typing = Typing.new
62
-
63
- sources.each do |source|
64
- Steep.logger.tagged source.path do
65
- Steep.logger.debug "Typechecking..."
66
- annotations = source.annotations(block: source.node, builder: check.builder, current_module: AST::Namespace.root)
67
-
68
- const_env = TypeInference::ConstantEnv.new(builder: check.builder, context: nil)
69
- type_env = TypeInference::TypeEnv.build(annotations: annotations,
70
- subtyping: check,
71
- const_env: const_env,
72
- signatures: check.builder.signatures)
73
-
74
- construction = TypeConstruction.new(
75
- checker: check,
76
- annotations: annotations,
77
- source: source,
78
- self_type: AST::Builtin::Object.instance_type,
79
- block_context: nil,
80
- module_context: TypeConstruction::ModuleContext.new(
81
- instance_type: nil,
82
- module_type: nil,
83
- implement_name: nil,
84
- current_namespace: AST::Namespace.root,
85
- const_env: const_env
86
- ),
87
- method_context: nil,
88
- typing: typing,
89
- break_context: nil,
90
- type_env: type_env
91
- )
92
- construction.synthesize(source.node)
93
- end
94
- end
72
+ def output_type_check_result(project)
73
+ # @type var project: Project
95
74
 
96
75
  if dump_all_types
97
- lines = []
98
-
99
- typing.nodes.each_value do |node|
100
- begin
101
- type = typing.type_of(node: node)
102
- lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, type]
103
- rescue
104
- lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, nil]
76
+ project.source_files.each_value do |file|
77
+ lines = []
78
+
79
+ if typing = file.typing
80
+ typing.nodes.each_value do |node|
81
+ begin
82
+ type = typing.type_of(node: node)
83
+ lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, type]
84
+ rescue
85
+ lines << [node.loc.expression.source_buffer.name, [node.loc.last_line,node.loc.last_column], [node.loc.first_line, node.loc.column], node, nil]
86
+ end
87
+ end
88
+
89
+ lines.sort {|x,y| y <=> x }.reverse_each do |line|
90
+ source = line[3].loc.expression.source
91
+ stdout.puts "#{line[0]}:(#{line[2].join(",")}):(#{line[1].join(",")}):\t#{line[3].type}:\t#{line[4]}\t(#{source.split(/\n/).first})"
92
+ end
105
93
  end
106
94
  end
95
+ end
107
96
 
108
- lines.sort {|x,y| y <=> x }.reverse_each do |line|
109
- source = line[3].loc.expression.source
110
- stdout.puts "#{line[0]}:(#{line[2].join(",")}):(#{line[1].join(",")}):\t#{line[3].type}:\t#{line[4]}\t(#{source.split(/\n/).first})"
97
+ project.source_files.each_value do |file|
98
+ file.errors&.each do |error|
99
+ error.print_to stdout
111
100
  end
112
101
  end
102
+ end
113
103
 
114
- errors = typing.errors.select do |error|
115
- case
116
- when error.is_a?(Errors::FallbackAny) && !fallback_any_is_error
117
- false
118
- when error.is_a?(Errors::MethodDefinitionMissing) && allow_missing_definitions
119
- false
104
+ def output_signature_errors(project)
105
+ project.signature.errors.each do |error|
106
+ case error
107
+ when Interface::Instantiated::InvalidMethodOverrideError
108
+ stdout.puts "😱 #{error.message}"
109
+ error.result.trace.each do |s, t|
110
+ case s
111
+ when Interface::Method
112
+ stdout.puts " #{s.name}(#{s.type_name}) <: #{t.name}(#{t.type_name})"
113
+ when Interface::MethodType
114
+ stdout.puts " #{s} <: #{t} (#{s.location&.name||"?"}:#{s.location&.start_line||"?"})"
115
+ else
116
+ stdout.puts " #{s} <: #{t}"
117
+ end
118
+ end
119
+ stdout.puts " 🚨 #{error.result.error.message}"
120
+ when Interface::Instantiated::InvalidIvarOverrideError
121
+ stdout.puts "😱 #{error.message}"
120
122
  else
121
- true
123
+ stdout.puts "😱 #{error.inspect}"
122
124
  end
123
125
  end
124
-
125
- errors.each do |error|
126
- error.print_to stdout
127
- end
128
-
129
- errors.empty? ? 0 : 1
130
126
  end
131
127
  end
132
128
  end
@@ -18,39 +18,70 @@ module Steep
18
18
  def run
19
19
  if type_name
20
20
  type = Parser.parse_type(type_name)
21
+ project = Project.new()
21
22
 
22
- env = AST::Signature::Env.new
23
-
24
- each_signature(signature_dirs, false) do |signature|
25
- env.add signature
23
+ signature_dirs.each do |path|
24
+ each_file_in_path(".rbi", path) do |file_path|
25
+ file = Project::SignatureFile.new(path: file_path)
26
+ file.content = file_path.read
27
+ project.signature_files[file_path] = file
28
+ end
26
29
  end
27
30
 
28
- begin
29
- builder = Interface::Builder.new(signatures: env)
30
- check = Subtyping::Check.new(builder: builder)
31
+ project.reload_signature
31
32
 
32
- interface = check.resolve(type)
33
+ case sig = project.signature
34
+ when Project::SignatureLoaded
35
+ begin
36
+ check = sig.check
37
+ interface = check.resolve(type)
33
38
 
34
- stdout.puts "#{type}"
35
- stdout.puts "- Instance variables:"
36
- interface.ivars.each do |name, type|
37
- puts " - #{name}: #{type}"
39
+ stdout.puts "#{type}"
40
+ stdout.puts "- Instance variables:"
41
+ interface.ivars.each do |name, type|
42
+ puts " - #{name}: #{type}"
43
+ end
44
+ stdout.puts "- Methods:"
45
+ interface.methods.each do |name, method|
46
+ puts " - #{Rainbow(name).blue}:"
47
+ method.types.each do |method_type|
48
+ loc = if method_type.location
49
+ "#{method_type.location.buffer.name}:#{method_type.location.to_s}"
50
+ else
51
+ "no location"
52
+ end
53
+ puts " - #{Rainbow(method_type.to_s).red} (#{loc})"
54
+ end
55
+ end
56
+ 0
57
+ rescue Steep::Subtyping::Check::CannotResolveError
58
+ stderr.puts "🤔 #{Rainbow(type.to_s).red} cannot be resolved to interface"
59
+ 1
38
60
  end
39
- stdout.puts "- Methods:"
40
- interface.methods.each do |name, method|
41
- puts " - #{Rainbow(name).blue}:"
42
- method.types.each do |method_type|
43
- loc = if method_type.location
44
- "#{method_type.location.buffer.name}:#{method_type.location.to_s}"
45
- else
46
- "no location"
47
- end
48
- puts " - #{Rainbow(method_type.to_s).red} (#{loc})"
61
+
62
+ when Project::SignatureHasError
63
+ sig.errors.each do |error|
64
+ case error
65
+ when Interface::Instantiated::InvalidMethodOverrideError
66
+ stdout.puts "😱 #{error.message}"
67
+ error.result.trace.each do |s, t|
68
+ case s
69
+ when Interface::Method
70
+ stdout.puts " #{s.name}(#{s.type_name}) <: #{t.name}(#{t.type_name})"
71
+ when Interface::MethodType
72
+ stdout.puts " #{s} <: #{t} (#{s.location&.name||"?"}:#{s.location&.start_line||"?"})"
73
+ else
74
+ stdout.puts " #{s} <: #{t}"
75
+ end
76
+ end
77
+ stdout.puts " 🚨 #{error.result.error.message}"
78
+ when Interface::Instantiated::InvalidIvarOverrideError
79
+ stdout.puts "😱 #{error.message}"
80
+ else
81
+ stdout.puts "😱 #{error.inspect}"
49
82
  end
50
83
  end
51
- 0
52
- rescue Steep::Subtyping::Check::CannotResolveError
53
- stderr.puts "🤔 #{Rainbow(type.to_s).red} cannot be resolved to interface"
84
+
54
85
  1
55
86
  end
56
87
  else
@@ -12,13 +12,16 @@ module Steep
12
12
  @source_paths = source_paths
13
13
  @stdout = stdout
14
14
  @stderr = stderr
15
-
16
- @labeling = ASTUtils::Labeling.new
17
15
  end
18
16
 
19
17
  def run
20
- each_ruby_source(source_paths, false) do |source|
21
- Generator.new(source: source, stderr: stderr).write(io: stdout)
18
+ source_paths.each do |path|
19
+ each_file_in_path(".rb", path) do |file_path|
20
+ file = Project::SourceFile.new(path: file_path, options: Project::Options.new)
21
+ file.content = file_path.read
22
+ file.parse
23
+ Generator.new(source: file.source, stderr: stderr).write(io: stdout)
24
+ end
22
25
  end
23
26
  0
24
27
  end
@@ -2,49 +2,14 @@ module Steep
2
2
  module Drivers
3
3
  module Utils
4
4
  module EachSignature
5
- def each_signature(signature_dirs, verbose)
6
- signature_dirs.each do |path|
7
- if path.file?
8
- stderr.puts "Loading signature #{path}..." if verbose
9
- Parser.parse_signature(path.read, name: path).each do |signature|
10
- yield signature
11
- end
12
- end
13
-
14
- if path.directory?
15
- each_file_in_dir(".rbi", path) do |file|
16
- stderr.puts "Loading signature #{file}..." if verbose
17
- Parser.parse_signature(file.read, name: file).each do |signature|
18
- yield signature
19
- end
20
- end
21
- end
22
- end
23
- end
24
-
25
- def each_ruby_source(source_paths, verbose)
26
- each_ruby_file source_paths do |file|
27
- begin
28
- stdout.puts "Loading Ruby program #{file}..." if verbose
29
- if (source = Source.parse(file.read, path: file.to_s, labeling: labeling))
30
- yield source
31
- end
32
- rescue => exn
33
- Steep.logger.error "Error occured on parsing #{file}: #{exn.inspect}"
34
- end
5
+ def each_file_in_path(suffix, path)
6
+ if path.file?
7
+ yield path
35
8
  end
36
- end
37
-
38
- def each_ruby_file(source_paths)
39
- source_paths.each do |path|
40
- if path.file?
41
- yield path
42
- end
43
9
 
44
- if path.directory?
45
- each_file_in_dir(".rb", path) do |file|
46
- yield file
47
- end
10
+ if path.directory?
11
+ each_file_in_dir(suffix, path) do |file|
12
+ yield file
48
13
  end
49
14
  end
50
15
  end
@@ -19,20 +19,45 @@ module Steep
19
19
  def run
20
20
  Steep.logger.level = Logger::DEBUG if verbose
21
21
 
22
- env = AST::Signature::Env.new
22
+ project = Project.new
23
23
 
24
- each_signature(signature_dirs, verbose) do |signature|
25
- env.add signature
24
+ signature_dirs.each do |path|
25
+ each_file_in_path(".rbi", path) do |file_path|
26
+ file = Project::SignatureFile.new(path: file_path)
27
+ file.content = file_path.read
28
+ project.signature_files[file_path] = file
29
+ end
26
30
  end
27
31
 
28
- builder = Interface::Builder.new(signatures: env)
29
- check = Subtyping::Check.new(builder: builder)
32
+ project.type_check
30
33
 
31
- validator = Utils::Validator.new(stdout: stdout, stderr: stderr, verbose: verbose)
32
-
33
- validator.run(env: env, builder: builder, check: check) do |sig|
34
- stderr.puts "Validating #{sig.name} (#{sig.location.name}:#{sig.location.start_line})..." if verbose
35
- end ? 0 : 1
34
+ case project.signature
35
+ when Project::SignatureHasError
36
+ project.signature.errors.each do |error|
37
+ case error
38
+ when Interface::Instantiated::InvalidMethodOverrideError
39
+ stdout.puts "😱 #{error.message}"
40
+ error.result.trace.each do |s, t|
41
+ case s
42
+ when Interface::Method
43
+ stdout.puts " #{s.name}(#{s.type_name}) <: #{t.name}(#{t.type_name})"
44
+ when Interface::MethodType
45
+ stdout.puts " #{s} <: #{t} (#{s.location&.name||"?"}:#{s.location&.start_line||"?"})"
46
+ else
47
+ stdout.puts " #{s} <: #{t}"
48
+ end
49
+ end
50
+ stdout.puts " 🚨 #{error.result.error.message}"
51
+ when Interface::Instantiated::InvalidIvarOverrideError
52
+ stdout.puts "😱 #{error.message}"
53
+ else
54
+ stdout.puts "😱 #{error.inspect}"
55
+ end
56
+ end
57
+ 1
58
+ else
59
+ 0
60
+ end
36
61
  end
37
62
  end
38
63
  end