diff --git a/doc/src/manual/variables-and-scoping.md b/doc/src/manual/variables-and-scoping.md index dd8d9b852bc75..c877958447ed0 100644 --- a/doc/src/manual/variables-and-scoping.md +++ b/doc/src/manual/variables-and-scoping.md @@ -13,15 +13,34 @@ set of source lines; instead, it will always line up with one of these blocks. T main types of scopes in Julia, *global scope* and *local scope*, the latter can be nested. The constructs introducing scope blocks are: -| Scope name | block/construct introducing this kind of scope | -|:-------------------- |:-------------------------------------------------------------------------------------------------------- | -| [Global Scope](@ref) | `module`, `baremodule`, at interactive prompt (REPL) | -| [Local Scope](@ref) | [Soft Local Scope](@ref): `for`, `while`, comprehensions, try-catch-finally, `let` | -| [Local Scope](@ref) | [Hard Local Scope](@ref): functions (either syntax, anonymous & do-blocks), `struct`, `macro` | +# [](@id man-scope-table) -Notably missing from this table are [begin blocks](@ref man-compound-expressions) and [if blocks](@ref man-conditional-evaluation), which do *not* -introduce new scope blocks. All three types of scopes follow somewhat different rules which will -be explained below as well as some extra rules for certain blocks. + * Scope blocks that may nest only in other global scope blocks: + + - global scope + + + module, baremodule + + + at interactive prompt (REPL) + + - local scope (don't allow nesting) + + + type, immutable, macro + + * Scope blocks which may nest anywhere (in global or local scope): + + - local scope + + + for, while, try-catch-finally, let + + + functions (either syntax, anonymous & do-blocks) + + + comprehensions, broadcast-fusing + +Notably missing from this table are +[begin blocks](@ref man-compound-expressions) and [if blocks](@ref man-conditional-evaluation) +which do *not* introduce new scope blocks. +Both types of scopes follow somewhat different rules which will be explained below. Julia uses [lexical scoping](https://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping_vs._dynamic_scoping), meaning that a function's scope does not inherit from its caller's scope, but from the scope in @@ -50,7 +69,7 @@ Thus *lexical scope* means that the scope of variables can be inferred from the ## Global Scope -*Each module introduces a new global scope*, separate from the global scope of all other modules; +Each module introduces a new global scope, separate from the global scope of all other modules; there is no all-encompassing global scope. Modules can introduce variables of other modules into their scope through the [using or import](@ref modules) statements or through qualified access using the dot-notation, i.e. each module is a so-called *namespace*. Note that variable bindings can only @@ -87,16 +106,20 @@ Note that the interactive prompt (aka REPL) is in the global scope of the module ## Local Scope -A new local scope is introduced by most code-blocks, see above table for a complete list. - A local scope *usually* inherits all the variables from its parent scope, both for reading and -writing. There are two subtypes of local scopes, hard and soft, with slightly different rules -concerning what variables are inherited. Unlike global scopes, local scopes are not namespaces, +A new local scope is introduced by most code blocks (see above +[table](@ref man-scope-table) for a complete list). +A local scope inherits all the variables from a parent local scope, +both for reading and writing. +Additionally, the local scope inherits all globals that are assigned +to in its parent global scope block (if it is surrounded by a global `if` or `begin` scope). +Unlike global scopes, local scopes are not namespaces, thus variables in an inner scope cannot be retrieved from the parent scope through some sort of qualified access. -The following rules and examples pertain to both hard and soft local scopes. A newly introduced -variable in a local scope does not back-propagate to its parent scope. For example, here the -`z` is not introduced into the top-level scope: +The following rules and examples pertain to local scopes. +A newly introduced variable in a local scope does not +back-propagate to its parent scope. +For example, here the ``z`` is not introduced into the top-level scope: ```jldoctest julia> for i = 1:10 @@ -110,13 +133,13 @@ ERROR: UndefVarError: z not defined (Note, in this and all following examples it is assumed that their top-level is a global scope with a clean workspace, for instance a newly started REPL.) -Inside a local scope a variable can be forced to be a local variable using the `local` keyword: +Inside a local scope a variable can be forced to be a new local variable using the `local` keyword: ```jldoctest julia> x = 0; julia> for i = 1:10 - local x + local x # this is also the default x = i + 1 end @@ -124,7 +147,7 @@ julia> x 0 ``` -Inside a local scope a new global variable can be defined using the keyword `global`: +Inside a local scope a global variable can be assigned to by using the keyword `global`: ```jldoctest julia> for i = 1:10 @@ -152,37 +175,14 @@ julia> z The `local` and `global` keywords can also be applied to destructuring assignments, e.g. `local x, y = 1, 2`. In this case the keyword affects all listed variables. -### Soft Local Scope - -> In a soft local scope, all variables are inherited from its parent scope unless a variable is -> specifically marked with the keyword `local`. - -Soft local scopes are introduced by for-loops, while-loops, comprehensions, try-catch-finally-blocks, -and let-blocks. There are some extra rules for [Let Blocks](@ref) and for [For Loops and Comprehensions](@ref). - -In the following example the `x` and `y` refer always to the same variables as the soft local -scope inherits both read and write variables: - -```jldoctest -julia> x, y = 0, 1; - -julia> for i = 1:10 - x = i + y + 1 - end - -julia> x -12 -``` - -### Hard Local Scope +Local scopes are introduced by most block keywords, +with notable exceptions of `begin` and `if`. -Hard local scopes are introduced by function definitions (in all their forms), struct type definition blocks, -and macro-definitions. +In a local scope, all variables are inherited from its parent +global scope block unless: -> In a hard local scope, all variables are inherited from its parent scope unless: -> -> * an assignment would result in a modified *global* variable, or -> * a variable is specifically marked with the keyword `local`. + * an assignment would result in a modified *global* variable, or + * a variable is specifically marked with the keyword `local`. Thus global variables are only inherited for reading but not for writing: @@ -203,6 +203,14 @@ julia> x An explicit `global` is needed to assign to a global variable: +!!! sidebar "Avoiding globals" + Avoiding changing the value of global variables is considered by many + to be a programming best-practice. + One reason for this is that remotely changing the state of global variables in other + modules should be done with care as it makes the local behavior of the program hard to reason about. + This is why the scope blocks that introduce local scope require the ``global`` + keyword to declare the intent to modify a global variable. + ```jldoctest julia> x = 1; @@ -216,8 +224,7 @@ julia> x 2 ``` -Note that *nested functions* can behave differently to functions defined in the global scope as -they can modify their parent scope's *local* variables: +Note that *nested functions* can modify their parent scope's *local* variables: ```jldoctest julia> x, y = 1, 2; @@ -234,19 +241,40 @@ julia> function baz() julia> baz() 22 -julia> x, y +julia> x, y # verify that global x and y are unchanged (1, 2) ``` -The distinction between inheriting global and local variables for assignment can lead to some -slight differences between functions defined in local vs. global scopes. Consider the modification -of the last example by moving `bar` to the global scope: +The reason to allow *modifying local* variables of parent scopes in +nested functions is to allow constructing `closures +`_ +which have a private state, for instance the ``state`` variable in the +following example: + +```jldoctest + julia> let state = 0 + global counter() = (state += 1) + end; + + julia> counter() + 1 + + julia> counter() + 2 +``` + +See also the closures in the examples in the next two sections. + +The distinction between inheriting global scope and nesting local scope +can lead to some slight differences between functions +defined in local vs. global scopes for variable assignments. +Consider the modification of the last example by moving `bar` to the global scope: ```jldoctest julia> x, y = 1, 2; julia> function bar() - x = 10 # local + x = 10 # local, no longer a closure variable return x + y end; @@ -258,11 +286,11 @@ julia> function quz() julia> quz() 14 -julia> x, y +julia> x, y # verify that global x and y are unchanged (1, 2) ``` -Note that above subtlety does not pertain to type and macro definitions as they can only appear +Note that the above nesting rules do not pertain to type and macro definitions as they can only appear at the global scope. There are special scoping rules concerning the evaluation of default and keyword function arguments which are described in the [Function section](@ref man-functions). @@ -292,9 +320,9 @@ they are actually called. As an example, here is an inefficient, mutually recurs if positive integers are even or odd: ```jldoctest -julia> even(n) = n == 0 ? true : odd(n-1); +julia> even(n) = (n == 0) ? true : odd(n - 1); -julia> odd(n) = n == 0 ? false : even(n-1); +julia> odd(n) = (n == 0) ? false : even(n - 1); julia> even(3) false @@ -304,37 +332,8 @@ true ``` Julia provides built-in, efficient functions to test for oddness and evenness called [`iseven`](@ref) -and [`isodd`](@ref) so the above definitions should only be taken as examples. - -### Hard vs. Soft Local Scope - -Blocks which introduce a soft local scope, such as loops, are generally used to manipulate the -variables in their parent scope. Thus their default is to fully access all variables in their -parent scope. - -Conversely, the code inside blocks which introduce a hard local scope (function, type, and macro -definitions) can be executed at any place in a program. Remotely changing the state of global -variables in other modules should be done with care and thus this is an opt-in feature requiring -the `global` keyword. - -The reason to allow *modifying local* variables of parent scopes in nested functions is to allow -constructing [closures](https://en.wikipedia.org/wiki/Closure_%28computer_programming%29) which -have a private state, for instance the `state` variable in the following example: - -```jldoctest -julia> let state = 0 - global counter - counter() = state += 1 - end; - -julia> counter() -1 - -julia> counter() -2 -``` - -See also the closures in the examples in the next two sections. +and [`isodd`](@ref) so the above definitions should only be considered to be examples of scope, +not efficient design. ### Let Blocks diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 7aa9565ec0e04..6286affbb2c87 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1710,9 +1710,9 @@ (define (expand-for while lhs X body) ;; (for (= lhs X) body) (let* ((coll (make-ssavalue)) - (state (gensy)) - (outer? (and (pair? lhs) (eq? (car lhs) 'outer))) - (lhs (if outer? (cadr lhs) lhs))) + (state (gensy)) + (outer? (and (pair? lhs) (eq? (car lhs) 'outer))) + (lhs (if outer? (cadr lhs) lhs))) `(block (= ,coll ,(expand-forms X)) (= ,state (call (top start) ,coll)) ;; TODO avoid `local declared twice` error from this @@ -2275,15 +2275,15 @@ 'while (lambda (e) `(break-block loop-exit - (_while ,(expand-forms (cadr e)) - (break-block loop-cont - (scope-block ,(blockify (expand-forms (caddr e)))))))) + (_while ,(expand-forms (cadr e)) + (break-block loop-cont + (scope-block ,(blockify (expand-forms (caddr e)))))))) 'inner-while (lambda (e) `(_while ,(expand-forms (cadr e)) - (break-block loop-cont - (scope-block ,(blockify (expand-forms (caddr e))))))) + (break-block loop-cont + (scope-block ,(blockify (expand-forms (caddr e))))))) 'break (lambda (e) @@ -2560,10 +2560,15 @@ (define (find-local-def-decls e) (find-decls 'local-def e)) (define (find-global-decls e) (find-decls 'global e)) -(define (implicit-locals e env glob) +(define (implicit-locals e env deprecated-env glob) ;; const decls on non-globals introduce locals (append! (diff (find-decls 'const e) glob) - (find-assigned-vars e env))) + (filter + (lambda (v) + (if (memq v deprecated-env) + (begin (syntax-deprecation #f (string "implicit assignment to global variable `" v "`") (string "global " v)) #f) + #t)) + (find-assigned-vars e env)))) (define (unbound-vars e bound tab) (cond ((or (eq? e 'true) (eq? e 'false) (eq? e UNUSED)) tab) @@ -2613,7 +2618,7 @@ ((eq? (car e) 'scope-block) (let* ((blok (cadr e)) ;; body of scope-block expression (other-locals (if lam (caddr lam) '())) ;; locals that are explicitly part of containing lambda expression - (iglo (find-decls 'implicit-global blok)) ;; globals defined implicitly outside blok + (iglo (find-decls 'implicit-global blok)) ;; globals possibly defined implicitly outside blok (glob (diff (find-global-decls blok) iglo)) ;; all globals declared in blok (vars-def (check-dups (find-local-def-decls blok) '())) (locals-declared (check-dups (find-local-decls blok) vars-def)) @@ -2621,7 +2626,8 @@ blok ;; being declared global prevents a variable ;; assignment from introducing a local - (append env glob iglo outerglobals locals-declared vars-def) + (append env glob iglo locals-declared vars-def) + outerglobals (append glob iglo))) (vars (delete-duplicates (append! locals-declared locals-implicit))) (all-vars (append vars vars-def)) @@ -2658,7 +2664,7 @@ (memq var implicitglobals) ;; remove anything only added implicitly in the last scope block (memq var glob))))) ;; remove anything that's now global renames))) - (new-oglo (append iglo outerglobals)) ;; list of all outer-globals from outside blok + (new-oglo (append iglo outerglobals)) ;; list of all implicit-globals from outside blok (body (resolve-scopes- blok new-env new-oglo new-iglo lam new-renames #f)) (real-new-vars (append (diff vars need-rename) renamed)) (real-new-vars-def (append (diff vars-def need-rename-def) renamed-def))) diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index e430da4dc2fb4..ce38b55215a06 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -576,41 +576,41 @@ end @test !contains(str, "backtrace()") end -msg = read(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --color=no -e ' -using Test +let msg = read(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --color=no -e ' + using Test -foo(x) = length(x)^2 + foo(x) = length(x)^2 -@testset "Foo Tests" begin - @testset "Animals" begin - @testset "Felines" begin - @test foo("cat") == 9 - end - @testset "Canines" begin - @test foo("dog") == 11 - end - end - @testset "Arrays" begin - @test foo(zeros(2)) == 4 - @test foo(ones(4)) == 15 - end -end'`), stderr=DevNull), String) - -@test contains(msg, -""" -Test Summary: | Pass Fail Total -Foo Tests | 2 2 4 - Animals | 1 1 2 - Felines | 1 1 - Canines | 1 1 - Arrays | 1 1 2 -""") + @testset "Foo Tests" begin + @testset "Animals" begin + @testset "Felines" begin + @test foo("cat") == 9 + end + @testset "Canines" begin + @test foo("dog") == 11 + end + end + @testset "Arrays" begin + @test foo(zeros(2)) == 4 + @test foo(ones(4)) == 15 + end + end'`), stderr=DevNull), String) + @test contains(msg, + """ + Test Summary: | Pass Fail Total + Foo Tests | 2 2 4 + Animals | 1 1 2 + Felines | 1 1 + Canines | 1 1 + Arrays | 1 1 2 + """) +end # 20489 -msg = split(read(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --color=no -e ' -Test.print_test_results(Test.DefaultTestSet(""))'`), stderr=DevNull), String), "\n")[1] - -@test msg == rstrip(msg) +let msg = split(read(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --color=no -e ' + Test.print_test_results(Test.DefaultTestSet(""))'`), stderr=DevNull), String), "\n")[1] + @test msg == rstrip(msg) +end @testset "test guarded srand" begin seed = rand(UInt) diff --git a/test/bigint.jl b/test/bigint.jl index 1b40d67a27409..6bf55c4f48fd4 100644 --- a/test/bigint.jl +++ b/test/bigint.jl @@ -196,11 +196,14 @@ end @test binomial(BigInt(-53), 42) == parse(BigInt,"959509335087854414441273718") @test binomial(BigInt(113), BigInt(42)) == parse(BigInt,"18672199984318438125634054194360") end -a = rand(1:100, 10000) -b = map(BigInt, a) -@test sum(a) == sum(b) +let a, b + a = rand(1:100, 10000) + b = map(BigInt, a) + @test sum(a) == sum(b) +end @testset "Iterated arithmetic" begin + local a, b, c, d, f, g a = parse(BigInt,"315135") b = parse(BigInt,"12412") c = parse(BigInt,"3426495623485904783478347") diff --git a/test/core.jl b/test/core.jl index 4d8b1311f0707..a4dfc79134b39 100644 --- a/test/core.jl +++ b/test/core.jl @@ -385,7 +385,7 @@ begin global f7234_cnt += -10000 end end -@test_throws UndefVarError f7234_a() +@test_throws UndefVarError(:glob_x2) f7234_a() @test f7234_cnt == 1 begin global glob_x2 = 24 @@ -395,11 +395,11 @@ begin global f7234_cnt += -10000 end end -@test_throws UndefVarError f7234_b() +@test_throws UndefVarError(:glob_x2) f7234_b() @test f7234_cnt == 2 -# existing globals can be inherited by non-function blocks +# globals can accessed if declared for i = 1:2 - glob_x2 += 1 + global glob_x2 += 1 end @test glob_x2 == 26 # globals declared as such in a non-global scope are inherited @@ -468,15 +468,15 @@ function const_implies_local() end @test const_implies_local() === (1, 0) -a = Vector{Any}(3) -for i=1:3 +a_global_closure_vector = Vector{Any}(3) +for i = 1:3 let ii = i - a[i] = x->x+ii + a_global_closure_vector[i] = x -> x + ii end end -@test a[1](10) == 11 -@test a[2](10) == 12 -@test a[3](10) == 13 +@test a_global_closure_vector[1](10) == 11 +@test a_global_closure_vector[2](10) == 12 +@test a_global_closure_vector[3](10) == 13 # issue #22032 let a = [], fs = [] @@ -513,8 +513,10 @@ end @test_throws UndefVarError f21900() @test f21900_cnt == 1 -@test_throws UndefVarError @eval begin +# use @eval so this runs as a toplevel scope block +@test_throws UndefVarError(:foo21900) @eval begin for i21900 = 1:10 + local bar21900 for j21900 = 1:10 foo21900 = 10 end @@ -525,8 +527,9 @@ end @test !@isdefined(foo21900) @test !@isdefined(bar21900) bar21900 = 0 -@test_throws UndefVarError @eval begin +@test_throws UndefVarError(:foo21900) @eval begin for i21900 = 1:10 + global bar21900 for j21900 = 1:10 foo21900 = 10 end @@ -537,8 +540,9 @@ end @test bar21900 == -1 @test !@isdefined foo21900 foo21900 = 0 -@test nothing === @eval begin +@test nothing === begin for i21900 = 1:10 + global bar21900, foo21900 for j21900 = 1:10 foo21900 = 10 end @@ -696,40 +700,47 @@ end # try/finally begin - after = 0 - b = try + try_finally_glo_after = 0 + try_finally_loc_after = 0 + try_finally_glo_b = try 1+2 finally - after = 1 + # try_finally_loc_after = 1 # enable with #19324 + global try_finally_glo_after = 1 end - @test b == 3 - @test after == 1 + @test try_finally_loc_after == 0 + @test try_finally_glo_b == 3 + @test try_finally_glo_after == 1 - after = 0 + try_finally_glo_after = 0 gothere = 0 try try error(" ") finally - after = 1 + # try_finally_loc_after = 1 # enable with #19324 + global try_finally_glo_after = 1 end - gothere = 1 + global gothere = 1 end - @test after == 1 + @test try_finally_loc_after == 0 + @test try_finally_glo_after == 1 @test gothere == 0 - after = 0 - b = try + try_finally_glo_after = 0 + try_finally_glo_b = try error(" ") catch 42 finally - after = 1 + # try_finally_loc_after = 1 # enable with #19324 + global try_finally_glo_after = 1 end - @test b == 42 - @test after == 1 + @test try_finally_loc_after == 0 + @test try_finally_glo_b == 42 + @test try_finally_glo_after == 1 - glo = 0 + global glo = 0 function retfinally() try return 5 @@ -1398,7 +1409,7 @@ C3729{D} = Vector{Vector{D}} # issue #3789 x3789 = 0 while(all([false for idx in 1:10])) - x3789 = 1 + global x3789 = 1 end @test x3789 == 0 @@ -1621,7 +1632,7 @@ b4688(y) = "not an Int" begin a4688(y::Int) = "an Int" let x = true - b4688(y::Int) = x == true ? a4688(y) : a4688(y) + global b4688(y::Int) = x == true ? a4688(y) : a4688(y) end end @test b4688(1) == "an Int" @@ -1715,9 +1726,8 @@ function tupledispatch(a::TupleParam{(1,:a)}) a.x end -let - # tuples can be used as type params - t1 = TupleParam{(1,:a)}(true) +# tuples can be used as type params +let t1 = TupleParam{(1,:a)}(true), t2 = TupleParam{(1,:b)}(true) # tuple type params can't contain invalid type params @@ -2178,11 +2188,13 @@ function issue7897!(data, arr) a = arr[1] end -a = ones(UInt8, 10) -sa = view(a,4:6) -# This can throw an error, but shouldn't segfault -try - issue7897!(sa, zeros(10)) +let + a = ones(UInt8, 10) + sa = view(a, 4:6) + # This can throw an error, but shouldn't segfault + try + issue7897!(sa, zeros(10)) + end end # issue #7582 @@ -3990,7 +4002,8 @@ end # issue #15283 j15283 = 0 let - k15283 = j15283+=1 + global j15283 + k15283 = (j15283 += 1) end @test j15283 == 1 @test !@isdefined k15283 @@ -4651,12 +4664,12 @@ end @test_throws ErrorException main18986() # issue #18085 -f18085(a,x...) = (0,) -for (f,g) in ((:asin,:sin), (:acos,:cos)) +f18085(a, x...) = (0, ) +for (f, g) in ((:asin, :sin), (:acos, :cos)) gx = eval(g) - f18085(::Type{Val{f}},x...) = map(x->2gx(x), f18085(Val{g},x...)) + global f18085(::Type{Val{f}}, x...) = map(x -> 2gx(x), f18085(Val{g}, x...)) end -@test f18085(Val{:asin},3) === (0.0,) +@test f18085(Val{:asin}, 3) === (0.0,) # issue #18236 constant VecElement in ast triggers codegen assertion/undef # VecElement of scalar diff --git a/test/dates/types.jl b/test/dates/types.jl index 3f76d3f0dc763..9810305204081 100644 --- a/test/dates/types.jl +++ b/test/dates/types.jl @@ -190,6 +190,7 @@ c = Dates.Time(0) @test isfinite(Dates.Time) end @testset "Date-DateTime conversion/promotion" begin + global a, b, c, d @test Dates.DateTime(a) == a @test Dates.Date(a) == b @test Dates.DateTime(b) == a diff --git a/test/float16.jl b/test/float16.jl index 10c2f934dedbb..6793a1dc2dbc0 100644 --- a/test/float16.jl +++ b/test/float16.jl @@ -151,11 +151,11 @@ end @test abs(f32 - f16) < abs(f32 - prevfloat(f16)) end # halfway between and last bit is 1 - f = reinterpret(Float32, 0b00111110101010100011000000000000) - @test Float32(Float16(f)) === reinterpret(Float32, 0b00111110101010100100000000000000) + ff = reinterpret(Float32, 0b00111110101010100011000000000000) + @test Float32(Float16(ff)) === reinterpret(Float32, 0b00111110101010100100000000000000) # halfway between and last bit is 0 - f = reinterpret(Float32, 0b00111110101010100001000000000000) - @test Float32(Float16(f)) === reinterpret(Float32, 0b00111110101010100000000000000000) + ff = reinterpret(Float32, 0b00111110101010100001000000000000) + @test Float32(Float16(ff)) === reinterpret(Float32, 0b00111110101010100000000000000000) end # issue #5948 diff --git a/test/linalg/dense.jl b/test/linalg/dense.jl index 4bd42229aeceb..6e625d7dba59f 100644 --- a/test/linalg/dense.jl +++ b/test/linalg/dense.jl @@ -139,7 +139,7 @@ bimg = randn(n,2)/2 end # for eltya @testset "test triu/tril bounds checking" begin - m, n = 5, 7 + local m, n = 5, 7 ainit = rand(m, n) for a in (copy(ainit), view(ainit, 1:m, 1:n)) @test_throws ArgumentError triu(a, -m) diff --git a/test/linalg/lq.jl b/test/linalg/lq.jl index 2ae6c634a7f2f..7f487e977fc12 100644 --- a/test/linalg/lq.jl +++ b/test/linalg/lq.jl @@ -115,7 +115,7 @@ end # orthogonal factor (say Q) should be a square matrix of order of A's number of # columns independent of factorization form (truncated, square), and L and Q # should have multiplication-compatible shapes. - m, n = 4, 2 + local m, n = 4, 2 A = randn(m, n) for thin in (true, false) L, Q = lq(A, thin = thin) @@ -146,6 +146,7 @@ end end @testset "getindex on LQPackedQ (#23733)" begin + local m, n function getqs(F::Base.LinAlg.LQ) implicitQ = F[:Q] explicitQ = A_mul_B!(implicitQ, eye(eltype(implicitQ), size(implicitQ.factors, 2))) diff --git a/test/linalg/triangular.jl b/test/linalg/triangular.jl index ec12d3ea52303..862fa75f184e3 100644 --- a/test/linalg/triangular.jl +++ b/test/linalg/triangular.jl @@ -523,7 +523,7 @@ let A = UpperTriangular([Furlong(1) Furlong(4); Furlong(0) Furlong(1)]) end @testset "similar should preserve underlying storage type" begin - m, n = 4, 3 + local m, n = 4, 3 sparsemat = sprand(m, m, 0.5) for TriType in (UpperTriangular, LowerTriangular, UnitUpperTriangular, UnitLowerTriangular) trisparsemat = TriType(sparsemat) diff --git a/test/replcompletions.jl b/test/replcompletions.jl index 45eb5a9335d37..a45fb05c7d28e 100644 --- a/test/replcompletions.jl +++ b/test/replcompletions.jl @@ -524,6 +524,7 @@ try touch(joinpath(Pack_folder2, "Test_pack2.jl")) # Test it completes on folders + local c, r, res # workaround for issue #24331 c, r, res = test_complete("using Test_p") @test !("Test_pack" in c) @test "Test_pack2" in c diff --git a/test/sparse/sparse.jl b/test/sparse/sparse.jl index f9cb45e3305c3..23689de033215 100644 --- a/test/sparse/sparse.jl +++ b/test/sparse/sparse.jl @@ -2044,7 +2044,7 @@ end end @testset "similar for SparseMatrixCSC" begin - A = speye(5) + local A = speye(5) # test similar without specifications (preserves stored-entry structure) simA = similar(A) @test typeof(simA) == typeof(A)