Skip to content

Commit 4ebec0d

Browse files
committed
deprecate for loop vars that overwrite outer vars (#22314)
1 parent db5ddfa commit 4ebec0d

14 files changed

+97
-45
lines changed

base/deprecated.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsyms)
9090
lkup = StackTraces.UNKNOWN
9191
for frame in bt
9292
lkups = StackTraces.lookup(frame)
93-
for lkup in lkups
93+
for l in lkups
94+
lkup = l
9495
if lkup == StackTraces.UNKNOWN
9596
continue
9697
end
@@ -1067,7 +1068,8 @@ function partial_linear_indexing_warning_lookup(nidxs_remaining)
10671068
caller = StackTraces.UNKNOWN
10681069
for frame in bt
10691070
lkups = StackTraces.lookup(frame)
1070-
for caller in lkups
1071+
for c_ in lkups
1072+
caller = c_
10711073
if caller == StackTraces.UNKNOWN
10721074
continue
10731075
end

base/docs/utils.jl

+4-2
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ function levsort(search, candidates)
289289
scores = map(cand -> (levenshtein(search, cand), -fuzzyscore(search, cand)), candidates)
290290
candidates = candidates[sortperm(scores)]
291291
i = 0
292-
for i = 1:length(candidates)
292+
for i_ = 1:length(candidates)
293+
i = i_
293294
levenshtein(search, candidates[i]) > 3 && break
294295
end
295296
return candidates[1:i]
@@ -328,7 +329,8 @@ printmatches(args...; cols = displaysize(STDOUT)[2]) = printmatches(STDOUT, args
328329
function print_joined_cols(io::IO, ss, delim = "", last = delim; cols = displaysize(io)[2])
329330
i = 0
330331
total = 0
331-
for i = 1:length(ss)
332+
for i_ = 1:length(ss)
333+
i = i_
332334
total += length(ss[i])
333335
total + max(i-2,0)*length(delim) + (i>1 ? 1 : 0)*length(last) > cols && (i-=1; break)
334336
end

base/inference.jl

+10-10
Original file line numberDiff line numberDiff line change
@@ -3515,9 +3515,9 @@ end
35153515
function type_annotate!(sv::InferenceState)
35163516
# remove all unused ssa values
35173517
gt = sv.src.ssavaluetypes
3518-
for i = 1:length(gt)
3519-
if gt[i] === NF
3520-
gt[i] = Union{}
3518+
for j = 1:length(gt)
3519+
if gt[j] === NF
3520+
gt[j] = Union{}
35213521
end
35223522
end
35233523

@@ -3568,9 +3568,9 @@ function type_annotate!(sv::InferenceState)
35683568
end
35693569

35703570
# finish marking used-undef variables
3571-
for i = 1:nslots
3572-
if undefs[i]
3573-
src.slotflags[i] |= Slot_UsedUndef
3571+
for j = 1:nslots
3572+
if undefs[j]
3573+
src.slotflags[j] |= Slot_UsedUndef
35743574
end
35753575
end
35763576
nothing
@@ -4572,10 +4572,10 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
45724572
if !isempty(stmts) && !propagate_inbounds
45734573
# avoid redundant inbounds annotations
45744574
s_1, s_end = stmts[1], stmts[end]
4575-
i = 2
4576-
while length(stmts) > i && ((isa(s_1,Expr)&&s_1.head===:line) || isa(s_1,LineNumberNode))
4577-
s_1 = stmts[i]
4578-
i += 1
4575+
si = 2
4576+
while length(stmts) > si && ((isa(s_1,Expr)&&s_1.head===:line) || isa(s_1,LineNumberNode))
4577+
s_1 = stmts[si]
4578+
si += 1
45794579
end
45804580
if isa(s_1, Expr) && s_1.head === :inbounds && s_1.args[1] === false &&
45814581
isa(s_end, Expr) && s_end.head === :inbounds && s_end.args[1] === :pop

base/intfuncs.jl

+2-3
Original file line numberDiff line numberDiff line change
@@ -801,9 +801,8 @@ end
801801

802802
function factorial(n::Integer)
803803
n < 0 && throw(DomainError())
804-
local f::typeof(n*n), i::typeof(n*n)
805-
f = 1
806-
for i = 2:n
804+
f::typeof(n*n) = 1
805+
for i::typeof(n*n) = 2:n
807806
f *= i
808807
end
809808
return f

base/linalg/triangular.jl

+10-4
Original file line numberDiff line numberDiff line change
@@ -1833,7 +1833,9 @@ function logm(A0::UpperTriangular{T}) where T<:Union{Float64,Complex{Float64}}
18331833
d4 = norm(AmI^4, 1)^(1/4)
18341834
alpha3 = max(d3, d4)
18351835
if alpha3 <= theta[tmax]
1836-
for j = 3:tmax
1836+
local j
1837+
for j_ = 3:tmax
1838+
j = j_
18371839
if alpha3 <= theta[j]
18381840
break
18391841
end
@@ -1853,7 +1855,8 @@ function logm(A0::UpperTriangular{T}) where T<:Union{Float64,Complex{Float64}}
18531855
eta = min(alpha3, alpha4)
18541856
if eta <= theta[tmax]
18551857
j = 0
1856-
for j = 6:tmax
1858+
for j_ = 6:tmax
1859+
j = j_
18571860
if eta <= theta[j]
18581861
m = j
18591862
break
@@ -2032,7 +2035,9 @@ function invsquaring(A0::UpperTriangular, theta)
20322035
d4 = norm(AmI^4, 1)^(1/4)
20332036
alpha3 = max(d3, d4)
20342037
if alpha3 <= theta[tmax]
2035-
for j = 3:tmax
2038+
local j
2039+
for j_ = 3:tmax
2040+
j = j_
20362041
if alpha3 <= theta[j]
20372042
break
20382043
elseif alpha3 / 2 <= theta[5] && p < 2
@@ -2056,7 +2061,8 @@ function invsquaring(A0::UpperTriangular, theta)
20562061
eta = min(alpha3, alpha4)
20572062
if eta <= theta[tmax]
20582063
j = 0
2059-
for j = 6:tmax
2064+
for j_ = 6:tmax
2065+
j = j_
20602066
if eta <= theta[j]
20612067
m = j
20622068
break

base/markdown/Markdown.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ macro doc_str(s::AbstractString, t...)
5656
docexpr(__source__, __module__, s, t...)
5757
end
5858

59-
function Base.display(d::Base.REPL.REPLDisplay, md::Vector{MD})
60-
for md in md
59+
function Base.display(d::Base.REPL.REPLDisplay, mds::Vector{MD})
60+
for md in mds
6161
display(d, md)
6262
end
6363
end

base/markdown/render/latex.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ function latexinline(io::IO, code::Code)
4646
end
4747

4848
function latex(io::IO, md::Paragraph)
49-
for md in md.content
50-
latexinline(io, md)
49+
for mdc in md.content
50+
latexinline(io, mdc)
5151
end
5252
println(io)
5353
println(io)

base/markdown/render/rst.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ end
9090

9191
function rst(io::IO, l::LaTeX)
9292
println(io, ".. math::\n")
93-
for l in lines(l.formula)
94-
println(io, " ", l)
93+
for line in lines(l.formula)
94+
println(io, " ", line)
9595
end
9696
end
9797

base/multidimensional.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -812,9 +812,9 @@ end
812812

813813
@noinline function _accumulate!(op, B, A, R1, ind, R2)
814814
# Copy the initial element in each 1d vector along dimension `axis`
815-
i = first(ind)
815+
ii = first(ind)
816816
@inbounds for J in R2, I in R1
817-
B[I, i, J] = A[I, i, J]
817+
B[I, ii, J] = A[I, ii, J]
818818
end
819819
# Accumulate
820820
@inbounds for J in R2, i in first(ind)+1:last(ind), I in R1

base/printf.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ function parse(s::AbstractString)
5757
i = 1
5858
while i < length(list)
5959
if isa(list[i],AbstractString)
60-
for j = i+1:length(list)
60+
for j_ = i+1:length(list)
61+
j = j_
6162
if !isa(list[j],AbstractString)
6263
j -= 1
6364
break

base/sparse/linalg.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ function A_rdiv_B!(A::SparseMatrixCSC{T}, D::Diagonal{T}) where T
301301
if iszero(ddj)
302302
throw(LinAlg.SingularException(j))
303303
end
304-
for k in nzrange(A, j)
305-
nonz[k] /= ddj
304+
for i in nzrange(A, j)
305+
nonz[i] /= ddj
306306
end
307307
end
308308
A

src/julia-syntax.scm

+49-8
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,10 @@
16471647
(cons (car e)
16481648
(map expand-forms (cdr e)))))))
16491649

