Skip to content

Commit

Permalink
Revert "allow slurping in lhs of assignment (#37410)"
Browse files Browse the repository at this point in the history
This reverts commit 6edf6d9.
  • Loading branch information
fredrikekre authored Oct 26, 2020
1 parent 031c877 commit e61b0e6
Show file tree
Hide file tree
Showing 8 changed files with 21 additions and 174 deletions.
7 changes: 0 additions & 7 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ New language features
* The postfix conjugate transpose operator `'` now accepts Unicode modifiers as
suffixes, so e.g. `a'ᵀ` is parsed as `var"'ᵀ"(a)`, which can be defined by the
user. `a'ᵀ` parsed as `a' * ᵀ` before, so this is a minor change ([#37247]).
* It is now possible to use varargs on the left-hand side of assignments for taking any
number of items from the front of an iterable collection, while also collecting the rest,
like `a, b... = [1, 2, 3]`, for example. This syntax is implemented using `Base.rest`,
which can be overloaded to customize its behavior for different collection types
([#37410]).

Language changes
----------------
Expand Down Expand Up @@ -101,8 +96,6 @@ New library functions
efficiently ([#35816]).
* New function `addenv` for adding environment mappings into a `Cmd` object, returning the new `Cmd` object.
* New function `insorted` for determining whether an element is in a sorted collection or not ([#37490]).
* New function `Base.rest` for taking the rest of a collection, starting from a specific
iteration state, in a generic way ([#37410]).

New library features
--------------------
Expand Down
8 changes: 0 additions & 8 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2399,11 +2399,3 @@ function hash(A::AbstractArray, h::UInt)

return h
end

# The semantics of `collect` are weird. Better to write our own
function rest(a::AbstractArray{T}, state...) where {T}
v = Vector{T}(undef, 0)
# assume only very few items are taken from the front
sizehint!(v, length(a))
return foldl(push!, Iterators.rest(a, state...), init=v)
end
32 changes: 0 additions & 32 deletions base/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,38 +96,6 @@ function indexed_iterate(I, i, state)
x
end

"""
Base.rest(collection[, itr_state])
Generic function for taking the tail of `collection`, starting from a specific iteration
state `itr_state`. Return a `Tuple`, if `collection` itself is a `Tuple`, a `Vector`, if
`collection` is an `AbstractArray` and `Iterators.rest(collection[, itr_state])` otherwise.
Can be overloaded for user-defined collection types to customize the behavior of slurping
in assignments, like `a, b... = collection`.
!!! compat "Julia 1.6"
`Base.rest` requires at least Julia 1.6.
# Examples
```jldoctest
julia> a = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> first, state = iterate(a)
(1, 2)
julia> first, Base.rest(a, state)
(1, [3, 2, 4])
```
"""
function rest end
rest(t::Tuple) = t
rest(t::Tuple, i::Int) = ntuple(x -> getfield(t, x+i-1), length(t)-i+1)
rest(a::Array, i::Int=1) = a[i:end]
rest(itr, state...) = Iterators.rest(itr, state...)

# Use dispatch to avoid a branch in first
first(::Tuple{}) = throw(ArgumentError("tuple must be non-empty"))
first(t::Tuple) = t[1]
Expand Down
1 change: 0 additions & 1 deletion doc/src/base/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ Base.filter!
Base.replace(::Any, ::Pair...)
Base.replace(::Base.Callable, ::Any)
Base.replace!
Base.rest
```

## Indexable Collections
Expand Down
71 changes: 21 additions & 50 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1430,8 +1430,7 @@
,@(reverse after)
(unnecessary (tuple ,@(reverse elts))))
(let ((L (car lhss))
;; rhss can be null iff L is a vararg
(R (if (null? rhss) '() (car rhss))))
(R (car rhss)))
(cond ((and (symbol-like? L)
(or (not (pair? R)) (quoted? R) (equal? R '(null)))
;; overwrite var immediately if it doesn't occur elsewhere
Expand All @@ -1443,16 +1442,6 @@
(cons (make-assignment L R) stmts)
after
(cons R elts)))
((vararg? L)
(if (null? (cdr lhss))
(let ((temp (make-ssavalue)))
`(block ,@(reverse stmts)
(= ,temp (tuple ,@rhss))
,@(reverse after)
(= ,(cadr L) ,temp)
(unnecessary (tuple ,@(reverse elts) (... ,temp)))))
(error (string "invalid \"...\" on non-final assignment location \""
(cadr L) "\""))))
((vararg? R)
(let ((temp (make-ssavalue)))
`(block ,@(reverse stmts)
Expand Down Expand Up @@ -2077,7 +2066,6 @@
(define (sides-match? l r)
;; l and r either have equal lengths, or r has a trailing ...
(cond ((null? l) (null? r))
((vararg? (car l)) #t)
((null? r) #f)
((vararg? (car r)) (null? (cdr r)))
(else (sides-match? (cdr l) (cdr r)))))
Expand All @@ -2087,43 +2075,26 @@
(expand-forms
(tuple-to-assignments lhss x))
;; (a, b, ...) = other
(begin
;; like memq, but if last element of lhss is (... sym),
;; check against sym instead
(define (in-lhs? x lhss)
(if (null? lhss)
#f
(let ((l (car lhss)))
(cond ((and (pair? l) (eq? (car l) '|...|))
(if (null? (cdr lhss))
(eq? (cadr l) x)
(error (string "invalid \"...\" on non-final assignment location \""
(cadr l) "\""))))
((eq? l x) #t)
(else (in-lhs? x (cdr lhss)))))))
;; in-lhs? also checks for invalid syntax, so always call it first
(let* ((xx (if (or (and (not (in-lhs? x lhss)) (symbol? x))
(ssavalue? x))
x (make-ssavalue)))
(ini (if (eq? x xx) '() (list (sink-assignment xx (expand-forms x)))))
(n (length lhss))
(st (gensy)))
`(block
(local ,st)
,@ini
,.(map (lambda (i lhs)
(expand-forms
(if (and (pair? lhs) (eq? (car lhs) '|...|))
`(= ,(cadr lhs) (call (top rest) ,xx ,.(if (eq? i 0) '() `(,st))))
(lower-tuple-assignment
(if (= i (- n 1))
(list lhs)
(list lhs st))
`(call (top indexed_iterate)
,xx ,(+ i 1) ,.(if (eq? i 0) '() `(,st)))))))
(iota n)
lhss)
(unnecessary ,xx)))))))
(let* ((xx (if (or (and (symbol? x) (not (memq x lhss)))
(ssavalue? x))
x (make-ssavalue)))
(ini (if (eq? x xx) '() (list (sink-assignment xx (expand-forms x)))))
(n (length lhss))
(st (gensy)))
`(block
(local ,st)
,@ini
,.(map (lambda (i lhs)
(expand-forms
(lower-tuple-assignment
(if (= i (- n 1))
(list lhs)
(list lhs st))
`(call (top indexed_iterate)
,xx ,(+ i 1) ,.(if (eq? i 0) '() `(,st))))))
(iota n)
lhss)
(unnecessary ,xx))))))
((typed_hcat)
(error "invalid spacing in left side of indexed assignment"))
((typed_vcat)
Expand Down
7 changes: 0 additions & 7 deletions test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1193,10 +1193,3 @@ end
@test last(itr, 1) == [itr[end]]
@test_throws ArgumentError last(itr, -6)
end

@testset "Base.rest" begin
a = reshape(1:4, 2, 2)'
@test Base.rest(a) == a[:]
_, st = iterate(a)
@test Base.rest(a, st) == [3, 2, 4]
end
51 changes: 0 additions & 51 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2532,54 +2532,3 @@ end

# PR #37973
@test Meta.parse("1¦2⌿3") == Expr(:call, , 1, Expr(:call, :⌿, 2, 3))

@testset "slurp in assignments" begin
res = begin x, y, z... = 1:7 end
@test res == 1:7
@test x == 1 && y == 2
@test z == Vector(3:7)

res = begin x, y, z... = [1, 2] end
@test res == [1, 2]
@test x == 1 && y == 2
@test z == Int[]

x = 1
res = begin x..., = x end
@test res == 1
@test x == 1

x, y, z... = 1:7
res = begin y, z, x... = z..., x, y end
@test res == ((3:7)..., 1, 2)
@test y == 3
@test z == 4
@test x == ((5:7)..., 1, 2)

res = begin x, _, y... = 1, 2 end
@test res == (1, 2)
@test x == 1
@test y == ()

res = begin x, y... = 1 end
@test res == 1
@test x == 1
@test y == Iterators.rest(1, nothing)

res = begin x, y, z... = 1, 2, 3:5 end
@test res == (1, 2, 3:5)
@test x == 1 && y == 2
@test z == (3:5,)

@test Meta.isexpr(Meta.@lower(begin a, b..., c = 1:3 end), :error)
@test Meta.isexpr(Meta.@lower(begin a, b..., c = 1, 2, 3 end), :error)
@test Meta.isexpr(Meta.@lower(begin a, b..., c... = 1, 2, 3 end), :error)

@test_throws BoundsError begin x, y, z... = 1:1 end
@test_throws BoundsError begin x, y, _, z... = 1, 2 end

car((a, d...)) = a
cdr((a, d...)) = d
@test car(1:3) == 1
@test cdr(1:3) == [2, 3]
end
18 changes: 0 additions & 18 deletions test/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -575,21 +575,3 @@ end
@test_throws BoundsError (1,2.0)[0:1]
@test_throws BoundsError (1,2.0)[0:0]
end

@testset "Base.rest" begin
t = (1, 2.0, 0x03, 4f0)
@test Base.rest(t) === t
@test Base.rest(t, 2) === (2.0, 0x03, 4f0)

a = [1 2; 3 4]
@test Base.rest(a) == a[:]
@test pointer(Base.rest(a)) != pointer(a)
@test Base.rest(a, 3) == [2, 4]

itr = (-i for i in a)
@test Base.rest(itr) == itr
_, st = iterate(itr)
r = Base.rest(itr, st)
@test r isa Iterators.Rest
@test collect(r) == -[3, 2, 4]
end

0 comments on commit e61b0e6

Please sign in to comment.