# Tests for named references %prep # Required in order to declare an unset hash for substitution test setopt TYPESET_TO_UNSET : ${ZTST_continue::=1} # The following test allows to assess what different types of named # references refer to during their lifetime depending on where they # were initialized and whether they were defined with or without the # "-u" flag. # # The first parameter determines whether the named references are # defined with or without the flag "-u". # # The second parameter determines where the named references are # initialized. In all cases the named references are defined at the # start of function "g". With value "0" they are initialized at the # same place (in the same statement). With the other values, the # initialization is delayed until later, the greater the value and the # later the initialization. function e() { local s=$0 a=($0); f "$@"; } function f() { local s=$0 a=($0); g "$@"; } function g() { if (($2)); then local -n $1 rs ra; else local -n $1 rs=s ra=a; fi; if (($2 == 1)); then rs=s; ra=a; fi; echo "$0:1: rs=$rs - ra=$ra"; local s=$0 a=($0); if (($2 == 2)); then rs=s; ra=a; fi; echo "$0:2: rs=$rs - ra=$ra"; h "$@"; echo "$0:3: rs=$rs - ra=$ra"; } function h() { if (($2 == 3)); then rs=s; ra=a; fi; echo "$0:1: rs=$rs - ra=$ra"; local s=$0 a=($0); if (($2 == 4)); then rs=s; ra=a; fi; echo "$0:2: rs=$rs - ra=$ra"; i "$@"; echo "$0:3: rs=$rs - ra=$ra"; # Check that re-entering the same scope doesn't undo scope exit k "$@" } function i() { if (($2 == 5)); then rs=s; ra=a; fi; echo "$0:1: rs=$rs - ra=$ra"; local s=$0 a=($0); if (($2 == 6)); then rs=s; ra=a; fi; echo "$0:2: rs=$rs - ra=$ra"; j "$@"; echo "$0:3: rs=$rs - ra=$ra"; k "$@"; } function j() { echo "$0:1: rs=$rs - ra=$ra"; local s=$0 a=($0); echo "$0:2: rs=$rs - ra=$ra"; } functions -c j k local s=T a=(T); function f1() { typeset var=$0; typeset -n ref1 ref2; typeset -n ref3=ref2; function f2() { typeset ref2=XX; function f3() { typeset var=$0; function f4() { typeset var=$0; ref1=var; ref3=var; # Initializes ref2 to var echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } f4; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; function g4() { typeset var=$0; function g5() { typeset var=$0; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } g5; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } g4; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } f3; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } f2; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; function h2() { typeset var=$0; function h3() { typeset var=$0; function h4() { typeset var=$0; function h5() { typeset var=$0; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } h5; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } h4; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } h3; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } h2; echo "$0: ref1=$ref1 ref2=$ref2 ref3=$ref3"; } # Helper function to test assigning and typesetting named references # in different contexts. # # Runs the code passed in "$1" for all combinations of the following # variables: # # - K: Kind of target reference. The assigned/typeset reference is # one of the following kind: # - "i": unInitialized reference: # e.g., "ref0" in "typeset -n ref0" # - "s": unSet reference: # e.g., "ref0" in "typeset -n ref0; unset ref0" # - "d": reference to not-yet-Defined variable: # e.g., "ref0" in "typeset -n ref0=var" where "var" isn't defined # # - G: Global vs local references # - "-g": All test variables/references are global ones. # - "" : All test variables/references are local ones. # # - N: direct vs indirect references # - "0": The target reference "ref0" is directly assigned/typeset. # - "1": The target reference "ref0" is assigned/typeset via a # named reference "ref1" that refers to "ref0". test-setting-ref() { local K G N; for K in i s d; do for G in -g ""; do for N in 0 1; do test-setting-ref-aux $1 done done done unset -n ref0 ref1 var } # Helper function for the function test-setting-ref defined above. # # Runs the code passed in "$1" for the context specified by the # variables "K", "G", and "N". test-setting-ref-aux() { unset -n ref0 ref1 var # In several contexts different code paths are involved depending # on whether the target reference "ref0" is assigned/typeset # directly or via a named reference that refers to it. However, it # doesn't seem to make a difference whether the chain of references # is short or long. Therefore only chains of one reference are # tested. One can manually double check that longer chains work the # same by replacing the following line by one of the commented one # just below and checking that all tests still pass. ((N < 1)) || typeset $G -n ref1=ref0 # ((N < 1)) || typeset $G -n refX=ref0 ref1=refX # ((N < 1)) || typeset $G -n refX=ref0 refY=refX ref1=refY local kind print case $K in i) kind="uninitialized reference" ; check=ref0; typeset $G -n ref0;; s) kind="unset reference" ; check=ref0; typeset $G -n ref0; unset -n ref0;; d) kind="reference to not-yet-defined"; check=var ; typeset $G -n ref0=var;; *) echo "Unrecognized case: $case"; return;; esac echo "# $K:$kind - ${${G:-local}/-g/global} - ref$N" { eval ${(e)1}; typeset -p $check } always { TRY_BLOCK_ERROR=0 } 2>&1 } %test typeset -n ptr typeset -n 0:minimal declaration >ptr typeset -n ptr= typeset -n 0:nameref placeholder >ptr='' typeset -n ptr ptr=var typeset -n 0:assign nameref placeholder >ptr=var unset ptr typeset -n ptr typeset -n ptr=var typeset -n 0:assign placeholder with new typeset >ptr=var typeset -n ptr1 typeset -n ptr2=ptr1 typeset -n 0:chain ending in placeholder >ptr1 >ptr2=ptr1 typeset ptr=var typeset -n ptr typeset -n 0:convert scalar to nameref >ptr=var typeset -n ptr=var typeset +n ptr typeset -p ptr 0:remove nameref attribute >typeset ptr=var typeset -n ptr=gvar () { local ptr typeset -p ptr } typeset -p ptr 0:Local non-reference hides outside reference >typeset ptr >typeset -n ptr=gvar typeset -n ptr typeset -p ptr typeset -t ptr typeset -p ptr 0:change type of a placeholder F:Other type changes are fatal errors, should this also be? >typeset -n ptr >typeset -n ptr *?*ptr: can't change type of a named reference typeset -n ptr=var typeset -t ptr typeset -p ptr var 0:change type of referenced var >typeset -n ptr=var >typeset -t var typeset var unset var typeset -n ptr=var typeset -t ptr typeset -p ptr var 0:change type of unset referenced var F:regression - at one time this incorrectly applied the tag to "ptr" F:note this causes "var" to become set >typeset -n ptr=var >typeset -t var typeset -n ptr[1]=var 1:illegal nameref name *?*reference variable cannot be an array typeset var=value typeset -n ptr=var print $ptr print $ptr[2,4] 0:nameref expansion, no braces >value >alu typeset var=value typeset -n ptr=var print ${ptr} print ${(U)ptr} print ${ptr[2,5][1,3]} print ${(U)ptr[2,5][1,3]} 0:nameref expansion, braces >value >VALUE >alu >ALU typeset var=(val1 val2) typeset -n ptr=var print $ptr print $ptr[2] 0:nameref array expansion, no braces >val1 val2 >val2 typeset var=(val1 val2) typeset -n ptr=var print ${ptr} print ${(O)ptr} print ${ptr[2]} print ${(U)ptr[2]} print ${ptr[2][2,4]} print ${(U)ptr[2][2,4]} 0:nameref array expansion, braces >val1 val2 >val2 val1 >val2 >VAL2 >al2 >AL2 typeset -A var=(key1 val1 key2 val2) typeset -n ptr=var print $ptr print $ptr[key2] 0:nameref hash expansion, no braces >val1 val2 >val2 typeset -A var=(key1 val1 key2 val2) typeset -n ptr=var print ${ptr} print ${(kv)ptr} print ${ptr[key2]} print ${(U)ptr[key2]} print ${ptr[key2][2,4]} print ${(U)ptr[key2][2,4]} 0:nameref hash expansion, braces >val1 val2 >key1 val1 key2 val2 >val2 >VAL2 >al2 >AL2 typeset var=value typeset -n ptr=var ptr=newvalue typeset -p var ptr[3]=xt typeset -p var typeset ptr=newvalue typeset -p var typeset ptr[3]=xt typeset -p var 0:assign/typeset existing scalar via nameref >typeset var=newvalue >typeset var=nextvalue >typeset var=newvalue >typeset var=nextvalue typeset var=(val1 val2) typeset -n ptr=var ptr=(new1 new2 new3 new4 new5) typeset -p var ptr[3]=new6 typeset -p var ptr[2,4]=(new7 new8) typeset -p var typeset ptr=(new1 new2 new3 new4 new5) typeset -p var typeset ptr[3]=new6 typeset -p var typeset ptr[2,4]=(new7 new8) typeset -p var 0:assign/typeset existing array via nameref >typeset -a var=( new1 new2 new3 new4 new5 ) >typeset -a var=( new1 new2 new6 new4 new5 ) >typeset -a var=( new1 new7 new8 new5 ) >typeset -a var=( new1 new2 new3 new4 new5 ) >typeset -a var=( new1 new2 new6 new4 new5 ) >typeset -a var=( new1 new7 new8 new5 ) typeset -A var=(key1 val1) typeset -n ptr=var ptr=(key2 val2 key3 val3) typeset -p var ptr[key3]=VAL3 ptr[key4]=val4 typeset -p var typeset ptr=(key2 val2 key3 val3) typeset -p var typeset ptr[key3]=VAL3 typeset ptr[key4]=val4 typeset -p var 0:assign/typeset existing array via nameref >typeset -A var=( [key2]=val2 [key3]=val3 ) >typeset -A var=( [key2]=val2 [key3]=VAL3 [key4]=val4 ) >typeset -A var=( [key2]=val2 [key3]=val3 ) >typeset -A var=( [key2]=val2 [key3]=VAL3 [key4]=val4 ) () { unset var typeset -n ptr=var ptr=value typeset -p var unset var typeset ptr=value typeset -p var } typeset -p var 1:assign/typeset new scalar via nameref >typeset -g var=value >typeset var=value *?*no such variable: var () { unset var typeset -n ptr=var ptr=(val1 val2) typeset -p var unset var typeset ptr=(val1 val2) typeset -p var } typeset -p var 1:assign/typeset new array via nameref >typeset -g -a var=( val1 val2 ) >typeset -a var=( val1 val2 ) *?*no such variable: var typeset var=value typeset -n ptr=var unset "ptr[3]" typeset -p var unset "ptr[2,3]" typeset -p var unset ptr typeset -p var typeset var=(val1 val2 val3 val4 val5) unset "ptr[3]" typeset -p var unset "ptr[2,4]" typeset -p var unset ptr typeset -p var typeset -A var=(key1 val1 key2 val2) unset "ptr[key2]" typeset -p var unset ptr typeset -p var 0:unset via nameref >typeset var=vaue >typeset var=ve >typeset -a var=( val1 val2 '' val4 val5 ) >typeset -a var=( val1 '' val5 ) >typeset -A var=( [key1]=val1 ) typeset var=value typeset -n ptr=var unset -n ptr typeset -p var ptr 0:unset of the nameref itself >typeset var=value typeset -p ptr ptr1 ptr2 var 1:check state of paramtab ONE F:unexpected side-effects of previous tests *?*no such variable: ptr *?*no such variable: ptr1 *?*no such variable: ptr2 *?*no such variable: var unset var typeset -n ptr2=var typeset -n ptr1=ptr2 typeset var=value typeset -p ptr1 ptr2 var print $ptr1 0:indirect nameref expansion >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset var=value >value typeset -p ptr1 ptr2 var 1:check state of paramtab TWO F:unexpected side-effects of previous tests *?*no such variable: ptr1 *?*no such variable: ptr2 *?*no such variable: var typeset var typeset -n ptr2=var typeset -n ptr1=ptr2 typeset ptr1=newvalue typeset -p ptr1 ptr2 var 0:typeset existing parameter indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset var=newvalue typeset var=value typeset -n ptr2=var typeset -n ptr1=ptr2 unset ptr1 typeset -p ptr1 ptr2 var 0:unset parameter indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var typeset -n ptr2=var typeset -n ptr1=ptr2 typeset ptr1=newvalue typeset -p ptr1 ptr2 var 0:typeset new parameter indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset var=newvalue unset var typeset -n ptr2=var typeset -n ptr1=ptr2 typeset var=value typeset -p ptr1 ptr2 var ptr1=newvalue typeset -p ptr1 ptr2 var 0:assign new parameter indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset var=value >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset var=newvalue typeset -p ptr1 ptr2 var 1:check state of paramtab THREE F:unexpected side-effects of previous tests *?*no such variable: ptr1 *?*no such variable: ptr2 *?*no such variable: var typeset -a var typeset -n ptr2=var typeset -n ptr1=ptr2 typeset ptr1=(val1 val2) typeset -p ptr1 ptr2 var 0:typeset existing array indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset -a var=( val1 val2 ) typeset -n ptr2=var typeset -n ptr1=ptr2 typeset ptr1=(val1 val2) typeset -p ptr1 ptr2 var 0:typeset new array indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset -a var=( val1 val2 ) typeset -p ptr1 ptr2 1:check state of paramtab FOUR F:unexpected side-effects of previous tests *?*no such variable: ptr1 *?*no such variable: ptr2 unset var typeset -n ptr2=var typeset -n ptr1=ptr2 ptr1=(val1 val2) typeset -p ptr1 ptr2 var 0:assign new array indirectly >typeset -n ptr1=ptr2 >typeset -n ptr2=var >typeset -g -a var=( val1 val2 ) typeset -n ptr1=ptr2 typeset -n ptr2=ptr1 1:direct nameref loop not allowed *?*invalid self reference unset var typeset -gn ptr1=var typeset -p ptr1 0:global reference to unset var >typeset -g -n ptr1=var unset -n ptr1 typeset -gn ptr1 typeset -p ptr1 ptr1=ptr1 1:global direct reference >typeset -g -n ptr1 *?*invalid self reference typeset -n ptr1=ptr2 typeset -n ptr2=ptr3 typeset -n ptr3=ptr1 1:indirect nameref loop not allowed *?*invalid self reference typeset -n ptr1 ptr2 ptr1=ptr2 ptr2=ptr1 1:looping assignment not allowed *?*invalid self reference typeset ptr1=not-a-ref () { typeset -n ptr1=ptr1 () { typeset -n ptr1=ptr1 echo $ptr1 } } 0:regression: not a self reference (test 1) >not-a-ref typeset -n ptr1 typeset -n ptr2=ptr1 () { typeset ptr2=no-a-ref typeset -n ptr1=ptr2 } 0:regression: not a self reference (test 2) typeset ptr2=foo () { typeset -n ptr1=ptr2 typeset -n ptr2=ptr1 } 0:regression: not a self reference (test 3) unset -n ptr1 typeset -n ptr1='not[2]good' 1:invalid nameref *?*invalid variable name: not\[2\]good unset -n ptr unset gval typeset -n ptr=gval gval=global () { local gval=local; print $ptr; typeset -p ptr gval } 0:up-reference part 1 >global >typeset -g -n ptr=gval >typeset gval=local typeset -p ptr ptr1 ptr2 val 1:check state of paramtab FIVE F:unexpected side-effects of previous tests *?*no such variable: ptr *?*no such variable: ptr1 *?*no such variable: ptr2 *?*no such variable: val unset gval typeset -n ptr1=gval typeset gval () { typeset gval=local; ptr1=global } typeset -p ptr1 gval 0:up-reference assignment part 1 F:All tests run inside a function, so "typeset gval" creates a local; F:if that were omitted, ptr1= assignment would create a true global F:and the output below would change to "typeset -g gval=global" >typeset -n ptr1=gval >typeset gval=global typeset -p ptr ptr1 ptr2 val gval 1:check state of paramtab SIX F:unexpected side-effects of previous tests *?*no such variable: ptr *?*no such variable: ptr1 *?*no such variable: ptr2 *?*no such variable: val *?*no such variable: gval typeset gval=global () { typeset -n ptr=gval local gval=local print $ptr } typeset -p ptr gval 1:up-reference part 2 >global *?*no such variable: ptr >typeset gval=global typeset -n ptr=gval () { local lval=local typeset -n ptr=lval ptr=LOCAL typeset -p lval gval ptr } typeset -p ptr 0:localized namerefs hide global namerefs *?*no such variable: gval >typeset lval=LOCAL >typeset -n ptr=lval >typeset -n ptr=gval typeset -A var=(myself outside) () { typeset -n myself=var local -h var print -r -- $myself[myself] typeset -p var } 0:up-reference part 3, hidden global >outside >typeset -h var () { typeset notdef unset notdef () { typeset -n ptr=notdef ptr=(DEFINED) } typeset -p notdef } 0:up-reference part 4, unset local and type change >typeset -a notdef=( DEFINED ) () { typeset -n ptr1=ptr2 typeset -n ptr2 typeset -p ptr1 ptr2 typeset val=LOCAL () { ptr1=val typeset -n printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" } typeset -p ptr1 ptr2 } typeset -p ptr2 1:up-reference part 5, stacked namerefs, end not in scope >typeset -n ptr1=ptr2 >typeset -n ptr2 >ptr1=ptr2 >ptr2=val >ptr1=LOCAL >ptr2=LOCAL >typeset -n ptr1=ptr2 >typeset -n ptr2=val *?*no such variable: ptr2 typeset ptr2 () { typeset -n ptr1=ptr2 typeset -n ptr2 typeset -p ptr1 ptr2 typeset val=LOCAL () { ptr1=val typeset -n printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" } typeset -p ptr1 ptr2 } typeset -p ptr2 0:up-reference part 6, stacked namerefs, end is in scope F:Same test, should part 5 output look like this? >typeset -n ptr1=ptr2 >typeset -n ptr2 >ptr1=ptr2 >ptr2 >ptr1=val >ptr2= >typeset -n ptr1=ptr2 >typeset -n ptr2 >typeset ptr2=val () { () { local var typeset -nu ptr1=var ptr1=outer && print -u2 assignment expected to fail typeset -n ptr2=var ptr2=inner typeset -n printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" } typeset -p var } typeset -p var 1:up-reference part 7, upscope namerefs, end not in scope >ptr1=var >ptr2=var >ptr1= >ptr2=inner *?*typeset*: no such variable: var *?*typeset*: no such variable: var typeset var () { () { local var typeset -nu ptr1=var ptr1=outer || print -u2 assignment expected to succeed typeset -n ptr2=var ptr2=inner typeset -n printf "%s=%s\n" ptr1 "$ptr1" ptr2 "$ptr2" } typeset -p var } typeset -p var 0:up-reference part 8, upscope namerefs, end in scope >ptr1=var >ptr2=var >ptr1=outer >ptr2=inner >typeset -g var=outer >typeset var=outer if zmodload zsh/parameter; then () { zmodload -u zsh/parameter typeset -n myself=parameters local -h parameters print -r -- $myself[myself] typeset -p parameters } else ZTST_skip='Cannot zmodload zsh/parameter, skipping autoload test' fi 0:up-reference part 9, autoloading with hidden special >nameref-local-association-readonly-hide-hideval-special >typeset -h parameters ( inner() { local -n var="${1:?}"; var=(alpha beta gamma); } outer() { local -a foo=(outer); inner foo; typeset -p foo; } foo=3 ; { outer foo } always { typeset -p foo } ) 0:up-reference part 10, assignment to enclosing scope, types match >typeset -a foo=( alpha beta gamma ) >typeset -g foo=3 ( inner() { local -n var="${1:?}"; var=(alpha beta gamma); } outer() { local foo=outer; inner foo; typeset -p foo; } foo=3 ; { outer foo } always { typeset -p foo } ) 0:up-reference part 11, assignment to enclosing scope, type mismatch >typeset -a foo=( alpha beta gamma ) >typeset -g foo=3 ( inner() { local -n var="${1:?}"; unset var; var=(alpha beta gamma); } outer() { local foo=outer; inner foo; typeset -p foo; } foo=3 ; { outer foo } always { typeset -p foo } ) 0:up-reference part 12, assignment to enclosing scope, unset by reference >typeset -a foo=( alpha beta gamma ) >typeset -g foo=3 ( inner() { local "${1:?}"; local -nu var="$1"; var=(alpha beta gamma); } outer() { local -a foo=(outer); inner foo; typeset -p foo; } foo=3 ; { outer foo } always { typeset -p foo } ) 0:up-reference part 13, assignment to enclosing scope, skip local >typeset -a foo=( alpha beta gamma ) >typeset -g foo=3 ( inner() { local "${1:?}"; local -nu var="$1"; typeset -g var=(alpha beta gamma); } outer() { local -a foo=(outer); inner foo; typeset -p foo; } foo=3 ; { outer foo } always { typeset -p foo } ) 0f:up-reference part 14, typeset -g to enclosing scope, skip local F:typeset cannot bypass a name in the local scope, even via nameref >typeset -a foo=( alpha beta gamma ) >typeset -g foo=3 () { # scope with no parameters () { local -nu upref=$1 local var=at_upref print -- $upref } var } 0:up-reference part 15, non-existent parameter in outer scope # no output expected > if [[ $options[typesettounset] != on ]]; then ZTST_skip='Ignoring zmodload bug that resets TYPESET_TO_UNSET' setopt typesettounset fi 0:options reloaded F:Checking for a bug in zmodload that affects later tests typeset ptr2=var2 typeset var2=GLOBAL () { typeset -n ptr1=ptr2 typeset ptr2=var1 typeset var1=VAR1 typeset var2=VAR2 print -r -- ${(P)ptr1} } 0:Order of evaluation with ${(P)...} >VAR2 ary=(one two three four) typeset -n ptr=ary print -r ${(j.:.)ptr//o/0} 0:expansion flags and string replacement >0ne:tw0:three:f0ur var=value typeset -n ptr=var myscalar=ptr echo ${(P)myscalar} 0:named references with (P), as ${(P)name_of_nameref} >value var=value myscalar=var typeset -n ptr=myscalar echo ${(P)ptr} 0:named references with (P), as ${(P)nameref} >value unset -n ref unset var typeset -n ref=var typeset var=GLOBAL () { typeset -n ref=$1 print -r $ref ref=RESET typeset -p ref var } ref typeset -p ref var 0:local reference points to same-name global reference, part 1 >GLOBAL >typeset -n ref=ref >typeset -g var=RESET >typeset -n ref=var >typeset var=RESET unset -n ref unset var typeset -n ref=var () { typeset -n ref=$1 print -r $ref ref=RESET typeset -p ref var } ref typeset -p ref var 0:local reference points to same-name global reference, part 2 > >typeset -n ref=ref >typeset -g var=RESET >typeset -n ref=var >typeset -g var=RESET unset -n ref unset var1 typeset -n ref=var1 () { typeset -n ref=var2 ref=RESET typeset -p ref var2 } typeset -p ref var2 0:local reference hides same-name global reference >typeset -n ref=var2 >typeset -g var2=RESET >typeset -n ref=var1 >typeset -g var2=RESET unset -n ref unset one typeset -n ref typeset one=ONE for ref in one ref two; do print -r $ref; done 1:for-loop variable is a reference, part 1 >ONE *?*ref: invalid self reference unset -n ref unset one typeset -n ref () { typeset one=ONE for ref in one ref two; do print -r ${(t)ref}; done } 1:for-loop variable is a reference, part 2 >scalar-local *?*ref: invalid self reference unset -n ref unset one var typeset -n ref=var () { typeset one=ONE typeset -n ref=ref for ref in one ref two; do typeset -p ref print -r $ref done typeset -p ref } typeset -p ref 0:for-loop variable is a reference, part 3 >typeset -n ref=one >ONE >typeset -n ref=ref > >typeset -n ref=two > >typeset -n ref=two >typeset -n ref=var typeset -g .K01.scalar='RW' typeset -gA .K01.assoc=(x y) typeset -ga .K01.array=(z) typeset -gi .K01.integer=0 typeset -gE .K01.double=0.0 typeset -gF .K01.float=0.0 typeset -gr .K01.readonly='RO' typeset -n gref for gref in ARGC .K01.{scalar,assoc,array,integer,double,float,readonly} do { unset gref } always { TRY_BLOCK_ERROR=0 } done typeset -p .K01.{scalar,assoc,array,integer,double,float,readonly} unset .K01.{scalar,assoc,array,integer,double,float} 0:unset various types via nameref, including a readonly special >typeset -g -r .K01.readonly=RO *?*read-only variable: ARGC *?*read-only variable: .K01.readonly *?*no such variable: .K01.scalar *?*no such variable: .K01.assoc *?*no such variable: .K01.array *?*no such variable: .K01.integer *?*no such variable: .K01.double *?*no such variable: .K01.float unset -n ref unset one typeset -n ref () { setopt localoptions warn_nested_var typeset one=ONE for ref in one two; do print -r ${(t)ref}; done typeset -n ref for ref in one two; do print -r ${(t)ref}; done } 0:for-loop variable is a reference, part 4, warnings >scalar-local > >scalar-local > *?*reference ref*to local variable one typeset -n ref=var { for ref in valid1 inv@lid valid2; do typeset -p ref; done } always { TRY_BLOCK_ERROR=0 } typeset -nr ref=var { for ref in valid3 valid4; do typeset -p ref; done } always { TRY_BLOCK_ERROR=0 } 1:for-loop variable is a reference, part 5, errors >typeset -n ref=valid1 *?*invalid variable name: inv@lid *?*read-only reference: ref unset -n ref typeset -n ref () { setopt localoptions warn_nested_var typeset inner ref=inner } typeset -p ref 0:Global variable is a reference, warning >typeset -n ref=inner *?*reference ref*to local variable inner unset -n ref typeset -n ref=GLOBAL () { typeset -gn ref=RESET } typeset -p ref 0:reset global reference within function >typeset -n ref=RESET unset -n ref typeset -rn ref=RO typeset -p ref (typeset -n ref=RW) print status: $? expected: 1 typeset +r -n ref typeset -p ref typeset -r +n ref typeset -p ref (typeset -rn ref) print status: $? expected: 1 typeset +r -n ref=RW # Assignment occurs after type change, typeset -p ref RO # so RO=RW here. Potentially confusing. typeset -r -n ref=RX # No type change, so referent changes ... typeset -p ref RO # ... and previous refererent does not. typeset +rn ref=RW # Here ref=RW, again type changed first. typeset -p ref 0:add and remove readonly attribute with references >typeset -rn ref=RO *?*: ref: read-only reference >status: 1 expected: 1 >typeset -n ref=RO >typeset -r ref=RO *?*: ref: read-only variable >status: 1 expected: 1 >typeset -n ref=RO >typeset -g RO=RW >typeset -rn ref=RX >typeset -g RO=RW >typeset ref=RW () { typeset -n r1 r2= typeset -p r1 r2 print -- ${(!)r1-unset} print -- ${+r1} typeset -p r1 } 0:unset nameref remains unset when resolved F:relies on global TYPESET_TO_UNSET in %prep >typeset -n r1 >typeset -n r2='' >unset >0 >typeset -n r1 bar=xx typeset -n foo=bar () { typeset -n foo; foo=zz foo=zz || print -u2 foo: assignment failed typeset -p bar zz } # prior to workers/53676 the assignment failed unset zz () { typeset -n foo; foo=zz; local zz; foo=zz; typeset -p bar zz } 0:regression: local nameref may not in-scope a global parameter F:previously this could create an infinite recursion and crash >typeset -g bar=xx >typeset -g zz=zz >typeset -g bar=xx >typeset zz=zz typeset -nm foo=bar 1:create nameref by pattern match not allowed *?*typeset:1: -m not allowed with -n typeset -nariu ref=var 1:regression: warn about invalid nameref options but never about valid ones *?*typeset:1: -a not allowed with -n *?*typeset:1: -i not allowed with -n e -u 0 0:assignment at different scope than declaration, -u 0 >g:1: rs=f - ra=f >g:2: rs=f - ra=f >h:1: rs=f - ra=f >h:2: rs=f - ra=f >i:1: rs=f - ra=f >i:2: rs=f - ra=f >j:1: rs=f - ra=f >j:2: rs=f - ra=f >i:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >h:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >g:3: rs=f - ra=f e '' 0 0:assignment at different scope than declaration, '' 0 >g:1: rs=f - ra=f >g:2: rs=f - ra=f >h:1: rs=f - ra=f >h:2: rs=f - ra=f >i:1: rs=f - ra=f >i:2: rs=f - ra=f >j:1: rs=f - ra=f >j:2: rs=f - ra=f >i:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >h:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >g:3: rs=f - ra=f e -u 2 0:assignment at different scope than declaration, -u 2 >g:1: rs= - ra= >g:2: rs=f - ra=f >h:1: rs=f - ra=f >h:2: rs=f - ra=f >i:1: rs=f - ra=f >i:2: rs=f - ra=f >j:1: rs=f - ra=f >j:2: rs=f - ra=f >i:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >h:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >g:3: rs=f - ra=f e -u 6 0:assignment at different scope than declaration, -u 6 >g:1: rs= - ra= >g:2: rs= - ra= >h:1: rs= - ra= >h:2: rs= - ra= >i:1: rs= - ra= >i:2: rs=f - ra=f >j:1: rs=f - ra=f >j:2: rs=f - ra=f >i:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >h:3: rs=f - ra=f >k:1: rs=f - ra=f >k:2: rs=f - ra=f >g:3: rs=f - ra=f e '' 6 0:assignment at different scope than declaration, '' 6 >g:1: rs= - ra= >g:2: rs= - ra= >h:1: rs= - ra= >h:2: rs= - ra= >i:1: rs= - ra= >i:2: rs=i - ra=i >j:1: rs=i - ra=i >j:2: rs=i - ra=i >i:3: rs=i - ra=i >k:1: rs=i - ra=i >k:2: rs=i - ra=i >h:3: rs=h - ra=h >k:1: rs=h - ra=h >k:2: rs=h - ra=h >g:3: rs=g - ra=g f1 0:Transitive references with scoping changes >f4: ref1=f4 ref2=XX ref3=f4 >f3: ref1=f3 ref2=XX ref3=f3 >g5: ref1=f3 ref2=XX ref3=f3 >g4: ref1=f3 ref2=XX ref3=f3 >f3: ref1=f3 ref2=XX ref3=f3 >f2: ref1=f1 ref2=XX ref3=f1 >f1: ref1=f1 ref2=f1 ref3=f1 >h5: ref1=f1 ref2=f1 ref3=f1 >h4: ref1=f1 ref2=f1 ref3=f1 >h3: ref1=f1 ref2=f1 ref3=f1 >h2: ref1=f1 ref2=f1 ref3=f1 >f1: ref1=f1 ref2=f1 ref3=f1 () { typeset -n ref1 ref2 local var=l1 () { () { local var=l3 ref1=var echo A1: ref1=$ref1 ref2=$ref2 } ref2=var # At this point, "ref1" and "ref2" refer to the same variable # "var". Going forward, they should behave the same. echo A2: ref1=$ref1 ref2=$ref2 () { local var=l3 echo A3: ref1=$ref1 ref2=$ref2 } echo A4: ref1=$ref1 ref2=$ref2 local var=l2 echo A5: ref1=$ref1 ref2=$ref2 } echo A6: ref1=$ref1 ref2=$ref2 } () { typeset -n ref1 ref2 () { () { local var=l3 ref1=var echo B1: ref1=$ref1 ref2=$ref2 } ref2=var # At this point, "ref1" and "ref2" refer to the same undefined # variable "var". Going forward, they should behave the same. echo B2: ref1=$ref1 ref2=$ref2 () { () { local var=l4 echo B3: ref1=$ref1 ref2=$ref2 } local var=l3 echo B4: ref1=$ref1 ref2=$ref2 } local var=l2 echo B5: ref1=$ref1 ref2=$ref2 () { () { local var=l4 echo B6: ref1=$ref1 ref2=$ref2 } local var=l3 echo B7: ref1=$ref1 ref2=$ref2 } echo B8: ref1=$ref1 ref2=$ref2 } local var=l1 echo B9: ref1=$ref1 ref2=$ref2 } 0:rebound nameref behaves the same as newly bound one >A1: ref1=l3 ref2= >A2: ref1=l1 ref2=l1 >A3: ref1=l1 ref2=l1 >A4: ref1=l1 ref2=l1 >A5: ref1=l1 ref2=l1 >A6: ref1=l1 ref2=l1 >B1: ref1=l3 ref2= >B2: ref1= ref2= >B3: ref1=l4 ref2=l4 >B4: ref1=l3 ref2=l3 >B5: ref1=l2 ref2=l2 >B6: ref1=l2 ref2=l2 >B7: ref1=l2 ref2=l2 >B8: ref1=l2 ref2=l2 >B9: ref1=l1 ref2=l1 check-valid-referent-name() { local -n ref=$1 [[ $ref = $2 ]] || echo "Unexpected expansion result: ref=$1, \$ref=$ref != $2" } check-invalid-variable-name() { { local -- $1=value-$1 2>/dev/null echo "Unexpected valid variable name: $1" } always { TRY_BLOCK_ERROR=0 } } check-invalid-referent-name() { { local -n -- ref=$1 2>/dev/null echo "Unexpected valid referent name: $1" } always { TRY_BLOCK_ERROR=0 } } local name value; # Test valid variable names. for name in \ foo foo. foo.bar foo.456 foo.4ar \ .foo .foo.bar .foo.456 do local $name=value-$name check-valid-referent-name "$name" value-$name check-invalid-referent-name "$name"@ check-invalid-referent-name "$name""[1]" done # Test valid builtin variable names for name value in 123 "" \! 0 \? 0 \$ $$ - 569X _ -n; do check-valid-referent-name "$name" $value check-invalid-referent-name "$name"@ check-invalid-referent-name "$name""[1]" done # Test invalid variable names. for name in \ .foo. .foo.4ar . foo.. \ 123. 123.bar 123.456 123.4ar .. .foo.. \ .123 .123. .123.bar .123.456 .123.4ar \ 1oo 1oo. 1oo.bar 1oo.456 1oo.4ar \ .1oo .1oo. .1oo.bar .1oo.456 .1oo.4ar do check-invalid-variable-name "$name" check-invalid-referent-name "$name" check-invalid-referent-name "$name"@ check-invalid-referent-name "$name""[1]" done # Any variable name with more than one non-leading '.' is invalid. for name in {,.}{foo,123,1oo}.{bar,456,4ar}.{,baz,789,7az}; do check-invalid-variable-name "$name" check-invalid-referent-name "$name" done unfunction check-valid-referent-name unfunction check-invalid-variable-name unfunction check-invalid-referent-name unset name value 0:references to invalid variable names edgelocal() ( local -n x=$1; typeset -p x; print -r $x ) edgeupper() ( local -nu x=$1; typeset -p x; print -r $x ) for edge in argv ARGC \@ \* \# 0 1 01 \! \? \$ - _ do edgelocal $edge edgeupper $edge done unfunction edgelocal edgeupper 0q:references to builtin specials F:BUG:References to 1, 2, ... are supported but don't work (always expand to "") >typeset -n x=argv >argv >typeset -n x=ARGC >1 >typeset -n x=0 >edgelocal >typeset -n x=1 > >typeset -n x=01 > >typeset -n x=! >0 >typeset -un x=! >0 >typeset -n x='?' >0 >typeset -un x='?' >0 >typeset -n x='$' >$$ >typeset -un x='$' >$$ >typeset -n x=- >569X >typeset -un x=- >569X >typeset -n x=_ >x >typeset -un x=_ >x ?edgeupper: invalid variable name: argv ?edgeupper: invalid variable name: ARGC ?edgelocal: invalid variable name: @ ?edgeupper: invalid variable name: @ ?edgelocal: invalid variable name: * ?edgeupper: invalid variable name: * ?edgelocal: invalid variable name: # ?edgeupper: invalid variable name: # ?edgeupper: invalid variable name: 0 ?edgeupper: invalid variable name: 1 ?edgeupper: invalid variable name: 01 # # The following tests are run in interactive mode, using PS1 as an # assignable special with side-effects. This crashed at one time. # # Note bypassing TYPESET_TO_UNSET here $ZTST_testdir/../Src/zsh -fis <<<$' typeset -n p=PS1 () { typeset -p p local p typeset -p p p=xx typeset -p p } ' 0:regression: assign to local that shadows global named reference >typeset -g -n p=PS1 >typeset p='' >typeset p=xx *?* # Note bypassing TYPESET_TO_UNSET here $ZTST_testdir/../Src/zsh -fis <<<$' () { typeset p=PS1 typeset -n p p=zz } typeset -p PS1 ' 0:regression - converting a string into a named reference >typeset PS1=zz *?* unset var1 var2 typeset -n ref1=var1 () { typeset -n ref2=ref1 typeset -n ref1=var2 typeset -i ref2=42 typeset -p ref1 ref2 var1 var2 } 1:typeset reference chain to not-yet-defined variable including a hidden reference ?(anon):typeset:4: no such variable: var2 >typeset -n ref1=var2 >typeset -n ref2=ref1 >typeset -i var1=42 typeset -n ref1 typeset -n ref2=ref1 () { typeset -n ref3=ref2 typeset ref2=foo ref1=ref3 } 1:self reference chain including a hidden reference ?(anon):3: ref3: invalid self reference zmodload -u zsh/random echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*} typeset -n ref=SRANDOM echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*} echo v=${ref/<->/integer} zmodload -u zsh/random echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*} echo v=${ref/<->/integer} 0:Referring and dereferring an autoload variable loads it >z=SRANDOM (zsh/random) >z= >v=integer >z=SRANDOM (zsh/random) >v=integer typeset -n ref=SRANDOM echo v=${ref/<->/integer} zmodload -u zsh/random echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*} typeset -h SRANDOM=local-variable echo v=${ref/<->/integer} echo NOT REACHED 1:Dereferring an autoload variable fails to load it if its hidden >v=integer >z=SRANDOM (zsh/random) ?(eval):6: Can't add module parameter `SRANDOM': local parameter exists ?(eval):zsh/random:6: error when adding parameter `SRANDOM' ?(eval):6: autoloading module zsh/random failed to define parameter: SRANDOM () { typeset var1=var1 typeset var2=var2 typeset -n ref1=var1 echo "ref1=$ref1"; () { typeset -n ref1=var2 typeset -n ref2=ref1 echo "ref1=$ref1"; echo "ref2=$ref2"; } } 0:regression: don't follow references when computing base scope - part 1 >ref1=var1 >ref1=var2 >ref2=var2 () { typeset var1=var1 typeset -n ref1=var1 echo ref1=$ref1; () { typeset var2=var2 typeset -n ref1 typeset -n ref2=ref1 ref1=var2 echo ref1=$ref1; echo ref2=$ref2; } } 0:regression: don't follow references when computing base scope - part 2 >ref1=var1 >ref1=var2 >ref2=var2 typeset -n ref1 typeset -n ref2=ref1; () { typeset ref2=foo ref1=ref2 echo reached } echo NOT REACHED 1:incidental reference loop triggers error >reached *?*: ref2: invalid self reference typeset -A -g VAR0=(aa AA) typeset -n -g REF0=VAR0 typeset -A -g var0=(aa AA) typeset -A var1=(aa AA) () { typeset -A var2=(aa AA) typeset -n ref0=var0 ref1=var1 ref2=var2 # Test initial association typeset -pm VAR0 var\? REF0=(zz ZZ); ref0=(zz ZZ); ref1=(zz ZZ); ref2=(zz ZZ); typeset -pm VAR0 var\? # Test change from association to string REF0=foo; ref0=foo; ref1=foo; ref2=foo; typeset -pm VAR0 var\? REF0=bar; ref0=bar; ref1=bar; ref2=bar; typeset -pm VAR0 var\? # Test change from string to array REF0=(aa AA); ref0=(aa AA); ref1=(aa AA); ref2=(aa AA); typeset -pm VAR0 var\? REF0=(zz ZZ); ref0=(zz ZZ); ref1=(zz ZZ); ref2=(zz ZZ); typeset -pm VAR0 var\? # Test change from array to string REF0=foo; ref0=foo; ref1=foo; ref2=foo; typeset -pm VAR0 var\? } 0:type changes via assignments to references >typeset -g -A VAR0=( [aa]=AA ) >typeset -g -A var0=( [aa]=AA ) >typeset -g -A var1=( [aa]=AA ) >typeset -A var2=( [aa]=AA ) >typeset -g -A VAR0=( [zz]=ZZ ) >typeset -g -A var0=( [zz]=ZZ ) >typeset -g -A var1=( [zz]=ZZ ) >typeset -A var2=( [zz]=ZZ ) >typeset -g VAR0=foo >typeset -g var0=foo >typeset -g var1=foo >typeset var2=foo >typeset -g VAR0=bar >typeset -g var0=bar >typeset -g var1=bar >typeset var2=bar >typeset -g -a VAR0=( aa AA ) >typeset -g -a var0=( aa AA ) >typeset -g -a var1=( aa AA ) >typeset -a var2=( aa AA ) >typeset -g -a VAR0=( zz ZZ ) >typeset -g -a var0=( zz ZZ ) >typeset -g -a var1=( zz ZZ ) >typeset -a var2=( zz ZZ ) >typeset -g VAR0=foo >typeset -g var0=foo >typeset -g var1=foo >typeset var2=foo typeset -A -g ass0=(aa AA) typeset -A ass1=(aa AA) typeset -a -g arr0=(aa AA) typeset -a arr1=(aa AA) typeset -g str0=foo typeset str1=foo () { typeset -n Ass0=ass0 Ass1=ass1 Arr0=arr0 Arr1=arr1 Str0=str0 Str1=str1 typeset ass0 ass1 arr0 arr1 str0 str1 { Ass0=foo } always { TRY_BLOCK_ERROR=0 }; echo $? { Ass1=foo } always { TRY_BLOCK_ERROR=0 }; echo $? { Arr0=foo } always { TRY_BLOCK_ERROR=0 }; echo $? { Arr1=foo } always { TRY_BLOCK_ERROR=0 }; echo $? { Str0=(x) } always { TRY_BLOCK_ERROR=0 }; echo $? { Str1=(x) } always { TRY_BLOCK_ERROR=0 }; echo $? } typeset -p ass0 ass1 arr0 arr1 str0 str1 0:can't change type of hidden variables via assignments to references >1 >1 >1 >1 >1 >1 >typeset -g -A ass0=( [aa]=AA ) >typeset -A ass1=( [aa]=AA ) >typeset -g -a arr0=( aa AA ) >typeset -a arr1=( aa AA ) >typeset -g str0=foo >typeset str1=foo ?(anon):3: can't change type of hidden variable: ass0 ?(anon):4: can't change type of hidden variable: ass1 ?(anon):5: can't change type of hidden variable: arr0 ?(anon):6: can't change type of hidden variable: arr1 ?(anon):7: can't change type of hidden variable: str0 ?(anon):8: can't change type of hidden variable: str1 typeset -A ass=(aa AA) typeset -a arr=(aa AA) typeset -i int=42 typeset str=foo typeset -n Ass=ass Arr=arr Int=int Str=str { typeset Ass=foo } always { TRY_BLOCK_ERROR=0 }; echo $? { typeset Arr=foo } always { TRY_BLOCK_ERROR=0 }; echo $? { typeset Int=(aa AA) } always { TRY_BLOCK_ERROR=0 }; echo $? { typeset Str=(aa AA) } always { TRY_BLOCK_ERROR=0 }; echo $? typeset -p ass arr int str 0:type changes via plain typeset to references F:converting from association/array to string should work here too >1 >1 >0 >0 >typeset -A ass=( [aa]=AA ) >typeset -a arr=( aa AA ) >typeset -a int=( aa AA ) >typeset -a str=( aa AA ) ?(eval):typeset:6: ass: inconsistent type for assignment ?(eval):typeset:7: arr: inconsistent type for assignment typeset var typeset -n ref=var # Change type to string unset var; typeset var=fubar; typeset ref=barfu; typeset -p var unset var; typeset -i var=12345; typeset +i ref=barfu; typeset -p var unset var; typeset -a var=(a A); typeset +a ref=barfu; typeset -p var unset var; typeset -A var=(a A); typeset +A ref=barfu; typeset -p var # Change type to integer unset var; typeset var=fubar; typeset -i ref=56789; typeset -p var unset var; typeset -i var=12345; typeset -i ref=56789; typeset -p var unset var; typeset -a var=(a A); typeset -i ref=56789; typeset -p var unset var; typeset -A var=(a A); typeset -i ref=56789; typeset -p var # Change type to array unset var; typeset var=fubar; typeset -a ref=(z Z); typeset -p var unset var; typeset -i var=12345; typeset -a ref=(z Z); typeset -p var unset var; typeset -a var=(a A); typeset -a ref=(z Z); typeset -p var unset var; typeset -A var=(a A); typeset -a ref=(z Z); typeset -p var # Change type to association unset var; typeset var=fubar; typeset -A ref=(z Z); typeset -p var unset var; typeset -i var=12345; typeset -A ref=(z Z); typeset -p var unset var; typeset -a var=(a A); typeset -A ref=(z Z); typeset -p var unset var; typeset -A var=(a A); typeset -A ref=(z Z); typeset -p var 0:type changes via typed typeset to references >typeset var=barfu >typeset var=barfu >typeset var=barfu >typeset var=barfu >typeset -i var=56789 >typeset -i var=56789 >typeset -i var=56789 >typeset -i var=56789 >typeset -a var=( z Z ) >typeset -a var=( z Z ) >typeset -a var=( z Z ) >typeset -a var=( z Z ) >typeset -A var=( [z]=Z ) >typeset -A var=( [z]=Z ) >typeset -A var=( [z]=Z ) >typeset -A var=( [z]=Z ) typeset ptr1=foo () { typeset -n ptr1 typeset -n ptr2=ptr1 ptr1=ptr2 echo ptr1=$ptr1 } 1:regression: reference loop with same name enclosing variable ?(anon):3: ptr2: invalid self reference typeset var=foo typeset -n ref=var () { typeset -n ref ref="" ref=ref echo $ref } 0:reference always prefers enclosing variable over itself >foo typeset -n ref1 () { typeset -n ref2=ref3 ref1=ref2 typeset -nu ref3=ref1 } 1:self reference via upper reference ?(anon):3: ref1: invalid self reference # The call to "test-setting-ref 'ref$N=str'" expands to the # equivalent of the following: # # # Test uninitialized references # typeset -g -n ref0 ; ref0=str; typeset -p ref0; unset -n ref0 # typeset -g -n ref0 ref1=ref0; ref1=str; typeset -p ref0; unset -n ref0 ref1 # typeset -n ref0 ; ref0=str; typeset -p ref0; unset -n ref0 # typeset -n ref0 ref1=ref0; ref1=str; typeset -p ref0; unset -n ref0 ref1 # # Test unset references # typeset -g -n ref0 ; unset -n ref0; ref0=str; typeset -p ref0; unset -n ref0 # ... # # Test references to not-yet-defined variables # typeset -g -n ref0=var ; ref0=str; typeset -p var ; unset -n ref0 var # ... test-setting-ref 'ref$N=str' 0:assign not fully defined reference with string ># i:uninitialized reference - global - ref0 >typeset -g -n ref0=str ># i:uninitialized reference - global - ref1 >typeset -g -n ref0=str ># i:uninitialized reference - local - ref0 >typeset -n ref0=str ># i:uninitialized reference - local - ref1 >typeset -n ref0=str ># s:unset reference - global - ref0 >typeset -g ref0=str ># s:unset reference - global - ref1 >typeset -g ref0=str ># s:unset reference - local - ref0 >typeset ref0=str ># s:unset reference - local - ref1 >typeset ref0=str ># d:reference to not-yet-defined - global - ref0 >typeset -g var=str ># d:reference to not-yet-defined - global - ref1 >typeset -g var=str ># d:reference to not-yet-defined - local - ref0 >typeset -g var=str ># d:reference to not-yet-defined - local - ref1 >typeset -g var=str test-setting-ref 'ref$N=( foo bar )' 0:assign not fully defined reference with array ># i:uninitialized reference - global - ref0 >(eval):1: ref0: can't change type of a named reference >typeset -g -n ref0 ># i:uninitialized reference - global - ref1 >(eval):1: ref1: can't change type of a named reference >typeset -g -n ref0 ># i:uninitialized reference - local - ref0 >(eval):1: ref0: can't change type of a named reference >typeset -n ref0 ># i:uninitialized reference - local - ref1 >(eval):1: ref1: can't change type of a named reference >typeset -n ref0 ># s:unset reference - global - ref0 >typeset -g -a ref0=( foo bar ) ># s:unset reference - global - ref1 >typeset -g -a ref0=( foo bar ) ># s:unset reference - local - ref0 >typeset -a ref0=( foo bar ) ># s:unset reference - local - ref1 >typeset -a ref0=( foo bar ) ># d:reference to not-yet-defined - global - ref0 >typeset -g -a var=( foo bar ) ># d:reference to not-yet-defined - global - ref1 >typeset -g -a var=( foo bar ) ># d:reference to not-yet-defined - local - ref0 >typeset -g -a var=( foo bar ) ># d:reference to not-yet-defined - local - ref1 >typeset -g -a var=( foo bar ) test-setting-ref 'typeset $G ref$N=str' 0:typeset not fully defined reference with string ># i:uninitialized reference - global - ref0 >typeset -g -n ref0=str ># i:uninitialized reference - global - ref1 >typeset -g -n ref0=str ># i:uninitialized reference - local - ref0 >typeset -n ref0=str ># i:uninitialized reference - local - ref1 >typeset -n ref0=str ># s:unset reference - global - ref0 >typeset -g ref0=str ># s:unset reference - global - ref1 >typeset -g ref0=str ># s:unset reference - local - ref0 >typeset ref0=str ># s:unset reference - local - ref1 >typeset ref0=str ># d:reference to not-yet-defined - global - ref0 >typeset -g var=str ># d:reference to not-yet-defined - global - ref1 >typeset -g var=str ># d:reference to not-yet-defined - local - ref0 >typeset var=str ># d:reference to not-yet-defined - local - ref1 >typeset var=str test-setting-ref 'typeset $G -a ref$N=( foo bar )' 0:typeset not fully defined reference with array ># i:uninitialized reference - global - ref0 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -g -n ref0 ># i:uninitialized reference - global - ref1 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -g -n ref0 ># i:uninitialized reference - local - ref0 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -n ref0 ># i:uninitialized reference - local - ref1 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -n ref0 ># s:unset reference - global - ref0 >typeset -g -a ref0=( foo bar ) ># s:unset reference - global - ref1 >typeset -g -a ref0=( foo bar ) ># s:unset reference - local - ref0 >typeset -a ref0=( foo bar ) ># s:unset reference - local - ref1 >typeset -a ref0=( foo bar ) ># d:reference to not-yet-defined - global - ref0 >typeset -g -a var=( foo bar ) ># d:reference to not-yet-defined - global - ref1 >typeset -g -a var=( foo bar ) ># d:reference to not-yet-defined - local - ref0 >typeset -a var=( foo bar ) ># d:reference to not-yet-defined - local - ref1 >typeset -a var=( foo bar ) typeset i42=42 test-setting-ref 'typeset $G -i ref$N=i42' 0:typeset not fully defined reference with integer ># i:uninitialized reference - global - ref0 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -g -n ref0 ># i:uninitialized reference - global - ref1 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -g -n ref0 ># i:uninitialized reference - local - ref0 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -n ref0 ># i:uninitialized reference - local - ref1 >(eval):typeset:1: ref0: can't change type of a named reference >typeset -n ref0 ># s:unset reference - global - ref0 >typeset -g -i ref0=42 ># s:unset reference - global - ref1 >typeset -g -i ref0=42 ># s:unset reference - local - ref0 >typeset -i ref0=42 ># s:unset reference - local - ref1 >typeset -i ref0=42 ># d:reference to not-yet-defined - global - ref0 >typeset -g -i var=42 ># d:reference to not-yet-defined - global - ref1 >typeset -g -i var=42 ># d:reference to not-yet-defined - local - ref0 >typeset -i var=42 ># d:reference to not-yet-defined - local - ref1 >typeset -i var=42 test-unset() { typeset var0=foo typeset -n ref1=var0 ref2=ref1 typeset cmd=(unset $@); echo "#" $cmd; $cmd typeset -p var0 ref1 ref2 } test-unset -n ref1 test-unset -n ref2 test-unset -n -m ref1 test-unset -n -m ref2 unfunction test-unset 0:unsetting references with -n unsets the references ># unset -n ref1 >typeset var0=foo >typeset -n ref2=ref1 ># unset -n ref2 >typeset var0=foo >typeset -n ref1=var0 ># unset -n -m ref1 >typeset var0=foo >typeset -n ref2=ref1 ># unset -n -m ref2 >typeset var0=foo >typeset -n ref1=var0 test-unset() { typeset var0=foo typeset -n ref1=var0 ref2=ref1 typeset cmd=(unset $@); echo "#" $cmd; $cmd typeset -p var0 ref1 ref2 } test-unset ref1 test-unset ref2 test-unset -m ref1 test-unset -m ref2 unfunction test-unset 0:unsetting references without -n unsets the referred parameters ># unset ref1 >typeset -n ref1=var0 >typeset -n ref2=ref1 ># unset ref2 >typeset -n ref1=var0 >typeset -n ref2=ref1 ># unset -m ref1 >typeset -n ref1=var0 >typeset -n ref2=ref1 ># unset -m ref2 >typeset -n ref1=var0 >typeset -n ref2=ref1 test-unset() { typeset var0=12345 typeset -n ref1=var0 ref2=ref1 typeset cmd=(unset $@); echo "#" $cmd; $cmd typeset -p var0 } test-unset ref1"[3]" test-unset ref2"[3]" test-unset -n ref1"[3]" test-unset -n ref2"[3]" unfunction test-unset 0:unsetting subscripted references unsets the referred elements ># unset ref1[3] >typeset var0=1245 ># unset ref2[3] >typeset var0=1245 ># unset -n ref1[3] >typeset var0=1245 ># unset -n ref2[3] >typeset var0=1245 test-unset() { typeset -r var=foo typeset -n ref=var typeset cmd=(unset $@); echo "#" $cmd; { $cmd 2>&1 } always { TRY_BLOCK_ERROR=0 } typeset -p var } test-unset var test-unset -m var test-unset ref test-unset -m ref test-unset var"[2]" test-unset ref"[2]" test-unset -n ref"[2]" unfunction test-unset 0:unsetting read-only parameter triggers an error ># unset var >test-unset:3: read-only variable: var >typeset -r var=foo ># unset -m var >test-unset:3: read-only variable: var >typeset -r var=foo ># unset ref >test-unset:3: read-only variable: var >typeset -r var=foo ># unset -m ref >test-unset:3: read-only variable: var >typeset -r var=foo ># unset var[2] >test-unset:3: read-only variable: var >typeset -r var=foo ># unset ref[2] >test-unset:3: read-only variable: var >typeset -r var=foo ># unset -n ref[2] >test-unset:3: read-only variable: var >typeset -r var=foo test-unset() { typeset -n ref1 ref2=ref1 typeset cmd=(unset $@); echo "#" $cmd; $cmd typeset -p ref1 ref2 } test-unset ref1 test-unset ref2 test-unset -m ref1 test-unset -m ref2 unfunction test-unset 0:unsetting placeholder references or their referents has no effect ># unset ref1 >typeset -n ref1 >typeset -n ref2=ref1 ># unset ref2 >typeset -n ref1 >typeset -n ref2=ref1 ># unset -m ref1 >typeset -n ref1 >typeset -n ref2=ref1 ># unset -m ref2 >typeset -n ref1 >typeset -n ref2=ref1 test-unset() { typeset -n ref1=undefined ref2=ref1 typeset cmd=(unset $@); echo "#" $cmd; $cmd typeset -p ref1 ref2 } typeset -p undefined 2>&1 test-unset ref1 test-unset ref2 test-unset -m ref1 test-unset -m ref2 unfunction test-unset 0:unsetting references to not-yet-defined variables or their referents has no effect >(eval):typeset:6: no such variable: undefined ># unset ref1 >typeset -n ref1=undefined >typeset -n ref2=ref1 ># unset ref2 >typeset -n ref1=undefined >typeset -n ref2=ref1 ># unset -m ref1 >typeset -n ref1=undefined >typeset -n ref2=ref1 ># unset -m ref2 >typeset -n ref1=undefined >typeset -n ref2=ref1 test-unset() { typeset -n refg1=g1 refl1=l1 () { typeset -g g1=glb1 g2=glb2 typeset l1=lcl1 l2=lcl2 () { typeset -n refg2=g2 refl2=l2 typeset cmd=(unset $@ refg1 refg2 refl1 refl2); echo "#" $cmd; $cmd } $@ typeset -p g1 g2 l1 l2 2>&1 } $@ unset g1 g2 } test-unset test-unset -m unfunction test-unset 0:unsetting references referring to parameters in enclosing scopes unsets the parameters ># unset refg1 refg2 refl1 refl2 >(anon):typeset:7: no such variable: g1 >(anon):typeset:7: no such variable: g2 ># unset -m refg1 refg2 refl1 refl2 >(anon):typeset:7: no such variable: g1 >(anon):typeset:7: no such variable: g2 test-unset() { typeset -g g=glb typeset l=lcl typeset -n refg=g refl=l () { typeset g=hide-g typeset l=hide-l typeset cmd=(unset $@ refg refl); echo "#" $cmd; $cmd echo "# inner scope" typeset -p g l 2>&1 } $@ echo "# outer scope" typeset -p g l 2>&1 unset g } test-unset test-unset -m unfunction test-unset 0:unsetting references referring to hidden parameters unsets the hidden parameters ># unset refg refl ># inner scope >typeset g=hide-g >typeset l=hide-l ># outer scope >test-unset:typeset:12: no such variable: g ># unset -m refg refl ># inner scope >typeset g=hide-g >typeset l=hide-l ># outer scope >test-unset:typeset:12: no such variable: g typeset -n ref1 typeset -n ref2 typeset -n ref3=ref2 typeset var=aaa () { typeset -i ref2=123 # Hides the reference ref2 in this scope and nested scopes typeset var=bbb () { typeset var=ccc ref1=var ref3=var # From now on ref1 and ref3 should always refer to the same variable echo A:ref1=$ref1 ref2=$ref2 ref3=$ref3 } # Both top-level references ref1 and ref2 should be rebound echo B:ref1=$ref1 ref2=$ref2 ref3=$ref3 () { typeset var=ddd # No reference should refer to this variable echo C:ref1=$ref1 ref2=$ref2 ref3=$ref3 } echo D:ref1=$ref1 ref2=$ref2 ref3=$ref3 } # Both top-level references ref1 and ref2 should be rebound echo E:ref1=$ref1 ref2=$ref2 ref3=$ref3 () { typeset var=eee # No reference should refer to this variable echo F:ref1=$ref1 ref2=$ref2 ref3=$ref3 } echo G:ref1=$ref1 ref2=$ref2 ref3=$ref3 0:hidden reference refers to a nested variable >A:ref1=ccc ref2=123 ref3=ccc >B:ref1=bbb ref2=123 ref3=bbb >C:ref1=bbb ref2=123 ref3=bbb >D:ref1=bbb ref2=123 ref3=bbb >E:ref1=aaa ref2=aaa ref3=aaa >F:ref1=aaa ref2=aaa ref3=aaa >G:ref1=aaa ref2=aaa ref3=aaa typeset ref typeset var1=var1@scope1 typeset var2=var2@scope1 () { # enter scope 2 typeset var1=var1@scope2 typeset var2=var2@scope2 typeset -g -n ref=var1; echo A:$ref # ref added to scope 2 typeset -g -n ref=var2; echo B:$ref # ref added to scope 2 () { # enter scope 3 typeset var1=var1@scope3 typeset -g -n ref=var1; echo C:$ref # ref added to scope 3 () { # enter scope 4 typeset var1=var1@scope4 typeset var2=var2@scope4 typeset -g -n ref=var1; echo D:$ref # ref added to scope 4 typeset -g -n ref=var2; echo E:$ref # ref added to scope 4 } # leave scope 4: ref rebound to var2 in scope 2 and added to scope 2 echo F:$ref } # leave scope 3: ref remains bound to var2 in scope 2 echo G:$ref unset -n ref # ref is unset echo H:$ref } # leave scope 2: ref remains unset echo I:$ref 0:reference refers successively to multiple variables in multiple nested scopes >A:var1@scope2 >B:var2@scope2 >C:var1@scope3 >D:var1@scope4 >E:var2@scope4 >F:var2@scope2 >G:var2@scope2 >H: >I: typeset ref () { # enter scope 2 typeset var=var typeset -g -n ref=var; echo A:$ref # ref added to scope 2 unset -n ref typeset -g -i16 ref=255; echo B:$ref # ref becomes an integer in base 16 } # leave scope 2: ref remains an integer in base 16 echo C:$ref 0:reference referring to a nested variable becomes an integer >A:var >B:16#FF >C:16#FF %clean