Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH] Remove support for named references to subscripted variables



Here is an updated patch obtained after syncing to the latest head.

Remove support for named references to subscripted variables

NOTE: The patch is missing updates to the documentation.

Philippe


On Thu, Feb 19, 2026 at 12:33 AM Philippe Altherr <philippe.altherr@xxxxxxxxx> wrote:
OK, thanks for clarity; no, that is not the difference I was thinking of.

There are still differences between the two functions but I assumed that both should agree on what qualifies as a regular variable name, i.e., one that can be used on the left of the equal sign in a typeset or in an assignment.

With the introduction of namespaces, it's no longer clear to me what qualifies as a valid variable name. Here are example of valid names (on the left of an equal sign in a typeset):

    foo  foo.  foo.bar  foo.456  foo.4ar
   .foo       .foo.bar .foo.456


And here examples of invalid names:

        .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

Given the description of namespaces in section 15.1, I'm surprised that ".foo" and "foo." are valid. I would have expected that names with namespaces must always contain two non-empty identifiers.

I'm also a little surprised that the second identifier may start with a digit. I'll admit that there is nothing in the documentation that forbids it. It's just because identifiers usually have to start with a letter.

Finally, I'm more than a little surprised that "foo", ".foo" and "foo." are all valid but not ".foo.". Same for "foo.456", ".foo.456", and "foo.4ar", which are all valid but not ".foo.4ar".

Philippe


On Wed, Feb 18, 2026 at 11:46 PM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
On Wed, Feb 18, 2026 at 1:29 PM Philippe Altherr
<philippe.altherr@xxxxxxxxx> wrote:
>
> Just to be clear, here is an example of what I mean: a variable named ".123" can't be created with an assignment or with a call to typeset but it works with a named reference initialized with ".123". Is that really expected?

OK, thanks for clarity; no, that is not the difference I was thinking of.
diff --git a/Src/builtin.c b/Src/builtin.c
index 7c095149d..7415c95e4 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2042,13 +2042,8 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 	    (on & ~(PM_NAMEREF|PM_LOCAL|PM_READONLY))) {
 	    /* Changing type of PM_SPECIAL|PM_AUTOLOAD is a fatal error.  *
 	     * Should this be a fatal error as well, rather than warning? */
-	    if (pm->width)
-		zwarnnam(cname,
-			 "%s: can't change type via subscript reference",
-			 pm->u.str);
-	    else
-		zwarnnam(cname, "%s: can't change type of a named reference",
-			 pname);
+	    zwarnnam(cname, "%s: can't change type of a named reference",
+		     pname);
 	    return NULL;
 	}
     }