1650+
;; If true, this will warn on all `for` loop variables that overwrite outer variables.
1651+
;; If false, this will try to warn only for uses of the last value after the loop.
1652+
(define *warn-all-loop-vars* #f)
1653+
16501654
(define (expand-for while lhs X body)
16511655
;; (for (= lhs X) body)
16521656
(let ((coll (make-ssavalue))
@@ -1661,6 +1665,9 @@
16611665
(block
16621666
;; NOTE: enable this to force loop-local var
16631667
#;,@(map (lambda (v) `(local ,v)) (lhs-vars lhs))
1668+
,@(if (or *depwarn* *deperror*)
1669+
(map (lambda (v) `(warn-if-existing ,v)) (lhs-vars lhs))
1670+
'())
16641671
,(lower-tuple-assignment (list lhs state)
16651672
`(call (top next) ,coll ,state))
16661673
,body))))))))
@@ -2491,7 +2498,7 @@
24912498
((eq? (car e) 'break-block) (unbound-vars (caddr e) bound tab))
24922499
((eq? (car e) 'with-static-parameters) (unbound-vars (cadr e) bound tab))
24932500
(else (for-each (lambda (x) (unbound-vars x bound tab))
2494-
(cdr e))
2501+
(cdr e))
24952502
tab)))
24962503

24972504
;; local variable identification and renaming, derived from:
@@ -2507,6 +2514,7 @@
25072514
((eq? (car e) 'local) '(null)) ;; remove local decls
25082515
((eq? (car e) 'local-def) '(null)) ;; remove local decls
25092516
((eq? (car e) 'implicit-global) '(null)) ;; remove implicit-global decls
2517+
((eq? (car e) 'warn-if-existing) '(null))
25102518
((eq? (car e) 'lambda)
25112519
(let* ((lv (lam:vars e))
25122520
(env (append lv env))
@@ -2547,6 +2555,9 @@
25472555
vars))))
25482556
(need-rename (need-rename? vars))
25492557
(need-rename-def (need-rename? vars-def))
2558+
(deprecated-loop-vars
2559+
(filter (lambda (v) (memq v env))
2560+
(delete-duplicates (find-decls 'warn-if-existing blok))))
25502561
;; new gensym names for conflicting variables
25512562
(renamed (map named-gensy need-rename))
25522563
(renamed-def (map named-gensy need-rename-def))
@@ -2576,12 +2587,21 @@
25762587
(if lam ;; update in-place the list of local variables in lam
25772588
(set-car! (cddr lam)
25782589
(append! (caddr lam) real-new-vars real-new-vars-def)))
2579-
(insert-after-meta ;; return the new, expanded scope-block
2580-
(if (and (pair? body) (eq? (car body) 'block))
2581-
body
2582-
`(block ,body))
2583-
(append! (map (lambda (v) `(local ,v)) real-new-vars)
2584-
(map (lambda (v) `(local-def ,v)) real-new-vars-def)))))
2590+
(let* ((warnings (map (lambda (v) `(warn-loop-var ,v)) deprecated-loop-vars))
2591+
(body (if *warn-all-loop-vars*
2592+
body
2593+
(if (and (pair? body) (eq? (car body) 'block))
2594+
(append body warnings)
2595+
`(block ,body ,@warnings)))))
2596+
(insert-after-meta ;; return the new, expanded scope-block
2597+
(if (and (pair? body) (eq? (car body) 'block))
2598+
body
2599+
`(block ,body))
2600+
(append! (map (lambda (v) `(local ,v)) real-new-vars)
2601+
(map (lambda (v) `(local-def ,v)) real-new-vars-def)
2602+
(if *warn-all-loop-vars*
2603+
(map (lambda (v) `(warn-loop-var ,v)) deprecated-loop-vars)
2604+
'()))))))
25852605
((eq? (car e) 'module)
25862606
(error "module expression not at top level"))
25872607
((eq? (car e) 'break-block)
@@ -3035,7 +3055,7 @@ f(x) = yt(x)
30353055
((atom? e) e)
30363056
(else
30373057
(case (car e)
3038-
((quote top core globalref outerref line break inert module toplevel null meta) e)
3058+
((quote top core globalref outerref line break inert module toplevel null meta warn-loop-var) e)
30393059
((=)
30403060
(let ((var (cadr e))
30413061
(rhs (cl-convert (caddr e) fname lam namemap toplevel interp)))
@@ -3282,6 +3302,11 @@ f(x) = yt(x)
32823302
(else (for-each linearize (cdr e))))
32833303
e)
32843304

3305+
(define (deprecation-message msg)
3306+
(if *deperror*
3307+
(error msg)
3308+
(io.write *stderr* msg)))
3309+
32853310
;; this pass behaves like an interpreter on the given code.
32863311
;; to perform stateful operations, it calls `emit` to record that something
32873312
;; needs to be done. in value position, it returns an expression computing
@@ -3294,6 +3319,7 @@ f(x) = yt(x)
32943319
(first-line #t)
32953320
(current-loc #f)
32963321
(rett #f)
3322+
(deprecated-loop-vars (table))
32973323
(arg-map #f) ;; map arguments to new names if they are assigned
32983324
(label-counter 0) ;; counter for generating label addresses
32993325
(label-map (table)) ;; maps label names to generated addresses
@@ -3387,6 +3413,11 @@ f(x) = yt(x)
33873413
(eq? (cadr e) '_))))
33883414
(syntax-deprecation #f (string "_ as an rvalue" (linenode-string current-loc))
33893415
""))
3416+
(if (and (not *warn-all-loop-vars*) (has? deprecated-loop-vars e))
3417+
(begin (deprecation-message
3418+
(string "Use of final value of loop variable \"" e "\"" (linenode-string current-loc) " "
3419+
"is deprecated. In the future the variable will be local to the loop instead." #\newline))
3420+
(del! deprecated-loop-vars e)))
33903421
(cond (tail (emit-return e1))
33913422
(value e1)
33923423
((or (eq? e1 'true) (eq? e1 'false)) #f)
@@ -3416,6 +3447,8 @@ f(x) = yt(x)
34163447
(lhs (if (and arg-map (symbol? lhs))
34173448
(get arg-map lhs lhs)
34183449
lhs)))
3450+
(if (and (not *warn-all-loop-vars*) (has? deprecated-loop-vars lhs))
3451+
(del! deprecated-loop-vars lhs))
34193452
(if value
34203453
(let ((rr (if (or (atom? rhs) (ssavalue? rhs) (eq? (car rhs) 'null))
34213454
rhs (make-ssavalue))))
@@ -3602,6 +3635,14 @@ f(x) = yt(x)
36023635
((implicit-global) #f)
36033636
((const) (emit e))
36043637
((isdefined) (if tail (emit-return e) e))
3638+
((warn-loop-var)
3639+
(if *warn-all-loop-vars*
3640+
(deprecation-message
3641+
(string "Loop variable \"" (cadr e) "\"" (linenode-string current-loc) " "
3642+
"overwrites a variable in an enclosing scope. "
3643+
"In the future the variable will be local to the loop instead." #\newline))
3644+
(put! deprecated-loop-vars (cadr e) #t))
3645+
'(null))
36053646

36063647
;; top level expressions returning values
36073648
((abstract_type bits_type composite_type thunk toplevel module)

test/read.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,14 @@ for (name, f) in l
176176
old_text = text
177177
cleanup()
178178

179-
for text in [
179+
for text_ in [
180180
old_text,
181181
String(Char['A' + i % 52 for i in 1:(div(Base.SZ_UNBUFFERED_IO,2))]),
182182
String(Char['A' + i % 52 for i in 1:( Base.SZ_UNBUFFERED_IO -1)]),
183183
String(Char['A' + i % 52 for i in 1:( Base.SZ_UNBUFFERED_IO )]),
184184
String(Char['A' + i % 52 for i in 1:( Base.SZ_UNBUFFERED_IO +1)])
185185
]
186+
text = text_
186187
write(filename, text)
187188

188189
verbose && println("$name readstring...")

test/sparse/sparse.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -1095,27 +1095,27 @@ end
10951095
N=2^3
10961096
Irand = randperm(M)
10971097
Jrand = randperm(N)
1098-
I = sort([Irand; Irand; Irand])
1098+
II = sort([Irand; Irand; Irand])
10991099
J = [Jrand; Jrand]
11001100

11011101
SA = [sprand(M, N, d) for d in [1., 0.1, 0.01, 0.001, 0.0001, 0.]]
11021102
for S in SA
11031103
res = Any[1,2,3]
11041104
for searchtype in [0, 1, 2]
1105-
res[searchtype+1] = test_getindex_algs(S, I, J, searchtype)
1105+
res[searchtype+1] = test_getindex_algs(S, II, J, searchtype)
11061106
end
11071107

11081108
@test res[1] == res[2] == res[3]
11091109
end
11101110

11111111
M = 2^14
11121112
N=2^4
1113-
I = randperm(M)
1113+
II = randperm(M)
11141114
J = randperm(N)
11151115
Jsorted = sort(J)
11161116

11171117
SA = [sprand(M, N, d) for d in [1., 0.1, 0.01, 0.001, 0.0001, 0.]]
1118-
IA = [I[1:round(Int,n)] for n in [M, M*0.1, M*0.01, M*0.001, M*0.0001, 0.]]
1118+
IA = [II[1:round(Int,n)] for n in [M, M*0.1, M*0.01, M*0.001, M*0.0001, 0.]]
11191119
debug = false
11201120
if debug
11211121
@printf(" | | | times | memory |\n")

0 commit comments

Comments
 (0)