Index: generic/nsf.c =================================================================== diff -u -r46c536260f793729feb23fff02cc15e3867ae0ee -rbe235fba6cf5b0d33391b6a1b6a1f1f6b71da33a --- generic/nsf.c (.../nsf.c) (revision 46c536260f793729feb23fff02cc15e3867ae0ee) +++ generic/nsf.c (.../nsf.c) (revision be235fba6cf5b0d33391b6a1b6a1f1f6b71da33a) @@ -12073,16 +12073,38 @@ object, cl, methodName, frameType, 0); #endif } else if (result == TCL_OK) { + NsfCallStackContent *topCscPtr = NULL; + int isLeafNext; + /* - * We could not find a cmd, but there was no error on the call. - * When we are at the end of a filter-chain, or within a next from - * an ensemble, set the unknown flag to allow higher levels to - * handle this case. + * We could not find a cmd, yet the dispatch attempt did not result + * in an error. This means that we find ourselves in either of three + * situations at this point: + * + * 1) A next cmd (NsfNextCmd()) at the end of a filter chain: Dispatch to + * unknown as there is no implementation of for the requested selector + * available. 2) A next cmd from within a leaf submethod (a "leaf next"): + * Remain silent, do not dispatch to unknown. 3) MethodDispatchCsc() + * realises the actual "ensemble next": Dispatch to unknown, the + * requested sub-selector is not resolvable to a cmd. + * + * For the cases 1) and 3), set the interp's unknown flag signalling to + * higher levels (e.g., in MethodDispatchCsc(), in NsfNextCmd()) the need + * for dispatching to unknown. */ + + topCscPtr = CallStackGetTopFrame(interp, NULL); + assert(topCscPtr); + + /* case 2 */ + isLeafNext = (cscPtr != topCscPtr) && (topCscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) && + (topCscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) == 0; - /*fprintf(stderr, "--- no cmd, csc %p frameType %.6x callType %.6x endOfFilterChain %d NSF_CSC_CALL_IS_ENSEMBLE %d\n", - cscPtr, cscPtr->frameType, cscPtr->flags, endOfFilterChain,(cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE)!=0);*/ - rst->unknown = endOfFilterChain || (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE); + /*fprintf(stderr, "--- no cmd, csc %p frameType %.6x callType %.6x endOfFilterChain %d NSF_CSC_CALL_IS_ENSEMBLE %d NSF_CSC_TYPE_ENSEMBLE % d NSF_CSC_CALL_IS_NEXT %d rst->unknown %d isLeafNext %d\n", cscPtr, cscPtr->frameType, cscPtr->flags, endOfFilterChain, (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE) != 0, (cscPtr->frameType & NSF_CSC_TYPE_ENSEMBLE) != 0, (cscPtr->flags & NSF_CSC_CALL_IS_NEXT) != 0, rst->unknown, isLeafNext);*/ + + rst->unknown = /* case 1 */ endOfFilterChain || + /* case 3 */ (!isLeafNext && (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE)); + /*fprintf(stderr, "******** setting unknown to %d\n", rst->unknown );*/ } Index: tests/disposition.test =================================================================== diff -u -r46c536260f793729feb23fff02cc15e3867ae0ee -rbe235fba6cf5b0d33391b6a1b6a1f1f6b71da33a --- tests/disposition.test (.../disposition.test) (revision 46c536260f793729feb23fff02cc15e3867ae0ee) +++ tests/disposition.test (.../disposition.test) (revision be235fba6cf5b0d33391b6a1b6a1f1f6b71da33a) @@ -1100,14 +1100,7 @@ c1 eval {set :msg} } "(1)--::c1--FOO--foo--(3)--::M2--FOO--::c1" - C mixin {} - - # - # TODO: [current class] in M2 FOO foo does not resolve! - # - # TODO: ensemble next (in submethod) + container filter -> leads to unknown ... - # - + C mixin {} } nx::Test case dispo-configure-transparency { Index: tests/submethods.test =================================================================== diff -u -r07bc50445a6b058e05eb942e793d99126afbedd1 -rbe235fba6cf5b0d33391b6a1b6a1f1f6b71da33a --- tests/submethods.test (.../submethods.test) (revision 07bc50445a6b058e05eb942e793d99126afbedd1) +++ tests/submethods.test (.../submethods.test) (revision be235fba6cf5b0d33391b6a1b6a1f1f6b71da33a) @@ -338,6 +338,33 @@ ? {obj foo} ::nx::Object } +# +# Leaf next: Do not trigger unknown handling (see also +# NextSearchAndInvoke()) +# + +nx::Test case leaf-next-in-submethods { + Object create container { + set :x 0 + :public method "FOO bar" {} { + incr :x; next; # a "leaf next" + } + :public method intercept args { + incr :x; next; # a "filter next" + } + :filter intercept + :FOO bar + # Rationale: A call count > 2 would indicate that the leaf next + # triggers a further call into filter ... + ? [list set _ ${:x}] 2 + } +} + +# :public method intercept {} { next } +# -> TODO: wrong # args: should be ":FOO" ... trim the colon! + + + nx::Test case submethods-and-filters { # # submethods as filters?