Project

General

Profile

ActionsLike0

Bug #15928

closed

Constant declaration does not conform to JIS 3017:2013

Added by yugui (Yuki Sonoda) almost 6 years ago. Updated about 3 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.7.0dev (2019-06-16T14:01:46Z master d4929f5185) [x86_64-darwin18]
[ruby-core:93184]
Tags:

Description

The order of evaluation in constant declaration does not conform to JIS 3017:2013 11.4.2.2.3.

Problem

Suppose that we are evaluating the following program.

expr::C = rhs

The standard seems to be requiring the following evaluation order:

  1. expr
  • raise a TypeError if the value is not a kind of Module
  1. rhs
  2. rb_const_set(expr, :C, rhs)

However, the actual implementation evaluates in the following order

  1. rhs
  2. expr
  3. rb_const_set(expr, :C, lhs)
  • raise a TypeError if the expr is not a kind of Module

How to reproduce

The next program does not raise "recv" but raises "value"

raise("recv")::C = raise("value")

The next program does not raise a TypeError but raises a RuntimeError

A = 1
A::C = raise("value")

Question

  • Is this interpretation of the standard correct?
  • If it is, Should we change the current behavior?
  • If we shouldn't, does it mean an issue in the standard?

c.f.


Related issues 1 (0 open1 closed)

Related to Ruby - Bug #4443: odd evaluation order in a multiple assignmentClosedko1 (Koichi Sasada)Actions

Added by jeremyevans (Jeremy Evans) about 3 years ago

Revision ca3d4052

Fix constant assignment evaluation order

Previously, the right hand side was always evaluated before the
left hand side for constant assignments. For the following:

lhs::C = rhs

rhs was evaluated before lhs, which is inconsistant with attribute
assignment (lhs.m = rhs), and apparently also does not conform to
JIS 3017:2013 11.4.2.2.3.

Fix this by changing evaluation order. Previously, the above
compiled to:

0000 putself                                                          (   1)[Li]
0001 opt_send_without_block                 <calldata!mid:rhs, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0003 dup
0004 putself
0005 opt_send_without_block                 <calldata!mid:lhs, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0007 setconstant                            :C
0009 leave

After this change:

0000 putself                                                          (   1)[Li]
0001 opt_send_without_block                 <calldata!mid:lhs, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0003 putself
0004 opt_send_without_block                 <calldata!mid:rhs, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0006 swap
0007 topn                                   1
0009 swap
0010 setconstant                            :C
0012 leave

Note that if expr is not a module/class, then a TypeError is not
raised until after the evaluation of rhs. This is because that
error is raised by setconstant. If we wanted to raise TypeError
before evaluation of rhs, we would have to add a VM instruction
for calling vm_check_if_namespace.

Changing assignment order for single assignments caused problems
in the multiple assignment code, revealing that the issue also
affected multiple assignment. Fix the multiple assignment code
so left-to-right evaluation also works for constant assignments.

Do some refactoring of the multiple assignment code to reduce
duplication after adding support for constants. Rename struct
masgn_attrasgn to masgn_lhs_node, since it now handles both
constants and attributes. Add add_masgn_lhs_node static function
for adding data for lhs attribute and constant setting.

Fixes [Bug #15928]

ActionsLike0

Also available in: Atom PDF