steep 0.5.1 → 0.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/bin/smoke_runner.rb +1 -1
- data/lib/steep.rb +6 -4
- data/lib/steep/ast/builtin.rb +96 -0
- data/lib/steep/ast/location.rb +9 -5
- data/lib/steep/ast/namespace.rb +80 -0
- data/lib/steep/ast/signature/env.rb +37 -31
- data/lib/steep/ast/types/boolean.rb +2 -2
- data/lib/steep/ast/types/hash.rb +50 -0
- data/lib/steep/ast/types/literal.rb +12 -10
- data/lib/steep/ast/types/name.rb +135 -94
- data/lib/steep/ast/types/nil.rb +3 -1
- data/lib/steep/ast/types/proc.rb +3 -1
- data/lib/steep/drivers/check.rb +4 -4
- data/lib/steep/drivers/utils/validator.rb +11 -16
- data/lib/steep/interface/builder.rb +201 -146
- data/lib/steep/interface/instantiated.rb +8 -0
- data/lib/steep/names.rb +86 -0
- data/lib/steep/parser.y +1093 -668
- data/lib/steep/source.rb +2 -2
- data/lib/steep/subtyping/check.rb +199 -63
- data/lib/steep/subtyping/constraints.rb +2 -5
- data/lib/steep/subtyping/variable_variance.rb +2 -2
- data/lib/steep/type_construction.rb +194 -175
- data/lib/steep/type_inference/block_params.rb +9 -21
- data/lib/steep/type_inference/constant_env.rb +26 -30
- data/lib/steep/type_inference/send_args.rb +4 -7
- data/lib/steep/type_inference/type_env.rb +3 -3
- data/lib/steep/version.rb +1 -1
- data/smoke/alias/a.rb +1 -1
- data/smoke/alias/b.rb +1 -1
- data/smoke/class/i.rbi +1 -1
- data/smoke/hash/a.rbi +8 -0
- data/smoke/hash/c.rb +18 -0
- data/smoke/hash/d.rb +6 -0
- data/smoke/hello/hello.rb +2 -2
- data/smoke/interface/a.rb +14 -0
- data/smoke/interface/a.rbi +12 -0
- data/smoke/module/a.rb +1 -1
- data/smoke/module/a.rbi +3 -3
- data/smoke/module/b.rb +1 -1
- data/smoke/stdout/a.rb +2 -2
- data/stdlib/builtin.rbi +6 -7
- data/steep.gemspec +1 -1
- metadata +14 -7
- data/lib/steep/module_name.rb +0 -116
- data/lib/steep/type_name.rb +0 -93
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 562a6dfa36fc5da260d7dfc0cbc2a92f44000038aeb45447d79185cf700dfa9b
|
4
|
+
data.tar.gz: 48a656998959cce3a87cd6c59f4115b753336b33f54e2d961d656efd3e47b0c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d22bbd0e6a251db6431a7f90a59b087ebf879d1664af7195aa889ade8d0c3a5191908740501bd97a5315dc041a8704946361f821f1c5d9e6ed79e2e07a80451
|
7
|
+
data.tar.gz: 3cd0b8bdd13aed0035f6a3f0363bb96f75ee67ed4d88fb0912bff7e828ebdcc0f2244a4eb3280c83c306b983270c97848b618b410c2002a887b1dc44aac6fe5b
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 0.6.0 (2018-09-23)
|
6
|
+
|
7
|
+
* Update ast_utils
|
8
|
+
* Introduce *hash* type `{ id: Integer, name: String }` (#54)
|
9
|
+
* Revise signature syntax; use `<` instead of `<:` for inheritance (#53)
|
10
|
+
* Interface and alias name can be namespaced (#52)
|
11
|
+
* Grammar formatting (#51 @iliabylich)
|
12
|
+
|
5
13
|
## 0.5.1 (2018-08-11)
|
6
14
|
|
7
15
|
* Relax dependency requirements (#49, #50)
|
@@ -12,7 +20,7 @@
|
|
12
20
|
* Introduce *incompatible* method (#45)
|
13
21
|
* Add type alias (#44)
|
14
22
|
* Steep is MIT license (#43)
|
15
|
-
* Improved block parameter typing (#41)
|
23
|
+
* Improved block parameter typing (#41)
|
16
24
|
* Support optional block
|
17
25
|
* Support attributes in module
|
18
26
|
* Support `:xstr` node
|
data/bin/smoke_runner.rb
CHANGED
@@ -33,7 +33,7 @@ ARGV.each do |arg|
|
|
33
33
|
if file.extname == ".rb"
|
34
34
|
buffer = ::Parser::Source::Buffer.new(file.to_s)
|
35
35
|
buffer.source = file.read
|
36
|
-
parser = ::Parser::
|
36
|
+
parser = ::Parser::Ruby25.new
|
37
37
|
|
38
38
|
_, comments, _ = parser.tokenize(buffer)
|
39
39
|
comments.each do |comment|
|
data/lib/steep.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
require "steep/version"
|
2
2
|
|
3
3
|
require "pathname"
|
4
|
+
require "parser/ruby25"
|
4
5
|
require "ast_utils"
|
5
6
|
require "active_support/core_ext/object/try"
|
6
7
|
require "logger"
|
7
8
|
require "active_support/tagged_logging"
|
8
9
|
require "rainbow"
|
9
10
|
|
10
|
-
require "steep/
|
11
|
+
require "steep/ast/namespace"
|
12
|
+
require "steep/names"
|
11
13
|
require "steep/ast/location"
|
12
14
|
require "steep/ast/types/helper"
|
13
15
|
require "steep/ast/types/any"
|
@@ -26,6 +28,7 @@ require "steep/ast/types/literal"
|
|
26
28
|
require "steep/ast/types/boolean"
|
27
29
|
require "steep/ast/types/tuple"
|
28
30
|
require "steep/ast/types/proc"
|
31
|
+
require "steep/ast/types/hash"
|
29
32
|
require "steep/ast/method_type"
|
30
33
|
require "steep/ast/type_params"
|
31
34
|
require "steep/ast/signature/class"
|
@@ -40,8 +43,7 @@ require "steep/ast/signature/alias"
|
|
40
43
|
require "steep/ast/annotation"
|
41
44
|
require "steep/ast/annotation/collection"
|
42
45
|
require "steep/ast/buffer"
|
43
|
-
|
44
|
-
require "steep/type_name"
|
46
|
+
require "steep/ast/builtin"
|
45
47
|
|
46
48
|
require "steep/interface/method_type"
|
47
49
|
require "steep/interface/method"
|
@@ -87,7 +89,7 @@ module Steep
|
|
87
89
|
unless @logger
|
88
90
|
@logger = ActiveSupport::TaggedLogging.new(Logger.new(STDERR))
|
89
91
|
@logger.push_tags "Steep #{VERSION}"
|
90
|
-
@logger.level = Logger::
|
92
|
+
@logger.level = Logger::WARN
|
91
93
|
end
|
92
94
|
|
93
95
|
@logger
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Steep
|
2
|
+
module AST
|
3
|
+
module Builtin
|
4
|
+
class Type
|
5
|
+
attr_reader :module_name
|
6
|
+
attr_reader :arity
|
7
|
+
|
8
|
+
def initialize(module_name, arity: 0)
|
9
|
+
@module_name = Names::Module.parse(module_name)
|
10
|
+
@arity = arity
|
11
|
+
end
|
12
|
+
|
13
|
+
def instance_type(*args)
|
14
|
+
arity == args.size or raise "Mulformed instance type: name=#{module_name}, args=#{args}"
|
15
|
+
Types::Name::Instance.new(name: module_name, args: args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def class_type(constructor: nil)
|
19
|
+
Types::Name::Class.new(name: module_name, constructor: constructor)
|
20
|
+
end
|
21
|
+
|
22
|
+
def module_type
|
23
|
+
Types::Name::Module.new(name: module_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def instance_type?(type, args: nil)
|
27
|
+
if type.is_a?(Types::Name::Instance)
|
28
|
+
if args
|
29
|
+
arity == args.size or raise "Mulformed instance type: name=#{module_name}, args=#{args}"
|
30
|
+
type.name == module_name && type.args == args
|
31
|
+
else
|
32
|
+
type.name == module_name && type.args.size == arity
|
33
|
+
end
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
NONE = ::Object.new
|
40
|
+
|
41
|
+
def class_type?(type, constructor: NONE)
|
42
|
+
if type.is_a?(Types::Name::Class)
|
43
|
+
unless constructor.equal?(NONE)
|
44
|
+
type.name == module_name && type.name.constructor == constructor
|
45
|
+
else
|
46
|
+
type.name == module_name
|
47
|
+
end
|
48
|
+
else
|
49
|
+
false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def module_type?(type)
|
54
|
+
if type.is_a?(Types::Name::Module)
|
55
|
+
type.name == module_name
|
56
|
+
else
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Object = Type.new("::Object")
|
63
|
+
BasicObject = Type.new("::BasicObject")
|
64
|
+
Array = Type.new("::Array", arity: 1)
|
65
|
+
Range = Type.new("::Range", arity: 1)
|
66
|
+
Hash = Type.new("::Hash", arity: 2)
|
67
|
+
Module = Type.new("::Module")
|
68
|
+
Class = Type.new("::Class")
|
69
|
+
Integer = Type.new("::Integer")
|
70
|
+
Float = Type.new("::Float")
|
71
|
+
String = Type.new("::String")
|
72
|
+
Symbol = Type.new("::Symbol")
|
73
|
+
TrueClass = Type.new("::TrueClass")
|
74
|
+
FalseClass = Type.new("::FalseClass")
|
75
|
+
Regexp = Type.new("::Regexp")
|
76
|
+
NilClass = Type.new("::NilClass")
|
77
|
+
Proc = Type.new("::Proc")
|
78
|
+
|
79
|
+
def self.nil_type
|
80
|
+
AST::Types::Nil.new
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.any_type
|
84
|
+
AST::Types::Any.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.bool_type
|
88
|
+
AST::Types::Boolean.new
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.optional(type)
|
92
|
+
AST::Types::Union.build(types: [type, nil_type])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/steep/ast/location.rb
CHANGED
@@ -59,11 +59,15 @@ module Steep
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def +(other)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
if other
|
63
|
+
raise "Invalid concat: buffer=#{buffer.name}, other.buffer=#{other.buffer.name}" unless other.buffer == buffer
|
64
|
+
|
65
|
+
self.class.new(buffer: buffer,
|
66
|
+
start_pos: start_pos,
|
67
|
+
end_pos: other.end_pos)
|
68
|
+
else
|
69
|
+
self
|
70
|
+
end
|
67
71
|
end
|
68
72
|
|
69
73
|
def self.concat(*locations)
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Steep
|
2
|
+
module AST
|
3
|
+
class Namespace
|
4
|
+
attr_reader :path
|
5
|
+
|
6
|
+
def initialize(path:, absolute:)
|
7
|
+
@path = path
|
8
|
+
@absolute = absolute
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.empty
|
12
|
+
new(path: [], absolute: false)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.root
|
16
|
+
new(path: [], absolute: true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def +(other)
|
20
|
+
if other.absolute?
|
21
|
+
other
|
22
|
+
else
|
23
|
+
self.class.new(path: path + other.path, absolute: absolute?)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def append(component)
|
28
|
+
self.class.new(path: path + [component], absolute: absolute?)
|
29
|
+
end
|
30
|
+
|
31
|
+
def parent
|
32
|
+
raise "Parent with empty namespace" if empty?
|
33
|
+
self.class.new(path: path.take(path.size - 1), absolute: absolute?)
|
34
|
+
end
|
35
|
+
|
36
|
+
def absolute?
|
37
|
+
@absolute
|
38
|
+
end
|
39
|
+
|
40
|
+
def relative?
|
41
|
+
!absolute?
|
42
|
+
end
|
43
|
+
|
44
|
+
def absolute!
|
45
|
+
self.class.new(path: path, absolute: true)
|
46
|
+
end
|
47
|
+
|
48
|
+
def empty?
|
49
|
+
path.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
def ==(other)
|
53
|
+
other.is_a?(Namespace) && other.path == path && other.absolute? == absolute?
|
54
|
+
end
|
55
|
+
|
56
|
+
alias eql? ==
|
57
|
+
|
58
|
+
def hash
|
59
|
+
self.class.hath ^ path.hash ^ absolute?.hash
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
if empty?
|
64
|
+
absolute? ? "::" : ""
|
65
|
+
else
|
66
|
+
s = path.join("::")
|
67
|
+
absolute? ? "::#{s}::" : "#{s}::"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.parse(string)
|
72
|
+
if string.start_with?("::")
|
73
|
+
new(path: string.split("::").drop(1).map(&:to_sym), absolute: true)
|
74
|
+
else
|
75
|
+
new(path: string.split("::").map(&:to_sym), absolute: false)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -20,15 +20,22 @@ module Steep
|
|
20
20
|
@aliases = {}
|
21
21
|
end
|
22
22
|
|
23
|
+
def assert_absolute_name(name)
|
24
|
+
name.namespace.absolute? or raise "Absolute name expected: #{name}"
|
25
|
+
end
|
26
|
+
|
23
27
|
def add(sig)
|
24
28
|
case sig
|
25
29
|
when Signature::Class
|
26
|
-
|
27
|
-
classes
|
30
|
+
assert_absolute_name sig.name
|
31
|
+
raise "Duplicated class: #{sig.name}" if classes.key?(sig.name) || modules.key?(sig.name)
|
32
|
+
classes[sig.name] = sig
|
28
33
|
when Signature::Module
|
29
|
-
|
34
|
+
assert_absolute_name sig.name
|
35
|
+
raise "Duplicated module: #{sig.name}" if classes.key?(sig.name) || modules.key?(sig.name)
|
30
36
|
modules[sig.name.absolute!] = sig
|
31
37
|
when Signature::Interface
|
38
|
+
assert_absolute_name sig.name
|
32
39
|
raise "Duplicated interface: #{sig.name}" if interfaces.key?(sig.name)
|
33
40
|
interfaces[sig.name] = sig
|
34
41
|
when Signature::Extension
|
@@ -38,11 +45,13 @@ module Steep
|
|
38
45
|
end
|
39
46
|
extensions[sig.module_name.absolute!] << sig
|
40
47
|
when Signature::Const
|
41
|
-
|
48
|
+
assert_absolute_name sig.name
|
49
|
+
constants[sig.name] = sig
|
42
50
|
when Signature::Gvar
|
43
51
|
raise "Duplicated global: #{sig.name}" if globals.key?(sig.name)
|
44
52
|
globals[sig.name] = sig
|
45
53
|
when Signature::Alias
|
54
|
+
assert_absolute_name sig.name
|
46
55
|
raise "Duplicated alias: #{sig.name}" if aliases.key?(sig.name)
|
47
56
|
aliases[sig.name] = sig
|
48
57
|
else
|
@@ -50,15 +59,15 @@ module Steep
|
|
50
59
|
end
|
51
60
|
end
|
52
61
|
|
53
|
-
def find_module(name, current_module:
|
62
|
+
def find_module(name, current_module: AST::Namespace.root)
|
54
63
|
find_name(modules, name, current_module: current_module) or raise "Unknown module: #{name}"
|
55
64
|
end
|
56
65
|
|
57
|
-
def find_class(name, current_module:
|
66
|
+
def find_class(name, current_module: AST::Namespace.root)
|
58
67
|
find_name(classes, name, current_module: current_module) or raise "Unknown class: #{name}"
|
59
68
|
end
|
60
69
|
|
61
|
-
def find_class_or_module(name, current_module:
|
70
|
+
def find_class_or_module(name, current_module: AST::Namespace.root)
|
62
71
|
sig =
|
63
72
|
find_name(modules, name, current_module: current_module) ||
|
64
73
|
find_name(classes, name, current_module: current_module)
|
@@ -66,11 +75,11 @@ module Steep
|
|
66
75
|
sig or raise "Unknown class/module: #{name}}"
|
67
76
|
end
|
68
77
|
|
69
|
-
def find_extensions(name, current_module:
|
78
|
+
def find_extensions(name, current_module: AST::Namespace.root)
|
70
79
|
find_name(extensions, name, current_module: current_module) || []
|
71
80
|
end
|
72
81
|
|
73
|
-
def find_const(name, current_module:
|
82
|
+
def find_const(name, current_module: Namespace.root)
|
74
83
|
find_name(constants, name, current_module: current_module)
|
75
84
|
end
|
76
85
|
|
@@ -78,42 +87,39 @@ module Steep
|
|
78
87
|
globals[name]
|
79
88
|
end
|
80
89
|
|
81
|
-
def find_alias(name)
|
82
|
-
aliases
|
90
|
+
def find_alias(name, namespace:)
|
91
|
+
find_name(aliases, name, current_module: namespace) or raise "Unknown alias: #{name}"
|
83
92
|
end
|
84
93
|
|
85
94
|
def find_name(hash, name, current_module:)
|
86
|
-
|
87
|
-
|
95
|
+
current_module.absolute? or raise "Current namespace should be absolute: #{current_module}"
|
96
|
+
|
97
|
+
if (object = hash[name.in_namespace(current_module)])
|
98
|
+
object
|
88
99
|
else
|
89
|
-
|
100
|
+
unless current_module.empty?
|
101
|
+
find_name(hash, name, current_module: current_module.parent)
|
102
|
+
end
|
90
103
|
end
|
91
104
|
end
|
92
105
|
|
93
|
-
def find_interface(name)
|
94
|
-
interfaces
|
95
|
-
end
|
96
|
-
|
97
|
-
def module?(type_name, current_module: nil)
|
98
|
-
name = type_name.map_module_name {|m| current_module ? current_module + m : m.absolute! }.name
|
99
|
-
modules.key?(name)
|
106
|
+
def find_interface(name, namespace: Namespace.root)
|
107
|
+
find_name(interfaces, name, current_module: namespace) or raise "Unknown interface: #{name}"
|
100
108
|
end
|
101
109
|
|
102
|
-
def
|
103
|
-
|
110
|
+
def class_name?(name)
|
111
|
+
assert_absolute_name name
|
104
112
|
classes.key?(name)
|
105
113
|
end
|
106
114
|
|
107
|
-
def
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
def module_name?(name, current_module: nil)
|
112
|
-
modules.key?(current_module ? current_module + name : name.absolute!)
|
115
|
+
def module_name?(name)
|
116
|
+
assert_absolute_name name
|
117
|
+
modules.key?(name)
|
113
118
|
end
|
114
119
|
|
115
|
-
def const_name?(name
|
116
|
-
|
120
|
+
def const_name?(name)
|
121
|
+
assert_absolute_name name
|
122
|
+
constants.key?(name)
|
117
123
|
end
|
118
124
|
|
119
125
|
def each(&block)
|
@@ -41,8 +41,8 @@ module Steep
|
|
41
41
|
def back_type
|
42
42
|
Union.build(types:
|
43
43
|
[
|
44
|
-
|
45
|
-
|
44
|
+
Builtin::TrueClass.instance_type,
|
45
|
+
Builtin::FalseClass.instance_type
|
46
46
|
],
|
47
47
|
location: location)
|
48
48
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Steep
|
2
|
+
module AST
|
3
|
+
module Types
|
4
|
+
class Hash
|
5
|
+
attr_reader :location
|
6
|
+
attr_reader :elements
|
7
|
+
|
8
|
+
def initialize(elements:, location: nil)
|
9
|
+
@elements = elements
|
10
|
+
@location = location
|
11
|
+
end
|
12
|
+
|
13
|
+
def ==(other)
|
14
|
+
other.is_a?(Hash) && other.elements == elements
|
15
|
+
end
|
16
|
+
|
17
|
+
def hash
|
18
|
+
self.class.hash ^ elements.hash
|
19
|
+
end
|
20
|
+
|
21
|
+
alias eql? ==
|
22
|
+
|
23
|
+
def subst(s)
|
24
|
+
self.class.new(location: location,
|
25
|
+
elements: elements.transform_values {|type| type.subst(s) })
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"{ #{elements.map {|key, value| "#{key.inspect} => #{value}" }.join(", ")} }"
|
30
|
+
end
|
31
|
+
|
32
|
+
def free_variables
|
33
|
+
elements.each_value.with_object(Set.new) do |type, set|
|
34
|
+
set.merge(type.free_variables)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
include Helper::ChildrenLevel
|
39
|
+
|
40
|
+
def level
|
41
|
+
[0] + level_of_children(elements.values)
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_location(new_location)
|
45
|
+
self.class.new(elements: elements, location: new_location)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|