Skip to content

Commit f0fdcba

Browse files
committed
Do not desugar Foo::Bar {||,&&,+}= baz as it is incorrect without a temporary variable
* See #1329 (comment) for details.
1 parent ebc324d commit f0fdcba

File tree

2 files changed

+8
-66
lines changed

2 files changed

+8
-66
lines changed

lib/yarp/desugar_visitor.rb

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -56,69 +56,6 @@ def visit_constant_operator_write_node(node)
5656
desugar_operator_write_node(node, ConstantReadNode, ConstantWriteNode)
5757
end
5858

59-
# Foo::Bar &&= baz
60-
#
61-
# becomes
62-
#
63-
# Foo::Bar && Foo::Bar = baz
64-
def visit_constant_path_and_write_node(node)
65-
AndNode.new(
66-
node.target,
67-
ConstantPathWriteNode.new(node.target, node.value, node.operator_loc, node.location),
68-
node.operator_loc,
69-
node.location
70-
)
71-
end
72-
73-
# Foo::Bar ||= baz
74-
#
75-
# becomes
76-
#
77-
# defined?(Foo::Bar) ? Foo::Bar : Foo::Bar = baz
78-
def visit_constant_path_or_write_node(node)
79-
IfNode.new(
80-
node.operator_loc,
81-
DefinedNode.new(nil, node.target, nil, node.operator_loc, node.target.location),
82-
StatementsNode.new([node.target], node.location),
83-
ElseNode.new(
84-
node.operator_loc,
85-
StatementsNode.new(
86-
[ConstantPathWriteNode.new(node.target, node.value, node.operator_loc, node.location)],
87-
node.location
88-
),
89-
node.operator_loc,
90-
node.location
91-
),
92-
node.operator_loc,
93-
node.location
94-
)
95-
end
96-
97-
# Foo::Bar += baz
98-
#
99-
# becomes
100-
#
101-
# Foo::Bar = Foo::Bar + baz
102-
def visit_constant_path_operator_write_node(node)
103-
ConstantPathWriteNode.new(
104-
node.target,
105-
CallNode.new(
106-
node.target,
107-
nil,
108-
node.operator_loc.copy(length: node.operator_loc.length - 1),
109-
nil,
110-
ArgumentsNode.new([node.value], node.value.location),
111-
nil,
112-
nil,
113-
0,
114-
node.operator_loc.slice.chomp("="),
115-
node.location
116-
),
117-
node.operator_loc.copy(start_offset: node.operator_loc.end_offset - 1, length: 1),
118-
node.location
119-
)
120-
end
121-
12259
# $foo &&= bar
12360
#
12461
# becomes

test/yarp/desugar_visitor_test.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module YARP
66
class DesugarVisitorTest < TestCase
77
def test_and_write
88
assert_desugars("(AndNode (ClassVariableReadNode) (ClassVariableWriteNode (CallNode)))", "@@foo &&= bar")
9-
assert_desugars("(AndNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (ConstantPathWriteNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (CallNode)))", "Foo::Bar &&= baz")
9+
assert_not_desugared("Foo::Bar &&= baz", "Desugaring would execute Foo twice or need temporary variables")
1010
assert_desugars("(AndNode (ConstantReadNode) (ConstantWriteNode (CallNode)))", "Foo &&= bar")
1111
assert_desugars("(AndNode (GlobalVariableReadNode) (GlobalVariableWriteNode (CallNode)))", "$foo &&= bar")
1212
assert_desugars("(AndNode (InstanceVariableReadNode) (InstanceVariableWriteNode (CallNode)))", "@foo &&= bar")
@@ -16,7 +16,7 @@ def test_and_write
1616

1717
def test_or_write
1818
assert_desugars("(IfNode (DefinedNode (ClassVariableReadNode)) (StatementsNode (ClassVariableReadNode)) (ElseNode (StatementsNode (ClassVariableWriteNode (CallNode)))))", "@@foo ||= bar")
19-
assert_desugars("(IfNode (DefinedNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode))) (StatementsNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode))) (ElseNode (StatementsNode (ConstantPathWriteNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (CallNode)))))", "Foo::Bar ||= baz")
19+
assert_not_desugared("Foo::Bar ||= baz", "Desugaring would execute Foo twice or need temporary variables")
2020
assert_desugars("(IfNode (DefinedNode (ConstantReadNode)) (StatementsNode (ConstantReadNode)) (ElseNode (StatementsNode (ConstantWriteNode (CallNode)))))", "Foo ||= bar")
2121
assert_desugars("(IfNode (DefinedNode (GlobalVariableReadNode)) (StatementsNode (GlobalVariableReadNode)) (ElseNode (StatementsNode (GlobalVariableWriteNode (CallNode)))))", "$foo ||= bar")
2222
assert_desugars("(OrNode (InstanceVariableReadNode) (InstanceVariableWriteNode (CallNode)))", "@foo ||= bar")
@@ -26,7 +26,7 @@ def test_or_write
2626

2727
def test_operator_write
2828
assert_desugars("(ClassVariableWriteNode (CallNode (ClassVariableReadNode) (ArgumentsNode (CallNode))))", "@@foo += bar")
29-
assert_desugars("(ConstantPathWriteNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (CallNode (ConstantPathNode (ConstantReadNode) (ConstantReadNode)) (ArgumentsNode (CallNode))))", "Foo::Bar += baz")
29+
assert_not_desugared("Foo::Bar += baz", "Desugaring would execute Foo twice or need temporary variables")
3030
assert_desugars("(ConstantWriteNode (CallNode (ConstantReadNode) (ArgumentsNode (CallNode))))", "Foo += bar")
3131
assert_desugars("(GlobalVariableWriteNode (CallNode (GlobalVariableReadNode) (ArgumentsNode (CallNode))))", "$foo += bar")
3232
assert_desugars("(InstanceVariableWriteNode (CallNode (InstanceVariableReadNode) (ArgumentsNode (CallNode))))", "@foo += bar")
@@ -55,5 +55,10 @@ def assert_desugars(expected, source)
5555
ast = YARP.parse(source).value.accept(DesugarVisitor.new)
5656
assert_equal expected, ast_inspect(ast.statements.body.last)
5757
end
58+
59+
def assert_not_desugared(source, reason)
60+
ast = YARP.parse(source).value
61+
assert_equal_nodes(ast, ast.accept(YARP::DesugarVisitor.new))
62+
end
5863
end
5964
end

0 commit comments

Comments
 (0)