Project

General

Profile

Actions

Bug #21669

open

Thoroughly implement void value expression check

Bug #21669: Thoroughly implement void value expression check

Added by mame (Yusuke Endoh) about 10 hours ago. Updated about 7 hours ago.

Status:
Open
Assignee:
Target version:
-
[ruby-core:123681]

Description

A void-value-expression check is a syntax check that raises a SyntaxError if an expression that cannot grammatically return a value (a "void value expression," such as a return expression) appears in a context where a value is expected (e.g., the right-hand side of an assignment, the argument of a method call, etc.). A typical example rejected by this check is x = return.

However, it has become clear that this check is incomplete. This ticket summarizes the results of a discussion with @matz (Yukihiro Matsumoto) at the hackathon before RubyWorld Conference today.

1. Expressions containing branches

@matz (Yukihiro Matsumoto) said that an expression containing branches should be considered a void value expression only if it can be grammatically determined that all possible branches do not return a value.

Based on this, both parse.y and prism currently reject the following code with a "void value expression" SyntaxError, but it should be accepted:

x = begin
  raise
  return
rescue
  "OK"
else
  return
end
# Expected: Code parses and executes successfully.
# Actual: Rejected with "unexpected void value expression" SyntaxError.

Reason: The rescue clause can return a value ("OK"), so the entire begin expression is not void.

Conversely, the following code is currently accepted by both parse.y and prism, but it should be rejected:

x = begin
  foo
rescue
  return
else
  return
end
# Expected: Rejected with SyntaxError.
# Actual: Code parses and executes.

Reason: This expression always does return, so it is void whether foo raises an exception or not.

Furthermore, case expressions must also be rejected similarly when all branches are void:

x =
  case
  when 1; return
  when 2; return
  else return
  end
# Expected: Rejected with SyntaxError.
# Actual: Code parses and executes.

Note that if expressions appear to be implemented correctly as intended:

x = if rand < 0.5
  return
else
  return
end
# Expected: Rejected with SyntaxError.
# Actual: Rejected. (OK!)

2. Statement lists containing a void value expression

@matz (Yukihiro Matsumoto) also said that if a statements node contains a void value expression, the entire statement list should be treated as a void value expression, even if the void expression is not the last one.

Therefore, the following code is currently accepted but should be rejected:

x = begin
  return
  "NG"
end
# Expected: Rejected with SyntaxError.
# Actual: Code parses and executes.

The same applies to branches within other expressions:

x = if rand < 0.5
  return
  "NG"
else
  return
end
# Expected: Rejected with SyntaxError.
# Actual: Code parses and executes.

Note that if a return statement is inside a branch, that statement cannot be considered a void value expression, so the entire expression also cannot be a void value expression.

x = begin
  return if true
  "NG"
end
# Expected: Code parses and executes.
# Actual: Code parses and executes as expected. (OK!)

This is considered a bug, but if it causes practical compatibility issues, it may be necessary to plan a migration path or revisit the specifications.

(Both prism and parse.y need to be fixed, but I'll assign it to the prism team for now.)

Actions

Also available in: PDF Atom