From: <no...@so...> - 2002-10-31 20:12:13
|
Bugs item #631741, was opened at 2002-10-31 15:12 You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=110894&aid=631741&group_id=10894 Category: 07. Variables Group: 8.4.1 Status: Open Resolution: None Priority: 5 Submitted By: Chris Darroch (cdarroch) Assigned to: miguel sofer (msofer) Summary: "variable" can't not call var resolvers Initial Comment: This is perhaps much more of an [incr Tcl] bug. I submitted it in that project first; see bug #631735. However, I thought I'd raise the issue here too, in case it was important in some other context. (If not, my apologies.) The essence of the issue is that the change in tclVar.c to make the new ObjMakeUpvar() function call TclLookupSimpleVar(), which in turn always calls any registered variable resolver functions, make it very difficult (maybe impossible?) for the "variable" command to create a new local variable and link it to a namespace variable, if a registered package like [incr Tcl]'s variable resolver normally makes the namespace variable visible in a local procedure scope. When using the latest (post-3.2.1) CVS version of [incr Tcl] with Tcl 8.4.1, the 5.6a test from the basic.test file fails due to a new, deep change to the tclVar.c file. Specifically, the test fails with the message "can't upvar from variable to itself". (Note also that there are two 5.6a tests; the first one is the one that fails. In the suggested patch below, the second one is renamed 5.6b.) A simple test case is the following: package require Itcl itcl::class test_globals { common foo goo proc getval {name} { variable $name return [set [namespace tail $name]] } } test_globals::getval foo Removing the "variable $name" command causes this test to work. A suggested patch for the [incr Tcl] test suite is shown in bug #631735. After some examination of the problem, this seems to me to be the preferred route, because I can't see any way to restore the old behaviour of the "variable" command with 8.4.1 without altering the tclVar.c file's functions considerably. The reason for the failure is that in tclVar.c, the MakeUpvar() function has been replaced in 8.4.1 with the ObjMakeUpvar() function. Further, this function no longer duplicates some code from TclLookupVar(), but instead, both functions now use the common TclLookupSimpleVar() function. TclLookupSimpleVar() is also used by TclObjLookupVar(). The TclLookupSimpleVar() function always calls the namespace's variable resolver(s) -- in this case, Itcl_ClassVarResolver() from [incr Tcl]'s itcl_class.c. Previously, MakeUpvar() did not call the variable resolver(s), but simply looked for local variables using similar code as appeared in TclLookupVar() -- except for the calls to the variable resolver(s). This is important because ObjMakeUpvar() -- previously MakeUpvar() -- is called by the Tcl_VariableObjCmd() function that handles the "variable" command, to create a link between a local variable and a namespace variable. Formerly, because MakeUpvar() did not call the Itcl_ClassVarResolver(), it would find no local variable when handling the test case shown above, and could proceed to create a local variable as a link to the namespace variable "foo", created by the "common" command. In Tcl 8.4.1, though, ObjMakeUpvar() calls the TclLookupSimpleVar() function to locate and create or replace the local variable that ObjMakeUpvar() wants to turn into a link to the namespace variable. The TclLookupSimpleVar() function calls the Itcl_ClassVarResolver() function, which of course finds no local variable named "foo" and proceeds to locate and return the namespace variable named "foo" that was created with the "common" command. ObjMakeUpvar() has also recieved a pointer to this same variable from Tcl_VariableObjCmd(), which used the TclObjLookupVar() function to locate the namespace variable to be linked to. And TclObjLookupVar() also called TclLookupSimpleVar(), which in turn called Itcl_ClassVarResolver(). So the ObjMakeUpvar() function now has two identical pointers for the namespace and local variables, and refuses to try to make a link. The only way I can see to resolve this is to alter the functions in tclVar.c to pass down some kind of flag that would allow Itcl_ClassVarResolver() to determine this specific case. It can't rely on !(flags & TCL_NAMESPACE_ONLY) because that may or may not be set in various combinations, depending on the caller -- specifically, Tcl_FindNamespaceVar() in tclNamesp.c calls the variable resolver function(s) too. Nor can it rely on varFramePtr->isProcCallFrame because that doesn't clarify which chain of functions is calling TclLookupSimpleVar() or Tcl_FindNamespaceVar() -- these are the two functions that can call the variable resolver(s), but they are in turn called in various contexts. We'd have to specifically catch the case of Tcl_VariableObjCmd() -> ObjMakeUpvar() -> TclLookupSimpleVar() -> Itcl_ClassVarResolver(), and specifically not catch the case of Tcl_VariableObjCmd() -> TclObjLookupVar() -> TclLookupSimpleVar() -> Itcl_ClassVarResolver(). All of this does raise one other small questions, which is whether the code in Itcl_ClassVarResolver() that looks for local variables, and is duplicated from portions of the old TclLookupVar() function (now that code has been moved into TclLookupSimpleVar() and altered), should be updated. For example, TclLookupSimpleVar() doesn't perform this logic if TCL_NAMESPACE_ONLY is passed. However, when Tcl_FindNamespaceVar() is calling Itcl_ClassVarResolver(), TCL_NAMESPACE_ONLY could be true or false -- so I don't see an obvious way to check it within Itcl_ClassVarResolver(), without having some additional context flags -- a similar issue as to the one discussed above. Well, hope that all helps someone. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=110894&aid=631741&group_id=10894 |