Skip to content

Commit

Permalink
Merge pull request #381 from soutaro/ruby3
Browse files Browse the repository at this point in the history
Ruby3 support
  • Loading branch information
soutaro committed May 9, 2021
2 parents 410a5de + 83948e9 commit 0c13ffc
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 42 deletions.
2 changes: 0 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,5 @@ gem "without_steep_types", path: "test/gems/without_steep_types"
gem "rake"
gem "minitest", "~> 5.0"
gem "racc", "~> 1.4"
gem "minitest-reporters"
gem "minitest-hooks"
gem "stackprof"
gem "rbs", git: "https://github.com/ruby/rbs.git"
2 changes: 1 addition & 1 deletion lib/steep.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "steep/version"

require "pathname"
require "parser/ruby27"
require "parser/ruby30"
require "active_support/core_ext/object/try"
require "active_support/core_ext/string/inflections"
require "logger"
Expand Down
16 changes: 6 additions & 10 deletions lib/steep/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,22 @@ def string_value(token)
self.emit_procarg0 = true
end

def self.parser
::Parser::Ruby27.new(Builder.new).tap do |parser|
def self.new_parser
::Parser::Ruby30.new(Builder.new).tap do |parser|
parser.diagnostics.all_errors_are_fatal = true
parser.diagnostics.ignore_warnings = true
end
end

def self.parse(source_code, path:, factory:)
buffer = ::Parser::Source::Buffer.new(path.to_s, 1)
buffer.source = source_code
node = parser.parse(buffer)
buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
node = new_parser().parse(buffer)

annotations = []

_, comments, _ = yield_self do
buffer = ::Parser::Source::Buffer.new(path.to_s)
buffer.source = source_code
parser = ::Parser::Ruby27.new

parser.tokenize(buffer)
buffer = ::Parser::Source::Buffer.new(path.to_s, 1, source: source_code)
new_parser().tokenize(buffer)
end

buffer = RBS::Buffer.new(name: path, content: source_code)
Expand Down
32 changes: 27 additions & 5 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ def add_call(call)
end

def synthesize(node, hint: nil, condition: false)
Steep.logger.tagged "synthesize:(#{node.location.expression.to_s.split(/:/, 2).last})" do
Steep.logger.tagged "synthesize:(#{node.location&.yield_self {|loc| loc.expression.to_s.split(/:/, 2).last } || "-"})" do
Steep.logger.debug node.type
case node.type
when :begin, :kwbegin
Expand Down Expand Up @@ -940,6 +940,25 @@ def synthesize(node, hint: nil, condition: false)
end
end

when :numblock
yield_self do
send_node, max_num, body = node.children

if max_num == 1
arg_nodes = [Parser::AST::Node.new(:procarg0, [:_1])]
else
arg_nodes = max_num.times.map {|i| Parser::AST::Node.new(:arg, [:"_#{i+1}"]) }
end

params = Parser::AST::Node.new(:args, arg_nodes)

if send_node.type == :lambda
type_lambda(node, block_params: params, block_body: body, type_hint: hint)
else
type_send(node, send_node: send_node, block_params: params, block_body: body, unwrap: send_node.type == :csend)
end
end

when :def
yield_self do
name, args_node, body_node = node.children
Expand Down Expand Up @@ -999,10 +1018,13 @@ def synthesize(node, hint: nil, condition: false)
end

if body_node
begin_pos = body_node.loc.expression.end_pos
end_pos = node.loc.end.begin_pos

typing.add_context(begin_pos..end_pos, context: body_pair.context)
# Add context to ranges from the end of the method body to the beginning of the `end` keyword
if node.loc.end
# Skip end-less def
begin_pos = body_node.loc.expression.end_pos
end_pos = node.loc.end.begin_pos
typing.add_context(begin_pos..end_pos, context: body_pair.context)
end
end

if module_context
Expand Down
67 changes: 46 additions & 21 deletions lib/steep/typing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,20 @@ def add_context_for_node(node, context:)
end

