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

Fix next error #271

Merged
merged 3 commits into from
Dec 10, 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
19 changes: 19 additions & 0 deletions lib/steep/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,25 @@ def to_s
end
end

class BlockBodyTypeMismatch < Base
attr_reader :expected
attr_reader :actual
attr_reader :result

include ResultPrinter

def initialize(node:, expected:, actual:, result:)
super(node: node)
@expected = expected
@actual = actual
@result = result
end

def to_s
"#{location_to_str}: BlockBodyTypeMismatch: expected=#{expected}, actual=#{actual}"
end
end

class BreakTypeMismatch < Base
attr_reader :expected
attr_reader :actual
Expand Down
133 changes: 82 additions & 51 deletions lib/steep/type_construction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1012,22 +1012,30 @@ def synthesize(node, hint: nil)
value = node.children[0]

if break_context
case
when value && break_context.break_type
check(value, break_context.break_type) do |break_type, actual_type, result|
typing.add_error Errors::BreakTypeMismatch.new(node: node,
expected: break_type,
actual: actual_type,
result: result)
if break_type = break_context.break_type
if value
check(value, break_type) do |break_type, actual_type, result|
typing.add_error Errors::BreakTypeMismatch.new(node: node,
expected: break_type,
actual: actual_type,
result: result)
end
else
check_relation(sub_type: AST::Builtin.nil_type, super_type: break_type).else do |result|
typing.add_error Errors::BreakTypeMismatch.new(node: node,
expected: break_type,
actual: AST::Builtin.nil_type,
result: result)
end
end
when !value
# ok
else
synthesize(value) if value
typing.add_error Errors::UnexpectedJumpValue.new(node: node)
if value
synthesize(value)
typing.add_error Errors::UnexpectedJumpValue.new(node: node)
end
end
else
synthesize(value)
synthesize(value) if value
typing.add_error Errors::UnexpectedJump.new(node: node)
end

Expand All @@ -1037,22 +1045,32 @@ def synthesize(node, hint: nil)
value = node.children[0]

if break_context
case
when value && break_context.next_type
check(value, break_context.next_type) do |break_type, actual_type, result|
typing.add_error Errors::BreakTypeMismatch.new(node: node,
expected: break_type,
actual: actual_type,
result: result)
if next_type = break_context.next_type
next_type = deep_expand_alias(next_type)

if value
_, constr = check(value, next_type) do |break_type, actual_type, result|
typing.add_error Errors::BreakTypeMismatch.new(node: node,
expected: break_type,
actual: actual_type,
result: result)
end
else
check_relation(sub_type: AST::Builtin.nil_type, super_type: next_type).else do |result|
typing.add_error Errors::BreakTypeMismatch.new(node: node,
expected: next_type,
actual: AST::Builtin.nil_type,
result: result)
end
end
when !value
# ok
else
synthesize(value) if value
typing.add_error Errors::UnexpectedJumpValue.new(node: node)
if value
synthesize(value)
typing.add_error Errors::UnexpectedJumpValue.new(node: node)
end
end
else
synthesize(value)
synthesize(value) if value
typing.add_error Errors::UnexpectedJump.new(node: node)
end

Expand Down Expand Up @@ -2408,6 +2426,7 @@ def type_lambda(node, block_params:, block_body:, type_hint:)
block_constr = for_block(
block_params: params,
block_param_hint: params_hint,
block_type_hint: return_hint,
block_annotations: block_annotations,
node_type_hint: nil
)
Expand All @@ -2422,10 +2441,22 @@ def type_lambda(node, block_params:, block_body:, type_hint:)
return_type = block_constr.synthesize_block(
node: node,
block_body: block_body,
topdown_hint: true,
block_type_hint: return_hint
) do |error|
typing.add_error(error)
)

if expected_block_type = block_constr.block_context.body_type
check_relation(sub_type: return_type, super_type: expected_block_type).else do |result|
block_constr.typing.add_error(
Errors::BlockBodyTypeMismatch.new(
node: block_body,
expected: expected_block_type,
actual: return_type,
result: result
)
)

return_type = expected_block_type
end
end
else
return_type = AST::Builtin.any_type
Expand Down Expand Up @@ -2505,9 +2536,7 @@ def type_send_interface(node, interface:, receiver:, receiver_type:, method_name
block_params: TypeInference::BlockParams.from_node(block_params, annotations: block_annotations),
block_annotations: block_annotations,
block_body: block_body
) do |error|
constr.typing.add_error(error)
end
)
end
end