@@ -3916,8 +3911,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
 	    zerrnam(name, "%s: restricted", pm->node.nam);
 	    returnval = 1;
 	} else if (ss) {
-	    if ((pm->node.flags & PM_NAMEREF) &&
-		(!(pm = resolve_nameref(pm)) || pm->width)) {
+	    if ((pm->node.flags & PM_NAMEREF) && !(pm = resolve_nameref(pm))) {
 		/* warning? */
 		continue;
 	    }
diff --git a/Src/params.c b/Src/params.c
index 461e02acf..94fd3449e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2230,7 +2230,6 @@ fetchvalue(Value v, char **pptr, int bracks, int scanflags)
     } else {
 	Param pm;
 	int isvarat;
-	int isrefslice = 0;
 
         isvarat = (t[0] == '@' && !t[1]);
 	if (scanflags & SCANPM_NONAMEREF)
@@ -2248,32 +2247,6 @@ fetchvalue(Value v, char **pptr, int bracks, int scanflags)
 	if (!pm || ((pm->node.flags & PM_UNSET) &&
 		    !(pm->node.flags & PM_DECLARED)))
 	    return NULL;
-	if ((pm->node.flags & PM_NAMEREF) && !(scanflags & SCANPM_NONAMEREF)) {
-	    char *refname = GETREFNAME(pm);
-	    if (refname && *refname) {
-		/* only happens for namerefs pointing to array elements */
-		char *ref = dupstring(refname);
-		char *ss = pm->width ? ref + pm->width : NULL;
-		if (ss) {
-		    sav = *ss;
-		    *ss = 0;
-		}
-		Param p1 = (Param)gethashnode2(paramtab, ref);
-		if (p1)
-		    pm = loadparamnode(paramtab, upscope(p1, pm), ref);
-		if (!(p1 && pm) ||
-		    ((pm->node.flags & PM_UNSET) &&
-		     !(pm->node.flags & PM_DECLARED)))
-		    return NULL;
-		if (ss) {
-		    scanflags |= SCANPM_NOEXEC;
-		    *ss = sav;
-		    s = dyncat(ss,*pptr);
-		    isrefslice = 1;
-		} else
-		    s = *pptr;
-	    }
-	}
 	if (!v)
 	    v = (Value) zhalloc(sizeof *v);
 	memset(v, 0, sizeof(*v));
@@ -2287,8 +2260,6 @@ fetchvalue(Value v, char **pptr, int bracks, int scanflags)
 		v->scanflags = SCANPM_ARRONLY;
 	}
 	v->pm = pm;
-	if (isrefslice)
-	    v->valflags = VALFLAG_REFSLICE;
 	v->end = -1;
 	if (bracks > 0 && (*s == '[' || *s == Inbrack)) {
 	    if (getindex(&s, v, scanflags)) {
@@ -3252,7 +3223,6 @@ assignsparam(char *s, char *val, int flags)
 	    createparam(t, PM_SCALAR);
 	    created = 1;
 	} else if ((((v->pm->node.flags & PM_ARRAY) &&
-		     !(v->valflags & VALFLAG_REFSLICE) &&
 		     !(flags & ASSPM_AUGMENT)) ||
 		    (v->pm->node.flags & PM_HASHED)) &&
 		   !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) &&
@@ -3415,7 +3385,6 @@ assignaparam(char *s, char **val, int flags)
 	    unqueue_signals();
 	    return NULL;
 	} else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) &&
