steep 0.1.0.pre2 → 0.1.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 (119) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -1
  3. data/README.md +146 -33
  4. data/bin/smoke_runner.rb +43 -10
  5. data/lib/steep/ast/annotation/collection.rb +93 -0
  6. data/lib/steep/ast/annotation.rb +131 -0
  7. data/lib/steep/ast/buffer.rb +47 -0
  8. data/lib/steep/ast/location.rb +82 -0
  9. data/lib/steep/ast/method_type.rb +116 -0
  10. data/lib/steep/ast/signature/class.rb +33 -0
  11. data/lib/steep/ast/signature/const.rb +17 -0
  12. data/lib/steep/ast/signature/env.rb +123 -0
  13. data/lib/steep/ast/signature/extension.rb +21 -0
  14. data/lib/steep/ast/signature/gvar.rb +17 -0
  15. data/lib/steep/ast/signature/interface.rb +31 -0
  16. data/lib/steep/ast/signature/members.rb +71 -0
  17. data/lib/steep/ast/signature/module.rb +21 -0
  18. data/lib/steep/ast/type_params.rb +13 -0
  19. data/lib/steep/ast/types/any.rb +39 -0
  20. data/lib/steep/ast/types/bot.rb +39 -0
  21. data/lib/steep/ast/types/class.rb +35 -0
  22. data/lib/steep/ast/types/helper.rb +21 -0
  23. data/lib/steep/ast/types/instance.rb +39 -0
  24. data/lib/steep/ast/types/intersection.rb +74 -0
  25. data/lib/steep/ast/types/name.rb +124 -0
  26. data/lib/steep/ast/types/self.rb +39 -0
  27. data/lib/steep/ast/types/top.rb +39 -0
  28. data/lib/steep/ast/types/union.rb +74 -0
  29. data/lib/steep/ast/types/var.rb +57 -0
  30. data/lib/steep/ast/types/void.rb +35 -0
  31. data/lib/steep/cli.rb +28 -1
  32. data/lib/steep/drivers/annotations.rb +32 -0
  33. data/lib/steep/drivers/check.rb +53 -77
  34. data/lib/steep/drivers/scaffold.rb +303 -0
  35. data/lib/steep/drivers/utils/each_signature.rb +66 -0
  36. data/lib/steep/drivers/utils/validator.rb +115 -0
  37. data/lib/steep/drivers/validate.rb +39 -0
  38. data/lib/steep/errors.rb +291 -19
  39. data/lib/steep/interface/abstract.rb +44 -0
  40. data/lib/steep/interface/builder.rb +470 -0
  41. data/lib/steep/interface/instantiated.rb +126 -0
  42. data/lib/steep/interface/ivar_chain.rb +26 -0
  43. data/lib/steep/interface/method.rb +60 -0
  44. data/lib/steep/{interface.rb → interface/method_type.rb} +111 -100
  45. data/lib/steep/interface/substitution.rb +65 -0
  46. data/lib/steep/module_name.rb +116 -0
  47. data/lib/steep/parser.rb +1314 -814
  48. data/lib/steep/parser.y +536 -175
  49. data/lib/steep/source.rb +220 -25
  50. data/lib/steep/subtyping/check.rb +673 -0
  51. data/lib/steep/subtyping/constraints.rb +275 -0
  52. data/lib/steep/subtyping/relation.rb +41 -0
  53. data/lib/steep/subtyping/result.rb +126 -0
  54. data/lib/steep/subtyping/trace.rb +48 -0
  55. data/lib/steep/subtyping/variable_occurrence.rb +49 -0
  56. data/lib/steep/subtyping/variable_variance.rb +69 -0
  57. data/lib/steep/type_construction.rb +1630 -524
  58. data/lib/steep/type_inference/block_params.rb +100 -0
  59. data/lib/steep/type_inference/constant_env.rb +55 -0
  60. data/lib/steep/type_inference/send_args.rb +222 -0
  61. data/lib/steep/type_inference/type_env.rb +226 -0
  62. data/lib/steep/type_name.rb +27 -7
  63. data/lib/steep/typing.rb +4 -0
  64. data/lib/steep/version.rb +1 -1
  65. data/lib/steep.rb +71 -16
  66. data/smoke/and/a.rb +4 -2
  67. data/smoke/array/a.rb +4 -5
  68. data/smoke/array/b.rb +4 -4
  69. data/smoke/block/a.rb +2 -2
  70. data/smoke/block/a.rbi +2 -0
  71. data/smoke/block/b.rb +15 -0
  72. data/smoke/case/a.rb +3 -3
  73. data/smoke/class/a.rb +3 -3
  74. data/smoke/class/b.rb +0 -2
  75. data/smoke/class/d.rb +2 -2
  76. data/smoke/class/e.rb +1 -1
  77. data/smoke/class/f.rb +2 -2
  78. data/smoke/class/g.rb +8 -0
  79. data/smoke/const/a.rb +3 -3
  80. data/smoke/dstr/a.rb +1 -1
  81. data/smoke/ensure/a.rb +22 -0
  82. data/smoke/enumerator/a.rb +6 -6
  83. data/smoke/enumerator/b.rb +22 -0
  84. data/smoke/extension/a.rb +2 -2
  85. data/smoke/extension/b.rb +3 -3
  86. data/smoke/extension/c.rb +1 -1
  87. data/smoke/hello/hello.rb +2 -2
  88. data/smoke/if/a.rb +4 -2
  89. data/smoke/kwbegin/a.rb +8 -0
  90. data/smoke/literal/a.rb +5 -5
  91. data/smoke/method/a.rb +5 -5
  92. data/smoke/method/a.rbi +4 -0
  93. data/smoke/method/b.rb +29 -0
  94. data/smoke/module/a.rb +3 -3
  95. data/smoke/module/a.rbi +9 -0
  96. data/smoke/module/b.rb +2 -2
  97. data/smoke/module/c.rb +1 -1
  98. data/smoke/module/d.rb +5 -0
  99. data/smoke/module/e.rb +13 -0
  100. data/smoke/module/f.rb +13 -0
  101. data/smoke/rescue/a.rb +62 -0
  102. data/smoke/super/a.rb +2 -2
  103. data/smoke/type_case/a.rb +35 -0
  104. data/smoke/yield/a.rb +2 -2
  105. data/stdlib/builtin.rbi +463 -24
  106. data/steep.gemspec +3 -2
  107. metadata +91 -29
  108. data/lib/steep/annotation.rb +0 -223
  109. data/lib/steep/signature/class.rb +0 -450
  110. data/lib/steep/signature/extension.rb +0 -51
  111. data/lib/steep/signature/interface.rb +0 -49
  112. data/lib/steep/types/any.rb +0 -31
  113. data/lib/steep/types/class.rb +0 -27
  114. data/lib/steep/types/instance.rb +0 -27
  115. data/lib/steep/types/merge.rb +0 -32
  116. data/lib/steep/types/name.rb +0 -57
  117. data/lib/steep/types/union.rb +0 -42
  118. data/lib/steep/types/var.rb +0 -38
  119. data/lib/steep/types.rb +0 -4
