Skip to content

Commit f1034d5

Browse files
committed
Merge pull request #11801 from JuliaLang/jb/globalscopefixes
fix scope issues #7234 and #10472
2 parents 69013eb + 1b3c585 commit f1034d5

13 files changed

+137
-114
lines changed

NEWS.md

+8-5
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ New language features
3535
Language changes
3636
----------------
3737

38-
* Unsigned `BigInt` literal syntax has been removed ([#11105]).
39-
Unsigned literals larger than `UInt128` now throw a syntax error.
40-
4138
* Tuple types are now written as `Tuple{A, B}` instead of as `(A, B)`.
4239
Tuples of bits types are inlined into structs and arrays, like other
4340
immutable types.
@@ -78,18 +75,21 @@ Language changes
7875
* `[x,y]` constructs a vector of `x` and `y` instead of concatenating them
7976
([#3737], [#2488], [#8599]).
8077

78+
* Unsigned `BigInt` literal syntax has been removed ([#11105]).
79+
Unsigned literals larger than `UInt128` now throw a syntax error.
80+
8181
* `error(::Exception)` and `error(::Type{Exception})` have been deprecated
8282
in favor of using an explicit `throw` ([#9690]).
8383

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

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

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

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

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

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

125+
* The keyword `local` is no longer allowed in global scope. Use `let` instead of
126+
`begin` to create a new scope from the top level ([#7234], [#10472]).
127+
125128
Command line option changes
126129
---------------------------
127130

base/broadcast.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ end
185185
function gen_broadcast_function(genbody::Function, nd::Int, narrays::Int, f::Function)
186186
As = [symbol("A_"*string(i)) for i = 1:narrays]
187187
body = genbody(nd, narrays, f)
188-
@eval begin
188+
@eval let
189189
local _F_
190190
function _F_(B, $(As...))
191191
$body
@@ -197,7 +197,7 @@ end
197197
function gen_broadcast_function_tobitarray(genbody::Function, nd::Int, narrays::Int, f::Function)
198198
As = [symbol("A_"*string(i)) for i = 1:narrays]
199199
body = genbody(nd, narrays, f)
200-
@eval begin
200+
@eval let
201201
local _F_
202202
function _F_(B::BitArray, $(As...))
203203
$body

base/printf.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,7 @@ function _printf(macroname, io, fmt, args)
10411041
end
10421042

10431043
unshift!(blk.args, :(out = $io))
1044-
blk
1044+
Expr(:let, blk)
10451045
end
10461046

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

10671067
end # module

base/sparse/sparsematrix.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ end
756756

757757
function gen_broadcast_function_sparse(genbody::Function, f::Function, is_first_sparse::Bool)
758758
body = genbody(f, is_first_sparse)
759-
@eval begin
759+
@eval let
760760
local _F_
761761
function _F_{Tv,Ti}(B::SparseMatrixCSC{Tv,Ti}, A_1, A_2)
762762
$body

base/sysimg.jl

+2-3
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,8 @@ include("multidimensional.jl")
149149

150150
include("primes.jl")
151151

152-
begin
153-
SOURCE_PATH = ""
154-
include = function(path)
152+
let SOURCE_PATH = ""
153+
global include = function(path)
155154
prev = SOURCE_PATH
156155
path = joinpath(dirname(prev),path)
157156
SOURCE_PATH = path

doc/manual/variables-and-scoping.rst

+2-13
Original file line numberDiff line numberDiff line change
@@ -284,16 +284,7 @@ block without creating any new bindings:
284284

285285
.. doctest::
286286

287-
julia> begin
288-
local x = 1
289-
begin
290-
local x = 2
291-
end
292-
x
293-
end
294-
ERROR: syntax: local "x" declared twice
295-
296-
julia> begin
287+
julia> let
297288
local x = 1
298289
let
299290
local x = 2
@@ -302,9 +293,7 @@ block without creating any new bindings:
302293
end
303294
1
304295

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

310299
For Loops and Comprehensions

src/jlfrontend.scm

+8-5
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,16 @@
5959
(append
6060
;; vars assigned at the outer level
6161
(filter (lambda (x) (not (some-gensym? x))) (find-assigned-vars e '()))
62-
;; vars declared const outside any scope block
63-
(find-decls 'const e '())
62+
;; vars declared const or global outside any scope block
63+
(find-decls 'const e)
64+
(find-decls 'global e)
6465
;; vars assigned anywhere, if they have been defined as global
6566
(filter defined-julia-global (find-possible-globals e))))
6667
(append
67-
(find-decls 'local e '())
68-
(find-decls 'local! e '()))))
68+
(if (null? (find-decls 'local e))
69+
'()
70+
(error "local declaration in global scope"))
71+
(find-decls 'local! e))))
6972

7073
;; return a lambda expression representing a thunk for a top-level expression
7174
;; note: expansion of stuff inside module is delayed, so the contents obey
@@ -88,7 +91,7 @@
8891
(th (julia-expand1
8992
`(lambda ()
9093
(scope-block
91-
(block ,@(map (lambda (v) `(global ,v)) gv)
94+
(block ,@(map (lambda (v) `(implicit-global ,v)) gv)
9295
,ex))))))
9396
(if (null? (car (caddr th)))
9497
;; if no locals, return just body of function

src/julia-syntax.scm

+39-34
Original file line numberDiff line numberDiff line change
@@ -971,19 +971,23 @@
971971
(sparam-name-bounds params '() '())
972972
`(block
973973
(const ,name)
974-
,@(map (lambda (v) `(local ,v)) params)
975-
,@(map make-assignment params (symbols->typevars params bounds #f))
976-
(abstract_type ,name (call (top svec) ,@params) ,super))))
974+
(scope-block
975+
(block
976+
,@(map (lambda (v) `(local ,v)) params)
977+
,@(map make-assignment params (symbols->typevars params bounds #f))
978+
(abstract_type ,name (call (top svec) ,@params) ,super))))))
977979

978980
(define (bits-def-expr n name params super)
979981
(receive
980982
(params bounds)
981983
(sparam-name-bounds params '() '())
982984
`(block
983985
(const ,name)
984-
,@(map (lambda (v) `(local ,v)) params)
985-
,@(map make-assignment params (symbols->typevars params bounds #f))
986-
(bits_type ,name (call (top svec) ,@params) ,n ,super))))
986+
(scope-block
987+
(block
988+
,@(map (lambda (v) `(local ,v)) params)
989+
,@(map make-assignment params (symbols->typevars params bounds #f))
990+
(bits_type ,name (call (top svec) ,@params) ,n ,super))))))
987991

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

2572-
(define (declared-global-vars e)
2573-
(if (or (not (pair? e)) (quoted? e))
2574-
'()
2575-
(case (car e)
2576-
((lambda scope-block) '())
2577-
((global) (cdr e))
2578-
(else
2579-
(apply append (map declared-global-vars e))))))
2580-
25812576
(define (check-dups locals)
25822577
(if (and (pair? locals) (pair? (cdr locals)))
25832578
(or (and (memq (car locals) (cdr locals))
@@ -2604,26 +2599,27 @@ So far only the second case can actually occur.
26042599
(apply append! (map (lambda (x) (find-assigned-vars x env))
26052600
e))))))
26062601

2607-
(define (find-decls kind e env)
2602+
(define (find-decls kind e)
26082603
(if (or (not (pair? e)) (quoted? e))
26092604
'()
26102605
(cond ((or (eq? (car e) 'lambda) (eq? (car e) 'scope-block))
26112606
'())
26122607
((eq? (car e) kind)
26132608
(list (decl-var (cadr e))))
26142609
(else
2615-
(apply append! (map (lambda (x) (find-decls kind x env))
2610+
(apply append! (map (lambda (x) (find-decls kind x))
26162611
e))))))
26172612

2618-
(define (find-local-decls e env) (find-decls 'local e env))
2619-
(define (find-local!-decls e env) (find-decls 'local! e env))
2613+
(define (find-local-decls e) (find-decls 'local e))
2614+
(define (find-local!-decls e) (find-decls 'local! e))
2615+
(define (find-global-decls e) (find-decls 'global e))
26202616

26212617
(define (find-locals e env glob)
26222618
(delete-duplicates
2623-
(append! (check-dups (find-local-decls e env))
2619+
(append! (check-dups (find-local-decls e))
26242620
;; const decls on non-globals also introduce locals
2625-
(diff (find-decls 'const e env) glob)
2626-
(find-local!-decls e env)
2621+
(diff (find-decls 'const e) glob)
2622+
(find-local!-decls e)
26272623
(find-assigned-vars e env))))
26282624

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

26532652
((eq? (car e) 'scope-block)
2654-
(let* ((glob (declared-global-vars (cadr e)))
2653+
(let* ((iglo (find-decls 'implicit-global (cadr e)))
2654+
(glob (diff (find-global-decls (cadr e)) iglo))
26552655
(vars (find-locals
26562656
;; being declared global prevents a variable
26572657
;; assignment from introducing a local
2658-
(cadr e) (append env glob) glob))
2659-
(body (add-local-decls (cadr e) (append vars glob env)))
2660-
(lineno (if (and (length> body 1)
2661-
(pair? (cadr body))
2658+
(cadr e)
2659+
(append env glob implicitglobals iglo)
2660+
(append glob iglo)))
2661+
(body (add-local-decls (cadr e)
2662+
(append vars glob env)
2663+
(append iglo implicitglobals)))
2664+
(lineno (if (and (length> body 1)
2665+
(pair? (cadr body))
26622666
(eq? 'line (car (cadr body))))
26632667
(list (cadr body))
26642668
'()))
@@ -2678,10 +2682,10 @@ So far only the second case can actually occur.
26782682
;; form (local! x) adds a local to a normal (non-scope) block
26792683
(let ((newenv (append (declared-local!-vars e) env)))
26802684
(map (lambda (x)
2681-
(add-local-decls x newenv))
2685+
(add-local-decls x newenv implicitglobals))
26822686
e))))))
26832687

2684-
(define (identify-locals e) (add-local-decls e '()))
2688+
(define (identify-locals e) (add-local-decls e '() '()))
26852689

26862690
(define (declared-local-vars e)
26872691
(map (lambda (x) (decl-var (cadr x)))
@@ -2719,10 +2723,10 @@ So far only the second case can actually occur.
27192723
(case (car e)
27202724
((lambda)
27212725
(append (lambda-all-vars e)
2722-
(declared-global-vars (cadddr e))))
2726+
(find-global-decls (cadddr e))))
27232727
((scope-block)
27242728
(append (declared-local-vars e)
2725-
(declared-global-vars (cadr e))))
2729+
(find-global-decls (cadr e))))
27262730
(else '())))))
27272731
(cons (car e)
27282732
(map (lambda (x)
@@ -2959,7 +2963,7 @@ So far only the second case can actually occur.
29592963
(if vi (free-vars (vinfo:type vi)) '())))
29602964
fv))))
29612965
(append (diff dv fv) fv)))
2962-
(glo (declared-global-vars (lam:body e)))
2966+
(glo (find-global-decls (lam:body e)))
29632967
;; make var-info records for vars introduced by this lambda
29642968
(vi (nconc
29652969
(map (lambda (decl) (make-var-info (decl-var decl)))
@@ -3194,6 +3198,7 @@ So far only the second case can actually occur.
31943198
))
31953199

31963200
((global) #f) ; remove global declarations
3201+
((implicit-global) #f)
31973202
((local!) #f)
31983203
((jlgensym) #f)
31993204
((local)

test/arrayops.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ for i = 1 : 3
383383
@test isequal(a', permutedims(a, [2, 1]))
384384
end
385385

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

644644
# mapslices
645-
begin
645+
let
646646
local a,h,i
647647
a = rand(5,5)
648648
h = mapslices(v -> hist(v,0:0.1:1)[2], a, 1)
@@ -725,7 +725,7 @@ a[a] = [4,5,6]
725725
@test lexcmp([1, 1], [1]) == 1
726726

727727
# sort on arrays
728-
begin
728+
let
729729
local a = rand(3,3)
730730

731731
asr = sortrows(a)

0 commit comments

Comments
 (0)