I explore what you can (almost) do below and explain what is going on. That said, there isnât a really good way to do this - youâre trying to make a collection that references various things on the stack and the compiler needs to understand that.
This is going to be complicated and annoying, but if you really want to do it, you can "almostâ do it today. Let me dive in. Here are your types mocked out so they compile. Note that I made Container copyable and movable so it can work with List:
struct Vector[dt: DType]:
fn __init__(out self, a: Int, b: Int, c: Int, d: Int): pass
struct Container[mut: Bool, //, origin: Origin[mut], dtype: DType](Copyable, Movable):
var address: Pointer[Vector[dtype], origin]
fn __init__(out self, ref [origin] vector: Vector[dtype]):
self.address = Pointer(to=vector)
fn __copyinit__(out self, other: Self):
self.address = other.address
Ok, now lets figure out how to put multiple things into the list, this looks like this:
fn main():
# 1)
v = Vector[DType.int32](1, 2, 3, 4)
v2 = Vector[DType.int32](5, 6, 7, 8)
# 2)
container = Container[origin_of(v,v2)](v)
container2 = Container[origin_of(v,v2)](v2)
#3)
l = List[Container[origin_of(v, v2), DType.int32]]()
#4)
l.append(container^)
l.append(container2^)
#1 declares the two vectors we want to reference from the list.
#3 declares a list containing elements of your Container type, and uses originof to say that the elements can point to either v or v2. This is the literal answer to your question.
However, one annoying thing is that Container[origin_of(v)]is not implicitly convertible to Container[origin_of(v, v2)] - these are different types and Mojo doesnât âknowâ they are related. We want this sort of thing to be implicitly convertible (e.g. UnsafePointer has the same issue) and the way to do this is to define an @implicit conversion. I /think/ we have the ability to do this (or the near ability) now that where clauses are coming in, but I havenât tried it. To work around this, I declared container and container2 with explicitly origin_of clauses in #2. The ârefâ argument in the initializer does support this implicit conversion (from an origin to a super set origin) so this approach works.
If you give this code example a try with the current nightly, youâll see that it âalmostâ works, in that it type checks. The issue is that the compiler pukes on it due to exclusivity checking:
c.mojo:26:12: error: argument of 'append' call allows writing a memory location previously writable through another aliased argument
l.append(container^)
^
c.mojo:26:12: note: 'v2' memory accessed through reference embedded in value of type 'Container[origin_of(v2, v), DType.int32]'
Mojo is complaining because it knows that âlâ may point to v or v2, and that youâre passing in something else that could point to âvâ or âv2â, and it doesnât know whether append is potentially causing an aliasing access. We know it isnât but Mojo doesnât.
There is no good way to solve this error with todayâs mojo, we need to continue to extend the type system to support this (this is related to the work to remove the @__unsafe_disable_nested_origin_exclusivity hack). In the meantime, Iâd recommend not doing this - instead use value semantics instead of references. If you âreally reallyâ need to do this, you can hackaround this by using something like ImmutableAnyOrigin.
-Chris