// C.3 — Auto-drop on early return and if branches
// @[Drop] types call Type_Drop at every exit (return + branch scope end).

import Std::Io::{PrintLine, PrintInt};
import Std::Test::{Test_AssertEqInt, Test_Pass};

@[Drop]
struct Token {
    id: int,
    counter: *int
}

func Token_Drop(self: *Token) {
    if self.counter != null as *int {
        *self.counter = *self.counter + 1;
    }
}

// Drop t on both early return and fallthrough return.
func Early(flag: int, counter: *int) -> int {
    let t: Token = Token { id: 1, counter: counter };
    if flag == 0 {
        return 0;
    }
    return 1;
}

// Branch-local Tokens: only the taken branch's Drop runs.
func Branched(flag: int, counter: *int) -> int {
    if flag == 1 {
        let a: Token = Token { id: 10, counter: counter };
        return a.id;
    } else {
        let b: Token = Token { id: 20, counter: counter };
        return b.id;
    }
}

// Fallthrough: Drop at end of block without return.
func Scoped(counter: *int) {
    let s: Token = Token { id: 99, counter: counter };
    discard s.id;
}

func Main() -> int {
    var drops: int = 0;
    discard Early(0, &drops);
    discard Early(1, &drops);
    Test_AssertEqInt(drops, 2);

    discard Branched(1, &drops);
    discard Branched(0, &drops);
    Test_AssertEqInt(drops, 4);

    Scoped(&drops);
    Test_AssertEqInt(drops, 5);

    PrintInt(drops);
    PrintLine("");
    Test_Pass("drop_early_return");
    return 0;
}
