Index: TODO =================================================================== diff -u -r3fd99736ac596563e18a0f8c242f2da4fc0cb2bf -r3e18b80be2883ba647c2110a2e8e2b1980940c30 --- TODO (.../TODO) (revision 3fd99736ac596563e18a0f8c242f2da4fc0cb2bf) +++ TODO (.../TODO) (revision 3e18b80be2883ba647c2110a2e8e2b1980940c30) @@ -3361,7 +3361,7 @@ * integrated "-local" and fully qualified handling with ObjectDispatch to ensure proper behavior of mixins/next etc. * added "/obj/ -local ..." similar to "/obj/ -system ..." - * added "nsf::object::disapatch /obj/ -local ..." similar to "/obj/ -local ..." + * added "nsf::object::dispatch /obj/ -local ..." similar to "/obj/ -local ..." * extended regression test (next from -local, fully qualified names, private methods, "...dispatch -local") * provide error message for "/obj/ -system" @@ -3372,7 +3372,13 @@ when obj has a method named "method". * extended regression test +- nsf.c: + * added "/obj/ -intrinsic ..." similar to "/obj/ -system ..." + * added "nsf::my /obj/ -intrinsic ..." similar to "/obj/ -intrinsic ..." + * added "nsf::object::dispatch /obj/ -intrinsic ..." similar to "/obj/ -intrinsic ..." + * extended regression test + TODO: - fix interp.test for tcl 8.6 - fix xocomm.test for tcl 8.6 Index: generic/nsf.c =================================================================== diff -u -ra695cb72c6594bae8b7abb49b76c0ee7b5367b7f -r3e18b80be2883ba647c2110a2e8e2b1980940c30 --- generic/nsf.c (.../nsf.c) (revision a695cb72c6594bae8b7abb49b76c0ee7b5367b7f) +++ generic/nsf.c (.../nsf.c) (revision 3e18b80be2883ba647c2110a2e8e2b1980940c30) @@ -9382,6 +9382,9 @@ } else if (strcmp(methodName + 1, "local") == 0) { flags |= NSF_CM_LOCAL_METHOD; shift = 2; + } else if (strcmp(methodName + 1, "intrinsic") == 0) { + flags |= NSF_CM_INTRINSIC_METHOD; + shift = 2; } else { shift = 1; } @@ -9540,7 +9543,7 @@ * Check if a mixed in method has to be called. */ if ((objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) == NSF_MIXIN_ORDER_DEFINED_AND_VALID - && (flags & NSF_CM_SYSTEM_METHOD) == 0 + && (flags & (NSF_CM_SYSTEM_METHOD|NSF_CM_INTRINSIC_METHOD)) == 0 && ((flags & NSF_CM_LOCAL_METHOD) == 0 || cl)) { /* @@ -12391,17 +12394,17 @@ } /* - * Next in Mixins + * Next in Mixins requires that we have already a mixinStack, and the + * current frame is not a plain frame. */ assert(objflags & NSF_MIXIN_ORDER_VALID); - /* otherwise: MixinComputeDefined(interp, object); */ - /*fprintf(stderr, "... mixinstack %p => %p\n", object, object->mixinStack);*/ - - if (object->mixinStack) { + if (object->mixinStack && cscPtr->frameType) { int result = MixinSearchProc(interp, object, *methodNamePtr, NULL, clPtr, currentCmdPtr, cmdPtr); + /* fprintf(stderr, "next in mixins %s frameType %.6x\n", *methodNamePtr, cscPtr->frameType); */ + if (unlikely(result != TCL_OK)) { return result; } @@ -18040,11 +18043,11 @@ } - /* cmd "object::dispatch" NsfObjectDispatchCmd { {-argName "object" -required 1 -type object} {-argName "-frame" -required 0 -nrargs 1 -type "method|object|default" -default "default"} + {-argName "-intrinsic" -required 0 -nrargs 0} {-argName "-local" -required 0 -nrargs 0} {-argName "-system" -required 0 -nrargs 0} {-argName "command" -required 1 -type tclobj} @@ -18053,7 +18056,7 @@ */ static int NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, - int withFrame, int withLocal, int withSystem, + int withFrame, int withIntrinsic, int withLocal, int withSystem, Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]) { int result; CONST char *methodName = ObjStr(command); @@ -18140,6 +18143,7 @@ methodName); } + if (withIntrinsic) {flags |= NSF_CM_INTRINSIC_METHOD;} if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} if (withLocal) {flags |= NSF_CM_LOCAL_METHOD;} @@ -18335,6 +18339,7 @@ /* cmd my NsfMyCmd { + {-argName "-intrinsic" -nrargs 0} {-argName "-local" -nrargs 0} {-argName "-system" -nrargs 0} {-argName "method" -required 1 -type tclobj} @@ -18343,8 +18348,8 @@ */ static int NsfMyCmd(Tcl_Interp *interp, - int withLocal, int withSystem, Tcl_Obj *methodObj, - int nobjc, Tcl_Obj *CONST nobjv[]) { + int withIntrinsic, int withLocal, int withSystem, + Tcl_Obj *methodObj, int nobjc, Tcl_Obj *CONST nobjv[]) { NsfObject *self = GetSelfObj(interp); int flags, result; @@ -18366,13 +18371,15 @@ fprintf(stderr, "XXX MY %s.%s frame has flags %.6x -> next-flags %.6x\n", ObjectName(self), ObjStr(methodObj), cscPtr->flags, flags); } - if (withLocal) {flags |= NSF_CM_LOCAL_METHOD;} - if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} + if (withIntrinsic) {flags |= NSF_CM_INTRINSIC_METHOD;} + if (withLocal) {flags |= NSF_CM_LOCAL_METHOD;} + if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} result = CallMethod(self, interp, methodObj, nobjc+2, nobjv, flags); #else flags = NSF_CSC_IMMEDIATE; - if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} - if (withLocal) {flags |= NSF_CM_LOCAL_METHOD;} + if (withIntrinsic) {flags |= NSF_CM_INTRINSIC_METHOD;} + if (withLocal) {flags |= NSF_CM_LOCAL_METHOD;} + if (withSystem) {flags |= NSF_CM_SYSTEM_METHOD;} result = CallMethod(self, interp, methodObj, nobjc+2, nobjv, flags); #endif Index: generic/nsfAPI.decls =================================================================== diff -u -rf67408d8e6f8ba9bdd6e4ec3c54dfa3a23576161 -r3e18b80be2883ba647c2110a2e8e2b1980940c30 --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision f67408d8e6f8ba9bdd6e4ec3c54dfa3a23576161) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision 3e18b80be2883ba647c2110a2e8e2b1980940c30) @@ -110,12 +110,13 @@ # object cmds # cmd "object::dispatch" NsfObjectDispatchCmd { - {-argName "object" -required 1 -type object} - {-argName "-frame" -required 0 -type "method|object|default" -default "default"} - {-argName "-local" -required 0 -nrargs 0} - {-argName "-system" -required 0 -nrargs 0} - {-argName "command" -required 1 -type tclobj} - {-argName "args" -type args} + {-argName "object" -required 1 -type object} + {-argName "-frame" -required 0 -type "method|object|default" -default "default"} + {-argName "-intrinsic" -required 0 -nrargs 0} + {-argName "-local" -required 0 -nrargs 0} + {-argName "-system" -required 0 -nrargs 0} + {-argName "command" -required 1 -type tclobj} + {-argName "args" -type args} } cmd "object::exists" NsfObjectExistsCmd { {-argName "value" -required 1 -type tclobj} @@ -138,10 +139,11 @@ } cmd my NsfMyCmd { - {-argName "-local" -nrargs 0} - {-argName "-system" -nrargs 0} + {-argName "-intrinsic" -nrargs 0} + {-argName "-local" -nrargs 0} + {-argName "-system" -nrargs 0} {-argName "methodName" -required 1 -type tclobj} - {-argName "args" -type args} + {-argName "args" -type args} } cmd next NsfNextCmd { {-argName "arguments" -required 0 -type tclobj} Index: generic/nsfAPI.h =================================================================== diff -u -rf67408d8e6f8ba9bdd6e4ec3c54dfa3a23576161 -r3e18b80be2883ba647c2110a2e8e2b1980940c30 --- generic/nsfAPI.h (.../nsfAPI.h) (revision f67408d8e6f8ba9bdd6e4ec3c54dfa3a23576161) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision 3e18b80be2883ba647c2110a2e8e2b1980940c30) @@ -345,11 +345,11 @@ static int NsfMethodPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodName, int methodproperty, Tcl_Obj *value); static int NsfMethodRegisteredCmd(Tcl_Interp *interp, Tcl_Obj *handle); static int NsfMethodSetterCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *parameter); -static int NsfMyCmd(Tcl_Interp *interp, int withLocal, int withSystem, Tcl_Obj *methodName, int nobjc, Tcl_Obj *CONST nobjv[]); +static int NsfMyCmd(Tcl_Interp *interp, int withIntrinsic, int withLocal, int withSystem, Tcl_Obj *methodName, int nobjc, Tcl_Obj *CONST nobjv[]); static int NsfNSCopyCmdsCmd(Tcl_Interp *interp, Tcl_Obj *fromNs, Tcl_Obj *toNs); static int NsfNSCopyVarsCmd(Tcl_Interp *interp, Tcl_Obj *fromNs, Tcl_Obj *toNs); static int NsfNextCmd(Tcl_Interp *interp, Tcl_Obj *arguments); -static int NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withFrame, int withLocal, int withSystem, Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]); +static int NsfObjectDispatchCmd(Tcl_Interp *interp, NsfObject *object, int withFrame, int withIntrinsic, int withLocal, int withSystem, Tcl_Obj *command, int nobjc, Tcl_Obj *CONST nobjv[]); static int NsfObjectExistsCmd(Tcl_Interp *interp, Tcl_Obj *value); static int NsfObjectPropertyCmd(Tcl_Interp *interp, NsfObject *objectName, int objectproperty); static int NsfObjectQualifyCmd(Tcl_Interp *interp, Tcl_Obj *objectName); @@ -1336,12 +1336,13 @@ &pc) != TCL_OK) { return TCL_ERROR; } else { - int withLocal = (int )PTR2INT(pc.clientData[0]); - int withSystem = (int )PTR2INT(pc.clientData[1]); - Tcl_Obj *methodName = (Tcl_Obj *)pc.clientData[2]; + int withIntrinsic = (int )PTR2INT(pc.clientData[0]); + int withLocal = (int )PTR2INT(pc.clientData[1]); + int withSystem = (int )PTR2INT(pc.clientData[2]); + Tcl_Obj *methodName = (Tcl_Obj *)pc.clientData[3]; assert(pc.status == 0); - return NsfMyCmd(interp, withLocal, withSystem, methodName, objc-pc.lastObjc, objv+pc.lastObjc); + return NsfMyCmd(interp, withIntrinsic, withLocal, withSystem, methodName, objc-pc.lastObjc, objv+pc.lastObjc); } } @@ -1415,12 +1416,13 @@ } else { NsfObject *object = (NsfObject *)pc.clientData[0]; int withFrame = (int )PTR2INT(pc.clientData[1]); - int withLocal = (int )PTR2INT(pc.clientData[2]); - int withSystem = (int )PTR2INT(pc.clientData[3]); - Tcl_Obj *command = (Tcl_Obj *)pc.clientData[4]; + int withIntrinsic = (int )PTR2INT(pc.clientData[2]); + int withLocal = (int )PTR2INT(pc.clientData[3]); + int withSystem = (int )PTR2INT(pc.clientData[4]); + Tcl_Obj *command = (Tcl_Obj *)pc.clientData[5]; assert(pc.status == 0); - return NsfObjectDispatchCmd(interp, object, withFrame, withLocal, withSystem, command, objc-pc.lastObjc, objv+pc.lastObjc); + return NsfObjectDispatchCmd(interp, object, withFrame, withIntrinsic, withLocal, withSystem, command, objc-pc.lastObjc, objv+pc.lastObjc); } } @@ -2528,7 +2530,8 @@ {"-per-object", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"parameter", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, -{"::nsf::my", NsfMyCmdStub, 4, { +{"::nsf::my", NsfMyCmdStub, 5, { + {"-intrinsic", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-local", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-system", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, @@ -2545,9 +2548,10 @@ {"::nsf::next", NsfNextCmdStub, 1, { {"arguments", 0, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, -{"::nsf::object::dispatch", NsfObjectDispatchCmdStub, 6, { +{"::nsf::object::dispatch", NsfObjectDispatchCmdStub, 7, { {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertToObject, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, {"-frame", 0|NSF_ARG_IS_ENUMERATION, 1, ConvertToFrame, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-intrinsic", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-local", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"-system", 0, 0, Nsf_ConvertToString, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"command", NSF_ARG_REQUIRED, 1, Nsf_ConvertToTclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, Index: tests/interceptor-slot.test =================================================================== diff -u -rf67408d8e6f8ba9bdd6e4ec3c54dfa3a23576161 -r3e18b80be2883ba647c2110a2e8e2b1980940c30 --- tests/interceptor-slot.test (.../interceptor-slot.test) (revision f67408d8e6f8ba9bdd6e4ec3c54dfa3a23576161) +++ tests/interceptor-slot.test (.../interceptor-slot.test) (revision 3e18b80be2883ba647c2110a2e8e2b1980940c30) @@ -328,5 +328,86 @@ } +# +# Test the next-path with mixin classes in cases where a +# method handle is used for method dispatch +# +nx::Test case mixins+method-handles+intrinsic { + # + # Just mixin classes + # + Class create A {:public method foo {} {return "A [next]"}} + Class create B {:public method foo {} {return "B [next]"}} + Class create C {:public method foo {} {return "C [next]"}} + Class create X -mixin {C B A} { + :public method foo {} {return "X [next]"} + } + X create c1 + ? {c1 foo} "C B A X " + ? {c1 -intrinsic foo} "X " + + + # + # Intrinsic classes and mixin classes + # + + Class create Y {:public method foo {} {return "Y [next]"}} + Class create Z -superclass Y {:public method foo {} {return "Z [next]"}} + + Z create c1 -mixin {C B A} + ? {c1 foo} "C B A Z Y " + ? {c1 -intrinsic foo} "Z Y " + + # + # check, whether the context of "my -intrinsic" is correct + # + A public method bar {} {nsf::my -intrinsic foo} + B public method bar {} {nsf::my -intrinsic foo} + C public method bar {} {nsf::my -intrinsic foo} + Y public method bar {} {nsf::my -intrinsic foo} + Z public method bar {} {nsf::my -intrinsic foo} + + ? {c1 info precedence} "::C ::B ::A ::Z ::Y ::nx::Object" + ? {c1 bar} "Z Y " + ? {c1 [C info method origin bar]} "Z Y " + ? {c1 [B info method origin bar]} "Z Y " + ? {c1 [A info method origin bar]} "Z Y " + ? {c1 [Z info method origin bar]} "Z Y " + ? {c1 [Y info method origin bar]} "Z Y " + + # + # check, whether the context of "[self] -intrinsic" is correct + # + A public method bar {} {[self] -intrinsic foo} + B public method bar {} {[self] -intrinsic foo} + C public method bar {} {[self] -intrinsic foo} + Y public method bar {} {[self] -intrinsic foo} + Z public method bar {} {[self] -intrinsic foo} + + ? {c1 bar} "Z Y " + ? {c1 [C info method origin bar]} "Z Y " + ? {c1 [B info method origin bar]} "Z Y " + ? {c1 [A info method origin bar]} "Z Y " + ? {c1 [Z info method origin bar]} "Z Y " + ? {c1 [Y info method origin bar]} "Z Y " + + # + # check, whether the context of "nsf::object::dispatch [self] -intrinsic" is correct + # + A public method bar {} {nsf::object::dispatch [self] -intrinsic foo} + B public method bar {} {nsf::object::dispatch [self] -intrinsic foo} + C public method bar {} {nsf::object::dispatch [self] -intrinsic foo} + Y public method bar {} {nsf::object::dispatch [self] -intrinsic foo} + Z public method bar {} {nsf::object::dispatch [self] -intrinsic foo} + + ? {c1 bar} "Z Y " + ? {c1 [C info method origin bar]} "Z Y " + ? {c1 [B info method origin bar]} "Z Y " + ? {c1 [A info method origin bar]} "Z Y " + ? {c1 [Z info method origin bar]} "Z Y " + ? {c1 [Y info method origin bar]} "Z Y " +} + +