Skip to content

Commit edec272

Browse files
committed
[GR-47464] Only evaluate LHS of annotated assignment once
PullRequest: graalpython/2882
2 parents d1dc3b7 + 401fe1f commit edec272

File tree

3 files changed

+93
-9
lines changed

3 files changed

+93
-9
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
class Counter:
41+
def __init__(self):
42+
self.count = 0
43+
def get(self, value):
44+
self.count += 1
45+
return value
46+
47+
# Whether there's an RHS or not, each component of a slice and attribute assignment should be evaluated exactly once.
48+
49+
arr = [0,0,0,0,0]
50+
51+
c = Counter()
52+
c.get(arr)[c.get(0): c.get(2): c.get(1)]: (int, int)
53+
slice_no_assign_count = c.count
54+
55+
c = Counter()
56+
c.get(arr)[c.get(0): c.get(2): c.get(1)]: (int, int) = (42, 42)
57+
slice_assign_count = c.count
58+
59+
60+
class Foo:
61+
def __init__(self):
62+
self.x = 42
63+
64+
foo = Foo()
65+
66+
c = Counter()
67+
c.get(foo).x: int
68+
attr_no_assign_count = c.count
69+
70+
c = Counter()
71+
c.get(foo).x: int = 43
72+
attr_assign_count = c.count

graalpython/com.oracle.graal.python.test/src/tests/test_annotations.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -98,3 +98,11 @@ def test_addAnnotation():
9898
m.addAnnotation('myKey', 10)
9999
assert len(m.addAnnotation.__annotations__) == 2
100100
assert 10 == m.addAnnotation.__annotations__['myKey']
101+
102+
def test_annotatedAssignments():
103+
import annotations.annotatedAssignments as m
104+
105+
assert m.slice_no_assign_count == 4
106+
assert m.slice_assign_count == 4
107+
assert m.attr_no_assign_count == 1
108+
assert m.attr_assign_count == 1

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/Compiler.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,17 +2084,21 @@ public Void visit(StmtTy.AnnAssign node) {
20842084
addOp(STORE_SUBSCR);
20852085
}
20862086
} else if (node.target instanceof ExprTy.Attribute) {
2087-
ExprTy.Attribute attr = (ExprTy.Attribute) node.target;
2088-
checkForbiddenName(attr.attr, ExprContextTy.Store);
2089-
if (attr.value != null) {
2090-
checkAnnExpr(attr.value);
2087+
if (node.value == null) {
2088+
ExprTy.Attribute attr = (ExprTy.Attribute) node.target;
2089+
checkForbiddenName(attr.attr, ExprContextTy.Store);
2090+
if (attr.value != null) {
2091+
checkAnnExpr(attr.value);
2092+
}
20912093
}
20922094
} else if (node.target instanceof ExprTy.Subscript) {
2093-
ExprTy.Subscript subscript = (ExprTy.Subscript) node.target;
2094-
if (subscript.value != null) {
2095-
checkAnnExpr(subscript.value);
2095+
if (node.value == null) {
2096+
ExprTy.Subscript subscript = (ExprTy.Subscript) node.target;
2097+
if (subscript.value != null) {
2098+
checkAnnExpr(subscript.value);
2099+
}
2100+
checkAnnSubscr(subscript.slice);
20962101
}
2097-
checkAnnSubscr(subscript.slice);
20982102
} else {
20992103
errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "invalid node type for annotated assignment");
21002104
}

0 commit comments

Comments
 (0)