[latex3-commits] [latex3/latex3] main: Ensure that all l3prop functions correctly check variable scopes (c512f5b16)

github at latex-project.org github at latex-project.org
Tue Feb 13 15:20:08 CET 2024


Repository : https://github.com/latex3/latex3
On branch  : main
Link       : https://github.com/latex3/latex3/commit/c512f5b163fff77a7987b9990611f5717b42e352

>---------------------------------------------------------------

commit c512f5b163fff77a7987b9990611f5717b42e352
Author: Bruno Le Floch <blflatex at gmail.com>
Date:   Sun Feb 11 23:52:52 2024 +0100

    Ensure that all l3prop functions correctly check variable scopes
    
    Since some l3prop functions such as \prop_put_from_keyval:Nn use
    others repeatedly, one has to make it so that none of the underlying
    code runs any debug check (by using lower-level \cs_set_nopar:Npe
    etc), and add a lot of prop functions to the list of patched
    commands in l3debug.


>---------------------------------------------------------------

c512f5b163fff77a7987b9990611f5717b42e352
 l3kernel/l3debug.dtx             |  26 ++++
 l3kernel/l3prop.dtx              | 261 ++++++++++++++++-----------------------
 l3kernel/testfiles/m3prop005.tlg |   2 +-
 3 files changed, 136 insertions(+), 153 deletions(-)

