Skip to content

Commit

Permalink
Merge pull request #11801 from JuliaLang/jb/globalscopefixes
Browse files Browse the repository at this point in the history
fix scope issues #7234 and #10472
  • Loading branch information
JeffBezanson committed Jun 22, 2015
2 parents 69013eb + 1b3c585 commit f1034d5
Show file tree
Hide file tree
Showing 13 changed files with 137 additions and 114 deletions.
13 changes: 8 additions & 5 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ New language features
Language changes
----------------

* Unsigned `BigInt` literal syntax has been removed ([#11105]).
Unsigned literals larger than `UInt128` now throw a syntax error.

* Tuple types are now written as `Tuple{A, B}` instead of as `(A, B)`.
Tuples of bits types are inlined into structs and arrays, like other
immutable types.
Expand Down Expand Up @@ -78,18 +75,21 @@ Language changes
* `[x,y]` constructs a vector of `x` and `y` instead of concatenating them
([#3737], [#2488], [#8599]).

* Unsigned `BigInt` literal syntax has been removed ([#11105]).
Unsigned literals larger than `UInt128` now throw a syntax error.

* `error(::Exception)` and `error(::Type{Exception})` have been deprecated
in favor of using an explicit `throw` ([#9690]).

* `Uint` etcetera are renamed to `UInt` ([#8905]).

* `String` is renamed to `AbstractString` ([#8872]).

* `None` is deprecated; use `Union()` instead ([#8423]).
* `None` is deprecated; use `Union{}` instead ([#8423]).

* `Nothing` (the type of `nothing`) is renamed to `Void` ([#8423]).

* Arrays can be constructed with the syntax `Array{T}(m,n)` ([#3214], [#10075])
* Arrays can be constructed with the syntax `Array{T}(m,n)` ([#3214], [#10075]).

* `Dict` literal syntax `[a=>b,c=>d]` is replaced by `Dict(a=>b,c=>d)`,
`{a=>b}` is replaced by `Dict{Any,Any}(a=>b)`, and
Expand Down Expand Up @@ -122,6 +122,9 @@ Language changes
* Unions of types should now be written with curly braces instead of parentheses, i.e.
`Union{Type1, Type2}` instead of `Union(Type1, Type2)` ([#11432]).

* The keyword `local` is no longer allowed in global scope. Use `let` instead of
`begin` to create a new scope from the top level ([#7234], [#10472]).

Command line option changes
---------------------------

Expand Down
4 changes: 2 additions & 2 deletions base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ end
function gen_broadcast_function(genbody::Function, nd::Int, narrays::Int, f::Function)
As = [symbol("A_"*string(i)) for i = 1:narrays]
body = genbody(nd, narrays, f)
@eval begin
@eval let
local _F_
function _F_(B, $(As...))
$body
Expand All @@ -197,7 +197,7 @@ end
function gen_broadcast_function_tobitarray(genbody::Function, nd::Int, narrays::Int, f::Function)
As = [symbol("A_"*string(i)) for i = 1:narrays]
body = genbody(nd, narrays, f)
@eval begin
@eval let
local _F_
function _F_(B::BitArray, $(As...))
$body
Expand Down
8 changes: 4 additions & 4 deletions base/printf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ function _printf(macroname, io, fmt, args)
end

unshift!(blk.args, :(out = $io))
blk
Expr(:let, blk)
end

macro printf(args...)
Expand All @@ -1059,9 +1059,9 @@ macro sprintf(args...)
!isempty(args) || throw(ArgumentError("@sprintf: called with zero arguments"))
isa(args[1], AbstractString) || is_str_expr(args[1]) ||
throw(ArgumentError("@sprintf: first argument must be a format string"))
blk = _printf("@sprintf", :(IOBuffer()), args[1], args[2:end])
push!(blk.args, :(takebuf_string(out)))
blk
letexpr = _printf("@sprintf", :(IOBuffer()), args[1], args[2:end])
push!(letexpr.args[1].args, :(takebuf_string(out)))
letexpr
end

end # module
2 changes: 1 addition & 1 deletion base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,7 @@ end

function gen_broadcast_function_sparse(genbody::Function, f::Function, is_first_sparse::Bool)
body = genbody(f, is_first_sparse)
@eval begin
@eval let
local _F_
function _F_{Tv,Ti}(B::SparseMatrixCSC{Tv,Ti}, A_1, A_2)
$body
Expand Down
5 changes: 2 additions & 3 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,8 @@ include("multidimensional.jl")

include("primes.jl")

begin
SOURCE_PATH = ""
include = function(path)
let SOURCE_PATH = ""
global include = function(path)
prev = SOURCE_PATH
path = joinpath(dirname(prev),path)
SOURCE_PATH = path
Expand Down
15 changes: 2 additions & 13 deletions doc/manual/variables-and-scoping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,7 @@ block without creating any new bindings:

.. doctest::

julia> begin
local x = 1
begin
local x = 2
end
x
end
ERROR: syntax: local "x" declared twice

julia> begin
julia> let
local x = 1
let
local x = 2
Expand All @@ -302,9 +293,7 @@ block without creating any new bindings:
end
1

The first example is invalid because you cannot declare the same
variable as local in the same scope twice. The second example is valid
since the ``let`` introduces a new scope block, so the inner local ``x``
Since ``let`` introduces a new scope block, the inner local ``x``
is a different variable than the outer local ``x``.

For Loops and Comprehensions
Expand Down
13 changes: 8 additions & 5 deletions src/jlfrontend.scm
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,16 @@
(append
;; vars assigned at the outer level
(filter (lambda (x) (not (some-gensym? x))) (find-assigned-vars e '()))
;; vars declared const outside any scope block
(find-decls 'const e '())
;; vars declared const or global outside any scope block
(find-decls 'const e)
(find-decls 'global e)
;; vars assigned anywhere, if they have been defined as global
(filter defined-julia-global (find-possible-globals e))))
(append
(find-decls 'local e '())
(find-decls 'local! e '()))))
(if (null? (find-decls 'local e))
'()
(error "local declaration in global scope"))
(find-decls 'local! e))))

;; return a lambda expression representing a thunk for a top-level expression
;; note: expansion of stuff inside module is delayed, so the contents obey
Expand All @@ -88,7 +91,7 @@
(th (julia-expand1
`(lambda ()
(scope-block
(block ,@(map (lambda (v) `(global ,v)) gv)
(block ,@(map (lambda (v) `(implicit-global ,v)) gv)
,ex))))))
(if (null? (car (caddr th)))
;; if no locals, return just body of function
Expand Down
73 changes: 39 additions & 34 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -971,19 +971,23 @@
(sparam-name-bounds params '() '())
`(block
(const ,name)
,@(map (lambda (v) `(local ,v)) params)
,@(map make-assignment params (symbols->typevars params bounds #f))
(abstract_type ,name (call (top svec) ,@params) ,super))))
(scope-block
(block
,@(map (lambda (v) `(local ,v)) params)
,@(map make-assignment params (symbols->typevars params bounds #f))
(abstract_type ,name (call (top svec) ,@params) ,super))))))

(define (bits-def-expr n name params super)
(receive
(params bounds)
(sparam-name-bounds params '() '())
`(block
(const ,name)
,@(map (lambda (v) `(local ,v)) params)
,@(map make-assignment params (symbols->typevars params bounds #f))
(bits_type ,name (call (top svec) ,@params) ,n ,super))))
(scope-block
(block
,@(map (lambda (v) `(local ,v)) params)
,@(map make-assignment params (symbols->typevars params bounds #f))
(bits_type ,name (call (top svec) ,@params) ,n ,super))))))

; take apart a type signature, e.g. T{X} <: S{Y}
(define (analyze-type-sig ex)
Expand Down Expand Up @@ -2569,15 +2573,6 @@ The first one gave something broken, but the second case works.
So far only the second case can actually occur.
|#

(define (declared-global-vars e)
(if (or (not (pair? e)) (quoted? e))
'()
(case (car e)
((lambda scope-block) '())
((global) (cdr e))
(else
(apply append (map declared-global-vars e))))))

(define (check-dups locals)
(if (and (pair? locals) (pair? (cdr locals)))
(or (and (memq (car locals) (cdr locals))
Expand All @@ -2604,26 +2599,27 @@ So far only the second case can actually occur.
(apply append! (map (lambda (x) (find-assigned-vars x env))
e))))))

(define (find-decls kind e env)
(define (find-decls kind e)
(if (or (not (pair? e)) (quoted? e))
'()
(cond ((or (eq? (car e) 'lambda) (eq? (car e) 'scope-block))
'())
((eq? (car e) kind)
(list (decl-var (cadr e))))
(else
(apply append! (map (lambda (x) (find-decls kind x env))
(apply append! (map (lambda (x) (find-decls kind x))
e))))))

(define (find-local-decls e env) (find-decls 'local e env))
(define (find-local!-decls e env) (find-decls 'local! e env))
(define (find-local-decls e) (find-decls 'local e))
(define (find-local!-decls e) (find-decls 'local! e))
(define (find-global-decls e) (find-decls 'global e))

(define (find-locals e env glob)
(delete-duplicates
(append! (check-dups (find-local-decls e env))
(append! (check-dups (find-local-decls e))
;; const decls on non-globals also introduce locals
(diff (find-decls 'const e env) glob)
(find-local!-decls e env)
(diff (find-decls 'const e) glob)
(find-local!-decls e)
(find-assigned-vars e env))))

(define (remove-local-decls e)
Expand All @@ -2643,22 +2639,30 @@ So far only the second case can actually occur.
;; 2. (const x) expressions in a scope-block where x is not declared global
;; 3. variables assigned inside this scope-block that don't exist in outer
;; scopes
(define (add-local-decls e env)
(define (add-local-decls e env implicitglobals)
(if (or (not (pair? e)) (quoted? e)) e
(cond ((eq? (car e) 'lambda)
(let* ((env (append (lam:vars e) env))
(body (add-local-decls (caddr e) env)))
(body (add-local-decls (caddr e) env
;; don't propagate implicit globals
;; issue #7234
'())))
(list 'lambda (cadr e) body)))

((eq? (car e) 'scope-block)
(let* ((glob (declared-global-vars (cadr e)))
(let* ((iglo (find-decls 'implicit-global (cadr e)))
(glob (diff (find-global-decls (cadr e)) iglo))
(vars (find-locals
;; being declared global prevents a variable
;; assignment from introducing a local
(cadr e) (append env glob) glob))
(body (add-local-decls (cadr e) (append vars glob env)))
(lineno (if (and (length> body 1)
(pair? (cadr body))
(cadr e)
(append env glob implicitglobals iglo)
(append glob iglo)))
(body (add-local-decls (cadr e)
(append vars glob env)
(append iglo implicitglobals)))
(lineno (if (and (length> body 1)
(pair? (cadr body))
(eq? 'line (car (cadr body))))
(list (cadr body))
'()))
Expand All @@ -2678,10 +2682,10 @@ So far only the second case can actually occur.
;; form (local! x) adds a local to a normal (non-scope) block
(let ((newenv (append (declared-local!-vars e) env)))
(map (lambda (x)
(add-local-decls x newenv))
(add-local-decls x newenv implicitglobals))
e))))))

(define (identify-locals e) (add-local-decls e '()))
(define (identify-locals e) (add-local-decls e '() '()))

(define (declared-local-vars e)
(map (lambda (x) (decl-var (cadr x)))
Expand Down Expand Up @@ -2719,10 +2723,10 @@ So far only the second case can actually occur.
(case (car e)
((lambda)
(append (lambda-all-vars e)
(declared-global-vars (cadddr e))))
(find-global-decls (cadddr e))))
((scope-block)
(append (declared-local-vars e)
(declared-global-vars (cadr e))))
(find-global-decls (cadr e))))
(else '())))))
(cons (car e)
(map (lambda (x)
Expand Down Expand Up @@ -2959,7 +2963,7 @@ So far only the second case can actually occur.
(if vi (free-vars (vinfo:type vi)) '())))
fv))))
(append (diff dv fv) fv)))
(glo (declared-global-vars (lam:body e)))
(glo (find-global-decls (lam:body e)))
;; make var-info records for vars introduced by this lambda
(vi (nconc
(map (lambda (decl) (make-var-info (decl-var decl)))
Expand Down Expand Up @@ -3194,6 +3198,7 @@ So far only the second case can actually occur.
))

((global) #f) ; remove global declarations
((implicit-global) #f)
((local!) #f)
((jlgensym) #f)
((local)
Expand Down
6 changes: 3 additions & 3 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ for i = 1 : 3
@test isequal(a', permutedims(a, [2, 1]))
end

begin
let
local A, A1, A2, A3, v, v2, cv, cv2, c, R, T
A = ones(Int,2,3,4)
A1 = reshape(repmat([1,2],1,12),2,3,4)
Expand Down Expand Up @@ -642,7 +642,7 @@ B = cat(3, 1, 2, 3)
@test isequal(symdiff(Int64[]), Int64[])

# mapslices
begin
let
local a,h,i
a = rand(5,5)
h = mapslices(v -> hist(v,0:0.1:1)[2], a, 1)
Expand Down Expand Up @@ -725,7 +725,7 @@ a[a] = [4,5,6]
@test lexcmp([1, 1], [1]) == 1

# sort on arrays
begin
let
local a = rand(3,3)

asr = sortrows(a)
Expand Down
Loading

0 comments on commit f1034d5

Please sign in to comment.