Index: TODO =================================================================== diff -u -r770232a210b63fdafc5e5e4a2caf45fa5097c6fe -rb053832535f9d1903fc0c0c3cb3523653bd63dfe --- TODO (.../TODO) (revision 770232a210b63fdafc5e5e4a2caf45fa5097c6fe) +++ TODO (.../TODO) (revision b053832535f9d1903fc0c0c3cb3523653bd63dfe) @@ -4022,7 +4022,6 @@ option parse nsf.c: - - added a SlotContainerCmdResolver() to avoid interaction of slot names with names of callable tcl commands. Without the SlotContainerCmdResolver() the call to "list" in a property named @@ -4031,7 +4030,12 @@ since it ignores the namespace path inside the slot container. - added regression test. +nsf.c: +- ignore in internall calls to "dealloc" protection settings +- handle cyclical class dependencies during object system finalize +- extend regression test + ======================================================================== TODO: Index: generic/nsf.c =================================================================== diff -u -r364a9eda329acd7d20173a4165d71394d3061aae -rb053832535f9d1903fc0c0c3cb3523653bd63dfe --- generic/nsf.c (.../nsf.c) (revision 364a9eda329acd7d20173a4165d71394d3061aae) +++ generic/nsf.c (.../nsf.c) (revision b053832535f9d1903fc0c0c3cb3523653bd63dfe) @@ -2912,7 +2912,7 @@ NsfObject *object = (NsfObject *)entryPtr->clorobj; /*fprintf(stderr, "key = %s %p %d flags %.6x\n", - ObjectName(object), object, object && !NsfObjectIsClass(object), object->flags);*/ + ObjectName(object), object, object && !NsfObjectIsClass(object), object->flags);*/ if (object && !NsfObjectIsClass(object) && !(object->flags & NSF_DESTROY_CALLED)) { @@ -21988,7 +21988,8 @@ } else { /*fprintf(stderr, "call dealloc\n");*/ result = NsfCallMethodWithArgs(interp, (Nsf_Object *)object->cl, methodObj, - object->cmdName, 1, NULL, NSF_CSC_IMMEDIATE); + object->cmdName, 1, NULL, + NSF_CSC_IMMEDIATE|NSF_CM_IGNORE_PERMISSIONS); if (unlikely(result != TCL_OK)) { /* * In case, the call of the dealloc method has failed above (e.g. NS_DYING), @@ -24424,7 +24425,34 @@ /*fprintf(stderr, "deleted %d Classes\n", deleted);*/ if (deleted == 0) { - break; + int reclassed = 0; + + /* + * Final check. If there are no cyclical dependencies, we should have now + * just the the base classes left. If this is not the case, reclass the + * remaining objects to their base classes. + */ + for (entry = *instances, lastEntry = NULL; + entry; + lastEntry = entry, entry = entry->nextPtr) { + NsfObject *object = (NsfObject *)entry->clorobj; + NsfClass *baseClass; + NsfObjectSystem *osPtr; + + if (NsfObjectIsClass(object) && IsBaseClass(object)) { + continue; + } + + osPtr = GetObjectSystem(object); + baseClass = NsfObjectIsClass(object) ? osPtr->rootMetaClass : osPtr->rootClass; + ChangeClass(interp, object, baseClass); + reclassed ++; + } + /*fprintf(stderr, "We have reclassed %d objects\n", reclassed);*/ + + if (reclassed == 0) { + break; + } } } } Index: tests/destroy.test =================================================================== diff -u -reae784ccc80b2a18b83fbe631c32d549189f7927 -rb053832535f9d1903fc0c0c3cb3523653bd63dfe --- tests/destroy.test (.../destroy.test) (revision eae784ccc80b2a18b83fbe631c32d549189f7927) +++ tests/destroy.test (.../destroy.test) (revision b053832535f9d1903fc0c0c3cb3523653bd63dfe) @@ -616,6 +616,7 @@ ::module destroy } + # to avoid CallDirectly, we could activate this line ::nx::Class create M {:method dealloc args {next}} Test case delete-parent-namespace-dealloc @@ -972,4 +973,23 @@ # We expect that the original method works again. # ? {string match ::nsf::__#* [A new]} 1 -} \ No newline at end of file +} + +# +# Create a cyclical class dependency and delete it manually +# +nx::Test case cyclical-dependency { + nx::Object create o1 + ? {nx::Class create o1::C} ::o1::C + ? {nsf::relation o1 class o1::C} ::o1::C + o1 destroy +} + +# +# Create a cyclical class dependency and let it be deleted on +# object-system-cleanup +# +nx::Object create o1 +nx::Class create o1::C +nsf::relation o1 class o1::C +