import edu.rice.cs.mint.runtime.*;

public class SeparableSample6 {
    public static int unsafeMethod() {
        return 2;
    }
    public static separable int safeMethod() {
        return 2;
    }
    public static separable SafeCode<Integer> method(final int i) {
        return <| i |>;
    }
    public static class Foo { }
    public static class Bar {
        public separable Bar() { }
    }
    public static class Fum {
        public Fum() { }
        public separable Fum(int i) { }
    }
    public static class Fee extends Fum {
    }
    public static class Coder {
        public Code<Integer> m() { return <| 1 |>; }
    }
    public static class Coder2 extends Coder {
        public Code<Integer> m() {
            System.out.println("foo");
            return <| 1 |>;
        }
    }
    public static void main (String [] args) {
        // SafeCode<Integer> c2 = <| unsafeMethod() |>; // error
        SafeCode<Integer> c2 = <| safeMethod() |>;
        Code<Integer> c = <| `(method(1)) + `c2 |>;
        System.out.println (c.run ());
        Code<Integer> c3 = <| new Integer(5) |>;
        Code<Code<Integer>> c4 = <| <| new Integer(5) |> |>;
        
        final SafeCode<? extends Object> co = <| new Object() |>;
        final SafeCode<? extends Object> co2 = <| new Object() { } |>;
        final SafeCode<? extends Foo> cf = <| new Foo() |>;
        final SafeCode<? extends Foo> cf2 = <| new Foo() { } |>;
        final SafeCode<? extends Bar> cb = <| new Bar() |>;
        final SafeCode<? extends Bar> cb2 = <| new Bar() { } |>;
        final Code<? extends Fum> cfu = <| new Fum() |>; // unsafe
        final Code<? extends Fum> cfu2 = <| new Fum() { } |>; // unsafe
        final SafeCode<? extends Fum> cfu3 = <| new Fum(1) |>;
        final SafeCode<? extends Fum> cfu4 = <| new Fum(2) { } |>;
        final Code<? extends Fee> cfe = <| new Fee() |>; // unsafe
        final Code<? extends Fee> cfe2 = <| new Fee() { } |>; // unsafe
        final SafeCode<? extends Coder> cco = <| new Coder() |>;
        final Code<Code<Integer>> ci = <| new Coder().m() |>; // unsafe
        final SafeCode<? extends Coder> cco2 = <| new Coder2() |>;
        final SafeCode<? extends Coder> cco3 = <| new Coder() {
            public SafeCode<Integer> m() {
                System.out.println("foo"); // should be okay
                return <| 2 |>;
            }
        } |>;
        final SafeCode<? extends Coder> cco4 = <| new Coder() {
            public Code<Integer> m() {
                System.out.println("foo"); // should be okay
                return <| unsafeMethod() |>; // unsafe
            }
        } |>;
        
        Code<? extends Object> x = <| `co |>;
        Object o = x.run();
        x = <| `co2 |>;
        x = <| `cf |>;
        x = <| `cf2 |>;
        x = <| `cb |>;
        x = <| `cb2 |>;
        x = <| `cfu |>;
        x = <| `cfu2 |>;
        x = <| `cfu3 |>;
        x = <| `cfu4 |>;
        x = <| `cfe |>;
        x = <| `cfe2 |>;
        
        x = <| `(<|`co|>) |>;
        x = <| `(<|`co2|>) |>;
        x = <| `(<|`cf|>) |>;
        x = <| `(<|`cf2|>) |>;
        x = <| `(<|`cb|>) |>;
        x = <| `(<|`cb2|>) |>;
        // x = <| `(<|`cfu|>) |>; // error
        // x = <| `(<|`cfu2|>) |>; // error
        x = <| `(<|`cfu3|>) |>;
        x = <| `(<|`cfu4|>) |>;
        // x = <| `(<|`cfe|>) |>; // error
        // x = <| `(<|`cfe2|>) |>; // error
        x = <| `(safeCode()) |>;
        x = <| `(unsafeCode()) |>;
    }
    
    public static separable SafeCode<Integer> safeCode() {
        return <| safeInt() |>;
    }
    public static separable Code<Integer> unsafeCode() {
        return <| unsafeInt() |>;
    }
    public static int unsafeInt() { return 1; }
    public static separable int safeInt() { return 1; }
}
