// #target: macos-x64
module test;

import std::io;
struct Vector
{
    usz size;
    int* elements;
}

macro int Vector.get(Vector* vector, usz element) @operator([])
{
    return vector.elements[element];
}

macro int* Vector.get_ref(Vector* vector, usz element) @operator(&[])
{
    return &vector.elements[element];
}

macro usz Vector.size(Vector vector) @operator(len) {
    return vector.size;
}

fn void main()
{
	int[2] x = { 1, 2 };
    Vector v = { 2, &x };

    foreach (int* &ref : v)
    {
        std::io::printf("%d\n", *ref);
        *ref += 2;
    }
    foreach (int i : v)
    {
        std::io::printf("%d\n", i);
    }
}

/* #expect: test.ll

define void @test.main() #0 {
entry:
  %x = alloca [2 x i32], align 4
  %v = alloca %Vector, align 8
  %vector = alloca %Vector, align 8
  %.anon = alloca i64, align 8
  %ref = alloca ptr, align 8
  %element = alloca i64, align 8
  %varargslots = alloca [1 x %any], align 16
  %retparam = alloca i64, align 8
  %vector2 = alloca %Vector, align 8
  %.anon3 = alloca i64, align 8
  %i = alloca i32, align 4
  %element7 = alloca i64, align 8
  %varargslots10 = alloca [1 x %any], align 16
  %retparam11 = alloca i64, align 8
  call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @.__const, i32 8, i1 false)
  store i64 2, ptr %v, align 8
  %ptradd = getelementptr inbounds i8, ptr %v, i64 8
  store ptr %x, ptr %ptradd, align 8
  call void @llvm.memcpy.p0.p0.i32(ptr align 8 %vector, ptr align 8 %v, i32 16, i1 false)
  %0 = load i64, ptr %vector, align 8
  store i64 0, ptr %.anon, align 8
  br label %loop.cond

loop.cond:                                        ; preds = %loop.body, %entry
  %1 = load i64, ptr %.anon, align 8
  %lt = icmp ult i64 %1, %0
  br i1 %lt, label %loop.body, label %loop.exit

loop.body:                                        ; preds = %loop.cond
  %2 = load i64, ptr %.anon, align 8
  store i64 %2, ptr %element, align 8
  %ptradd1 = getelementptr inbounds i8, ptr %v, i64 8
  %3 = load ptr, ptr %ptradd1, align 8
  %4 = load i64, ptr %element, align 8
  %ptroffset = getelementptr inbounds [4 x i8], ptr %3, i64 %4
  store ptr %ptroffset, ptr %ref, align 8
  %5 = load ptr, ptr %ref, align 8
  %6 = insertvalue %any undef, ptr %5, 0
  %7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %7, ptr %varargslots, align 16
  %8 = call i64 @std.io.printf(ptr %retparam, ptr @.str, i64 3, ptr %varargslots, i64 1)
  %9 = load ptr, ptr %ref, align 8
  %10 = load i32, ptr %9, align 4
  %add = add i32 %10, 2
  store i32 %add, ptr %9, align 4
  %11 = load i64, ptr %.anon, align 8
  %addnuw = add nuw i64 %11, 1
  store i64 %addnuw, ptr %.anon, align 8
  br label %loop.cond

loop.exit:                                        ; preds = %loop.cond
  call void @llvm.memcpy.p0.p0.i32(ptr align 8 %vector2, ptr align 8 %v, i32 16, i1 false)
  %12 = load i64, ptr %vector2, align 8
  store i64 0, ptr %.anon3, align 8
  br label %loop.cond4

loop.cond4:                                       ; preds = %loop.body6, %loop.exit
  %13 = load i64, ptr %.anon3, align 8
  %lt5 = icmp ult i64 %13, %12
  br i1 %lt5, label %loop.body6, label %loop.exit13

loop.body6:                                       ; preds = %loop.cond4
  %14 = load i64, ptr %.anon3, align 8
  store i64 %14, ptr %element7, align 8
  %ptradd8 = getelementptr inbounds i8, ptr %v, i64 8
  %15 = load ptr, ptr %ptradd8, align 8
  %16 = load i64, ptr %element7, align 8
  %ptroffset9 = getelementptr inbounds [4 x i8], ptr %15, i64 %16
  %17 = load i32, ptr %ptroffset9, align 4
  store i32 %17, ptr %i, align 4
  %18 = insertvalue %any undef, ptr %i, 0
  %19 = insertvalue %any %18, i64 ptrtoint (ptr @"$ct.int" to i64), 1
  store %any %19, ptr %varargslots10, align 16
  %20 = call i64 @std.io.printf(ptr %retparam11, ptr @.str.1, i64 3, ptr %varargslots10, i64 1)
  %21 = load i64, ptr %.anon3, align 8
  %addnuw12 = add nuw i64 %21, 1
  store i64 %addnuw12, ptr %.anon3, align 8
  br label %loop.cond4

loop.exit13:                                      ; preds = %loop.cond4
  ret void
}