diff --git a/l3kernel/l3debug.dtx b/l3kernel/l3debug.dtx
index 7136fd5c2..4189cf747 100644
--- a/l3kernel/l3debug.dtx
+++ b/l3kernel/l3debug.dtx
@@ -720,6 +720,8 @@
     {
       \clist_concat:NNN
       \clist_gconcat:NNN
+      \prop_concat:NNN
+      \prop_gconcat:NNN
       \seq_concat:NNN
       \seq_gconcat:NNN
       \str_concat:NNN
@@ -774,6 +776,17 @@
       \muskip_add:Nn
       \muskip_sub:Nn
       \muskip_set_eq:NN
+      \prop_clear:N
+      \prop_concat:NNN
+      \prop_pop:NnN
+      \prop_pop:NnNT
+      \prop_pop:NnNF
+      \prop_pop:NnNTF
+      \prop_put:Nnn
+      \prop_put_if_new:Nnn
+      \prop_put_from_keyval:Nn
+      \prop_remove:Nn
+      \prop_set_eq:NN
       \seq_set_eq:NN
       \skip_zero:N
       \skip_set:Nn
@@ -843,6 +856,17 @@
       \muskip_gadd:Nn
       \muskip_gsub:Nn
       \muskip_gset_eq:NN
+      \prop_gclear:N
+      \prop_gconcat:NNN
+      \prop_gpop:NnN
+      \prop_gpop:NnNT
+      \prop_gpop:NnNF
+      \prop_gpop:NnNTF
+      \prop_gput:Nnn
+      \prop_gput_if_new:Nnn
+      \prop_gput_from_keyval:Nn
+      \prop_gremove:Nn
+      \prop_gset_eq:NN
       \seq_gset_eq:NN
       \skip_gzero:N
       \skip_gset:Nn
@@ -890,6 +914,8 @@
       \int_const:Nn
       \intarray_const_from_clist:Nn
       \muskip_const:Nn
+      \prop_const_from_keyval:Nn
+      \prop_const_linked_from_keyval:Nn
       \skip_const:Nn
       \str_const:Nn
       \tl_const:Nn
diff --git a/l3kernel/l3prop.dtx b/l3kernel/l3prop.dtx
index 58dd37f72..39f8f2386 100644
--- a/l3kernel/l3prop.dtx
+++ b/l3kernel/l3prop.dtx
@@ -1235,69 +1235,52 @@
 % \end{variable}
 % \end{variable}
 %
-% \begin{variable}{\l_@@_internal_prop}
-%   Used in functions that require adding items one by one and checking
-%   duplicates, like \cs{prop_concat:NNN} or \cs{prop_set_from_keyval:Nn}.  To
-%   efficiently search for items, this is a linked prop.  Because
-%   \cs{prop_clear:N} is not so immediate even on an empty linked prop, we make
-%   sure to empty it after every time it is used.  Other reasons are to save
-%   some memory and to avoid that each use would affect the timing of the next
-%   use in confusing ways.
-%    \begin{macrocode}
-\prop_new_linked:N \l_@@_internal_prop
-%    \end{macrocode}
-% \end{variable}
-%
 % \begin{macro}
 %   {
 %     \prop_concat:NNN, \prop_concat:ccc,
-%     \prop_gconcat:NNN, \prop_gconcat:ccc, \@@_concat:NNNNNN
+%     \prop_gconcat:NNN, \prop_gconcat:ccc,
+%     \@@_concat:NNNNN, \@@_concat:nNNN
 %   }
-%   Combine two property lists.  We must beware of duplicate keys
-%   between the two property lists.  The basic idea of
-%   \cs{@@_concat:NNNNNN} is to copy the first prop |#5| into the target
-%   |#4| (converting as needed between flat and linked props), and then
-%   loop through the second prop |#6| (with \cs{@@_concat:NNN}), calling
-%   \cs[index=prop_put:Nnn]{prop_(g)put:Nnn}.  We work directly with the
-%   target prop |#4| as a scratch space, because copying over from a
-%   temporary \cs{l_@@_internal_prop} to |#4| would be slow in the
-%   linked case.  If |#6| is |#4| itself we have to be careful not to
-%   lose the data.  We could expand |#6| in advance, but instead we
-%   optimize by treating this case separately, avoiding an unnecessary
-%   copy; we use \cs[index=prop_put_if_new:Nnn]{prop_(g)put_if_new:Nnn}
-%   to keep the correct version of duplicate keys.  There is no need to
-%   check for the case where |#4| is equal to~|#5| because in that case
-%   the line |#1| |#4| |#5|, namely
-%   \cs[index=prop_set_eq:NN]{prop_(g)set_eq:NN} |#4| |#5| is correctly
-%   set up to do no needless work.
+%   The basic strategy is to copy the first variable into the target,
+%   then loop through the second variable, calling
+%   \cs[index=prop_put:Nnn]{prop_(g)put:Nnn} on each item.  To avoid
+%   running the \pkg{l3debug} scope checks on each of these steps, we
+%   use the auxiliaries that underly \cs{prop_set_eq:NN} and
+%   \cs{prop_put:Nnn}, whose syntax is a bit unwieldy.
+%   We work directly with the target prop |#3| as a scratch space,
+%   because copying over from a temporary variable to |#3| would be slow
+%   in the linked case.  If |#5| is |#3| itself we have to be careful
+%   not to lose the data, and we even take the opportunity to skip the
+%   copying step completely.  To keep the correct version of the
+%   duplicate keys we use the code underlying \cs{prop_put_if_new:Nnn},
+%   which involves passing \cs{use_none:nnn} to the auxiliary instead of
+%   nothing.
+%   There is no need to check for the case where |#3| is equal to~|#4|
+%   because in that case \cs[index=prop_set_eq:NN]{prop_(g)set_eq:NN}
+%   |#3| |#4| (or rather the underlying auxiliary) is correctly set up
+%   to do no needless work.
 %    \begin{macrocode}
 \cs_new_protected:Npn \prop_concat:NNN
-  {
-    \@@_concat:NNNNNN
-      \prop_set_eq:NN \prop_put:Nnn \prop_put_if_new:Nnn
-  }
+  { \@@_concat:NNNNN \cs_set_eq:NN \cs_set_nopar:Npe }
 \cs_generate_variant:Nn \prop_concat:NNN { ccc }
 \cs_new_protected:Npn \prop_gconcat:NNN
-  {
-    \@@_concat:NNNNNN
-      \prop_gset_eq:NN \prop_gput:Nnn \prop_gput_if_new:Nnn
-  }
+  { \@@_concat:NNNNN \cs_gset_eq:NN \cs_gset_nopar:Npe }
 \cs_generate_variant:Nn \prop_gconcat:NNN { ccc }
-\cs_new_protected:Npn \@@_concat:NNNNNN #1#2#3#4#5#6
+\cs_new_protected:Npn \@@_concat:NNNNN #1#2#3#4#5
   {
-    \cs_if_eq:NNTF #4 #6
-      { \@@_concat:NNN #3 #4 #5 }
+    \cs_if_eq:NNTF #3 #5
+      { \@@_concat:nNNN \use_none:nnn #2 #3 #4 }
       {
-        #1 #4 #5
-        \@@_concat:NNN #2 #4 #6
+        \@@_set_eq:NNNN #1 #2 #3 #4
+        \@@_concat:nNNN { } #2 #3 #5
       }
   }
-\cs_new_protected:Npn \@@_concat:NNN #1#2#3
+\cs_new_protected:Npn \@@_concat:nNNN #1#2#3#4
   {
     \cs_gset_eq:NN \@@_tmp:w \@@_pair:wn
     \cs_gset_protected:Npn \@@_pair:wn ##1 \s_@@
-      { #1 #2 {##1} }
-    \exp_last_unbraced:Nf \use_none:nn #3
+      { \@@_put:nNNnn {#1} #2 #3 {##1} }
+    \exp_last_unbraced:Nf \use_none:nn #4
     \cs_gset_eq:NN \@@_pair:wn \@@_tmp:w
   }
 %    \end{macrocode}
@@ -1307,57 +1290,36 @@
 %   {
 %     \prop_put_from_keyval:Nn, \prop_put_from_keyval:cn,
 %     \prop_gput_from_keyval:Nn, \prop_gput_from_keyval:cn,
-%     \@@_from_keyval:NNNn, \@@_from_keyval:nnn, \@@_from_keyval:Nnnn,
+%     \@@_from_keyval:nn, \@@_from_keyval:Nnn,
 %     \@@_missing_eq:n
 %   }
 %   The core is a call to \cs{keyval_parse:nnn}, with an error message
-%   \cs{@@_missing_eq:n} for entries without~|=|, and a call to
+%   \cs{@@_missing_eq:n} for entries without~|=|, and a call to (essentially)
 %   \cs[index=prop_put:Nnn]{prop_(g)put:Nnn} for valid key--value pairs.
+%   To avoid repeated scope checks (and errors) when \pkg{l3debug} is
+%   active, we instead use the auxiliary underlying \cs{prop_put:Nnn}.
 %   Because blank keys are valid here, in contrast to \pkg{l3keys}, we set and
-%   restore \cs{l__kernel_keyval_allow_blank_keys_bool}.  The trailing |#2| in
-%   the definition of \cs{@@_from_keyval:Nnnn} (first argument of
-%   \cs{@@_from_keyval:nnn}) is some code to place the result of all of these
-%   \cs[index=prop_put:Nnn]{prop_(g)put:Nnn} in the correct variable.
-%
-%   There are two cases.  If the target prop is a linked prop then we do all of
-%   the additions directly there, and the aforementioned |#2| is empty.  If the
-%   target prop is a flat prop then we do the work in \cs{l_@@_internal_prop}
-%   (after copying the original variable into it), and then the clean-up
-%   code~|#2| consists of copying the result back into the original variable and
-%   emptying \cs{l_@@_internal_prop}.
+%   restore \cs{l__kernel_keyval_allow_blank_keys_bool}.
+%   The key--value argument may be quite large so we avoid reading it until it
+%   is really necessary.
 %    \begin{macrocode}
-\cs_new_protected:Npn \prop_put_from_keyval:Nn
-  { \@@_from_keyval:NNNn \prop_set_eq:NN \prop_put:Nnn }
+\cs_new_protected:Npn \prop_put_from_keyval:Nn #1
+  { \@@_from_keyval:nn { \@@_put:nNNnn { } \cs_set_nopar:Npe #1 } }
 \cs_generate_variant:Nn \prop_put_from_keyval:Nn { c }
-\cs_new_protected:Npn \prop_gput_from_keyval:Nn
-  { \@@_from_keyval:NNNn \prop_gset_eq:NN \prop_gput:Nnn }
+\cs_new_protected:Npn \prop_gput_from_keyval:Nn #1
+  { \@@_from_keyval:nn { \@@_put:nNNnn { } \cs_gset_nopar:Npe #1 } }
 \cs_generate_variant:Nn \prop_gput_from_keyval:Nn { c }
-\cs_new_protected:Npn \@@_from_keyval:NNNn #1#2#3
-  {
-    \@@_if_flat:NTF #3
-      {
-        \prop_set_eq:NN \l_@@_internal_prop #3
-        \@@_from_keyval:nnn
-          {
-            #1 #3 \l_@@_internal_prop
-            \prop_clear:N \l_@@_internal_prop
-          }
-          { \prop_put:Nnn \l_@@_internal_prop }
-      }
-      { \@@_from_keyval:nnn { } { #2 #3 } }
-  }
-\cs_new_protected:Npn \@@_from_keyval:nnn
+\cs_new_protected:Npn \@@_from_keyval:nn
   {
     \bool_if:NTF \l__kernel_keyval_allow_blank_keys_bool
-      { \@@_from_keyval:Nnnn \c_true_bool }
-      { \@@_from_keyval:Nnnn \c_false_bool }
+      { \@@_from_keyval:Nnn \c_true_bool }
+      { \@@_from_keyval:Nnn \c_false_bool }
   }
-\cs_new_protected:Npn \@@_from_keyval:Nnnn #1#2#3#4
+\cs_new_protected:Npn \@@_from_keyval:Nnn #1#2#3
   {
     \bool_set_eq:NN \l__kernel_keyval_allow_blank_keys_bool \c_true_bool
-    \keyval_parse:nnn \@@_missing_eq:n {#3} {#4}
+    \keyval_parse:nnn \@@_missing_eq:n {#2} {#3}
     \bool_set_eq:NN \l__kernel_keyval_allow_blank_keys_bool #1
-    #2
   }
 \cs_new_protected:Npn \@@_missing_eq:n
   { \msg_error:nnn { prop } { prop-keyval } }
@@ -1369,58 +1331,48 @@
 %     \prop_set_from_keyval:Nn, \prop_set_from_keyval:cn,
 %     \prop_gset_from_keyval:Nn, \prop_gset_from_keyval:cn,
 %   }
-%   Just empty the prop and push key--value entries using
+%   Just empty the prop (with the auxiliary underlying
+%   \cs{prop_clear:N} to avoid \pkg{l3debug} problems) and push
+%   key--value entries using
 %   \cs[index=prop_put_from_keyval:Nn]{prop_(g)put_from_keyval:Nn}.
 %    \begin{macrocode}
 \cs_new_protected:Npn \prop_set_from_keyval:Nn #1
   {
-    \prop_clear:N #1
+    \@@_clear:NNN \cs_set_eq:NN \cs_set_nopar:Npe #1
     \prop_put_from_keyval:Nn #1
   }
 \cs_generate_variant:Nn \prop_set_from_keyval:Nn { c }
 \cs_new_protected:Npn \prop_gset_from_keyval:Nn #1
   {
-    \prop_gclear:N #1
+    \@@_clear:NNN \cs_gset_eq:NN \cs_gset_nopar:Npe #1
     \prop_gput_from_keyval:Nn #1
   }
 \cs_generate_variant:Nn \prop_gset_from_keyval:Nn { c }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\prop_const_from_keyval:Nn, \prop_const_from_keyval:cn}
-%   We recall \cs{l_@@_internal_prop} is always correctly emptied.  Here we add
-%   key--value entries to it, then make a constant using \cs{tl_const:Ne}.
-%   It would also be possible to replace the first line by
-%   \cs{prop_set_from_keyval:Nn} \cs{l_@@_internal_prop} |{#2}| but that seems
-%   more likely to break if we change other code, since \cs{l_@@_internal_prop}
-%   is used in \cs{prop_set_from_keyval:Nn} itself.
+% \begin{macro}
+%   {
+%     \prop_const_from_keyval:Nn, \prop_const_from_keyval:cn,
+%     \prop_const_linked_from_keyval:Nn, \prop_const_linked_from_keyval:cn
+%   }
+%   For both flat and linked constant props, we create |#1| then use the
+%   same auxiliary as for \cs{prop_gput_from_keyval:Nn}.  It is most
+%   natural to use the already packaged \cs{prop_gput:Nnn}, but that
+%   would mean doing an assignment on a supposedly constant property
+%   list.  To avoid errors when \pkg{l3debug} is activated, we use the
+%   auxiliary underlying \cs{prop_gput:Nnn}.
 %    \begin{macrocode}
-\cs_new_protected:Npn \prop_const_from_keyval:Nn #1#2
+\cs_new_protected:Npn \prop_const_from_keyval:Nn #1
   {
-    \@@_from_keyval:nnn { } { \prop_put:Nnn \l_@@_internal_prop } {#2}
-    \tl_const:Ne #1 { \@@_flatten:N \l_@@_internal_prop }
-    \prop_clear:N \l_@@_internal_prop
+    \prop_new:N #1
+    \@@_from_keyval:nn { \@@_put:nNNnn { } \cs_gset_nopar:Npe #1 }
   }
 \cs_generate_variant:Nn \prop_const_from_keyval:Nn { c }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-%   {\prop_const_linked_from_keyval:Nn, \prop_const_linked_from_keyval:cn}
-%   To avoid needing a slow \cs{prop_gset_eq:NN} for a linked prop we add items
-%   directly into~|#1| itself.  It is most convenient to use the already
-%   packaged \cs{prop_gput:Nnn}, but that means doing an assignment on a
-%   supposedly constant property list.  To avoid errors when \pkg{l3debug} is
-%   activated, we surround the problematic assignment with \cs{debug_suspend:}
-%   and \cs{debug_resume:}.  The latter is correctly placed at the end by
-%   \cs{@@_from_keyval:nnn}, which allows us to avoid needlessly grabbing the
-%   key--value argument, which may be a very large argument.
-%    \begin{macrocode}
 \cs_new_protected:Npn \prop_const_linked_from_keyval:Nn #1
   {
     \prop_new_linked:N #1
-    \debug_suspend:
-    \@@_from_keyval:nnn { \debug_resume: } { \prop_gput:Nnn #1 }
+    \@@_from_keyval:nn { \@@_put:nNNnn { } \cs_gset_nopar:Npe #1 }
   }
 \cs_generate_variant:Nn \prop_const_linked_from_keyval:Nn { c }
 %    \end{macrocode}
@@ -1631,7 +1583,7 @@
 %
 % \begin{macro}
 %   {
-%     \@@_pop:NnNNNnTF,
+%     \@@_pop:NnNNnTF,
 %     \@@_pop_linked:wnNNnTF, \@@_pop_linked:NNNn,
 %     \@@_pop_linked:w,
 %     \@@_pop_linked_prev:w, \@@_pop_linked_next:w
@@ -1653,18 +1605,18 @@
 %   three arguments \Arg{code} \Arg{true code} \Arg{false code} depending on
 %   whether the key--value is found, in the same way as for flat props.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_pop:NnNNNnTF #1#2#3#4#5#6#7#8
+\cs_new_protected:Npn \@@_pop:NnNNnTF #1#2#3#4#5#6#7
   {
     \@@_split:NnTFn #1 {#2}
       {
-        #3 #1 { \s_@@ \@@_chk:w ##2 ##4 }
-        #6 {##3}
-        #7
+        #4 #1 { \exp_not:n { \s_@@ \@@_chk:w ##2 ##4 } }
+        #5 {##3}
+        #6
       }
-      {#8}
+      {#7}
       {
         \exp_after:wN \@@_pop_linked:wnNNnTF #1 {#2}
-          #4 #5 {#6} {#7} {#8}
+          #3 #4 {#5} {#6} {#7}
       }
   }
 %    \end{macrocode}
@@ -1729,7 +1681,7 @@
 %     \prop_gremove:Nn, \prop_gremove:NV, \prop_gremove:Ne,
 %     \prop_gremove:cn, \prop_gremove:cV, \prop_gremove:ce
 %   }
-%   Deleting from a property relies on \cs{@@_pop:NnNNNnTF}.  The three
+%   Deleting from a property relies on \cs{@@_pop:NnNNnTF}.  The three
 %   assignment functions are suitably local or global.  The last three arguments
 %   are \cs{use_none:n} and two empty brace groups: if the key is found we get
 %   \cs{use_none:n} \Arg{key} \meta{empty}, which expands to nothing, and
@@ -1738,14 +1690,14 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \prop_remove:Nn #1#2
   {
-    \@@_pop:NnNNNnTF #1 {#2}
-      \tl_set:Nn \cs_set_eq:NN \cs_set_nopar:Npe
+    \@@_pop:NnNNnTF #1 {#2}
+      \cs_set_eq:NN \cs_set_nopar:Npe
       \use_none:n { } { }
   }
 \cs_new_protected:Npn \prop_gremove:Nn #1#2
   {
-    \@@_pop:NnNNNnTF #1 {#2}
-      \tl_gset:Nn \cs_gset_eq:NN \cs_gset_nopar:Npe
+    \@@_pop:NnNNnTF #1 {#2}
+      \cs_gset_eq:NN \cs_gset_nopar:Npe
       \use_none:n { } { }
   }
 \cs_generate_variant:Nn \prop_remove:Nn  { NV , Ne , c , cV , ce }
@@ -1775,14 +1727,14 @@
 %    \begin{macrocode}
 \cs_new_protected:Npn \prop_pop:NnN #1#2#3
   {
-    \@@_pop:NnNNNnTF #1 {#2}
-      \tl_set:Nn \cs_set_eq:NN \cs_set_nopar:Npe
+    \@@_pop:NnNNnTF #1 {#2}
+      \cs_set_eq:NN \cs_set_nopar:Npe
       { \tl_set:Nn #3 } { } { \tl_set:Nn #3 { \q_no_value } }
   }
 \cs_new_protected:Npn \prop_gpop:NnN #1#2#3
   {
-    \@@_pop:NnNNNnTF #1 {#2}
-      \tl_gset:Nn \cs_gset_eq:NN \cs_gset_nopar:Npe
+    \@@_pop:NnNNnTF #1 {#2}
+      \cs_gset_eq:NN \cs_gset_nopar:Npe
       { \tl_set:Nn #3 } { } { \tl_set:Nn #3 { \q_no_value } }
   }
 \cs_generate_variant:Nn \prop_pop:NnN  {     NV , No }
@@ -1791,14 +1743,14 @@
 \cs_generate_variant:Nn \prop_gpop:NnN { c , cV , co }
 \prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 { T , F , TF }
   {
-    \@@_pop:NnNNNnTF #1 {#2}
-      \tl_set:Nn \cs_set_eq:NN \cs_set_nopar:Npe
+    \@@_pop:NnNNnTF #1 {#2}
+      \cs_set_eq:NN \cs_set_nopar:Npe
       { \tl_set:Nn #3 } \prg_return_true: \prg_return_false:
   }
 \prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T , F , TF }
   {
-    \@@_pop:NnNNNnTF #1 {#2}
-      \tl_gset:Nn \cs_gset_eq:NN \cs_gset_nopar:Npe
+    \@@_pop:NnNNnTF #1 {#2}
+      \cs_gset_eq:NN \cs_gset_nopar:Npe
       { \tl_set:Nn #3 } \prg_return_true: \prg_return_false:
   }
 \prg_generate_conditional_variant:Nnn \prop_pop:NnN
@@ -1855,26 +1807,31 @@
 %     \@@_put_linked_new:w
 %   }
 %   All of the \cs[no-index]{prop_(g)put(_if_new):Nnn} functions are
-%   based on the same auxiliary, which receives \meta{code} and two
-%   \enquote{assignments}, followed by \meta{prop} \Arg{key} \Arg{new
-%   value}.  The first assignment
-%   \cs[index=__kernel_tl_set:Nx]{__kernel_tl_(g)set:Nx} is used for
-%   flat props, and it is subject to the debug options, while the second
+%   based on the same auxiliary, which receives \meta{code} and an
+%   \enquote{assignment}, followed by \meta{prop} \Arg{key} \Arg{new
+%   value}.  The
 %   assignment \cs[index=cs_set_nopar:Npe]{cs_(g)set_nopar:Npe} is the
-%   primitive assignment without any checking: it is applied to individual
+%   primitive assignment without any checking: in the case of linked
+%   props it is applied to individual
 %   pieces of the linked prop, which are typically not yet defined.
+%   Debugging the scope of the variable is done at a higher level by
+%   letting \pkg{l3debug} change \cs{prop_put:Nnn} and friends.  This
+%   allows other \pkg{l3prop} commands to directly call the underlying
+%   auxiliary to skip this checking step and avoid getting multiple
+%   error messages for the same error.
 %   The \meta{code} (empty for |put| and \cs{use_none:nnn} for
 %   |put_if_new|) is placed before the assignment in cases where the key
-%   is already present.
+%   is already present, in order to suppress the assignment in the
+%   |put_if_new| case.
 %    \begin{macrocode}
 \cs_new_protected:Npn \prop_put:Nnn
-  { \@@_put:nNNNnn { } \__kernel_tl_set:Nx \cs_set_nopar:Npe }
+  { \@@_put:nNNnn { } \cs_set_nopar:Npe }
 \cs_new_protected:Npn \prop_gput:Nnn
-  { \@@_put:nNNNnn { } \__kernel_tl_gset:Nx \cs_gset_nopar:Npe }
+  { \@@_put:nNNnn { } \cs_gset_nopar:Npe }
 \cs_new_protected:Npn \prop_put_if_new:Nnn
-  { \@@_put:nNNNnn \use_none:nnn \__kernel_tl_set:Nx \cs_set_nopar:Npe }
+  { \@@_put:nNNnn \use_none:nnn \cs_set_nopar:Npe }
 \cs_new_protected:Npn \prop_gput_if_new:Nnn
-  { \@@_put:nNNNnn \use_none:nnn \__kernel_tl_gset:Nx \cs_gset_nopar:Npe }
+  { \@@_put:nNNnn \use_none:nnn \cs_gset_nopar:Npe }
 \cs_generate_variant:Nn \prop_put:Nnn
   {
          NnV , Nnv , Nne , NV , NVV , NVv , NVe ,
@@ -1926,23 +1883,23 @@
 %   \cs{@@_put_linked_new:w}, otherwise it was already there and we use
 %   \cs{@@_put_linked_old:w}.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_put:nNNNnn #1#2#3#4#5#6
+\cs_new_protected:Npn \@@_put:nNNnn #1#2#3#4#5
   {
     \tl_set:Nn \l_@@_internal_tl
       {
-        \exp_not:N \@@_pair:wn \tl_to_str:n {#5}
-        \s_@@ { \exp_not:n {#6} }
+        \exp_not:N \@@_pair:wn \tl_to_str:n {#4}
+        \s_@@ { \exp_not:n {#5} }
       }
-    \@@_split:NnTFn #4 {#5}
+    \@@_split:NnTFn #3 {#4}
       {
-        #1 #2 #4
+        #1 #2 #3
           {
             \s_@@ \@@_chk:w \exp_not:n {##2}
             \l_@@_internal_tl \exp_not:n {##4}
           }
       }
-      { #2 #4 { \exp_not:o {#4} \l_@@_internal_tl } }
-      { \exp_after:wN \@@_put_linked:wnnN #4 {#5} {#1} #3 }
+      { #2 #3 { \exp_not:o {#3} \l_@@_internal_tl } }
+      { \exp_after:wN \@@_put_linked:wnnN #3 {#4} {#1} #2 }
   }
 \cs_new_protected:Npn \@@_put_linked:wnnN
     \@@_flatten:w #1 \s_@@ #2#3#4
diff --git a/l3kernel/testfiles/m3prop005.tlg b/l3kernel/testfiles/m3prop005.tlg
index 7c89893e7..d4eca4576 100644
--- a/l3kernel/testfiles/m3prop005.tlg
+++ b/l3kernel/testfiles/m3prop005.tlg
@@ -88,6 +88,7 @@ Try typing <return> to proceed.
 If that doesn't work, type X <return> to quit.
 The property list \g_tmpa_prop is empty
 > .
+Defining \c_B_prop on line ...
 ! Use of \??? doesn't match its definition.
 <argument> \???  
                  ! LaTeX Error: Misplaced '=' in key-value input on line ...
@@ -118,7 +119,6 @@ l. ...  }
 LaTeX does not know anything more about this error, sorry.
 Try typing <return> to proceed.
 If that doesn't work, type X <return> to quit.
-Defining \c_B_prop on line ...
 The property list \c_B_prop is empty
 > .
 ============================================================





More information about the latex3-commits mailing list.