-		   !(v->valflags & VALFLAG_REFSLICE) &&
 		   !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) {
 	    int uniq = v->pm->node.flags & PM_UNIQUE;
 	    if ((flags & ASSPM_AUGMENT) && !(v->pm->node.flags & PM_UNSET)) {
@@ -3642,8 +3611,7 @@ sethparam(char *s, char **val)
     if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) {
 	createparam(t, PM_HASHED);
 	checkcreate = 1;
-    } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) &&
-	       !(v->valflags & VALFLAG_REFSLICE)) {
+    } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED)) {
 	if (!(v->pm->node.flags & PM_SPECIAL)) {
 	    if (resetparam(v->pm, PM_HASHED)) {
 		unqueue_signals();
@@ -6351,9 +6319,7 @@ resolve_nameref_rec(Param pm, const Param stop, int keep_lastref)
     Param ref = pm;
     char *refname;
     if (!pm || !(pm->node.flags & PM_NAMEREF) || (pm->node.flags & PM_UNSET)
-	/* pm->width is the offset of any subscript */
-	/* If present, it has to be the end of any chain, see fetchvalue() */
-	|| pm->width || !(refname = GETREFNAME(pm)) || !*refname)
+	|| !(refname = GETREFNAME(pm)) || !*refname)
 	return pm;
     if (pm->node.flags & PM_TAGGED) {
 	zerr("%s: invalid self reference", pm->node.nam);
@@ -6386,7 +6352,11 @@ setloopvar(char *name, char *value)
 	  zerr("read-only reference: %s", pm->node.nam);
 	  return;
       }
-      pm->base = pm->width = 0;
+      if (!valid_refname(value, pm->node.flags)) {
+	  zerr("invalid name reference: %s", value);
+	  return;
+      }
+      pm->base = 0;
       SETREFNAME(pm, ztrdup(value));
       pm->node.flags &= ~PM_UNSET;
       setscope(pm);
@@ -6402,21 +6372,8 @@ setscope(Param pm)
     if (pm->node.flags & PM_NAMEREF) {
 	Param basepm = NULL;
 	char *refname = GETREFNAME(pm);
-	char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL;
 	int q = queue_signal_level();
 
-	/* Compute pm->width */
-	/* Temporarily change nameref to array parameter itself */
-	if (t && *t == '[')
-	    *t = 0;
-	else
-	    t = 0;
-	if (t) {
-	    pm->width = t - refname;
-	    *t = '[';
-	    refname = dupstrpfx(refname, pm->width);
-	}
-
 	/* Compute pm->base */
 	if (!(pm->node.flags & PM_UPPER) && refname &&
 	    (basepm = (Param)gethashnode2(realparamtab, refname)) &&
@@ -6435,7 +6392,7 @@ setscope(Param pm)
 	}
 
 	/* Check for self references */
-	if (refname && *refname && !pm->width && basepm != pm) {
+	if (refname && *refname && basepm != pm) {
 	    dont_queue_signals();	/* Prevent unkillable loops */
 	    basepm = resolve_nameref_rec(pm, pm, 0);
 	    restore_queue_signals(q);
@@ -6482,47 +6439,14 @@ upscope(Param pm, const Param ref)
 static int
 valid_refname(char *val, int flags)
 {
-    char *t;
-
     if (flags & PM_UPPER) {
 	/* Upward reference to positionals is doomed to fail */
-	if (idigit(*val))
-	    return 0;
-	t = itype_end(val, INAMESPC, 0);
-	if ((t - val == 4) &&
-	    (!strncmp(val, "argv", 4) ||
-	     !strncmp(val, "ARGC", 4)))
-	    return 0;
-    } else if (idigit(*val)) {
-	t = val;
-	while (*++t)
-	    if (!idigit(*t))
-		break;
-	if (*t && *t != '[')	/* Need to test Inbrack here too? */
-	    return 0;
-    } else
-	t = itype_end(val, INAMESPC, 0);
-
-    if (t == val) {
-	if (!(*t == '!' || *t == '?' ||
-	      *t == '$' || *t == '-' ||
-	      *t == '_'))
+	if (idigit(*val) || !strcmp(val, "argv") || !strcmp(val, "ARGC"))
 	    return 0;
-	++t;
     }
-    if (*t == '[') {
-	/* Another bit of isident() to emulate */
-	tokenize(t = dupstring(t+1));
-	while ((t = parse_subscript(t, 0, ']')) && *t++ == Outbrack) {
-	    if (*t == Inbrack)
-		++t;
-	    else
-		break;
-	}
-	if (t && *t) {
-	    /* zwarn("%s: stuff after subscript: %s", val, t); */
-	    return 0;
-	}
-    }
-    return !!t;
+
+    if (*val == '!' || *val == '?' || *val == '$' || *val == '-')
+    	return !*(++val);
+
+    return !*itype_end(val, INAMESPC, 0) && isident(val);
 }
diff --git a/Src/zsh.h b/Src/zsh.h
index dd58c0816..c3a2544f2 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -758,7 +758,6 @@ enum {
     VALFLAG_INV =	0x0001,	/* We are performing inverse subscripting */
     VALFLAG_EMPTY =	0x0002,	/* Subscripted range is empty */
     VALFLAG_SUBST =	0x0004,	/* Substitution, so apply padding, case flags */
-    VALFLAG_REFSLICE=	0x0008	/* Value is a reference to an array slice */
 };
 
 #define MAX_ARRLEN    262144
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 0b4475827..0048a44e1 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -33,44 +33,44 @@
    }
 
    function g() {
-     if (($2)); then local -n $1 rs ra rs1 ra1;
-     else local -n $1 rs=s ra=a rs1="s[1]" ra1="a[1]"; fi;
-     if (($2 == 1)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
-     echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     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; rs1="s[1]"; ra1="a[1]"; fi;
-     echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     if (($2 == 2)); then rs=s; ra=a; fi;
+     echo "$0:2: rs=$rs - ra=$ra";
      h "$@";
-     echo "$0:3: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     echo "$0:3: rs=$rs - ra=$ra";
    }
 
    function h() {
-     if (($2 == 3)); then rs=s; ra=a; rs1="s[1]"; ra1="a[1]"; fi;
-     echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     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; rs1="s[1]"; ra1="a[1]"; fi;
-     echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     if (($2 == 4)); then rs=s; ra=a; fi;
+     echo "$0:2: rs=$rs - ra=$ra";
      i "$@";
-     echo "$0:3: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     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; rs1="s[1]"; ra1="a[1]"; fi;
-     echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     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; rs1="s[1]"; ra1="a[1]"; fi;
-     echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     if (($2 == 6)); then rs=s; ra=a; fi;
+     echo "$0:2: rs=$rs - ra=$ra";
      j "$@";
-     echo "$0:3: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     echo "$0:3: rs=$rs - ra=$ra";
      k "$@";
    }
 
    function j() {
-     echo "$0:1: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     echo "$0:1: rs=$rs - ra=$ra";
      local s=$0 a=($0);
-     echo "$0:2: rs=$rs - ra=$ra - rs1=$rs1 - ra1=$ra1";
+     echo "$0:2: rs=$rs - ra=$ra";
    }
 
    functions -c j k
@@ -276,11 +276,6 @@ F:note this causes "var" to become set
 >typeset -n ptr=var
 >typeset -t var
 
- typeset -n ptr=var[2]
- typeset -t ptr
-1:change type of referenced array element
-*?*var\[2\]: can't change type via subscript reference
-
  typeset -n ptr[1]=var
 1:illegal nameref name
 *?*reference variable cannot be an array
@@ -288,82 +283,191 @@ F:note this causes "var" to become set
  typeset var=value
  typeset -n ptr=var
  print $ptr
-0:basic nameref expansion, no braces
+ print $ptr[2,4]
+0:nameref expansion, no braces
 >value
+>alu
 
  typeset var=value
  typeset -n ptr=var
  print ${ptr}
-0:basic nameref expansion, braces
+ 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
-0:nameref array expansion
+ print $ptr[2]
+0:nameref array expansion, no braces
 >val1 val2
+>val2
 
- typeset -A var=(val1 val2)
+ typeset var=(val1 val2)
  typeset -n ptr=var
- print ${(kv)ptr}
-0:nameref hash expansion
+ 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 -p ptr var
+ typeset -n ptr=var
  ptr=newvalue
- typeset -p ptr var
-0:assign existing scalar via nameref
->typeset -n ptr=var
->typeset var=value
->typeset -n ptr=var
+ 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 -n ptr=var
  typeset var=value
+ typeset -n ptr=var
  unset -n ptr
  typeset -p var ptr
 0:unset of the nameref itself
-F:If earlier tests change, might get "no such variable" here
 >typeset var=value
 
- typeset -n ptr=var
- typeset var=value
- typeset -p ptr var
- typeset ptr=newvalue
- typeset -p ptr var
-0:typeset existing scalar via nameref
->typeset -n ptr=var
->typeset var=value
->typeset -n ptr=var
->typeset var=newvalue
-
- typeset -n ptr=var
- ptr=value
- typeset -p var ptr
-0:assign new scalar via nameref
->typeset -g var=value
->typeset -n ptr=var
-
- unset var
- typeset -n ptr=var
- typeset var=(val1 val2)
- typeset -p ptr var
- ptr=(new1 new2)
- typeset -p ptr var
-0:assign existing array via nameref
->typeset -n ptr=var
->typeset -a var=( val1 val2 )
->typeset -n ptr=var
->typeset -a var=( new1 new2 )
-
  typeset -p ptr ptr1 ptr2 var
 1:check state of paramtab ONE
 F:unexpected side-effects of previous tests
@@ -372,13 +476,6 @@ F:unexpected side-effects of previous tests
 *?*no such variable: ptr2
 *?*no such variable: var
 
- typeset -n ptr=var
- ptr=(val1 val2)
- typeset -p var ptr
-0:assign new array via nameref
->typeset -g -a var=( val1 val2 )
->typeset -n ptr=var
-
  unset var
  typeset -n ptr2=var
  typeset -n ptr1=ptr2
@@ -540,82 +637,11 @@ F:unexpected side-effects of previous tests
  }
 0:regression: not a self reference (test 3)
 
-
- unset -n ptr2
- typeset -n ptr2='path[2]'
- print -r -- $ptr2
-0q:nameref to array element, no braces
->${path[2]}
-
- unset -n ptr2
- typeset -n ptr2='path[2]'
- print -r -- ${ptr2}
-0q:nameref to array element, with braces
->${path[2]}
-
- unset -n ptr1
- typeset -A hash=(x MISS y HIT)
- typeset -n ptr1='hash[y]'
- print -r -- $ptr1
-0:nameref to hash element, no braces
->HIT
-
- unset -n ptr1
- typeset -A hash=(x MISS y HIT)
- typeset -n ptr1='hash[y]'
- print -r -- ${ptr1}
-0:nameref to hash element, with braces
->HIT
-
- unset -n ptr2
- typeset -a ary=(1 2)
- typeset -n ptr2='ary[2]'
- ptr2=TWO
- typeset -p ary
-0:assign array element by nameref
->typeset -a ary=( 1 TWO )
-
- unset -n ptr2
- typeset -n ptr2='ary[2]'
- ptr2=TWO
- typeset -p ary
-0f:create array element by nameref
-F:ksh93 does not implement this either
->typeset -a ary=( '' TWO )
-
- unset -n ptr1
- typeset -A hash=(x MISS y MISS)
- typeset -n ptr1='hash[y]'
- ptr1=HIT
- typeset -p hash
-0:assign to hash element by nameref
->typeset -A hash=( [x]=MISS [y]=HIT )
-
- unset -n ptr1
- typeset -A hash
- typeset -n ptr1='hash[y]'
- ptr1=HIT
- typeset -p hash
-0f:create hash by element nameref
-F:ksh93 does not implement this either
->typeset -A hash=( [y]=HIT )
-
  unset -n ptr1
  typeset -n ptr1='not[2]good'
 1:invalid nameref
 *?*invalid name reference: not\[2\]good
 
- unset -n ptr1
- unset hash
- typeset -A hash
- typeset -n ptr1='hash[y]'
- print ${ptr1::=HIT}
- typeset -p ptr1 hash
-0f:create hash by element substitution
->HIT
->typeset -n ptr1='hash[y]'
->typeset -A hash=( [y]=HIT )
-
  unset -n ptr
  unset gval
  typeset -n ptr=gval
@@ -683,9 +709,9 @@ F:unexpected side-effects of previous tests
 
  typeset -A var=(myself outside)
  () {
-   typeset -n myself=var[myself]
+   typeset -n myself=var
    local -h var
-   print -r -- $myself
+   print -r -- $myself[myself]
    typeset -p var
  }
 0:up-reference part 3, hidden global
@@ -800,15 +826,15 @@ F:Same test, should part 5 output look like this?
  if zmodload zsh/parameter; then
  () {
    zmodload -u zsh/parameter
-   typeset -n myself=parameters[myself]
+   typeset -n myself=parameters
    local -h parameters
-   print -r -- $myself
+   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-nameref-local
+>nameref-local-association-readonly-hide-hideval-special
 >typeset -h parameters
 
  (
@@ -909,15 +935,6 @@ F:Checking for a bug in zmodload that affects later tests
 0:named references with (P), as ${(P)nameref}
 >value
 
- ary=( 'bry[1]' 'bry[2]' ) 
- bry=( lorem ipsum )
- typeset -n ptr='ary[2]'
- print -r -- ${ptr}
- print -r -- ${(P)ptr}
-0:named references with (P), array element to array element
->bry[2]
->ipsum
-
  unset -n ref
  unset var
  typeset -n ref=var
@@ -1053,6 +1070,19 @@ F:Checking for a bug in zmodload that affects later tests
 >
 *?*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 name reference: inv@lid
+*?*read-only reference: ref
+
  unset -n ref
  typeset -n ref
  () {
@@ -1065,13 +1095,6 @@ F:Checking for a bug in zmodload that affects later tests
 >typeset -n ref=inner
 *?*reference ref*to local variable inner
 
- typeset -n ptr='ary[$(echo 2)]'
- typeset -a ary=(one two three)
- print $ptr
-1:attempt deferred command substitution in subscript
-F:runs in `setopt noexec` so $(...) returns nothing
-*?*bad math expression: empty string
-
  unset -n ref
  typeset -n ref=GLOBAL
  () {
@@ -1155,93 +1178,93 @@ F:previously this could create an infinite recursion and crash
 
  e -u 0
 0:assignment at different scope than declaration, -u 0
->g:1: rs=f - ra=f - rs1=f - ra1=f
->g:2: rs=f - ra=f - rs1=f - ra1=f
->h:1: rs=f - ra=f - rs1=f - ra1=f
->h:2: rs=f - ra=f - rs1=f - ra1=f
->i:1: rs=f - ra=f - rs1=f - ra1=f
->i:2: rs=f - ra=f - rs1=f - ra1=f
->j:1: rs=f - ra=f - rs1=f - ra1=f
->j:2: rs=f - ra=f - rs1=f - ra1=f
->i:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->h:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->g:3: rs=f - ra=f - rs1=f - ra1=f
+>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 - rs1=f - ra1=f
->g:2: rs=f - ra=f - rs1=f - ra1=f
->h:1: rs=f - ra=f - rs1=f - ra1=f
->h:2: rs=f - ra=f - rs1=f - ra1=f
->i:1: rs=f - ra=f - rs1=f - ra1=f
->i:2: rs=f - ra=f - rs1=f - ra1=f
->j:1: rs=f - ra=f - rs1=f - ra1=f
->j:2: rs=f - ra=f - rs1=f - ra1=f
->i:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->h:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->g:3: rs=f - ra=f - rs1=f - ra1=f
+>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= - rs1= - ra1=
->g:2: rs=f - ra=f - rs1=f - ra1=f
->h:1: rs=f - ra=f - rs1=f - ra1=f
->h:2: rs=f - ra=f - rs1=f - ra1=f
->i:1: rs=f - ra=f - rs1=f - ra1=f
->i:2: rs=f - ra=f - rs1=f - ra1=f
->j:1: rs=f - ra=f - rs1=f - ra1=f
->j:2: rs=f - ra=f - rs1=f - ra1=f
->i:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->h:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->g:3: rs=f - ra=f - rs1=f - ra1=f
+>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= - rs1= - ra1=
->g:2: rs= - ra= - rs1= - ra1=
->h:1: rs= - ra= - rs1= - ra1=
->h:2: rs= - ra= - rs1= - ra1=
->i:1: rs= - ra= - rs1= - ra1=
->i:2: rs=f - ra=f - rs1=f - ra1=f
->j:1: rs=f - ra=f - rs1=f - ra1=f
->j:2: rs=f - ra=f - rs1=f - ra1=f
->i:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->h:3: rs=f - ra=f - rs1=f - ra1=f
->k:1: rs=f - ra=f - rs1=f - ra1=f
->k:2: rs=f - ra=f - rs1=f - ra1=f
->g:3: rs=f - ra=f - rs1=f - ra1=f
+>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= - rs1= - ra1=
->g:2: rs= - ra= - rs1= - ra1=
->h:1: rs= - ra= - rs1= - ra1=
->h:2: rs= - ra= - rs1= - ra1=
->i:1: rs= - ra= - rs1= - ra1=
->i:2: rs=i - ra=i - rs1=i - ra1=i
->j:1: rs=i - ra=i - rs1=i - ra1=i
->j:2: rs=i - ra=i - rs1=i - ra1=i
->i:3: rs=i - ra=i - rs1=i - ra1=i
->k:1: rs=i - ra=i - rs1=i - ra1=i
->k:2: rs=i - ra=i - rs1=i - ra1=i
->h:3: rs=h - ra=h - rs1=h - ra1=h
->k:1: rs=h - ra=h - rs1=h - ra1=h
->k:2: rs=h - ra=h - rs1=h - ra1=h
->g:3: rs=g - ra=g - rs1=g - ra1=g
+>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
@@ -1333,91 +1356,119 @@ F:previously this could create an infinite recursion and crash
 >B8: ref1=l2 ref2=l2
 >B9: ref1=l1 ref2=l1
 
-#
-# The following two tests are linked, do not separate
-#
+ 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 \! \? - _
+ for edge in argv ARGC \@ \* \# 0 1 01 \! \? \$ - _
  do
   edgelocal $edge
-  edgelocal "$edge""[1]"
   edgeupper $edge
  done
-0:references to builtin specials
-F:Subscripting on 1 01 ! ? - should print first character but do not
+ 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='argv[1]'
->argv[1]
 >typeset -n x=ARGC
 >1
->typeset -n x='ARGC[1]'
->1
 >typeset -n x=0
 >edgelocal
->typeset -n x='0[1]'
->e
 >typeset -n x=1
 >
->typeset -n x='1[1]'
->
 >typeset -n x=01
 >
->typeset -n x='01[1]'
->
 >typeset -n x=!
 >0
->typeset -n x='![1]'
->
 >typeset -un x=!
 >0
 >typeset -n x='?'
 >0
->typeset -n x='?[1]'
->
 >typeset -un x='?'
 >0
+>typeset -n x='$'
+>$$
+>typeset -un x='$'
+>$$
 >typeset -n x=-
 >569X
->typeset -n x='-[1]'
->
 >typeset -un x=-
 >569X
 >typeset -n x=_
 >x
->typeset -n x='_[1]'
->x
 >typeset -un x=_
 >x
 ?edgeupper: invalid name reference: argv
 ?edgeupper: invalid name reference: ARGC
 ?edgelocal: invalid name reference: @
-?edgelocal: invalid name reference: @[1]
 ?edgeupper: invalid name reference: @
 ?edgelocal: invalid name reference: *
-?edgelocal: invalid name reference: *[1]
 ?edgeupper: invalid name reference: *
 ?edgelocal: invalid name reference: #
-?edgelocal: invalid name reference: #[1]
 ?edgeupper: invalid name reference: #
 ?edgeupper: invalid name reference: 0
 ?edgeupper: invalid name reference: 1
 ?edgeupper: invalid name reference: 01
 
- edgelocal \$
- edgelocal '$[1]'
- edgeupper \$
- unfunction edgelocal edgeupper
-0qf:references to $$
-F:$$[1] reference should print the first digit of $$ but prints nothing
->typeset -n x='$'
->$$
->typeset -n x='\$[1]'
->$$[1]
->$$
-
 #
 # The following tests are run in interactive mode, using PS1 as an
 # assignable special with side-effects.  This crashed at one time.
@@ -1485,22 +1536,7 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
  zmodload -u zsh/random
  echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
  echo v=${ref/<->/integer}
-0:Referring and dereferring an autoload variable loads it (direct)
->z=SRANDOM (zsh/random)
->z=
->v=integer
->z=SRANDOM (zsh/random)
->v=integer
-
- zmodload -u zsh/random
- echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
- typeset -n ref=SRANDOM[1,20]
- 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 (subscript)
+0:Referring and dereferring an autoload variable loads it
 >z=SRANDOM (zsh/random)
 >z=
 >v=integer
@@ -1514,21 +1550,7 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
  typeset -h SRANDOM=local-variable
  echo v=${ref/<->/integer}
  echo NOT REACHED
-1:Dereferring an autoload variable fails to load it if its hidden (direct)
->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 -n ref=SRANDOM[1,20]
- 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 (subscript)
+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
@@ -1747,10 +1769,6 @@ F:converting from association/array to string should work here too
 1:regression: reference loop with same name enclosing variable
 ?(anon):3: ptr2: invalid self reference
 
- typeset -n ref=ref[1]
-1:self reference with subscript
-*?*: ref: invalid self reference
-
  typeset var=foo
  typeset -n ref=var
  () {


Messages sorted by: Reverse Date, Date, Thread, Author