Skip to content

Commit

Permalink
make x[...] .= ... assign in-place (fixes bug in JuliaLang#17510)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengj committed Jul 21, 2016
1 parent 1ff1cbb commit 8bf99cb
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 3 deletions.
4 changes: 4 additions & 0 deletions doc/manual/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,10 @@ calls do not allocate new arrays over and over again for the results
except that, as above, the ``broadcast!`` loop is fused with any nested
"dot" calls. For example, ``X .= sin.(Y)`` is equivalent to
``broadcast!(sin, X, Y)``, overwriting ``X`` with ``sin.(Y)`` in-place.
If the left-hand side is a ``getindex`` expression, e.g.
``X[2:end] .= sin(Y)``, then it translates to ``broadcast!`` on a ``view``,
e.g. ``broadcast!(sin, view(X, 2:length(X)), Y)``, so that the left-hand
side is updated in-place.

(In future versions of Julia, operators like ``.*`` will also be handled with
the same mechanism: they will be equivalent to ``broadcast`` calls and
Expand Down
16 changes: 13 additions & 3 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,15 @@
(cadr expr) ;; eta reduce `x->f(x)` => `f`
`(-> ,argname (block ,@splat ,expr)))))

(define (ref-to-view expr)
(if (and (pair? expr) (eq? (car expr) 'ref))
(let* ((ex (partially-expand-ref expr))
(stmts (butlast (cdr ex)))
(refex (last (cdr ex)))
(nuref `(call view ,(caddr refex) ,@(cdddr refex))))
`(block ,@stmts ,nuref))
expr))

; fuse nested calls to expr == f.(args...) into a single broadcast call,
; or a broadcast! call if lhs is non-null.
(define (expand-fuse-broadcast lhs rhs)
Expand Down Expand Up @@ -1657,14 +1666,15 @@
(cons farg new-fargs) (cons arg new-args) renames varfarg vararg))))))
(cf (cdadr f) args '() '() '() '() '()))
e)) ; (not (fuse? e))
(let ((e (compress-fuse (dot-to-fuse rhs)))) ; an expression '(fuse func args) if expr is a dot call
(let ((e (compress-fuse (dot-to-fuse rhs))) ; an expression '(fuse func args) if expr is a dot call
(lhs_ (ref-to-view lhs))) ; x[...] expressions on lhs turn in to view(x, ...) to update x in-place
(if (fuse? e)
(if (null? lhs)
(expand-forms `(call broadcast ,(from-lambda (cadr e)) ,@(caddr e)))
(expand-forms `(call broadcast! ,(from-lambda (cadr e)) ,lhs ,@(caddr e))))
(expand-forms `(call broadcast! ,(from-lambda (cadr e)) ,lhs_ ,@(caddr e))))
(if (null? lhs)
(expand-forms e)
(expand-forms `(call broadcast! identity ,lhs ,e))))))
(expand-forms `(call broadcast! identity ,lhs_ ,e))))))

;; table mapping expression head to a function expanding that form
(define expand-table
Expand Down
8 changes: 8 additions & 0 deletions test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,14 @@ let x = [1:4;], y = x
@test y === x == [8,8,8,8]
y .-= 1:4
@test y === x == [7,6,5,4]
x[1:2] .= 1
@test y === x == [1,1,5,4]
x[1:2] .+= [2,3]
@test y === x == [3,4,5,4]
x[:] .= 0
@test y === x == [0,0,0,0]
x[2:end] .= 1:3
@test y === x == [0,1,2,3]
end

# PR 16988
Expand Down

0 comments on commit 8bf99cb

Please sign in to comment.