New Issue: moveFrom, moveInitialize: the compiler needs to be aware

20437, "vasslitvinov", "moveFrom, moveInitialize: the compiler needs to be aware", "2022-08-12T07:02:49Z"

These functions are also discussed in #20330 and #20328.

The charter of the Memory.Initialization module is "[to enable the user] to implement collections in a manner similar to those implemented by the Chapel standard modules (such as List or Map)."

I claim that at present the functions moveFrom and moveInitialize do not achieve this purpose.

Example 1: LinkedList.pop_front()

I expect pop_front() to pass to the caller the ownership of the element being popped:

var oldFront = ... the front listNode ...;
var ret = moveFrom(oldFront.data);
delete oldFront;
return ret;

However, it does not -- and cannot do that. Because delete oldFront deinitializes oldFront.data among other things - because it does not know that oldFront.data has been "consumed". So if I called moveFrom(oldFront.data), the deinitializer would deinitialize invalid memory contents.

Example 2: chpl__hashtable.clearSlot()

I expect the out val formal to take over the ownership of tableEntry.val:

proc chpl__hashtable.clearSlot(ref tableEntry, out key: keyType, out val: valType) {
  moveInitialize(key, moveFrom(tableEntry.key));
  moveInitialize(val, moveFrom(tableEntry.val));
  ....
}

However, it does not do that. If it did, the compiler would not know that key and value would be initialized and would default-initialize them prior to the moveInitialize() calls. So moveInitialize() would clobber objects without deinitializing them properly. Instead, key and value get initialized using =:

proc chpl__hashtable.clearSlot(ref tableEntry, out key: keyType, out val: valType) {
  key = moveFrom(tableEntry.key);
  val = moveFrom(tableEntry.val);
  ....
}

The problem with that is that the compiler inserts calls to chpl__coerceMove(), passing in the results of moveFrom and using the returned values to initialize key/value. chpl__coerceMove() is a Really Big Function and is completely unnecessary here.

In summary, this issue calls for compiler awareness of initialization and deinitialization performed by moveFrom and moveInitialize.