| Ticket UUID: | ecf35c71200d782cbd63e15c4df80b5e3c75cbd4 | ||
| Title: | [return]: broken ordering of nested -options | ||
| Type: | Bug | Created on: | 2025-06-20 15:33:36 |
| Submitter: | dgp | Assigned to: | dgp |
| Subsystem: | 45. Parsing and Eval | Severity: | Important |
| Priority: | 5 Medium | Last modified: | 2025-06-24 16:24:36 |
| Status: | Closed | Closed by: | dgp |
| Resolution: | Fixed | Closed on: | 2025-06-24 16:24:36 |
| Version: | 8.5+ | ||
| Description: | ||||
While out on an arduous hunt for a memory leak, I noticed that
the coding of TclMergeReturnOptions() contains an ordering error
which can be demonstrated in an interactive session:
% catch {return -level 0 -options {-options {-code break} -code ok}} m o
3
% set o
-code 3 -level 0
| ||||
| User Comments: | ||||
dgp added on 2025-06-20 15:46:49:
The documentation says:
-options options
The value options must be a valid dictionary. The entries of
that dictionary are treated as additional option value pairs
for the return command.
While an explicit ordering guarantee is not stated, the description
suggests a lifting of the dictionary entries out of the dictionary
to enter the options alongside the other options.
This is the same kind of expansion offered by the {*} syntax, but
the -options option debuted at the same time as that syntax, when
reliance on it was unclear.
An explicit aim was to enable a re-raising pattern:
catch $script m o
return -options $o $m
Had the {*} syntax been better established at the time, we might
have gone without -options and prescribed:
catch $script m 0
return {*}$o $m
Whatever precise mental model is in use, we expect later appearances
of the same option to overwrite earlier ones, so that we reason:
return -level 0 -options {-options {-code break} -code ok}
is same as
return -level 0 -options {-code break} -code ok
is same as
return -level 0 -code break -code ok
is same as
return -level 0 -code ok
and that's not what Tcl is doing.
Nested options are rare. A single test even attempts it
(cmdMZ-return-2.14), but doesn't illustrate the bug.
Not noticed for all this time.
dgp added on 2025-06-20 15:50:24:
Note that only nesting brings out the trouble.
A single level of -options behaves properly
% catch {return -level 0 -options {-code break} -code ok} m o
0
% set o
-code 0 -level 0
dgp added on 2025-06-23 17:42:17:
Branch bug-ecf35c7120 is open to address this ticket. So far it includes
tests demonstrating the problem. Briefly, processing so that the -options
switch emulates {*} argument expansion is not consistent with standard
dictionary creation processing in the handling of duplicate keys.
dgp added on 2025-06-23 19:59:06:
A pending fix is committed to the bugfix branch. dgp added on 2025-06-24 16:24:36:
Fix accepted into the 9.0 branch | ||||
