1/*
2 * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16class A {}
17class B extends A {}
18
19class KlassA {
20    public Foo() : String {
21        return "KlassA::Foo()";
22    }
23
24    public Bar() : String {
25        return "KlassA::Bar()";
26    }
27
28    // NOTE(vpukhov): Baz order affects override resoluition!
29    public Baz(x: A, y: B) : String {
30        return "KlassA::Baz(B, B)";
31    }
32
33    public final Baz(x: A, y: A) : String {
34        return "KlassA::Baz(A, A)";
35    }
36}
37
38class KlassB extends KlassA {
39    public override Foo() : String {
40        return "KlassB::Foo()";
41    }
42
43    public override Bar() : String {
44        return "KlassB::Bar()";
45    }
46
47    public override Baz(x: A, y: B) : String {
48        return "KlassB::Baz(A, B)";
49    }
50}
51
52class KlassC extends KlassB {
53    public override Foo() : String {
54        return "KlassC::Foo()";
55    }
56
57    public Baz(x: B, y: B) : String {
58        return "KlassC::Baz(B, B)";
59    }
60
61    public final CheckThisAndSuper() : void {
62        assert(this.Foo() == "KlassC::Foo()");
63        assert(super.Foo() == "KlassB::Foo()");
64    }
65}
66
67function Foo(x: A, y: B) : String { return "GLOBAL::Foo(A, B)"; }
68function Foo(x: B, y: B) : String { return "GLOBAL::Foo(B, B)"; }
69
70function Bar(x: int) : String { return "GLOBAL::Bar(int)"; }
71function Bar(x: short) : String { return "GLOBAL::Bar(short)"; }
72function Bar(x: char) : String { return "GLOBAL::Bar(char)"; }
73function Bar(x: double) : String { return "GLOBAL::Bar(double)"; }
74
75function Bar2(x: long) : String { return "GLOBAL::Bar2(long)"; }
76function Bar2(x: double) : String { return "GLOBAL::Bar2(double)"; }
77
78function Baz(x: Object) : String { return "GLOBAL::Baz(Object)"; }
79function Baz(x: Int) : String { return "GLOBAL::Baz(Int)"; }
80function Baz(x: Short) : String { return "GLOBAL::Baz(Short)"; }
81function Baz(x: Char) : String { return "GLOBAL::Baz(Char)"; }
82function Baz(x: String) : String { return "GLOBAL::Baz(String)"; }
83
84function main() : void {
85    let a: KlassA = new KlassA();
86    let b: KlassB = new KlassB();
87    let c: KlassC = new KlassC();
88
89    assert(a.Foo() == "KlassA::Foo()");
90    assert(b.Foo() == "KlassB::Foo()");
91    assert(c.Foo() == "KlassC::Foo()");
92
93    let d: KlassA = new KlassC();
94    let f: KlassB = new KlassC();
95
96    assert(d.Foo() == "KlassC::Foo()");
97    assert(f.Foo() == "KlassC::Foo()");
98    assert(c.Bar() == "KlassB::Bar()");
99
100    let objA : A = new A();
101    let objB : B = new B();
102
103    assert(c.Baz(objB, objB) == "KlassC::Baz(B, B)");
104    assert(c.Baz(objA, objB) == "KlassB::Baz(A, B)");
105    assert(c.Baz(objA, objA) == "KlassA::Baz(A, A)");
106
107    c.CheckThisAndSuper();
108
109    assert(Foo(objA, objB) == "GLOBAL::Foo(A, B)");
110    assert(Foo(objB, objB) == "GLOBAL::Foo(B, B)");
111
112    assert(Baz(new Int(1)) == "GLOBAL::Baz(Int)");
113    assert(Baz(new Char(c'1')) == "GLOBAL::Baz(Char)");
114    assert(Baz(new Short(1 as short)) == "GLOBAL::Baz(Short)");
115    assert(Baz("hello") == "GLOBAL::Baz(String)");
116
117    assert(Bar(1) == "GLOBAL::Bar(int)");
118    assert(Bar(c'1') == "GLOBAL::Bar(char)");
119    assert(Bar(3.14) == "GLOBAL::Bar(double)");
120
121    assert(Bar2(1) == "GLOBAL::Bar2(long)");
122    assert(Bar2(1 as long) == "GLOBAL::Bar2(long)");
123    assert(Bar2(1.1) == "GLOBAL::Bar2(double)");
124
125}
126