From 7415dd020ec2b4eddb528040d366f67ead7d2564 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 09:30:51 +0000 Subject: [PATCH] =?UTF-8?q?tcl:=20Phase=206a=20fix=20vwait=20::=20routing?= =?UTF-8?q?=20=E2=80=94=20was=20infinite-looping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vwait used frame-lookup which doesn't honor `::` global routing. So `vwait ::done` after `set ::done fired` (where set routes to root frame) never saw the var change in the local frame, looping forever. Added tcl-vwait-lookup helper that mirrors tcl-var-get's `::` routing but returns nil instead of erroring on missing vars. Was the deadlock that hung the full test suite past test 32. Co-Authored-By: Claude Sonnet 4.6 --- lib/tcl/runtime.sx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/tcl/runtime.sx b/lib/tcl/runtime.sx index 48861596..b1665224 100644 --- a/lib/tcl/runtime.sx +++ b/lib/tcl/runtime.sx @@ -3544,6 +3544,22 @@ (tcl-event-step interp (- target-ms now)) target-ms))))) +; Look up a Tcl var by name, returning nil instead of erroring if missing. +; Handles `::var` global-prefix routing the same way tcl-var-get does. +(define + tcl-vwait-lookup + (fn + (interp name) + (if + (tcl-global-ref? name) + (let + ((root-frame + (let ((stack (get interp :frame-stack))) + (if (= 0 (len stack)) (get interp :frame) (first stack)))) + (gname (tcl-strip-global name))) + (frame-lookup root-frame gname)) + (frame-lookup (get interp :frame) name)))) + (define tcl-cmd-vwait (fn @@ -3554,7 +3570,7 @@ (let ((name (first args))) (let - ((initial (frame-lookup (get interp :frame) name))) + ((initial (tcl-vwait-lookup interp name))) (assoc (tcl-vwait-loop interp name initial) :result "")))))) (define @@ -3562,7 +3578,7 @@ (fn (interp name initial) (let - ((cur (frame-lookup (get interp :frame) name))) + ((cur (tcl-vwait-lookup interp name))) (if (and (not (nil? cur)) (not (equal? cur initial))) interp