Expand Down Expand Up @@ -2882,6 +2911,7 @@ def try_method_type(node, receiver_type:, method_name:, method_type:, args:, arg
block_constr = constr.for_block(
block_params: block_params_,
block_param_hint: method_type.block.type.params,
block_type_hint: method_type.block.type.return_type,
block_annotations: block_annotations,
node_type_hint: method_type.type.return_type
)
Expand Down Expand Up @@ -2920,12 +2950,9 @@ def try_method_type(node, receiver_type:, method_name:, method_type:, args:, arg
if block_body
block_body_type = block_constr.synthesize_block(
node: node,
block_type_hint: method_type.block.type.return_type,
block_body: block_body,
topdown_hint: topdown_hint
) do |error|
errors << error
end
block_type_hint: method_type.block.type.return_type
)
else
block_body_type = AST::Builtin.nil_type
end
Expand Down Expand Up @@ -2972,6 +2999,7 @@ def try_method_type(node, receiver_type:, method_name:, method_type:, args:, arg
end

block_constr.typing.save!

rescue Subtyping::Constraints::UnsatisfiableConstraint => exn
errors << Errors::UnsatisfiableConstraint.new(
node: node,
Expand Down Expand Up @@ -3101,6 +3129,7 @@ def type_block_without_hint(node:, block_annotations:, block_params:, block_body
block_constr = for_block(
block_params: block_params,
block_param_hint: nil,
block_type_hint: nil,
block_annotations: block_annotations,
node_type_hint: nil
)
Expand All @@ -3111,10 +3140,23 @@ def type_block_without_hint(node:, block_annotations:, block_params:, block_body
_, block_constr = block_constr.synthesize(param.node, hint: param.type)
end

block_constr.synthesize_block(node: node, block_type_hint: nil, block_body: block_body, topdown_hint: false, &block)
block_type = block_constr.synthesize_block(node: node, block_type_hint: nil, block_body: block_body)

if expected_block_type = block_constr.block_context.body_type
block_constr.check_relation(sub_type: block_type, super_type: expected_block_type).else do |result|
block_constr.typing.add_error(
Errors::BlockBodyTypeMismatch.new(
node: node,
expected: expected_block_type,
actual: block_type,
result: result
)
)
end
end
end

def for_block(block_params:, block_param_hint:, block_annotations:, node_type_hint:)
def for_block(block_params:, block_param_hint:, block_type_hint:, block_annotations:, node_type_hint:)
block_param_pairs = block_param_hint && block_params.zip(block_param_hint)

param_types_hash = {}
Expand Down Expand Up @@ -3146,7 +3188,7 @@ def for_block(block_params:, block_param_hint:, block_annotations:, node_type_hi
end

block_context = TypeInference::Context::BlockContext.new(
body_type: block_annotations.block_type
body_type: block_annotations.block_type || block_type_hint || AST::Builtin.any_type
)
break_context = TypeInference::Context::BreakContext.new(
break_type: break_type,
Expand All @@ -3171,20 +3213,9 @@ def for_block(block_params:, block_param_hint:, block_annotations:, node_type_hi
)
end

def synthesize_block(node:, block_type_hint:, block_body:, topdown_hint:)
def synthesize_block(node:, block_type_hint:, block_body:)
if block_body
body_type, _, context =
if (body_type = block_context.body_type)
check(block_body, body_type) do |expected, actual, result|
error = Errors::BlockTypeMismatch.new(node: block_body,
expected: expected,
actual: actual,
result: result)
yield(error) if block_given?
end
else
synthesize(block_body, hint: topdown_hint ? block_type_hint : nil)
end
body_type, _, context = synthesize(block_body, hint: block_context.body_type || block_type_hint)

range = block_body.loc.expression.end_pos..node.loc.end.begin_pos
typing.add_context(range, context: context)
Expand Down
9 changes: 0 additions & 9 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,6 @@ def assert_argument_type_mismatch(error, expected: nil, actual: nil)
yield error.expected, error.actual if block_given?
end

def assert_block_type_mismatch(error, expected: nil, actual: nil)
assert_instance_of Steep::Errors::BlockTypeMismatch, error

assert_equal expected, error.expected.to_s if expected
assert_equal actual, error.actual.to_s if actual

yield expected, actual if block_given?
end

def assert_break_type_mismatch(error, expected: nil, actual: nil)
assert_instance_of Steep::Errors::BreakTypeMismatch, error

Expand Down
Loading