//! returns: 0

/// Aggregate call result.
record Pair: Copy {
    /// First argument value.
    first: u32,
    /// Second argument value.
    second: u32,
}

/// Record one evaluated argument.
fn argument(trace: &mut u32, digit: u32) -> u32 {
    set *trace = *trace * 10 + digit;
    return digit;
}

/// Return both arguments through a hidden result pointer.
fn pair(first: u32, second: u32) -> Pair {
    return Pair { first, second };
}

/// Combine the receiver with explicit arguments.
fn (value: &Pair) combine(first: u32, second: u32) -> Pair {
    return Pair { first: value.first + first, second: value.second + second };
}

/// Return an aggregate result or an error after evaluating both arguments.
fn checked(first: u32, second: u32) -> Pair throws (u32) {
    if first == 3 {
        throw second;
    }
    return pair(first, second);
}

/// Check direct, indirect, method, and throwing call argument order.
@default fn main() -> u32 {
    let mut trace: u32 = 0;
    let first = pair(argument(&mut trace, 1), argument(&mut trace, 2));
    assert trace == 12;
    let second = first.combine(argument(&mut trace, 3), argument(&mut trace, 4));
    assert trace == 1234;
    assert second.first == 4;
    assert second.second == 6;
    let call: fn(u32, u32) -> Pair = pair;
    let third = call(argument(&mut trace, 5), argument(&mut trace, 6));
    assert trace == 123456;
    assert third.first == 5;
    assert third.second == 6;
    let result = try! checked(argument(&mut trace, 1), argument(&mut trace, 2));
    assert trace == 12345612;
    assert result.first == 1;
    assert result.second == 2;
    set trace = 0;
    let mut caught = false;
    try checked(argument(&mut trace, 3), argument(&mut trace, 4)) catch {
        set caught = true;
    };
    assert caught;
    assert trace == 34;
    assert first.first == 1;
    assert first.second == 2;
    return 0;
}
