[Idea] Returning unsized locals via stack

CPS is great :+1:

a new calling convention sketched above could be useful as well
Rust being one of the languages that could use it


The most awkward part is the requirement to order items on stack. I still see it as necessary. This comment is to spell out the "rule" better:

  • I see a case for introducing a new kind of local let bindings in an fn: so called dyn let bindings
    • already existing unsized local traits: dyn Trait
    • already existing unsized arrays - suggestion here is to change syntax from T[] to dyn T[]; I'm suggesting to change syntax so as to avoid false similarity with unsized members of structs
    • new kind of local let bindings:
      • regular local variables of known concrete type but allocated dynamically via alloca
        struct S {..}
        fn ...() .. {
          let s : dyn S = ...;
        
      • the difference is that programmer has a degree of control over where exactly on the stack they will be located
      • if such a variable is assigned to after an unsized local like dyn Trait has been assigned to then the programmer can be assured that it will be allocated on stack after the said dyn Trait
      • further when concrete types are returned via the new CC they become exactly this: dyn ConcreteType
  • once we have introduced the new kind of local let bindings the rule is now this:
    • when constructing a tuple with dyn members to be returned via the new CC
    • only regular (non-dyn) local bindings, only dyn local bindings or a mix thereof can be used
    • if a mix is used all regular (non-dyn) local bindings have to come before all dyn local bindings
    • all bindings used to construct such tuples dyn or not have to be declared in the order they are used to construct them
    • all dyn bindings used to construct such tuples which are unsized (dyn Trait, dyn T[]) have to be assigned to in the order they have been declared
    • all dyn bindings used to construct such tuples which are sized (dyn ConcreteType) have to be assigned to only after all preceding unsized dyn bindings (dyn Trait, dyn T[]) used to construct such tuples have been assigned too; this is because only after that has happened the exact location of the said dyn ConcreteType on stack can be determined
    • the compiler then guarantees to lay them them out on stack - both dyn and not dyn - in the order they were declared; so all dyn will come after all non-dyn
    • if these rules cannot be followed the programmer needs to resort to explicitly creating new copies of some of the local variables involved or to invoke some sort of compiler provided facility to automate this; the surface syntax for the new facility may look like a macro invocation
  • the purpose of introducing this rather complex rule is that the objects returned via such tuple can be compacted - shifted up the stack - in the simplest possible manner
    • in particular the goal is to ensure that the code doing the shifting doesn't have any conditional branches; just a sequence of straight-forward size/location calculations and memcpy-s
  • the purpose of not always automating this - and indeed forcing programmer to manually create extra copies or to manually invoke the built-in mechanism helping with this - is to make programmer aware that the fn as written is indeed incurring extra costs and to push programmer where possible into writing fn-s in such a manner that this extra shifting of objects is not necessary