Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proc with block #503

Merged
merged 5 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 1 addition & 31 deletions lib/rbs/method_type.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,5 @@
module RBS
class MethodType
class Block
attr_reader :type
attr_reader :required

def initialize(type:, required:)
@type = type
@required = required
end

def ==(other)
other.is_a?(Block) &&
other.type == type &&
other.required == required
end

def to_json(*a)
{
type: type,
required: required
}.to_json(*a)
end

def sub(s)
self.class.new(
type: type.sub(s),
required: required
)
end
end

attr_reader :type_params
attr_reader :type
attr_reader :block
Expand Down Expand Up @@ -86,7 +56,7 @@ def map_type(&block)
type_params: type_params,
type: type.map_type(&block),
block: self.block&.yield_self do |b|
Block.new(type: b.type.map_type(&block), required: b.required)
Types::Block.new(type: b.type.map_type(&block), required: b.required)
end,
location: location
)
Expand Down
1,454 changes: 735 additions & 719 deletions lib/rbs/parser.rb

Large diffs are not rendered by default.

64 changes: 38 additions & 26 deletions lib/rbs/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -484,26 +484,13 @@ rule
}

method_type:
start_merged_scope type_params params_opt block_opt kARROW simple_type {
start_merged_scope type_params proc_type {
reset_variable_scope

location = (val[1] || val[2] || val[3] || val[4]).location + val[5].location
location = (val[1] || val[2]).location + val[2].location
type_params = val[1]&.value || []

params = val[2]&.value || empty_params_result

type = Types::Function.new(
required_positionals: params[0],
optional_positionals: params[1],
rest_positionals: params[2],
trailing_positionals: params[3],
required_keywords: params[4],
optional_keywords: params[5],
rest_keywords: params[6],
return_type: val[5]
)

block = val[3]&.value
type, block = val[2].value

result = MethodType.new(type_params: type_params,
type: type,
Expand All @@ -517,14 +504,13 @@ rule
result = LocatedValue.new(value: val[1], location: val[0].location + val[2].location)
}

block_opt:
{ result = nil }
| kLBRACE function_type kRBRACE {
block = MethodType::Block.new(type: val[1].value, required: true)
block:
kLBRACE simple_function_type kRBRACE {
block = Types::Block.new(type: val[1].value, required: true)
result = LocatedValue.new(value: block, location: val[0].location + val[2].location)
}
| kQUESTION kLBRACE function_type kRBRACE {
block = MethodType::Block.new(type: val[2].value, required: false)
| kQUESTION kLBRACE simple_function_type kRBRACE {
block = Types::Block.new(type: val[2].value, required: false)
result = LocatedValue.new(value: block, location: val[0].location + val[3].location)
}

Expand Down Expand Up @@ -807,8 +793,9 @@ rule
result = Types::ClassSingleton.new(name: val[2].value,
location: val[0].location + val[3].location)
}
| kHAT function_type {
result = Types::Proc.new(type: val[1].value, location: val[0].location + val[1].location)
| kHAT proc_type {
type, block = val[1].value
result = Types::Proc.new(type: type, block: block, location: val[0].location + val[1].location)
}
| simple_type kQUESTION {
result = Types::Optional.new(type: val[0], location: val[0].location + val[1].location)
Expand Down Expand Up @@ -861,7 +848,32 @@ rule

keyword: tLKEYWORD | tUKEYWORD | tLKEYWORD_Q_E | tUKEYWORD_Q_E

function_type:
proc_type:
params_opt block kARROW simple_type {
location = (val[0] || val[1] || val[2]).location + val[3].location

params = val[0]&.value || [[], [], nil, [], {}, {}, nil]

type = Types::Function.new(
required_positionals: params[0],
optional_positionals: params[1],
rest_positionals: params[2],
trailing_positionals: params[3],
required_keywords: params[4],
optional_keywords: params[5],
rest_keywords: params[6],
return_type: val[3]
)

block = val[1].value

result = LocatedValue.new(value: [type, block], location: location)
}
| simple_function_type {
result = LocatedValue.new(value: [val[0].value, nil], location: val[0].location)
}

simple_function_type:
kLPAREN params kRPAREN kARROW simple_type {
location = val[0].location + val[4].location
type = Types::Function.new(
Expand Down Expand Up @@ -893,7 +905,7 @@ rule
result = LocatedValue.new(value: type, location: location)
}

params:
params:
required_positional kCOMMA params {
result = val[2]
result[0].unshift(val[0])
Expand Down
4 changes: 2 additions & 2 deletions lib/rbs/prototype/rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -552,15 +552,15 @@ def block_from_body(node)
method_block = nil

if block
method_block = MethodType::Block.new(
method_block = Types::Block.new(
required: true,
type: Types::Function.empty(untyped)
)
end

if body_node
if (yields = any_node?(body_node) {|n| n.type == :YIELD })
method_block = MethodType::Block.new(
method_block = Types::Block.new(
required: true,
type: Types::Function.empty(untyped)
)
Expand Down
10 changes: 5 additions & 5 deletions lib/rbs/prototype/rbi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -387,19 +387,19 @@ def parse_params(args_node, args, method_type, variables:)
if block
if (type = vars[block])
if type.is_a?(Types::Proc)
method_block = MethodType::Block.new(required: true, type: type.type)
method_block = Types::Block.new(required: true, type: type.type)
elsif type.is_a?(Types::Bases::Any)
method_block = MethodType::Block.new(
method_block = Types::Block.new(
required: true,
type: Types::Function.empty(Types::Bases::Any.new(location: nil))
)
# Handle an optional block like `T.nilable(T.proc.void)`.
elsif type.is_a?(Types::Optional) && type.type.is_a?(Types::Proc)
method_block = MethodType::Block.new(required: false, type: type.type.type)
method_block = Types::Block.new(required: false, type: type.type.type)
else
STDERR.puts "Unexpected block type: #{type}"
PP.pp args_node, STDERR
method_block = MethodType::Block.new(
method_block = Types::Block.new(
required: true,
type: Types::Function.empty(Types::Bases::Any.new(location: nil))
)
Expand Down Expand Up @@ -485,7 +485,7 @@ def type_of0(type_node, variables:)
Types::Tuple.new(types: types, location: nil)
else
if proc_type?(type_node)
Types::Proc.new(type: method_type(nil, type_node, variables: variables).type, location: nil)
Types::Proc.new(type: method_type(nil, type_node, variables: variables).type, block: nil, location: nil)
else
STDERR.puts "Unexpected type_node:"
PP.pp type_node, STDERR
Expand Down
2 changes: 1 addition & 1 deletion lib/rbs/prototype/runtime.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def method_type(method)
when :keyrest
rest_keywords = Types::Function::Param.new(name: nil, type: untyped)
when :block
block = MethodType::Block.new(
block = Types::Block.new(
type: Types::Function.empty(untyped).update(rest_positionals: Types::Function::Param.new(name: nil, type: untyped)),
required: true
)
Expand Down
69 changes: 63 additions & 6 deletions lib/rbs/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -947,44 +947,100 @@ def has_keyword?
end
end

class Block
attr_reader :type
attr_reader :required

def initialize(type:, required:)
@type = type
@required = required
end

def ==(other)
other.is_a?(Block) &&
other.type == type &&
other.required == required
end

def to_json(*a)
{
type: type,
required: required
}.to_json(*a)
end

def sub(s)
self.class.new(
type: type.sub(s),
required: required
)
end

def map_type(&block)
Block.new(
required: required,
type: type.map_type(&block)
)
end
end

class Proc
attr_reader :type
attr_reader :block
attr_reader :location

def initialize(location:, type:)
def initialize(location:, type:, block:)
@type = type
@block = block
@location = location
end

def ==(other)
other.is_a?(Proc) && other.type == type
other.is_a?(Proc) && other.type == type && other.block == block
end

alias eql? ==

def hash
self.class.hash ^ type.hash
self.class.hash ^ type.hash ^ block.hash
end

def free_variables(set = Set[])
type.free_variables(set)
block&.type&.free_variables(set)
set
end

def to_json(*a)
{ class: :proc, type: type, location: location }.to_json(*a)
{
class: :proc,
type: type,
block: block,
location: location
}.to_json(*a)
end

def sub(s)
self.class.new(type: type.sub(s), location: location)
self.class.new(type: type.sub(s), block: block&.sub(s), location: location)
end

def to_s(level = 0)
"^(#{type.param_to_s}) -> #{type.return_to_s}".lstrip
case
when b = block
if b.required
"^(#{type.param_to_s}) { #{b.type.param_to_s} -> #{b.type.return_to_s} } -> #{type.return_to_s}"
else
"^(#{type.param_to_s}) ?{ #{b.type.param_to_s} -> #{b.type.return_to_s} } -> #{type.return_to_s}"
end
else
"^(#{type.param_to_s}) -> #{type.return_to_s}"
end
end

def each_type(&block)
if block
type.each_type(&block)
self.block&.type&.each_type(&block)
else
enum_for :each_type
end
Expand All @@ -993,6 +1049,7 @@ def each_type(&block)
def map_type_name(&block)
Proc.new(
type: type.map_type_name(&block),
block: self.block&.map_type {|type| type.map_type_name(&block) },
location: location
)
end
Expand Down
19 changes: 3 additions & 16 deletions sig/method_types.rbs
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
module RBS
class MethodType
class Block
attr_reader type: Types::Function
attr_reader required: bool

def initialize: (type: Types::Function, required: boolish) -> void

def ==: (untyped other) -> bool

def to_json: (*untyped) -> String

def sub: (Substitution) -> Block
end

attr_reader type_params: Array[Symbol]
attr_reader type: Types::Function
attr_reader block: Block?
attr_reader block: Types::Block?
attr_reader location: Location?

def initialize: (type_params: Array[Symbol], type: Types::Function, block: Block?, location: Location?) -> void
def initialize: (type_params: Array[Symbol], type: Types::Function, block: Types::Block?, location: Location?) -> void

def ==: (untyped other) -> bool

def to_json: (*untyped) -> String

def sub: (Substitution) -> MethodType

def update: (?type_params: Array[Symbol], ?type: Types::Function, ?block: Block?, ?location: Location?) -> MethodType
def update: (?type_params: Array[Symbol], ?type: Types::Function, ?block: Types::Block?, ?location: Location?) -> MethodType

def free_variables: (?Set[Symbol] set) -> Set[Symbol]

Expand Down
18 changes: 17 additions & 1 deletion sig/types.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,27 @@ module RBS
def has_keyword?: () -> bool
end

class Block
attr_reader type: Types::Function
attr_reader required: boolish

def initialize: (type: Types::Function, required: boolish) -> void

def ==: (untyped other) -> bool

def to_json: (*untyped) -> String

def sub: (Substitution) -> Block

def map_type: () { (Types::t) -> Types::t } -> Block
end

class Proc
attr_reader type: Function
attr_reader block: Block?
attr_reader location: Location?

def initialize: (location: Location?, type: Function) -> void
def initialize: (location: Location?, type: Function, block: Block?) -> void

include _TypeBase
end
Expand Down
Loading