Skip to content

Commit 8bf99cb

Browse files
committed
make x[...] .= ... assign in-place (fixes bug in JuliaLang#17510)
1 parent 1ff1cbb commit 8bf99cb

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

doc/manual/functions.rst

+4
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,10 @@ calls do not allocate new arrays over and over again for the results
660660
except that, as above, the ``broadcast!`` loop is fused with any nested
661661
"dot" calls. For example, ``X .= sin.(Y)`` is equivalent to
662662
``broadcast!(sin, X, Y)``, overwriting ``X`` with ``sin.(Y)`` in-place.
663+
If the left-hand side is a ``getindex`` expression, e.g.
664+
``X[2:end] .= sin(Y)``, then it translates to ``broadcast!`` on a ``view``,
665+
e.g. ``broadcast!(sin, view(X, 2:length(X)), Y)``, so that the left-hand
666+
side is updated in-place.
663667

664668
(In future versions of Julia, operators like ``.*`` will also be handled with
665669
the same mechanism: they will be equivalent to ``broadcast`` calls and

src/julia-syntax.scm

+13-3
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,15 @@
15421542
(cadr expr) ;; eta reduce `x->f(x)` => `f`
15431543
`(-> ,argname (block ,@splat ,expr)))))
15441544

1545+
(define (ref-to-view expr)
1546+
(if (and (pair? expr) (eq? (car expr) 'ref))
1547+
(let* ((ex (partially-expand-ref expr))
1548+
(stmts (butlast (cdr ex)))
1549+
(refex (last (cdr ex)))
1550+
(nuref `(call view ,(caddr refex) ,@(cdddr refex))))
1551+
`(block ,@stmts ,nuref))
1552+
expr))
1553+
15451554
; fuse nested calls to expr == f.(args...) into a single broadcast call,
15461555
; or a broadcast! call if lhs is non-null.
15471556
(define (expand-fuse-broadcast lhs rhs)
@@ -1657,14 +1666,15 @@
16571666
(cons farg new-fargs) (cons arg new-args) renames varfarg vararg))))))
16581667
(cf (cdadr f) args '() '() '() '() '()))
16591668
e)) ; (not (fuse? e))
1660-
(let ((e (compress-fuse (dot-to-fuse rhs)))) ; an expression '(fuse func args) if expr is a dot call
1669+
(let ((e (compress-fuse (dot-to-fuse rhs))) ; an expression '(fuse func args) if expr is a dot call
1670+
(lhs_ (ref-to-view lhs))) ; x[...] expressions on lhs turn in to view(x, ...) to update x in-place
16611671
(if (fuse? e)
16621672
(if (null? lhs)
16631673
(expand-forms `(call broadcast ,(from-lambda (cadr e)) ,@(caddr e)))
1664-
(expand-forms `(call broadcast! ,(from-lambda (cadr e)) ,lhs ,@(caddr e))))
1674+
(expand-forms `(call broadcast! ,(from-lambda (cadr e)) ,lhs_ ,@(caddr e))))
16651675
(if (null? lhs)
16661676
(expand-forms e)
1667-
(expand-forms `(call broadcast! identity ,lhs ,e))))))
1677+
(expand-forms `(call broadcast! identity ,lhs_ ,e))))))
16681678

16691679
;; table mapping expression head to a function expanding that form
16701680
(define expand-table

test/broadcast.jl

+8
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ let x = [1:4;], y = x
265265
@test y === x == [8,8,8,8]
266266
y .-= 1:4
267267
@test y === x == [7,6,5,4]
268+
x[1:2] .= 1
269+
@test y === x == [1,1,5,4]
270+
x[1:2] .+= [2,3]
271+
@test y === x == [3,4,5,4]
272+
x[:] .= 0
273+
@test y === x == [0,0,0,0]
274+
x[2:end] .= 1:3
275+
@test y === x == [0,1,2,3]
268276
end
269277

270278
# PR 16988

0 commit comments

Comments
 (0)