Ticket UUID: | ecf35c71200d782cbd63e15c4df80b5e3c75cbd4 | |||
Title: | [return]: broken ordering of nested -options | |||
Type: | Bug | Version: | 8.5+ | |
Submitter: | dgp | Created on: | 2025-06-20 15:33:36 | |
Subsystem: | 45. Parsing and Eval | Assigned To: | dgp | |
Priority: | 5 Medium | Severity: | Important | |
Status: | Closed | Last Modified: | 2025-06-24 16:24:36 | |
Resolution: | Fixed | Closed By: | dgp | |
Closed on: | 2025-06-24 16:24:36 | |||
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-24 16:24:36:
Fix accepted into the 9.0 branch dgp added on 2025-06-23 19:59:06: A pending fix is committed to the bugfix branch. 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-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-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. |