@@ -0,0 +1,39 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Instance
5
+ attr_reader :location
6
+
7
+ def initialize(location: nil)
8
+ @location = location
9
+ end
10
+
11
+ def ==(other)
12
+ other.is_a?(Instance)
13
+ end
14
+
15
+ def hash
16
+ self.class.hash
17
+ end
18
+
19
+ alias eql? ==
20
+
21
+ def subst(s)
22
+ s.instance_type or raise "Unexpected substitution: #{inspect}"
23
+ end
24
+
25
+ def free_variables
26
+ Set.new
27
+ end
28
+
29
+ def to_s
30
+ "instance"
31
+ end
32
+
33
+ def level
34
+ [0]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,74 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Intersection
5
+ attr_reader :types
6
+ attr_reader :location
7
+
8
+ def initialize(types:, location: nil)
9
+ @types = types
10
+ @location = location
11
+ end
12
+
13
+ def self.build(types:, location: nil)
14
+ types.flat_map do |type|
15
+ if type.is_a?(Intersection)
16
+ type.types
17
+ else
18
+ [type]
19
+ end
20
+ end.map do |type|
21
+ case type
22
+ when AST::Types::Any
23
+ return AST::Types::Any.new()
24
+ when AST::Types::Bot
25
+ return AST::Types::Bot.new()
26
+ when AST::Types::Top
27
+ nil
28
+ else
29
+ type
30
+ end
31
+ end.compact.uniq.yield_self do |tys|
32
+ if tys.size == 1
33
+ tys.first
34
+ else
35
+ new(types: tys.sort_by(&:hash), location: location)
36
+ end
37
+ end
38
+ end
39
+
40
+ def ==(other)
41
+ other.is_a?(Intersection) &&
42
+ other.types == types
43
+ end
44
+
45
+ def hash
46
+ self.class.hash ^ types.hash
47
+ end
48
+
49
+ alias eql? ==
50
+
51
+ def subst(s)
52
+ self.class.build(location: location,
53
+ types: types.map {|ty| ty.subst(s) })
54
+ end
55
+
56
+ def to_s
57
+ "(#{types.map(&:to_s).sort.join(" & ")})"
58
+ end
59
+
60
+ def free_variables
61
+ types.each.with_object(Set.new) do |type, set|
62
+ set.merge(type.free_variables)
63
+ end
64
+ end
65
+
66
+ include Helper::ChildrenLevel
67
+
68
+ def level
69
+ [0] + level_of_children(types)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,124 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Name
5
+ attr_reader :location
6
+ attr_reader :name
7
+ attr_reader :args
8
+
9
+ def initialize(name:, args:, location: nil)
10
+ @location = location
11
+ @name = name
12
+ @args = args
13
+ end
14
+
15
+ def ==(other)
16
+ other.is_a?(Name) &&
17
+ other.name == name &&
18
+ other.args == args
19
+ end
20
+
21
+ def hash
22
+ self.class.hash ^ name.hash ^ args.hash
23
+ end
24
+
25
+ alias eql? ==
26
+
27
+ def to_s
28
+ if args.empty?
29
+ "#{name}"
30
+ else
31
+ "#{name}<#{args.join(", ")}>"
32
+ end
33
+ end
34
+
35
+ def self.new_module(location: nil, name:, args: [])
36
+ name = ModuleName.parse(name) unless name.is_a?(ModuleName)
37
+ new(location: location,
38
+ name: TypeName::Module.new(name: name),
39
+ args: args)
40
+ end
41
+
42
+ def self.new_class(location: nil, name:, constructor:, args: [])
43
+ name = ModuleName.parse(name) unless name.is_a?(ModuleName)
44
+ new(location: location,
45
+ name: TypeName::Class.new(name: name, constructor: constructor),
46
+ args: args)
47
+ end
48
+
49
+ def self.new_instance(location: nil, name:, args: [])
50
+ name = ModuleName.parse(name) unless name.is_a?(ModuleName)
51
+ new(location: location,
52
+ name: TypeName::Instance.new(name: name),
53
+ args: args)
54
+ end
55
+
56
+ def self.new_interface(location: nil, name:, args: [])
57
+ new(location: location, name: TypeName::Interface.new(name: name), args: args)
58
+ end
59
+
60
+ def subst(s)
61
+ self.class.new(location: location,
62
+ name: name,
63
+ args: args.map {|a| a.subst(s) })
64
+ end
65
+
66
+ def instance_type
67
+ case name
68
+ when TypeName::Interface, TypeName::Instance
69
+ self
70
+ when TypeName::Module, TypeName::Class
71
+ self.class.new_instance(location: location,
72
+ name: name.name,
73
+ args: args)
74
+ else
75
+ raise "Unknown name: #{name.inspect}"
76
+ end
77
+ end
78
+
79
+ def class_type(constructor:)
80
+ case name
81
+ when TypeName::Instance
82
+ self.class.new_class(location: location,
83
+ name: name.name,
84
+ constructor: constructor,
85
+ args: [])
86
+ when TypeName::Class
87
+ self
88
+ when TypeName::Module, TypeName::Interface
89
+ raise "Cannot make class type: #{inspect}"
90
+ else
91
+ raise "Unknown name: #{name.inspect}"
92
+ end
93
+ end
94
+
95
+ def module_type
96
+ case name
97
+ when TypeName::Instance,
98
+ self.class.new_module(location: location,
99
+ name: name.name,
100
+ args: args)
101
+ when TypeName::Module
102
+ self
103
+ when TypeName::Class, TypeName::Interface
104
+ raise "Cannot make module type: #{inspect}"
105
+ else
106
+ raise "Unknown name: #{name.inspect}"
107
+ end
108
+ end
109
+
110
+ def free_variables
111
+ self.args.each.with_object(Set.new) do |type, vars|
112
+ vars.merge(type.free_variables)
113
+ end
114
+ end
115
+
116
+ include Helper::ChildrenLevel
117
+
118
+ def level
119
+ [0] + level_of_children(args)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,39 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Self
5
+ attr_reader :location
6
+
7
+ def initialize(location: nil)
8
+ @location = location
9
+ end
10
+
11
+ def ==(other)
12
+ other.is_a?(Self)
13
+ end
14
+
15
+ def hash
16
+ self.class.hash
17
+ end
18
+
19
+ alias eql? ==
20
+
21
+ def to_s
22
+ "self"
23
+ end
24
+
25
+ def subst(s)
26
+ s.self_type or raise "Unexpected substitution: #{inspect}"
27
+ end
28
+
29
+ def free_variables
30
+ Set.new
31
+ end
32
+
33
+ def level
34
+ [0]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Top
5
+ attr_reader :location
6
+
7
+ def initialize(location: nil)
8
+ @location = location
9
+ end
10
+
11
+ def ==(other)
12
+ other.is_a?(Top)
13
+ end
14
+
15
+ def hash
16
+ self.class.hash
17
+ end
18
+
19
+ alias eql? ==
20
+
21
+ def subst(s)
22
+ self
23
+ end
24
+
25
+ def to_s
26
+ "⟙"
27
+ end
28
+
29
+ def free_variables
30
+ Set.new
31
+ end
32
+
33
+ def level
34
+ [2]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,74 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Union
5
+ attr_reader :types
6
+ attr_reader :location
7
+
8
+ def initialize(types:, location: nil)
9
+ @types = types
10
+ @location = location
11
+ end
12
+
13
+ def self.build(types:, location: nil)
14
+ types.flat_map do |type|
15
+ if type.is_a?(Union)
16
+ type.types
17
+ else
18
+ [type]
19
+ end
20
+ end.map do |type|
21
+ case type
22
+ when AST::Types::Any
23
+ return AST::Types::Any.new()
24
+ when AST::Types::Top
25
+ return AST::Types::Top.new()
26
+ when AST::Types::Bot
27
+ nil
28
+ else
29
+ type
30
+ end
31
+ end.compact.uniq.yield_self do |tys|
32
+ if tys.length == 1
33
+ tys.first
34
+ else
35
+ new(types: tys.sort_by(&:hash), location: location)
36
+ end
37
+ end
38
+ end
39
+
40
+ def ==(other)
41
+ other.is_a?(Union) &&
42
+ other.types == types
43
+ end
44
+
45
+ def hash
46
+ self.class.hash ^ types.hash
47
+ end
48
+
49
+ alias eql? ==
50
+
51
+ def subst(s)
52
+ self.class.build(location: location,
53
+ types: types.map {|ty| ty.subst(s) })
54
+ end
55
+
56
+ def to_s
57
+ "(#{types.map(&:to_s).sort.join(" | ")})"
58
+ end
59
+
60
+ def free_variables
61
+ types.each.with_object(Set.new) do |type, set|
62
+ set.merge(type.free_variables)
63
+ end
64
+ end
65
+
66
+ include Helper::ChildrenLevel
67
+
68
+ def level
69
+ [0] + level_of_children(types)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,57 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Var
5
+ attr_reader :name
6
+ attr_reader :location
7
+
8
+ def initialize(name:, location: nil)
9
+ @name = name
10
+ @location = location
11
+ end
12
+
13
+ def ==(other)
14
+ other.is_a?(Var) &&
15
+ other.name == name
16
+ end
17
+
18
+ def hash
19
+ self.class.hash ^ name.hash
20
+ end
21
+
22
+ alias eql? ==
23
+
24
+ def self.fresh(name)
25
+ @mutex ||= Mutex.new
26
+
27
+ @mutex.synchronize do
28
+ @max ||= 0
29
+ @max += 1
30
+
31
+ new(name: :"#{name}(#{@max})")
32
+ end
33
+ end
34
+
35
+ def to_s
36
+ "'#{name}"
37
+ end
38
+
39
+ def subst(s)
40
+ if s.key?(name)
41
+ s[name]
42
+ else
43
+ self
44
+ end
45
+ end
46
+
47
+ def free_variables
48
+ Set.new([name])
49
+ end
50
+
51
+ def level
52
+ [0]
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,35 @@
1
+ module Steep
2
+ module AST
3
+ module Types
4
+ class Void
5
+ attr_reader :location
6
+
7
+ def initialize(location: nil)
8
+ @location = location
9
+ end
10
+
11
+ def ==(other)
12
+ other.is_a?(Void)
13
+ end
14
+
15
+ def hash
16
+ self.class.hash
17
+ end
18
+
19
+ alias eql? ==
20
+
21
+ def subst(s)
22
+ self
23
+ end
24
+
25
+ def to_s
26
+ "void"
27
+ end
28
+
29
+ def free_variables
30
+ Set.new
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/steep/cli.rb CHANGED
@@ -16,7 +16,7 @@ module Steep
16
16
  end
