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

Re: BUG: Assigning a string to an array via a reference fails to change its type



Here is a patch that enables conversions between scalars and arrays via references. Afaict, it also eliminates the "BUG: local parameter is not unset" debug messages that showed up in some of my other patches. I'll look into adding tests for these conversions.

Philippe


On Fri, Jun 13, 2025 at 1:31 PM Mikael Magnusson <mikachu@xxxxxxxxx> wrote:
On Fri, Jun 13, 2025 at 3:28 AM Philippe Altherr
<philippe.altherr@xxxxxxxxx> wrote:
>
> When a string is assigned to an array variable, the variable becomes a string variable initialized with that string. When the same is done via a reference, the content of the array is replaced with the string and a debug message is emitted (when debugging is enabled).
>
> typeset -a arr=(aa bb cc)
> typeset -n ref=arr
> ref=foo
> typeset -p ref arr
> Output:
> 3: params.c:1068: BUG: local parameter is not unset
> typeset -n ref=arr
> typeset -a arr=( foo )
>
> I haven't tried to understand what/where the problem was. Neither Bart's patch to disallow array initializers nor my patch to change PM_TYPE help.
>
> Philippe
>

I reported this in zw/53751 already.

--
Mikael Magnusson
diff --git a/Src/params.c b/Src/params.c
index 7b515515e..a52c4fd5e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2245,6 +2245,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
 		    flags |= SCANPM_NOEXEC;
 		    *ss = sav;
 		    s = dyncat(ss,*pptr);
+		    v->isrefslice = 1;
 		} else
 		    s = *pptr;
 	    }
@@ -3217,12 +3218,17 @@ assignsparam(char *s, char *val, int flags)
 	if (!(v = getvalue(&vbuf, &s, 1))) {
 	    createparam(t, PM_SCALAR);
 	    created = 1;
-	} else if ((((v->pm->node.flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) ||
-	    	 (v->pm->node.flags & PM_HASHED)) &&
-		 !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) && 
+	} else if ((((v->pm->node.flags & PM_ARRAY) && !v->isrefslice &&
+		     !(flags & ASSPM_AUGMENT) ) ||
+		    (v->pm->node.flags & PM_HASHED)) &&
+		   !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) &&
 		 unset(KSHARRAYS)) {
-	    unsetparam(t);
-	    createparam(t, PM_SCALAR);
+	    if (resetparam(v->pm, PM_SCALAR)) {
+		unqueue_signals();
+		zsfree(val);
+		errflag |= ERRFLAG_ERROR;
+		return NULL;
+	    }
 	    /* not regarded as a new creation */
 	    v = NULL;
 	}
@@ -3369,7 +3375,8 @@ assignaparam(char *s, char **val, int flags)
 	    createparam(t, PM_ARRAY);
 	    created = 1;
 	} else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) &&
-		 !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) {
+		   !v->isrefslice &&
+		   !(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)) {
 	    	/* insert old value at the beginning of the val array */
@@ -3382,8 +3389,12 @@ assignaparam(char *s, char **val, int flags)
 		free(val);
 		val = new;
 	    }
-	    unsetparam(t);
-	    createparam(t, PM_ARRAY | uniq);
+	    if (resetparam(v->pm, PM_ARRAY | uniq)) {
+		unqueue_signals();
+		freearray(val);
+		errflag |= ERRFLAG_ERROR;
+		return NULL;
+	    }
 	    v = NULL;
 	}
     }
@@ -3591,11 +3602,14 @@ 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)) {
+    } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) && !v->isrefslice) {
 	if (!(v->pm->node.flags & PM_SPECIAL)) {
-	    unsetparam(t);
-	    /* no WARNCREATEGLOBAL check here as parameter already existed */
-	    createparam(t, PM_HASHED);
+	    if (resetparam(v->pm, PM_HASHED)) {
+		unqueue_signals();
+		freearray(val);
+		errflag |= ERRFLAG_ERROR;
+		return NULL;
+	    }
 	    v = NULL;
 	} else {
 	    zerr("%s: can't change type of a special parameter", t);
@@ -3752,6 +3766,29 @@ setiparam_no_convert(char *s, zlong val)
     return assignsparam(s, ztrdup(buf), ASSPM_WARN);
 }
 
+/* Reset a parameter */
+
+/**/
+mod_export int
+resetparam(Param pm, int flags)
+{
+    char *s = pm->node.nam;
+    queue_signals();
+    if (pm != (Param)(paramtab == realparamtab ?
+	       /* getnode2() to avoid autoloading */
+	       paramtab->getnode2(paramtab, s) :
+	       paramtab->getnode(paramtab, s))) {
+	unqueue_signals();
+	zerr("can't change type of hidden variable: %s", s);
+	return 1;
+    }
+    s = dupstring(s);
+    unsetparam_pm(pm, 0, 1);
+    unqueue_signals();
+    createparam(s, flags);
+    return 0;
+}
+
 /* Unset a parameter */
 
 /**/
diff --git a/Src/zsh.h b/Src/zsh.h
index 4e5c02980..3bd5412b2 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -748,6 +748,7 @@ struct value {
     int start;		/* first element of array slice, or -1 */
     int end;		/* 1-rel last element of array slice, or -1 */
     char **arr;		/* cache for hash turned into array */
+    int isrefslice;
 };
 
 enum {
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 54f0aaf68..d2fb59d82 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -734,9 +734,9 @@ F:Same test, should part 5 output look like this?
   outer() { local foo=outer; inner foo; typeset -p foo; }
   foo=3 ; { outer foo } always { typeset -p foo }
  )
-1:up-reference part 11, assignment to enclosing scope, type mismatch
+0:up-reference part 11, assignment to enclosing scope, type mismatch
+>typeset -a foo=( alpha beta gamma )
 >typeset -g foo=3
-?inner: foo: attempt to assign array value to non-array
 
  (
   inner() { local -n var="${1:?}"; unset var; var=(alpha beta gamma); }


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