Subject: bug#63290: 30.0.50; Customize UI shows extra fields for (choice (const ...) (alist ...))

From: Thomas Fitzsimmons <[email-masked]>
Date: Fri, 05 May 2023 02:02:53 -0400

This test case shows the issue:

(defcustom test-custom nil "" :type
  '(choice (alist
	    :key-type (string :tag "key")
	    :value-type (string :tag "value"))
           (const :tag "auto" nil)))
(customize-variable 'test-custom)

The UI first shows:

Hide Test Custom: Choice: Value Menu Alist:
INS
    State : STANDARD.

Then if I choose "Value Menu", and option 1 to choose the "auto" const
value, I get:

Hide Test Custom: Choice: Value Menu auto
    State : EDITED, shown value does not take effect until you set or save it.

which is fine.  Then if I choose "Value Menu" again and choose 0 for the
Alist, I get:

Hide Test Custom: Choice: Value Menu Alist:
INS DEL key: 
            value: 
INS
    State : EDITED, shown value does not take effect until you set or save it.

I wasn't expecting:

INS DEL key: 
            value: 

If I then save the customization, test-custom is ("" . "").  I think it
should instead be nil.

I noticed this on excorporate-configuration, which has:

(defcustom test-custom nil "" :type
  '(choice (const :tag "auto" nil)
           (alist
	    :key-type (string :tag "key")
	    :value-type (string :tag "value"))))

but where the alist is a large nested structure.  If the user
customizes, test-custom, selects the alist, and saves, the structure has
degenerate ("" . ""), or (nil . nil) entries in it.  To avoid this, the
user would have to hit "DEL" on the empty key/value entries, which is
not ideal.

It seems like after a const is shown, Customize considers the variable
"edited".  I don't know why it is adding those extra INS/DEL key/value
UI boxes though.

Thomas