17
17
 
18
18
  def self.available_commands
19
- [:check]
19
+ [:check, :validate, :annotations, :scaffold]
20
20
  end
21
21
 
22
22
  def setup_global_options
@@ -75,5 +75,32 @@ module Steep
75
75
  check.fallback_any_is_error = fallback_any_is_error
76
76
  end.run
77
77
  end
78
+
79
+ def process_validate
80
+ verbose = false
81
+
82
+ OptionParser.new do |opts|
83
+ opts.on("--verbose") { verbose = true }
84
+ end.parse!(argv)
85
+
86
+ signature_dirs = argv.map {|path| Pathname(path) }
87
+ if signature_dirs.empty?
88
+ signature_dirs << Pathname(".")
89
+ end
90
+
91
+ Drivers::Validate.new(signature_dirs: signature_dirs, stdout: stdout, stderr: stderr).tap do |validate|
92
+ validate.verbose = verbose
93
+ end.run
94
+ end
95
+
96
+ def process_annotations
97
+ source_paths = argv.map {|file| Pathname(file) }
98
+ Drivers::Annotations.new(source_paths: source_paths, stdout: stdout, stderr: stderr).run
99
+ end
100
+
101
+ def process_scaffold
102
+ source_paths = argv.map {|file| Pathname(file) }
103
+ Drivers::Scaffold.new(source_paths: source_paths, stdout: stdout, stderr: stderr).run
104
+ end
78
105
  end
79
106
  end
@@ -0,0 +1,32 @@
1
+ module Steep
2
+ module Drivers
3
+ class Annotations
4
+ attr_reader :source_paths
5
+ attr_reader :stdout
6
+ attr_reader :stderr
7
+ attr_reader :labeling
8
+
9
+ include Utils::EachSignature
10
+
11
+ def initialize(source_paths:, stdout:, stderr:)
12
+ @source_paths = source_paths
13
+ @stdout = stdout
14
+ @stderr = stderr
15
+
16
+ @labeling = ASTUtils::Labeling.new
17
+ end
18
+
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|
22
+ loc = node.loc
23
+ stdout.puts "#{source.path}:#{loc.line}:#{loc.column}:#{node.type}:\t#{node.loc.expression.source.lines.first}"
24
+ annotations.each do |annotation|
25
+ stdout.puts " #{annotation.location.source}"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end