def block_range(node)
send_node, args_node, _ = node.children
begin_pos = if send_node.type != :lambda && args_node.loc.expression
args_node.loc.expression.end_pos
else
node.loc.begin.end_pos
end
end_pos = node.loc.end.begin_pos
case node.type
when :block
send_node, args_node, _ = node.children
begin_pos = if send_node.type != :lambda && args_node.loc.expression
args_node.loc.expression.end_pos
else
node.loc.begin.end_pos
end
end_pos = node.loc.end.begin_pos
when :numblock
send_node, _ = node.children
begin_pos = node.loc.begin.end_pos
end_pos = node.loc.end.begin_pos
end

begin_pos..end_pos
end
Expand Down Expand Up @@ -139,21 +146,39 @@ def add_context_for_body(node, context:)
add_context(begin_pos..end_pos, context: context)

when :def, :defs
args_node = case node.type
when :def
node.children[1]
when :defs
node.children[2]
end
body_begin_pos = if args_node.loc.expression
args_node.loc.expression.end_pos
else
node.loc.name.end_pos
end
body_end_pos = node.loc.end.begin_pos
add_context(body_begin_pos..body_end_pos, context: context)
if node.children.last
args_node =
case node.type
when :def
node.children[1]
when :defs
node.children[2]
end

body_begin_pos =
case
when node.loc.assignment
# endless def
node.loc.assignment.end_pos
when args_node.loc.expression
# with args
args_node.loc.expression.end_pos
else
# without args
node.loc.name.end_pos
end

body_end_pos =
if node.loc.end
node.loc.end.begin_pos
else
node.loc.expression.end_pos
end

add_context(body_begin_pos..body_end_pos, context: context)
end

when :block
when :block, :numblock
range = block_range(node)
add_context(range, context: context)

Expand Down
2 changes: 1 addition & 1 deletion steep.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Gem::Specification.new do |spec|

spec.required_ruby_version = '>= 2.6.0'

spec.add_runtime_dependency "parser", ">= 2.7"
spec.add_runtime_dependency "parser", ">= 3.0"
spec.add_runtime_dependency "activesupport", ">= 5.1"
spec.add_runtime_dependency "rainbow", ">= 2.2.2", "< 4.0"
spec.add_runtime_dependency "listen", "~> 3.0"
Expand Down
2 changes: 0 additions & 2 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
require "bundler/setup"
require 'steep'

require "minitest/reporters"
Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new]
require 'minitest/autorun'
require "pp"
require "open3"
Expand Down
89 changes: 89 additions & 0 deletions test/type_construction_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7601,4 +7601,93 @@ def g(&block)
end
end
end

def test_ruby3_endless_def
with_checker(<<-RBS) do |checker|
module Ruby3
class Test
def foo: (String) -> Integer
end
end
RBS

source = parse_ruby(<<-'RUBY')
module Ruby3
class Test
def foo(x) = x.size
end
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
type, _ = construction.synthesize(source.node)

assert_no_error typing
end
end
end

def test_ruby3_numbered_parameter1
with_checker do |checker|
source = parse_ruby(<<RUBY)
[1].map { _1.to_s }
RUBY

with_standard_construction(checker, source) do |construction, typing|
type, _ = construction.synthesize(source.node)

assert_equal parse_type("::Array[::String]"), type

assert_no_error typing
end
end
end

def test_ruby3_numbered_parameter2
with_checker(<<RBS) do |checker|
module Ruby3
class Foo
def foo: () { ([String, Integer]) -> void } -> void
end
end
RBS

source = parse_ruby(<<RUBY)
Ruby3::Foo.new().foo do
_1[0] + ""
_1[1] + 0
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
type, _ = construction.synthesize(source.node)

assert_no_error typing
end
end
end

def test_ruby3_numbered_parameter3
with_checker(<<RBS) do |checker|
module Ruby3
class Foo
def foo: () { ([String, Integer]) -> void } -> void
end
end
RBS

source = parse_ruby(<<RUBY)
Ruby3::Foo.new().foo do
_1 + ""
_2 + 0
end
RUBY

with_standard_construction(checker, source) do |construction, typing|
type, _ = construction.synthesize(source.node)

assert_no_error typing
end
end
end
end

0 comments on commit 0c13ffc

Please sign in to comment.