GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
937 / 952
98.4%
Branches:
353 / 540, 10 excl
65.4%
Functions:
71 / 75
94.7%

typechecker/op-rule-manager.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/data/vector";
5 import "std/data/unordered-map";
6 import "std/data/pair";
7 import "std/text/stringstream";
8 import "std/math/hash";
9
10 // Own imports
11 import "@/source-file";
12 import "@/ast/ast-nodes";
13 import "@/exception/error-manager";
14 import "@/exception/semantic-error";
15 import "@/model/function";
16 import "@/symboltablebuilder/lifecycle";
17 import "@/symboltablebuilder/qual-type";
18 import "@/symboltablebuilder/scope";
19 import "@/symboltablebuilder/super-type";
20 import "@/symboltablebuilder/symbol-table-entry";
21 import "@/symboltablebuilder/type";
22 import "@/symboltablebuilder/type-qualifiers";
23 import "@/typechecker/expr-result";
24 import "@/typechecker/function-manager";
25 import "@/typechecker/type-checker";
26 import "@/util/custom-hash-functions";
27
28 // Custom error message prefixes
29 public const string ERROR_MSG_RETURN = "Passed wrong data type to return statement";
30 public const string ERROR_FOREACH_ITEM = "Passed wrong data type to foreach item";
31 public const string ERROR_FIELD_ASSIGN = "Given type of the field value does not match declaration";
32
33 // Unary operator rule: lhs type, result type
34 public type UnaryOpRule struct {
35 public SuperType lhsType
36 public SuperType resultType
37 }
38
39 // Binary operator rule: lhs type, rhs type, result type
40 public type BinaryOpRule struct {
41 public SuperType lhsType
42 public SuperType rhsType
43 public SuperType resultType
44 }
45
46 public type UnaryOpRules alias Vector<UnaryOpRule>;
47 public type BinaryOpRules alias Vector<BinaryOpRule>;
48
49 /**
50 * Helper class for the TypeChecker to check whether certain operator/type combinations are valid or not and which result type
51 * is produced.
52 *
53 * Spice only supports globals of primitive type, so the operator rules are stored in the OpRuleManager and filled once by its
54 * constructor (see initRules).
55 *
56 * Error handling: for invalid operator/type combinations, a soft error is recorded and the unresolved type is returned, which
57 * the visit methods of the TypeChecker propagate.
58 */
59 15513 public type OpRuleManager struct {
60 15850 TypeChecker* typeChecker = nil<TypeChecker*>
61 BinaryOpRules assignOpRules
62 BinaryOpRules plusEqualOpRules
63 BinaryOpRules minusEqualOpRules
64 BinaryOpRules mulEqualOpRules
65 BinaryOpRules divEqualOpRules
66 BinaryOpRules remEqualOpRules
67 BinaryOpRules shlEqualOpRules
68 BinaryOpRules shrEqualOpRules
69 BinaryOpRules andEqualOpRules
70 BinaryOpRules orEqualOpRules
71 BinaryOpRules xorEqualOpRules
72 BinaryOpRules logicalAndOpRules
73 BinaryOpRules logicalOrOpRules
74 BinaryOpRules bitwiseOrOpRules
75 BinaryOpRules bitwiseXorOpRules
76 BinaryOpRules bitwiseAndOpRules
77 BinaryOpRules equalOpRules
78 BinaryOpRules notEqualOpRules
79 BinaryOpRules lessOpRules
80 BinaryOpRules greaterOpRules
81 BinaryOpRules lessEqualOpRules
82 BinaryOpRules greaterEqualOpRules
83 BinaryOpRules shiftLeftOpRules
84 BinaryOpRules shiftRightOpRules
85 BinaryOpRules plusOpRules
86 BinaryOpRules minusOpRules
87 BinaryOpRules mulOpRules
88 BinaryOpRules divOpRules
89 BinaryOpRules remOpRules
90 UnaryOpRules prefixMinusOpRules
91 UnaryOpRules prefixPlusPlusOpRules
92 UnaryOpRules prefixMinusMinusOpRules
93 UnaryOpRules prefixNotOpRules
94 UnaryOpRules prefixBitwiseNotOpRules
95 UnaryOpRules postfixPlusPlusOpRules
96 UnaryOpRules postfixMinusMinusOpRules
97 BinaryOpRules castOpRules
98 }
99
100 // Only default-initializes the field of the TypeChecker, whose ctor replaces it with a manager created by the ctor below. It does
101 // not fill the rule tables, because those would be leaked by that replacement.
102 15850 public p OpRuleManager.ctor() {}
103
104 7925 public p OpRuleManager.ctor(TypeChecker* typeChecker) {
105 7925 this.typeChecker = typeChecker;
106 7925 this.initRules();
107 7925 }
108
109 // Fill the operator rule tables
110 7925 p OpRuleManager.initRules() {
111 // Assign op rules
112 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double = double -> double
113 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int = int -> int
114 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short = short -> short
115 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long = long -> long
116 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte = byte -> byte
117 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_CHAR}); // char = char -> char
118 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_STRING}); // string = string -> string
119 7925 this.assignOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool = bool -> bool
120
121 // Plus equal op rules
122 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double += double -> double
123 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int += int -> int
124 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int += short -> int
125 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int += long -> int
126 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short += int -> short
127 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short += short -> short
128 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short += long -> short
129 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long += int -> long
130 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long += short -> long
131 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long += long -> long
132 7925 this.plusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_CHAR}); // char += int -> char
133
134 // Minus equal op rules
135 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double -= double -> double
136 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int -= int -> int
137 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int -= short -> int
138 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int -= long -> int
139 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short -= int -> short
140 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short -= short -> short
141 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short -= long -> short
142 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long -= int -> long
143 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long -= short -> long
144 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long -= long -> long
145 7925 this.minusEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_CHAR}); // char -= int -> char
146
147 // Mul equal op rules
148 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double *= double -> double
149 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int *= int -> int
150 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int *= short -> int
151 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int *= long -> int
152 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short *= int -> short
153 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short *= short -> short
154 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short *= long -> short
155 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long *= int -> long
156 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long *= short -> long
157 7925 this.mulEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long *= long -> long
158
159 // Div equal op rules
160 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double /= double -> double
161 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int /= int -> int
162 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int /= short -> int
163 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int /= long -> int
164 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short /= int -> short
165 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short /= short -> short
166 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short /= long -> short
167 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long /= int -> long
168 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long /= short -> long
169 7925 this.divEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long /= long -> long
170
171 // Rem equal op rules
172 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double %= double -> double
173 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int %= int -> int
174 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int %= short -> int
175 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int %= long -> int
176 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short %= int -> short
177 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short %= short -> short
178 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short %= long -> short
179 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long %= int -> long
180 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long %= short -> long
181 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long %= long -> long
182 7925 this.remEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte %= byte -> byte
183
184 // Shl equal op rules
185 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int <<= int -> int
186 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int <<= short -> int
187 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int <<= long -> int
188 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short <<= int -> short
189 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short <<= short -> short
190 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short <<= long -> short
191 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long <<= int -> long
192 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long <<= short -> long
193 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long <<= long -> long
194 7925 this.shlEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte <<= byte -> byte
195
196 // Shr equal op rules
197 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int >>= int -> int
198 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int >>= short -> int
199 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int >>= long -> int
200 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short >>= int -> short
201 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short >>= short -> short
202 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short >>= long -> short
203 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long >>= int -> long
204 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long >>= short -> long
205 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long >>= long -> long
206 7925 this.shrEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte >>= byte -> byte
207
208 // And equal op rules
209 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int &= int -> int
210 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int &= short -> int
211 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int &= long -> int
212 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short &= int -> short
213 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short &= short -> short
214 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short &= long -> short
215 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long &= int -> long
216 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long &= short -> long
217 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long &= long -> long
218 7925 this.andEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte &= byte -> byte
219
220 // Or equal op rules
221 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int |= int -> int
222 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int |= short -> int
223 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int |= long -> int
224 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short |= int -> short
225 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short |= short -> short
226 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short |= long -> short
227 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long |= int -> long
228 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long |= short -> long
229 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long |= long -> long
230 7925 this.orEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte |= byte -> byte
231
232 // Xor equal op rules
233 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int ^= int -> int
234 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int ^= short -> int
235 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int ^= long -> int
236 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short ^= int -> short
237 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short ^= short -> short
238 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short ^= long -> short
239 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long ^= int -> long
240 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long ^= short -> long
241 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long ^= long -> long
242 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte ^= byte -> byte
243 7925 this.xorEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_CHAR}); // char ^= char -> char
244
245 // Logical and op rules
246 7925 this.logicalAndOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool && bool -> bool
247
248 // Logical or op rules
249 7925 this.logicalOrOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool || bool -> bool
250
251 // Bitwise or op rules
252 7925 this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int | int -> int
253 7925 this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short | short -> short
254 7925 this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long | long -> long
255 7925 this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte | byte -> byte
256 7925 this.bitwiseOrOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool | bool -> bool
257
258 // Bitwise xor op rules
259 7925 this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int ^ int -> int
260 7925 this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short ^ short -> short
261 7925 this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long ^ long -> long
262 7925 this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte ^ byte -> byte
263 7925 this.bitwiseXorOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool ^ bool -> bool
264
265 // Bitwise and op rules
266 7925 this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int & int -> int
267 7925 this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short & short -> short
268 7925 this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long & long -> long
269 7925 this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte & byte -> byte
270 7925 this.bitwiseAndOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool & bool -> bool
271
272 // Equal op rules
273 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double == double -> bool
274 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double == int -> bool
275 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double == short -> bool
276 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double == long -> bool
277 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int == double -> bool
278 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int == int -> bool
279 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int == short -> bool
280 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int == long -> bool
281 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // int == char -> bool
282 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short == double -> bool
283 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short == int -> bool
284 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short == short -> bool
285 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short == long -> bool
286 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // short == char -> bool
287 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long == double -> bool
288 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long == int -> bool
289 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long == short -> bool
290 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long == long -> bool
291 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_CHAR, SuperType::TY_BOOL}); // long == char -> bool
292 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte == byte -> bool
293 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_BOOL}); // char == int -> bool
294 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_SHORT, SuperType::TY_BOOL}); // char == short -> bool
295 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_LONG, SuperType::TY_BOOL}); // char == long -> bool
296 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char == char -> bool
297 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_BOOL}); // string == string -> bool
298 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool == bool -> bool
299 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_FUNCTION, SuperType::TY_FUNCTION, SuperType::TY_BOOL}); // function == function -> bool
300 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_PROCEDURE, SuperType::TY_PROCEDURE, SuperType::TY_BOOL}); // procedure == procedure -> bool
301 7925 this.equalOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* == any* -> bool
302
303 // Not equal op rules
304 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double != double -> bool
305 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double != int -> bool
306 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double != short -> bool
307 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double != long -> bool
308 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int != double -> bool
309 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int != int -> bool
310 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int != short -> bool
311 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int != long -> bool
312 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // int != char -> bool
313 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short != double -> bool
314 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short != int -> bool
315 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short != short -> bool
316 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short != long -> bool
317 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_CHAR, SuperType::TY_BOOL}); // short != char -> bool
318 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long != double -> bool
319 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long != int -> bool
320 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long != short -> bool
321 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long != long -> bool
322 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_CHAR, SuperType::TY_BOOL}); // long != char -> bool
323 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte != byte -> bool
324 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_BOOL}); // char != int -> bool
325 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_SHORT, SuperType::TY_BOOL}); // char != short -> bool
326 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_LONG, SuperType::TY_BOOL}); // char != long -> bool
327 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char != char -> bool
328 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_BOOL}); // string != string -> bool
329 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // bool != bool -> bool
330 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_FUNCTION, SuperType::TY_FUNCTION, SuperType::TY_BOOL}); // function != function -> bool
331 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PROCEDURE, SuperType::TY_PROCEDURE, SuperType::TY_BOOL}); // procedure != procedure -> bool
332 7925 this.notEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* != any* -> bool
333
334 // Less op rules
335 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double < double -> bool
336 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double < int -> bool
337 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double < short -> bool
338 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double < long -> bool
339 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int < double -> bool
340 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int < int -> bool
341 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int < short -> bool
342 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int < long -> bool
343 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short < double -> bool
344 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short < int -> bool
345 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short < short -> bool
346 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short < long -> bool
347 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long < double -> bool
348 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long < int -> bool
349 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long < short -> bool
350 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long < long -> bool
351 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte < byte -> bool
352 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char < char -> bool
353 7925 this.lessOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* < any* -> bool
354
355 // Greater op rules
356 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double > double -> bool
357 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double > int -> bool
358 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double > short -> bool
359 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double > long -> bool
360 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int > double -> bool
361 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int > int -> bool
362 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int > short -> bool
363 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int > long -> bool
364 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short > double -> bool
365 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short > int -> bool
366 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short > short -> bool
367 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short > long -> bool
368 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long > double -> bool
369 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long > int -> bool
370 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long > short -> bool
371 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long > long -> bool
372 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte > byte -> bool
373 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char > char -> bool
374 7925 this.greaterOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* > any* -> bool
375
376 // Less equal op rules
377 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double <= double -> bool
378 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double <= int -> bool
379 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double <= short -> bool
380 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double <= long -> bool
381 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int <= double -> bool
382 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int <= int -> bool
383 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int <= short -> bool
384 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int <= long -> bool
385 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short <= double -> bool
386 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short <= int -> bool
387 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short <= short -> bool
388 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short <= long -> bool
389 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long <= double -> bool
390 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long <= int -> bool
391 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long <= short -> bool
392 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long <= long -> bool
393 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte <= byte -> bool
394 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char <= char -> bool
395 7925 this.lessEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* <= any* -> bool
396
397 // Greater equal op rules
398 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // double >= double -> bool
399 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_BOOL}); // double >= int -> bool
400 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_BOOL}); // double >= short -> bool
401 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_BOOL}); // double >= long -> bool
402 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // int >= double -> bool
403 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_BOOL}); // int >= int -> bool
404 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // int >= short -> bool
405 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_BOOL}); // int >= long -> bool
406 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // short >= double -> bool
407 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_BOOL}); // short >= int -> bool
408 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_BOOL}); // short >= short -> bool
409 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BOOL}); // short >= long -> bool
410 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_BOOL}); // long >= double -> bool
411 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_BOOL}); // long >= int -> bool
412 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_BOOL}); // long >= short -> bool
413 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_BOOL}); // long >= long -> bool
414 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BOOL}); // byte >= byte -> bool
415 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_BOOL}); // char >= char -> bool
416 7925 this.greaterEqualOpRules.pushBack(BinaryOpRule{SuperType::TY_PTR, SuperType::TY_PTR, SuperType::TY_BOOL}); // any* >= any* -> bool
417
418 // Shift left op rules
419 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int << int -> int
420 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int << short -> int
421 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int << long -> int
422 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short << int -> short
423 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short << short -> short
424 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short << long -> short
425 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long << int -> long
426 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long << short -> long
427 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long << long -> long
428 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_INT, SuperType::TY_BYTE}); // byte << int -> byte
429 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_SHORT, SuperType::TY_BYTE}); // byte << short -> byte
430 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_LONG, SuperType::TY_BYTE}); // byte << long -> byte
431 7925 this.shiftLeftOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte << byte -> byte
432
433 // Shift right op rules
434 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int >> int -> int
435 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int >> short -> int
436 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // int >> long -> int
437 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // short >> int -> short
438 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short >> short -> short
439 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // short >> long -> short
440 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long >> int -> long
441 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long >> short -> long
442 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long >> long -> long
443 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_INT, SuperType::TY_BYTE}); // byte >> int -> byte
444 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_SHORT, SuperType::TY_BYTE}); // byte >> short -> byte
445 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_LONG, SuperType::TY_BYTE}); // byte >> long -> byte
446 7925 this.shiftRightOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte >> byte -> byte
447
448 // Plus op rules
449 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double + double -> double
450 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double + int -> double
451 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double + short -> double
452 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double + long -> double
453 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int + double -> double
454 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int + int -> int
455 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int + short -> int
456 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int + long -> long
457 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short + double -> double
458 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short + int -> int
459 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short + short -> short
460 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short + long -> long
461 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long + double -> double
462 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long + int -> long
463 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long + short -> long
464 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long + long -> long
465 7925 this.plusOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte + byte -> byte
466
467 // Minus op rules
468 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double - double -> double
469 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double - int -> double
470 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double - short -> double
471 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double - long -> double
472 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int - double -> double
473 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int - int -> int
474 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int - short -> int
475 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int - long -> long
476 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short - double -> double
477 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short - int -> int
478 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short - short -> short
479 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short - long -> long
480 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long - double -> double
481 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long - int -> long
482 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long - short -> long
483 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long - long -> long
484 7925 this.minusOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte - byte -> byte
485
486 // Mul op rules
487 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double * double -> double
488 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double * int -> double
489 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double * short -> double
490 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double * long -> double
491 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int * double -> double
492 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int * int -> int
493 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int * short -> int
494 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int * long -> long
495 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short * double -> double
496 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short * int -> int
497 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short * short -> short
498 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short * long -> long
499 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long * double -> double
500 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long * int -> long
501 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long * short -> long
502 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long * long -> long
503 7925 this.mulOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte * byte -> byte
504
505 // Div op rules
506 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double / double -> double
507 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // double / int -> double
508 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // double / short -> double
509 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // double / long -> double
510 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // int / double -> double
511 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int / int -> int
512 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int / short -> int
513 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int / long -> long
514 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // short / double -> double
515 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short / int -> int
516 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short / short -> short
517 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short / long -> long
518 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // long / double -> double
519 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long / int -> long
520 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long / short -> long
521 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long / long -> long
522 7925 this.divOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // byte / byte -> byte
523
524 // Rem op rules
525 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // double % double -> double
526 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // int % int -> int
527 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // int % short -> int
528 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_LONG}); // int % long -> long
529 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_INT}); // short % int -> int
530 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // short % short -> short
531 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_LONG}); // short % long -> long
532 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // long % int -> long
533 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // long % short -> long
534 7925 this.remOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // long % long -> long
535
536 // Prefix Minus op rules
537 7925 this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // -double -> double
538 7925 this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // -int -> int
539 7925 this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // -short -> short
540 7925 this.prefixMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // -long -> long
541
542 // Prefix Plus-Plus op rules
543 7925 this.prefixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // int++ -> int
544 7925 this.prefixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short++ -> short
545 7925 this.prefixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long++ -> long
546
547 // Prefix Minus-Minus op rules
548 7925 this.prefixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // in-- -> int
549 7925 this.prefixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short-- -> short
550 7925 this.prefixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long-- -> long
551
552 // Prefix not op rules
553 7925 this.prefixNotOpRules.pushBack(UnaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL}); // !bool -> bool
554
555 // Prefix bitwise not op rules
556 7925 this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // ~int -> int
557 7925 this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // ~short -> short
558 7925 this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // ~long -> long
559 7925 this.prefixBitwiseNotOpRules.pushBack(UnaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE}); // ~byte -> byte
560
561 // Postfix Plus-Plus op rules
562 7925 this.postfixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // int++ -> int
563 7925 this.postfixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short++ -> short
564 7925 this.postfixPlusPlusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long++ -> long
565
566 // Postfix Minus-Minus op rules
567 7925 this.postfixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_INT, SuperType::TY_INT}); // int++ -> int
568 7925 this.postfixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT}); // short++ -> short
569 7925 this.postfixMinusMinusOpRules.pushBack(UnaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG}); // long++ -> long
570
571 // Cast op rules
572 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE}); // cast<double>(double) -> double
573 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_INT, SuperType::TY_DOUBLE}); // cast<double>(int) -> double
574 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_SHORT, SuperType::TY_DOUBLE}); // cast<double>(short) -> double
575 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_DOUBLE, SuperType::TY_LONG, SuperType::TY_DOUBLE}); // cast<double>(long) -> double
576 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_DOUBLE, SuperType::TY_INT}); // cast<int>(double) -> int
577 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_INT, SuperType::TY_INT}); // cast<int>(int) -> int
578 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_INT}); // cast<int>(short) -> int
579 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_INT}); // cast<int>(long) -> int
580 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_BYTE, SuperType::TY_INT}); // cast<int>(byte) -> int
581 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_CHAR, SuperType::TY_INT}); // cast<int>(char) -> int
582 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_INT, SuperType::TY_BOOL, SuperType::TY_INT}); // cast<int>(bool) -> int
583 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_DOUBLE, SuperType::TY_SHORT}); // cast<short>(double) -> short
584 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_INT, SuperType::TY_SHORT}); // cast<short>(int) -> short
585 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_SHORT, SuperType::TY_SHORT}); // cast<short>(short) -> short
586 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_SHORT}); // cast<short>(long) -> short
587 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_SHORT, SuperType::TY_BOOL, SuperType::TY_SHORT}); // cast<short>(bool) -> short
588 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_DOUBLE, SuperType::TY_LONG}); // cast<long>(double) -> long
589 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_INT, SuperType::TY_LONG}); // cast<long>(int) -> long
590 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_SHORT, SuperType::TY_LONG}); // cast<long>(short) -> long
591 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_LONG, SuperType::TY_LONG}); // cast<long>(long) -> long
592 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_LONG, SuperType::TY_BOOL, SuperType::TY_LONG}); // cast<long>(bool) -> long
593 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_INT, SuperType::TY_BYTE}); // cast<byte>(int) -> byte
594 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BYTE, SuperType::TY_BYTE}); // cast<byte>(byte) -> byte
595 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_CHAR, SuperType::TY_BYTE}); // cast<byte>(char) -> byte
596 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BYTE, SuperType::TY_BOOL, SuperType::TY_BYTE}); // cast<byte>(bool) -> byte
597 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_INT, SuperType::TY_CHAR}); // cast<char>(int) -> char
598 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_SHORT, SuperType::TY_CHAR}); // cast<char>(short) -> char
599 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_LONG, SuperType::TY_CHAR}); // cast<char>(long) -> char
600 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_BYTE, SuperType::TY_CHAR}); // cast<char>(byte) -> char
601 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_CHAR, SuperType::TY_CHAR, SuperType::TY_CHAR}); // cast<char>(char) -> char
602 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_STRING, SuperType::TY_STRING, SuperType::TY_STRING}); // cast<string>(string) -> string
603 7925 this.castOpRules.pushBack(BinaryOpRule{SuperType::TY_BOOL, SuperType::TY_BOOL, SuperType::TY_BOOL}); // cast<bool>(bool) -> bool
604 7925 }
605
606 // Build an expression result without symbol table entry
607 169469 f<ExprResult> toExprResult(const QualType& qualType) {
608 169469 return ExprResult{qualType, nil<SymbolTableEntry*>};
609 }
610
611 // Operand list for the overload lookup of a binary operator
612 73129 f<Vector<ExprResult>> binaryOperands(const ExprResult& lhs, const ExprResult& rhs) {
613 73129 Vector<ExprResult> operands;
614 73129 operands.pushBack(lhs);
615 73129 operands.pushBack(rhs);
616 73129 return operands;
617 }
618
619 // Operand list for the overload lookup of a unary operator
620 9338 f<Vector<ExprResult>> unaryOperand(const ExprResult& lhs) {
621 9338 Vector<ExprResult> operands;
622 9338 operands.pushBack(lhs);
623 9338 return operands;
624 }
625
626 // Result of an assignment: the result type and the called copy ctor
627 110673 f<Pair<QualType, Function*>> assignResult(const QualType& qualType, Function* copyCtor = nil<Function*>) {
628 110673 return Pair<QualType, Function*>(qualType, copyCtor);
629 }
630
631 106554 public f<Pair<QualType, Function*>> OpRuleManager.getAssignResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, bool isDecl = false, bool isReturn = false, string errMsgPrefix = "") {
632 // Retrieve types
633 106554 const QualType lhsType = lhs.ty;
634 106554 const QualType rhsType = rhs.ty;
635
636 // Check if lhs is a temporary
637
3/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38730 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 67823 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
106554 if lhs.isTemporary() {
638 1 throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, String("Cannot assign to a temporary value"));
639 2 return assignResult(QualType(SuperType::TY_UNRESOLVED));
640 1 }
641
642 // Skip type compatibility check if the lhs is of type dyn -> perform type inference
643
3/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 38730 times.
✓ Branch 4 taken 283 times.
✓ Branch 5 taken 67540 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
106553 if lhsType.is(SuperType::TY_DYN) {
644 283 return assignResult(rhsType);
645 }
646
647 // Check if we try to assign a constant value
648 106270 this.ensureNoConstAssign(node, lhsType, isDecl, isReturn);
649
650 // Allow pointers and references of the same type straight away
651 106270 const dyn ptrOrRefTypes = [SuperType::TY_PTR, SuperType::TY_REF];
652
8/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 35036 times.
✓ Branch 5 taken 3694 times.
✓ Branch 6 taken 2404 times.
✓ Branch 7 taken 36326 times.
✓ Branch 8 taken 52818 times.
✓ Branch 9 taken 14722 times.
✓ Branch 10 taken 11572 times.
✓ Branch 11 taken 55968 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
106270 if lhsType.isOneOf(ptrOrRefTypes, len(ptrOrRefTypes)) && lhsType.matches(rhsType, false, false, true) {
653 // If we perform a heap x* = heap x* assignment, we need set the right hand side to MOVED
654 13976 const QualType rhsUnwrappedType = rhsType.removeReferenceWrapper();
655
18/40
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1203 times.
✓ Branch 11 taken 1201 times.
✓ Branch 12 taken 801 times.
✓ Branch 13 taken 402 times.
✓ Branch 14 taken 573 times.
✓ Branch 15 taken 228 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 573 times.
✓ Branch 18 taken 1831 times.
✓ Branch 19 taken 573 times.
✓ Branch 20 taken 2854 times.
✓ Branch 21 taken 8718 times.
✓ Branch 22 taken 2069 times.
✓ Branch 23 taken 785 times.
✓ Branch 24 taken 1286 times.
✓ Branch 25 taken 783 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 1286 times.
✓ Branch 28 taken 10286 times.
✓ Branch 29 taken 1286 times.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
13976 if rhs.entry != nil<SymbolTableEntry*> && lhsType.isPtr() && lhsType.isHeap() && rhsUnwrappedType.isPtr() && rhsType.isHeap() {
656 1859 rhs.entry.updateState(LifecycleState::MOVED);
657 1859 }
658 13976 return assignResult(rhsType);
659 }
660 // Allow ref type to type of the same contained type straight away
661
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 36124 times.
✓ Branch 3 taken 202 times.
✓ Branch 4 taken 53992 times.
✓ Branch 5 taken 1976 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
92294 if rhsType.isRef() {
662 // If this is const ref, remove both: the reference and the constness
663 2178 const QualType rhsContainedType = rhsType.getContained();
664 2178 const QualType rhsNonRef = rhsContainedType.toNonConst();
665
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 201 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1971 times.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2178 if lhsType.matches(rhsNonRef, false, false, true) {
666
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 92 times.
✓ Branch 3 taken 109 times.
✓ Branch 4 taken 928 times.
✓ Branch 5 taken 1043 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2172 if rhsNonRef.is(SuperType::TY_STRUCT) {
667 1020 return this.performStructAssign(node, lhs, rhs, rhsNonRef, isDecl, isReturn);
668 }
669 1152 return assignResult(lhsType);
670 }
671 6 }
672 // Allow arrays, unions, interfaces, functions, procedures of the same type straight away
673 90122 const dyn directlyAssignableTypes = [SuperType::TY_ARRAY, SuperType::TY_UNION, SuperType::TY_INTERFACE, SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE];
674
8/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 36062 times.
✓ Branch 5 taken 63 times.
✓ Branch 6 taken 63 times.
✓ Branch 7 taken 36062 times.
✓ Branch 8 taken 53533 times.
✓ Branch 9 taken 464 times.
✓ Branch 10 taken 459 times.
✓ Branch 11 taken 53538 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
90122 if lhsType.isOneOf(directlyAssignableTypes, len(directlyAssignableTypes)) && lhsType.matches(rhsType, false, true, true) {
675 522 return assignResult(rhsType);
676 }
677 // Allow struct of the same type straight away
678
8/16
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 30162 times.
✓ Branch 5 taken 5900 times.
✓ Branch 6 taken 5900 times.
✓ Branch 7 taken 30162 times.
✓ Branch 8 taken 48465 times.
✓ Branch 9 taken 5073 times.
✓ Branch 10 taken 5072 times.
✓ Branch 11 taken 48466 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
89600 if lhsType.is(SuperType::TY_STRUCT) && lhsType.matches(rhsType, false, true, true) {
679 10972 return this.performStructAssign(node, lhs, rhs, rhsType, isDecl, isReturn);
680 }
681 // Allow assignment through an already-bound reference to a struct. Unlike binding a reference (declaration/return,
682 // which pass isDecl/isReturn and fall through to the common rules below), an assign-through must run the struct's
683 // copy-assignment operator / copy ctor on the referenced value instead of rebinding or shallow-copying it. Otherwise
684 // the referent would alias the rhs' owned members (heap buffers) and double-free once one of them is destructed.
685
10/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 30161 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 30158 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 30162 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 18603 times.
✓ Branch 13 taken 29863 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 18603 times.
✓ Branch 16 taken 47984 times.
✓ Branch 17 taken 482 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
78628 if !isDecl && !isReturn && lhsType.isRef() {
686 482 const QualType lhsContainedType = lhsType.getContained();
687 482 const QualType rhsUnwrappedType = rhsType.removeReferenceWrapper();
688
6/32
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 51 times.
✓ Branch 17 taken 431 times.
✓ Branch 18 taken 51 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 51 times.
✓ Branch 22 taken 51 times.
✓ Branch 23 taken 431 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
482 if lhsContainedType.is(SuperType::TY_STRUCT) && lhs.entry != nil<SymbolTableEntry*> && lhs.entry.isInitialized() && lhsContainedType.matches(rhsUnwrappedType, false, true, true) {
689 51 return this.performStructAssign(node, lhs, rhs, lhsContainedType, isDecl, isReturn);
690 }
691 431 }
692
693 // Check common type combinations
694 78577 const QualType resultType = this.getAssignResultTypeCommon(node, lhs, rhs, isDecl, isReturn);
695
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1261 times.
✓ Branch 3 taken 28901 times.
✓ Branch 4 taken 2433 times.
✓ Branch 5 taken 45982 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
78577 if !resultType.is(SuperType::TY_INVALID) {
696 3694 return assignResult(resultType);
697 }
698
699 // An assignment through an already-bound reference assigns the referenced value, so it follows the rules for assigning to
700 // the referenced type. E.g. the value of a const source can be copied into a non-const referent.
701
10/24
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 28900 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 28897 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 28901 times.
✓ Branch 12 taken 17694 times.
✓ Branch 13 taken 28288 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 17694 times.
✓ Branch 16 taken 6 times.
✓ Branch 17 taken 45976 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
74883 if !isDecl && !isReturn && lhsType.isRef() {
702 6 const ExprResult referencedLhs = ExprResult{lhsType.getContained(), lhs.entry};
703 6 const Pair<QualType, Function*> referencedResult = this.getAssignResultType(node, referencedLhs, rhs, false, false, errMsgPrefix);
704 6 const QualType referencedResultType = referencedResult.getFirst();
705
2/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6 if referencedResultType.is(SuperType::TY_UNRESOLVED) {
706 1 return referencedResult;
707 }
708 5 return assignResult(lhsType, referencedResult.getSecond());
709 }
710
711 // Check primitive type combinations
712 74877 const QualType binOpType = this.validateBinaryOperation(node, this.assignOpRules, "=", lhsType, rhsType, true, errMsgPrefix);
713 74877 return assignResult(binOpType);
714 }
715
716 4120 public f<Pair<QualType, Function*>> OpRuleManager.getFieldAssignResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, bool imm, bool isDecl = false) {
717 // Retrieve types
718 4120 const QualType lhsType = lhs.ty;
719 4120 const QualType rhsType = rhs.ty;
720 4120 assert !lhsType.is(SuperType::TY_DYN);
721
722 // Check if we try to assign a constant value
723 4120 this.ensureNoConstAssign(node, lhsType, isDecl, false);
724
725 // Allow pointers and arrays of the same type straight away
726 4120 const dyn ptrOrArrayTypes = [SuperType::TY_PTR, SuperType::TY_ARRAY];
727
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3371 times.
✓ Branch 5 taken 749 times.
✓ Branch 6 taken 746 times.
✓ Branch 7 taken 3374 times.
4120 if lhsType.isOneOf(ptrOrArrayTypes, len(ptrOrArrayTypes)) && lhsType == rhsType {
728 // If we perform a heap x* = heap x* assignment, we need set the right hand side to MOVED
729 746 const QualType rhsUnwrappedType = rhsType.removeReferenceWrapper();
730
6/20
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 170 times.
✓ Branch 11 taken 576 times.
✓ Branch 12 taken 166 times.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 166 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 746 times.
✗ Branch 19 not taken.
746 if rhs.entry != nil<SymbolTableEntry*> && lhsType.isPtr() && lhsType.isHeap() && rhsUnwrappedType.isPtr() && rhsType.isHeap() {
731 ✗ rhs.entry.updateState(LifecycleState::MOVED);
732 ✗ }
733 746 return assignResult(rhsType);
734 }
735 // Allow struct of the same type straight away
736
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3288 times.
✓ Branch 5 taken 86 times.
✓ Branch 6 taken 75 times.
✓ Branch 7 taken 3299 times.
3374 if lhsType.is(SuperType::TY_STRUCT) && lhsType.matches(rhsType, false, true, true) {
737 75 return this.performStructAssign(node, lhs, rhs, rhsType, isDecl, false);
738 }
739 // Allow union of the same type straight away (always trivially copyable, so no copy-ctor machinery is needed)
740
2/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3299 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3299 times.
3299 if lhsType.is(SuperType::TY_UNION) && lhsType.matches(rhsType, false, true, true) {
741 ✗ return assignResult(rhsType);
742 }
743 // Allow ref type to type of the same contained type straight away
744
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3280 times.
✓ Branch 3 taken 19 times.
3299 if rhsType.isRef() {
745 19 const QualType rhsContainedType = rhsType.getContained();
746
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 13 times.
19 if lhsType.matches(rhsContainedType, false, false, true) {
747 // Initializing a field constructs a new value, so we copy via the copy ctor instead of calling an overloaded
748 // assign operator. The rhs may have no entry (e.g. a function call returning a reference), so go by type
749 6 Function* copyCtor = nil<Function*>;
750 6 const QualType rhsContainedNonConstType = rhsContainedType.toNonConst();
751
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 1 time.
6 if rhsContainedNonConstType.is(SuperType::TY_STRUCT) && !rhs.isTemporary() {
752 1 copyCtor = this.typeChecker.implicitlyCallStructCopyCtor(rhsContainedNonConstType, node);
753 1 }
754 6 return assignResult(lhsType, copyCtor);
755 }
756 13 }
757 // Allow ref type to type of the same contained type straight away
758
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3280 times.
✓ Branch 3 taken 13 times.
3293 if rhsType.isRef() {
759 // If this is const ref, remove both: the reference and the constness
760 13 const QualType rhsContainedType = rhsType.getContained();
761 13 const QualType rhsNonRef = rhsContainedType.toNonConst();
762
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 if lhsType.matches(rhsNonRef, false, false, true) {
763 13 return this.performStructAssign(node, lhs, rhs, rhsNonRef, isDecl, false);
764 }
765 ✗ }
766 // Allow immediate value to const ref of the same contained type straight away
767
4/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3278 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3278 times.
3280 if lhsType.isConstRef() && imm {
768 2 return assignResult(rhsType);
769 }
770
771 // Check common type combinations
772 3278 const QualType resultType = this.getAssignResultTypeCommon(node, lhs, rhs, isDecl, false);
773
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3269 times.
3278 if !resultType.is(SuperType::TY_INVALID) {
774 9 return assignResult(resultType);
775 }
776
777 // Check primitive type combinations
778 3269 const QualType binOpType = this.validateBinaryOperation(node, this.assignOpRules, "=", lhsType, rhsType, true, ERROR_FIELD_ASSIGN);
779 3269 return assignResult(binOpType);
780 }
781
782 81855 f<QualType> OpRuleManager.getAssignResultTypeCommon(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, bool isDecl, bool isReturn) {
783 // Retrieve types
784 81855 const QualType lhsType = lhs.ty;
785 81855 const QualType rhsType = rhs.ty;
786
787 // Allow type to ref type of the same contained type straight away
788
2/2
✓ Branch 0 taken 78877 times.
✓ Branch 1 taken 2978 times.
81855 if lhsType.isRef() {
789 2978 const QualType lhsContainedType = lhsType.getContained();
790
2/2
✓ Branch 0 taken 2961 times.
✓ Branch 1 taken 17 times.
2978 if lhsContainedType.matches(rhsType, false, false, true) {
791
2/2
✓ Branch 0 taken 1316 times.
✓ Branch 1 taken 1645 times.
2961 const bool isDeclOrReturn = isDecl || isReturn;
792
4/4
✓ Branch 0 taken 425 times.
✓ Branch 1 taken 2536 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2959 times.
2961 if isDeclOrReturn && !lhsType.canBind(rhsType, rhs.isTemporary()) {
793 2 throwSemanticError(node, SemanticErrorType::TEMP_TO_NON_CONST_REF, String("Temporary values can only be bound to const reference variables/fields"));
794 4 return QualType(SuperType::TY_UNRESOLVED);
795 2 }
796
4/4
✓ Branch 0 taken 1739 times.
✓ Branch 1 taken 1220 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2958 times.
2959 if isReturn && rhs.isTemporary() {
797 1 throwSemanticError(node, SemanticErrorType::RETURN_OF_TEMPORARY_VALUE, String("Cannot return reference to temporary value"));
798 2 return QualType(SuperType::TY_UNRESOLVED);
799 1 }
800 2958 return lhsType;
801 }
802 17 }
803 // Allow char* = string
804
5/6
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 78893 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 78893 times.
78894 if lhsType.isPtrTo(SuperType::TY_CHAR) && rhsType.is(SuperType::TY_STRING) && lhsType.qualifiers == rhsType.qualifiers {
805 1 return lhsType;
806 }
807 // Allow array to pointer
808
4/4
✓ Branch 0 taken 78157 times.
✓ Branch 1 taken 736 times.
✓ Branch 2 taken 78881 times.
✓ Branch 3 taken 12 times.
78893 if lhsType.isPtr() && rhsType.isArray() {
809 12 const QualType lhsContainedType = lhsType.getContained();
810 12 const QualType rhsContainedType = rhsType.getContained();
811
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if lhsContainedType.matches(rhsContainedType, false, false, true) {
812 12 return lhsType;
813 }
814 ✗ }
815 // Allow interface* = struct* or interface& = struct that implements this interface
816 78881 const bool sameChainDepth = hasSameTypeChainDepth(lhsType.getType(), rhsType.getType());
817
6/6
✓ Branch 0 taken 724 times.
✓ Branch 1 taken 78157 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 723 times.
✓ Branch 4 taken 723 times.
✓ Branch 5 taken 78158 times.
78881 const bool typesCompatible = (lhsType.isPtr() && rhsType.isPtr() && sameChainDepth) || lhsType.isRef();
818
6/6
✓ Branch 0 taken 740 times.
✓ Branch 1 taken 78141 times.
✓ Branch 2 taken 715 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 78856 times.
✓ Branch 5 taken 25 times.
78881 if typesCompatible && lhsType.isBase(SuperType::TY_INTERFACE) && rhsType.isBase(SuperType::TY_STRUCT) {
819 25 QualType lhsTypeCopy = lhsType;
820 25 QualType rhsTypeCopy = rhsType;
821 25 unwrapBothWithRefWrappers(lhsTypeCopy, rhsTypeCopy);
822
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 if lhsTypeCopy.matchesInterfaceImplementedByStruct(rhsTypeCopy) {
823 25 return lhsType;
824 }
825 ✗ }
826 // Allow type* = heap type* straight away. This is used for initializing non-owning pointers to heap allocations
827
6/6
✓ Branch 0 taken 707 times.
✓ Branch 1 taken 78149 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 704 times.
✓ Branch 4 taken 78152 times.
✓ Branch 5 taken 704 times.
78856 if lhsType.isPtr() && rhsType.isHeap() && lhsType.matches(rhsType, false, true, true) {
828 704 TypeQualifiers rhsQualifiers = rhsType.qualifiers;
829 704 rhsQualifiers.isHeap = false;
830
1/2
✓ Branch 0 taken 704 times.
✗ Branch 1 not taken.
704 if lhsType.qualifiers == rhsQualifiers {
831 704 return lhsType;
832 }
833 ✗ }
834
835 // Nothing matched
836 78152 return QualType(SuperType::TY_INVALID);
837 }
838
839 12131 f<Pair<QualType, Function*>> OpRuleManager.performStructAssign(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, const QualType& rhsType, bool isDecl, bool isReturn) {
840 12131 const bool rhsIsRef = rhs.ty.isRef();
841
842 // Check is there is an overloaded operator function available
843
6/6
✓ Branch 0 taken 8495 times.
✓ Branch 1 taken 3636 times.
✓ Branch 2 taken 5965 times.
✓ Branch 3 taken 2530 times.
✓ Branch 4 taken 10473 times.
✓ Branch 5 taken 1658 times.
12131 if !isDecl && !isReturn && lhs.entry.isInitialized() {
844 1658 const ExprResult overloadResult = this.isOperatorOverloadingFctAvailable(node, OP_FCT_ASSIGN, binaryOperands(lhs, rhs), 0l);
845
2/2
✓ Branch 0 taken 687 times.
✓ Branch 1 taken 971 times.
1658 if !overloadResult.ty.is(SuperType::TY_INVALID) {
846 1374 return assignResult(overloadResult.ty);
847 }
848 1658 }
849
850 // If temp stealing is possible, delete any rhs anonymous entry
851
4/4
✓ Branch 0 taken 841 times.
✓ Branch 1 taken 10603 times.
✓ Branch 2 taken 9960 times.
✓ Branch 3 taken 1484 times.
11444 if !rhsIsRef && rhs.isTemporary() {
852
4/4
✓ Branch 0 taken 4375 times.
✓ Branch 1 taken 5585 times.
✓ Branch 2 taken 4375 times.
✓ Branch 3 taken 5585 times.
9960 if rhs.entry != nil<SymbolTableEntry*> && rhs.entry.anonymous {
853 5585 this.typeChecker.currentScope.symbolTable.deleteAnonymous(rhs.entry.name);
854 5585 }
855 9960 return assignResult(rhsType);
856 }
857
858 // If RVO is possible, cancel here
859
4/4
✓ Branch 0 taken 898 times.
✓ Branch 1 taken 586 times.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 1284 times.
1484 if isReturn && this.typeChecker.isReturnValueOptimizable(rhs) {
860 200 return assignResult(rhsType);
861 }
862
863 // => We have to copy
864 // If struct, try to call copy ctor
865
2/2
✓ Branch 0 taken 1280 times.
✓ Branch 1 taken 4 times.
1284 if rhsType.is(SuperType::TY_STRUCT) {
866 1280 return assignResult(rhsType, this.typeChecker.implicitlyCallStructCopyCtor(rhsType, node));
867 }
868
869 // Perform shallow copy
870 4 return assignResult(rhsType);
871 }
872
873 // Result of the compound assignment operators +=, -=, *= and /=, which support operator overloading
874 2360 f<ExprResult> OpRuleManager.getArithmeticEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, string fctName, const BinaryOpRules& opRules, string name, bool allowPtrArithmetic) {
875 // Check is there is an overloaded operator function available
876 2360 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), 0l);
877
2/2
✓ Branch 0 taken 876 times.
✓ Branch 1 taken 1484 times.
2360 if !resultType.ty.is(SuperType::TY_INVALID) {
878 1752 return resultType;
879 }
880
881 // Check if we try to assign a constant value
882 1484 this.ensureNoConstAssign(node, lhs.ty, false, false);
883
884 // Remove reference wrappers
885 1484 const QualType lhsType = lhs.ty.removeReferenceWrapper();
886 1484 const QualType rhsType = rhs.ty.removeReferenceWrapper();
887
888 // Check if this is an unsafe operation
889 1484 const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_SHORT];
890
6/6
✓ Branch 0 taken 1289 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 1274 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 1469 times.
1484 if allowPtrArithmetic && lhsType.isPtr() && rhsType.isOneOf(integerTypes, len(integerTypes)) {
891 15 this.ensureUnsafeAllowed(node, name, lhsType, rhsType);
892 30 return lhs;
893 }
894
895 1469 const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, "");
896 2938 return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, false));
897 2360 }
898
899 1998 public f<ExprResult> OpRuleManager.getPlusEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
900 1998 return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_PLUS_EQUAL, this.plusEqualOpRules, "+=", true);
901 }
902
903 94 public f<ExprResult> OpRuleManager.getMinusEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
904 94 return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_MINUS_EQUAL, this.minusEqualOpRules, "-=", true);
905 }
906
907 160 public f<ExprResult> OpRuleManager.getMulEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
908 160 return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_MUL_EQUAL, this.mulEqualOpRules, "*=", false);
909 }
910
911 108 public f<ExprResult> OpRuleManager.getDivEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
912 108 return this.getArithmeticEqualResultType(node, lhs, rhs, OP_FCT_DIV_EQUAL, this.divEqualOpRules, "/=", false);
913 }
914
915 // Result of the compound assignment operators without operator overloading support (%=, <<=, >>=, &=, |=, ^=)
916 407 f<QualType> OpRuleManager.getSimpleEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, const BinaryOpRules& opRules, string name) {
917 // Check if we try to assign a constant value
918 407 this.ensureNoConstAssign(node, lhs.ty, false, false);
919
920 // Remove reference wrappers
921 407 const QualType lhsType = lhs.ty.removeReferenceWrapper();
922 407 const QualType rhsType = rhs.ty.removeReferenceWrapper();
923
924 407 const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, "");
925 407 return applyIntegerSignedness(binOpType, lhsType, rhsType, false);
926 }
927
928 62 public f<QualType> OpRuleManager.getRemEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
929 62 return this.getSimpleEqualResultType(node, lhs, rhs, this.remEqualOpRules, "%=");
930 }
931
932 13 public f<QualType> OpRuleManager.getSHLEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
933 13 return this.getSimpleEqualResultType(node, lhs, rhs, this.shlEqualOpRules, "<<=");
934 }
935
936 20 public f<QualType> OpRuleManager.getSHREqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
937 20 return this.getSimpleEqualResultType(node, lhs, rhs, this.shrEqualOpRules, ">>=");
938 }
939
940 30 public f<QualType> OpRuleManager.getAndEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
941 30 return this.getSimpleEqualResultType(node, lhs, rhs, this.andEqualOpRules, "&=");
942 }
943
944 32 public f<QualType> OpRuleManager.getOrEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
945 32 return this.getSimpleEqualResultType(node, lhs, rhs, this.orEqualOpRules, "|=");
946 }
947
948 250 public f<QualType> OpRuleManager.getXorEqualResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
949 250 return this.getSimpleEqualResultType(node, lhs, rhs, this.xorEqualOpRules, "^=");
950 }
951
952 // Result of a binary operator without operator overloading support and without special cases
953 20337 f<QualType> OpRuleManager.getSimpleBinaryResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, const BinaryOpRules& opRules, string name) {
954 // Remove reference wrappers
955 20337 const QualType lhsType = lhs.ty.removeReferenceWrapper();
956 20337 const QualType rhsType = rhs.ty.removeReferenceWrapper();
957
958 20337 const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, "");
959 20337 return applyIntegerSignedness(binOpType, lhsType, rhsType, true);
960 }
961
962 4421 public f<QualType> OpRuleManager.getLogicalOrResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
963 4421 return this.getSimpleBinaryResultType(node, lhs, rhs, this.logicalOrOpRules, "||");
964 }
965
966 2257 public f<QualType> OpRuleManager.getLogicalAndResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
967 2257 return this.getSimpleBinaryResultType(node, lhs, rhs, this.logicalAndOpRules, "&&");
968 }
969
970 // Result of a binary operator with operator overloading support and without special cases
971 4672 f<ExprResult> OpRuleManager.getOverloadableBinaryResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx, string fctName, const BinaryOpRules& opRules, string name, bool considerRhsSignedness = true) {
972 // Check if there is an overloaded operator function available
973 4672 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), opIdx);
974
4/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 3635 times.
✓ Branch 2 taken 547 times.
✓ Branch 3 taken 443 times.
4672 if !resultType.ty.is(SuperType::TY_INVALID) {
975 1188 return resultType;
976 }
977
978 // Remove reference wrappers
979 4078 const QualType lhsType = lhs.ty.removeReferenceWrapper();
980 4078 const QualType rhsType = rhs.ty.removeReferenceWrapper();
981
982 4078 const QualType binOpType = this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, "");
983 8156 return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, considerRhsSignedness));
984 4672 }
985
986 446 public f<ExprResult> OpRuleManager.getBitwiseOrResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
987 446 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_BITWISE_OR, this.bitwiseOrOpRules, "|");
988 }
989
990 91 public f<ExprResult> OpRuleManager.getBitwiseXorResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
991 91 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_BITWISE_XOR, this.bitwiseXorOpRules, "^");
992 }
993
994 314 public f<ExprResult> OpRuleManager.getBitwiseAndResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
995 314 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_BITWISE_AND, this.bitwiseAndOpRules, "&");
996 }
997
998 // Result of == and !=
999 28633 f<ExprResult> OpRuleManager.getEqualityResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, string fctName, const BinaryOpRules& opRules, string name) {
1000 // Check is there is an overloaded operator function available
1001 28633 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), 0l);
1002
2/2
✓ Branch 0 taken 1773 times.
✓ Branch 1 taken 26860 times.
28633 if !resultType.ty.is(SuperType::TY_INVALID) {
1003 3546 return resultType;
1004 }
1005
1006 // Remove reference wrappers
1007 26860 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1008 26860 const QualType rhsType = rhs.ty.removeReferenceWrapper();
1009
1010 // Allow 'pointer == unsigned long' straight away
1011
6/6
✓ Branch 0 taken 5926 times.
✓ Branch 1 taken 20934 times.
✓ Branch 2 taken 5924 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 26858 times.
26860 if lhsType.isPtr() && rhsType.is(SuperType::TY_LONG) && rhsType.isUnsigned() {
1012 4 return toExprResult(QualType(SuperType::TY_BOOL));
1013 }
1014
1015 // Allow 'string == char*' and vice versa straight away
1016
7/8
✓ Branch 0 taken 26305 times.
✓ Branch 1 taken 553 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26858 times.
✓ Branch 4 taken 23685 times.
✓ Branch 5 taken 3173 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 26856 times.
26858 if (lhsType.is(SuperType::TY_STRING) && rhsType.isPtrTo(SuperType::TY_CHAR)) || (lhsType.isPtrTo(SuperType::TY_CHAR) && rhsType.is(SuperType::TY_STRING)) {
1017 4 return toExprResult(QualType(SuperType::TY_BOOL));
1018 }
1019
1020 // Check primitive type combinations
1021 53712 return toExprResult(this.validateBinaryOperation(node, opRules, name, lhsType, rhsType, false, ""));
1022 28633 }
1023
1024 23659 public f<ExprResult> OpRuleManager.getEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1025 23659 return this.getEqualityResultType(node, lhs, rhs, OP_FCT_EQUAL, this.equalOpRules, "==");
1026 }
1027
1028 4974 public f<ExprResult> OpRuleManager.getNotEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1029 4974 return this.getEqualityResultType(node, lhs, rhs, OP_FCT_NOT_EQUAL, this.notEqualOpRules, "!=");
1030 }
1031
1032 // Result of <, > and <=
1033 13467 f<ExprResult> OpRuleManager.getRelationalResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, string fctName, const BinaryOpRules& opRules, string name) {
1034 // Check if there is an overloaded operator function available
1035 13467 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, binaryOperands(lhs, rhs), 0l);
1036
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 13449 times.
13467 if !resultType.ty.is(SuperType::TY_INVALID) {
1037 36 return resultType;
1038 }
1039 26898 return toExprResult(this.getSimpleBinaryResultType(node, lhs, rhs, opRules, name));
1040 13467 }
1041
1042 7303 public f<ExprResult> OpRuleManager.getLessResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1043 7303 return this.getRelationalResultType(node, lhs, rhs, OP_FCT_LESS, this.lessOpRules, "<");
1044 }
1045
1046 3862 public f<ExprResult> OpRuleManager.getGreaterResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1047 3862 return this.getRelationalResultType(node, lhs, rhs, OP_FCT_GREATER, this.greaterOpRules, ">");
1048 }
1049
1050 2302 public f<ExprResult> OpRuleManager.getLessEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1051 2302 return this.getRelationalResultType(node, lhs, rhs, OP_FCT_LESS_EQUAL, this.lessEqualOpRules, "<=");
1052 }
1053
1054 4346 public f<ExprResult> OpRuleManager.getGreaterEqualResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1055 // Check if there is an overloaded operator function available
1056 4346 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, OP_FCT_GREATER_EQUAL, binaryOperands(lhs, rhs), 0l);
1057
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4340 times.
4346 if !resultType.ty.is(SuperType::TY_INVALID) {
1058 12 return resultType;
1059 }
1060
1061 // Remove reference wrappers
1062 4340 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1063 4340 const QualType rhsType = rhs.ty.removeReferenceWrapper();
1064
1065 // Allow 'pointer == pointer' straight away
1066
4/4
✓ Branch 0 taken 4336 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4336 times.
4340 if lhsType.isPtr() && rhsType.isPtr() {
1067 8 return toExprResult(QualType(SuperType::TY_BOOL));
1068 }
1069
1070 8672 return toExprResult(this.validateBinaryOperation(node, this.greaterEqualOpRules, ">=", lhsType, rhsType, false, ""));
1071 4346 }
1072
1073 666 public f<ExprResult> OpRuleManager.getShiftLeftResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
1074 666 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_SHL, this.shiftLeftOpRules, "<<", false);
1075 }
1076
1077 324 public f<ExprResult> OpRuleManager.getShiftRightResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
1078 324 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_SHR, this.shiftRightOpRules, ">>", false);
1079 }
1080
1081 10918 public f<ExprResult> OpRuleManager.getPlusResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
1082 // Check is there is an overloaded operator function available
1083 10918 const ExprResult overloadResult = this.isOperatorOverloadingFctAvailable(node, OP_FCT_PLUS, binaryOperands(lhs, rhs), opIdx);
1084
2/2
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 10803 times.
10918 if !overloadResult.ty.is(SuperType::TY_INVALID) {
1085 230 return overloadResult;
1086 }
1087
1088 // Remove reference wrappers
1089 10803 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1090 10803 const QualType rhsType = rhs.ty.removeReferenceWrapper();
1091
1092 // Allow any* + <int/long/short>
1093 10803 const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_SHORT];
1094
4/4
✓ Branch 0 taken 8120 times.
✓ Branch 1 taken 2683 times.
✓ Branch 2 taken 2683 times.
✓ Branch 3 taken 8120 times.
10803 if lhsType.isPtr() && rhsType.isOneOf(integerTypes, len(integerTypes)) {
1095 2683 this.ensureUnsafeAllowed(node, "+", lhsType, rhsType);
1096 5366 return toExprResult(lhsType);
1097 }
1098 // Allow <int/long/short> + any*
1099
3/4
✓ Branch 0 taken 293 times.
✓ Branch 1 taken 7827 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8120 times.
8120 if lhsType.isOneOf(integerTypes, len(integerTypes)) && rhsType.isPtr() {
1100 ✗ this.ensureUnsafeAllowed(node, "+", lhsType, rhsType);
1101 ✗ return toExprResult(rhsType);
1102 }
1103
1104 8120 const QualType binOpType = this.validateBinaryOperation(node, this.plusOpRules, "+", lhsType, rhsType, false, "");
1105 16240 return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, true));
1106 10918 }
1107
1108 7075 public f<ExprResult> OpRuleManager.getMinusResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
1109 // Check is there is an overloaded operator function available
1110 7075 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, OP_FCT_MINUS, binaryOperands(lhs, rhs), opIdx);
1111
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7073 times.
7075 if !resultType.ty.is(SuperType::TY_INVALID) {
1112 4 return resultType;
1113 }
1114
1115 // Remove reference wrappers
1116 7073 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1117 7073 const QualType rhsType = rhs.ty.removeReferenceWrapper();
1118
1119 // Allow any* - <int/long/short>
1120 7073 const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_LONG, SuperType::TY_SHORT];
1121
4/4
✓ Branch 0 taken 6806 times.
✓ Branch 1 taken 267 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 6806 times.
7073 if lhsType.isPtr() && rhsType.isOneOf(integerTypes, len(integerTypes)) {
1122 267 this.ensureUnsafeAllowed(node, "-", lhsType, rhsType);
1123 534 return lhs;
1124 }
1125
1126 6806 const QualType binOpType = this.validateBinaryOperation(node, this.minusOpRules, "-", lhsType, rhsType, false, "");
1127 13612 return toExprResult(applyIntegerSignedness(binOpType, lhsType, rhsType, true));
1128 7075 }
1129
1130 2482 public f<ExprResult> OpRuleManager.getMulResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
1131 2482 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_MUL, this.mulOpRules, "*");
1132 }
1133
1134 349 public f<ExprResult> OpRuleManager.getDivResultType(ASTNode* node, const ExprResult& lhs, const ExprResult& rhs, unsigned long opIdx) {
1135 349 return this.getOverloadableBinaryResultType(node, lhs, rhs, opIdx, OP_FCT_DIV, this.divOpRules, "/");
1136 }
1137
1138 210 public f<ExprResult> OpRuleManager.getRemResultType(const ASTNode* node, const ExprResult& lhs, const ExprResult& rhs) {
1139 210 return toExprResult(this.getSimpleBinaryResultType(node, lhs, rhs, this.remOpRules, "%"));
1140 }
1141
1142 948 public f<QualType> OpRuleManager.getPrefixMinusResultType(const ASTNode* node, const ExprResult& lhs) {
1143 // Remove reference wrappers
1144 948 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1145
1146 948 return this.validateUnaryOperation(node, this.prefixMinusOpRules, "-", lhsType);
1147 }
1148
1149 // Result of the prefix operators ++ and --
1150 70 f<QualType> OpRuleManager.getPrefixIncDecResultType(const ASTNode* node, const ExprResult& lhs, const UnaryOpRules& opRules, string name) {
1151 // Check if we try to assign a constant value
1152 70 this.ensureNoConstAssign(node, lhs.ty, false, false);
1153
1154 // Remove reference wrappers
1155 70 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1156
1157 // Check if this is an unsafe operation
1158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if lhsType.isPtr() {
1159 ✗ this.ensureUnsafeAllowed(node, name, lhsType);
1160 ✗ return lhsType;
1161 }
1162
1163 70 return this.validateUnaryOperation(node, opRules, name, lhsType);
1164 }
1165
1166 25 public f<QualType> OpRuleManager.getPrefixPlusPlusResultType(const ASTNode* node, const ExprResult& lhs) {
1167 25 return this.getPrefixIncDecResultType(node, lhs, this.prefixPlusPlusOpRules, "++");
1168 }
1169
1170 45 public f<QualType> OpRuleManager.getPrefixMinusMinusResultType(const ASTNode* node, const ExprResult& lhs) {
1171 45 return this.getPrefixIncDecResultType(node, lhs, this.prefixMinusMinusOpRules, "--");
1172 }
1173
1174 4072 public f<QualType> OpRuleManager.getPrefixNotResultType(const ASTNode* node, const ExprResult& lhs) {
1175 // Remove reference wrappers
1176 4072 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1177
1178 4072 return this.validateUnaryOperation(node, this.prefixNotOpRules, "!", lhsType);
1179 }
1180
1181 33 public f<ExprResult> OpRuleManager.getPrefixBitwiseNotResultType(ASTNode* node, const ExprResult& lhs) {
1182 // Check if there is an overloaded operator function available
1183 33 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, OP_FCT_BITWISE_NOT, unaryOperand(lhs), 0l);
1184
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 31 times.
33 if !resultType.ty.is(SuperType::TY_INVALID) {
1185 4 return resultType;
1186 }
1187
1188 // Remove reference wrappers
1189 31 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1190
1191 62 return toExprResult(this.validateUnaryOperation(node, this.prefixBitwiseNotOpRules, "~", lhsType));
1192 33 }
1193
1194 999 public f<QualType> OpRuleManager.getPrefixMulResultType(const ASTNode* node, const ExprResult& lhs) {
1195 // Remove reference wrappers
1196 999 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1197
1198
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 998 times.
999 if !lhsType.isPtr() {
1199 1 throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, "Cannot apply de-referencing operator on type " + lhsType.getName(true));
1200 2 return QualType(SuperType::TY_UNRESOLVED);
1201 1 }
1202 998 return lhsType.getContained();
1203 }
1204
1205 1577 public f<QualType> OpRuleManager.getPrefixBitwiseAndResultType(const ASTNode* node, const ExprResult& lhs) {
1206 // Remove reference wrappers
1207 1577 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1208
1209 1577 return lhsType.toPtr(node);
1210 }
1211
1212 // Result of the postfix operators ++ and --
1213 9305 f<ExprResult> OpRuleManager.getPostfixIncDecResultType(ASTNode* node, const ExprResult& lhs, string fctName, const UnaryOpRules& opRules, string name) {
1214 // Check is there is an overloaded operator function available
1215 9305 const ExprResult resultType = this.isOperatorOverloadingFctAvailable(node, fctName, unaryOperand(lhs), 0l);
1216
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 9282 times.
9305 if !resultType.ty.is(SuperType::TY_INVALID) {
1217 46 return resultType;
1218 }
1219
1220 // Check if we try to assign a constant value
1221 9282 this.ensureNoConstAssign(node, lhs.ty, false, false);
1222
1223 // Remove reference wrappers
1224 9282 const QualType lhsType = lhs.ty.removeReferenceWrapper();
1225
1226 // Check if this is an unsafe operation
1227
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 9250 times.
9282 if lhsType.isPtr() {
1228 32 this.ensureUnsafeAllowed(node, name, lhsType);
1229 64 return lhs;
1230 }
1231
1232 18500 return toExprResult(this.validateUnaryOperation(node, opRules, name, lhsType));
1233 9305 }
1234
1235 8526 public f<ExprResult> OpRuleManager.getPostfixPlusPlusResultType(ASTNode* node, const ExprResult& lhs) {
1236 8526 return this.getPostfixIncDecResultType(node, lhs, OP_FCT_POSTFIX_PLUS_PLUS, this.postfixPlusPlusOpRules, "++");
1237 }
1238
1239 779 public f<ExprResult> OpRuleManager.getPostfixMinusMinusResultType(ASTNode* node, const ExprResult& lhs) {
1240 779 return this.getPostfixIncDecResultType(node, lhs, OP_FCT_POSTFIX_MINUS_MINUS, this.postfixMinusMinusOpRules, "--");
1241 }
1242
1243 12175 public f<QualType> OpRuleManager.getCastResultType(const ASTNode* node, const QualType& origLhsType, const ExprResult& rhs) {
1244 // Remove reference wrappers
1245 12175 const QualType lhsType = origLhsType.removeReferenceWrapper();
1246 12175 const QualType rhsType = rhs.ty.removeReferenceWrapper();
1247
1248 // Only allow to cast the 'heap' qualifier away, if we are in unsafe mode
1249
2/2
✓ Branch 0 taken 11454 times.
✓ Branch 1 taken 721 times.
12175 if lhsType.qualifiers.isHeap != rhsType.qualifiers.isHeap {
1250 721 this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType);
1251 721 }
1252
1253 // Allow identity casts
1254
2/2
✓ Branch 0 taken 1352 times.
✓ Branch 1 taken 10823 times.
12175 if lhsType.matches(rhsType, false, true, true) {
1255 1352 return lhsType;
1256 }
1257 // Allow casts string -> char* and string -> char[]
1258 10823 const dyn ptrOrArrayTypes = [SuperType::TY_PTR, SuperType::TY_ARRAY];
1259
4/4
✓ Branch 0 taken 4380 times.
✓ Branch 1 taken 6443 times.
✓ Branch 2 taken 6578 times.
✓ Branch 3 taken 4245 times.
10823 if lhsType.isOneOf(ptrOrArrayTypes, len(ptrOrArrayTypes)) && rhsType.is(SuperType::TY_STRING) {
1260 4245 const QualType lhsContainedType = lhsType.getContained();
1261
2/2
✓ Branch 0 taken 4244 times.
✓ Branch 1 taken 1 time.
4245 if lhsContainedType.is(SuperType::TY_CHAR) {
1262 4244 return lhsType;
1263 }
1264 1 }
1265 // Allow casts char* -> string and char[] -> string
1266
4/4
✓ Branch 0 taken 6280 times.
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 6281 times.
✓ Branch 3 taken 298 times.
6579 if lhsType.is(SuperType::TY_STRING) && rhsType.isOneOf(ptrOrArrayTypes, len(ptrOrArrayTypes)) {
1267 298 const QualType rhsContainedType = rhsType.getContained();
1268
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 31 times.
298 if rhsContainedType.is(SuperType::TY_CHAR) {
1269 267 return lhsType;
1270 }
1271 31 }
1272 // Allow safe upcasts baseStruct* <- derivedStruct* and interface* <- struct* without requiring an unsafe
1273 // block. These are the only struct-pointer casts where the target subobject is guaranteed to be present;
1274 // the IR generator advances the pointer to that subobject (past any vtable prefix). The reverse direction
1275 // (down/sibling casts) is not covered here and still falls through to the unsafe any* -> any* rule below.
1276
4/4
✓ Branch 0 taken 4113 times.
✓ Branch 1 taken 2199 times.
✓ Branch 2 taken 4165 times.
✓ Branch 3 taken 2147 times.
6312 if lhsType.isPtr() && rhsType.isPtr() {
1277 2147 const QualType lhsContained = lhsType.getContained();
1278 2147 const QualType rhsContained = rhsType.getContained();
1279
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2145 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2141 times.
2147 if lhsContained.matchesInterfaceImplementedByStruct(rhsContained) || lhsContained.matchesComposedBaseOfStruct(rhsContained) {
1280 6 return lhsType;
1281 }
1282 2141 }
1283 // Allow casts any* -> any*
1284 6306 const dyn ptrOrStringTypes = [SuperType::TY_PTR, SuperType::TY_STRING];
1285
4/4
✓ Branch 0 taken 4081 times.
✓ Branch 1 taken 2225 times.
✓ Branch 2 taken 2173 times.
✓ Branch 3 taken 4133 times.
6306 if lhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) && rhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) {
1286 2173 this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType);
1287 2173 return lhsType;
1288 }
1289 // Allow casts any* -> long and long -> any*. Only 'long' is accepted on the integer side: it is the only Spice
1290 // integer type that is guaranteed to be 64 bit wide on every target (see docs/docs/language/primitive-types.md),
1291 // so it is the only one that can round-trip a pointer without silently truncating it on a 64-bit target. The
1292 // qualifiers of the cast destination are preserved, so 'unsigned long' works just as well as the signed variant.
1293
4/4
✓ Branch 0 taken 2442 times.
✓ Branch 1 taken 1691 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4121 times.
4133 if lhsType.is(SuperType::TY_LONG) && rhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) {
1294 12 this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType);
1295 12 return lhsType;
1296 }
1297
4/4
✓ Branch 0 taken 4069 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 4111 times.
4121 if lhsType.isOneOf(ptrOrStringTypes, len(ptrOrStringTypes)) && rhsType.is(SuperType::TY_LONG) {
1298 10 this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType);
1299 10 return lhsType;
1300 }
1301 // Allow casts p()/f<>() -> byte*
1302 4111 const dyn functionTypes = [SuperType::TY_FUNCTION, SuperType::TY_PROCEDURE];
1303
4/4
✓ Branch 0 taken 4069 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 4069 times.
4111 if lhsType.isPtrTo(SuperType::TY_BYTE) && rhsType.isOneOf(functionTypes, len(functionTypes)) {
1304 42 this.ensureUnsafeAllowed(node, "(cast)", lhsType, rhsType);
1305 42 return lhsType;
1306 }
1307 // Check primitive type combinations
1308 4069 return this.validateBinaryOperation(node, this.castOpRules, "(cast)", lhsType, rhsType, true, "");
1309 }
1310
1311 /**
1312 * Check if there is an operator overloading function available for the given operator and operand types. The operands are
1313 * passed as a list of one or two elements.
1314 *
1315 * @param node AST node of the operator
1316 * @param fctName Name of the operator function
1317 * @param op Operands
1318 * @param opIdx Index of the operator within the node
1319 * @return Result of the operator function call or the invalid type if no operator function is available
1320 */
1321 95644 public f<ExprResult> OpRuleManager.isOperatorOverloadingFctAvailable(ASTNode* node, string fctName, const Vector<ExprResult>& op, unsigned long opIdx) {
1322 95644 assert op.getSize() == 1l || op.getSize() == 2l; // Only unary and binary operators are overloadable
1323 95644 const String fctNameStr = String(fctName);
1324
1325 // Most operators are applied to operands without an overloaded operator function (e.g. int == int). Searching all
1326 // source files for one is expensive, so skip the search if it found nothing for the same operator and operand types in
1327 // this source file before and no function was inserted since then.
1328 95644 Hash cacheKey = 0ul;
1329 95644 hashCombine64(cacheKey, hashPointer(this.typeChecker.sourceFile));
1330 95644 hashCombine64(cacheKey, hash(fctNameStr));
1331
2/2
✓ Branch 0 taken 181950 times.
✓ Branch 1 taken 95644 times.
277594 foreach const ExprResult& operand : op {
1332 181950 hashCombine64(cacheKey, hashQualType(operand.ty));
1333 181950 hashCombine64(cacheKey, hash(operand.isTemporary()));
1334 181950 }
1335 95644 const unsigned long registryVersion = getFunctionRegistryVersion();
1336 95644 UnorderedMap<Hash, unsigned long>& unavailableOpFctCache = this.typeChecker.resourceManager.unavailableOpFctCache;
1337
4/4
✓ Branch 0 taken 34763 times.
✓ Branch 1 taken 60881 times.
✓ Branch 2 taken 58763 times.
✓ Branch 3 taken 36881 times.
95644 if unavailableOpFctCache.contains(cacheKey) && unavailableOpFctCache.get(cacheKey) == registryVersion {
1338 117526 return toExprResult(QualType(SuperType::TY_INVALID));
1339 }
1340
1341 36881 Scope* calleeParentScope = nil<Scope*>;
1342 36881 Function* callee = nil<Function*>;
1343 36881 const QualType thisType = QualType(SuperType::TY_DYN);
1344 36881 ArgList args;
1345 // The first match wins, so iterate the source files in creation order. The order of the source file map depends on the
1346 // hash function, which would make the choice between operator functions of different source files arbitrary
1347
2/2
✓ Branch 0 taken 31828 times.
✓ Branch 1 taken 400555 times.
432383 foreach SourceFile* sourceFile : this.typeChecker.resourceManager.sourceFilesInCreationOrder {
1348 // Check if there is a registered operator function
1349
2/2
✓ Branch 0 taken 143970 times.
✓ Branch 1 taken 256585 times.
400555 if sourceFile.getNameRegistryEntry(fctNameStr) == nil<const NameRegistryEntry*> {
1350 256585 continue;
1351 }
1352
1353 // Match callees in the global scope of this source file
1354 143970 calleeParentScope = sourceFile.globalScope;
1355 143970 args.clear();
1356
2/2
✓ Branch 0 taken 285308 times.
✓ Branch 1 taken 143970 times.
429278 for unsigned long i = 0l; i < op.getSize(); i++ {
1357 285308 const ExprResult& operand = op[i];
1358 285308 const QualType argType = this.typeChecker.mapLocalTypeToImportedScopeType(calleeParentScope, operand.ty);
1359 285308 args.pushBack(Pair<QualType, bool>(argType, operand.isTemporary()));
1360 285308 }
1361 143970 const QualTypeList noTemplateTypeHints;
1362 143970 callee = matchFunction(calleeParentScope, fctNameStr, thisType, args, noTemplateTypeHints, false, node);
1363
2/2
✓ Branch 0 taken 138917 times.
✓ Branch 1 taken 5053 times.
143970 if callee != nil<Function*> {
1364 5053 break;
1365 }
1366 143970 }
1367
1368 // Return invalid type if the callee was not found
1369
2/2
✓ Branch 0 taken 5053 times.
✓ Branch 1 taken 31828 times.
36881 if callee == nil<Function*> {
1370 31828 unavailableOpFctCache.upsert(cacheKey, registryVersion);
1371 63656 return toExprResult(QualType(SuperType::TY_INVALID));
1372 }
1373 5053 assert calleeParentScope != nil<Scope*>;
1374
1375 // Save the pointer to the operator function in the AST node
1376 5053 Vector<const Function*>& opFctPointers = this.typeChecker.getOpFctPointers(node);
1377
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 5053 times.
5321 while opFctPointers.getSize() <= cast<long>(opIdx) {
1378 268 opFctPointers.pushBack(nil<const Function*>);
1379 268 }
1380 5053 const Function*& opFctPointer = opFctPointers.get(opIdx);
1381 5053 opFctPointer = callee;
1382
1383 // Check if we need to request a re-visit, because the function body was not type-checked yet
1384 5053 requestRevisitIfRequired(callee);
1385
1386 // By-value params of non-trivially copyable types get copies of the operands, which require their copy ctors
1387 5053 this.typeChecker.matchCopyCtorsForOwnedParams(callee, node);
1388
1389 // Check if the called function has sufficient visibility
1390 5053 const bool isImported = calleeParentScope.isImportedBy(this.typeChecker.rootScope);
1391 5053 const SymbolTableEntry* calleeEntry = callee.entry;
1392 5053 const QualType calleeEntryType = calleeEntry.getQualType();
1393
4/4
✓ Branch 0 taken 1742 times.
✓ Branch 1 taken 3311 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 5052 times.
5053 if isImported && !calleeEntryType.isPublic() {
1394 1 throwSemanticError(node, SemanticErrorType::INSUFFICIENT_VISIBILITY, "Overloaded operator '" + callee.getSignature() + "' has insufficient visibility");
1395 2 return toExprResult(QualType(SuperType::TY_UNRESOLVED));
1396 1 }
1397
1398 // Procedures always have the return type 'bool'
1399
2/2
✓ Branch 0 taken 1581 times.
✓ Branch 1 taken 3471 times.
5052 if callee.isProcedure() {
1400 3162 return toExprResult(QualType(SuperType::TY_BOOL));
1401 }
1402 3471 const QualType& returnType = callee.returnType;
1403
1404 // Add anonymous symbol to keep track of dtor call, if non-trivially destructible
1405 3471 SymbolTableEntry* anonymousSymbol = nil<SymbolTableEntry*>;
1406
4/4
✓ Branch 0 taken 3303 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 3322 times.
✓ Branch 3 taken 149 times.
3471 if returnType.is(SuperType::TY_STRUCT) && !returnType.isTriviallyDestructible(node) {
1407 149 anonymousSymbol = this.typeChecker.currentScope.symbolTable.insertAnonymous(returnType, node, opIdx);
1408 149 }
1409
1410 3471 const QualType localReturnType = this.typeChecker.mapImportedScopeTypeToLocalType(calleeParentScope, returnType);
1411 6942 return ExprResult{localReturnType, anonymousSymbol};
1412 95644 }
1413
1414 /**
1415 * Apply the signedness of the operands to an integer result type. The op rule tables only contain the super types, so the
1416 * result type would always be signed otherwise. Like in C, the result is unsigned if an operand that has the same type as
1417 * the result is unsigned: e.g. 'unsigned int + unsigned long' and 'int + unsigned long' are unsigned, but
1418 * 'unsigned int + long' is signed, because a long can hold all values of an unsigned int.
1419 *
1420 * @param resultType Result type of the operation
1421 * @param lhs Left side of the operation
1422 * @param rhs Right side of the operation
1423 * @param considerRhs Whether the right side is considered (not for unary, shift and compound assign operations)
1424 * @return Result type with the correct signedness
1425 */
1426 55586 f<QualType> applyIntegerSignedness(const QualType& origResultType, const QualType& lhs, const QualType& rhs, bool considerRhs) {
1427 55586 const dyn integerTypes = [SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG];
1428
2/2
✓ Branch 0 taken 25572 times.
✓ Branch 1 taken 30014 times.
55586 if !origResultType.isOneOf(integerTypes, len(integerTypes)) {
1429 25572 return origResultType;
1430 }
1431 30014 QualType resultType = origResultType;
1432 30014 const SuperType resultSuperType = resultType.getSuperType();
1433
2/2
✓ Branch 0 taken 297 times.
✓ Branch 1 taken 29717 times.
30014 const bool isLhsUnsigned = lhs.getSuperType() == resultSuperType && lhs.isUnsigned();
1434
4/4
✓ Branch 0 taken 17770 times.
✓ Branch 1 taken 12244 times.
✓ Branch 2 taken 1567 times.
✓ Branch 3 taken 16203 times.
30014 const bool isRhsUnsigned = considerRhs && rhs.getSuperType() == resultSuperType && rhs.isUnsigned();
1435
4/4
✓ Branch 0 taken 25616 times.
✓ Branch 1 taken 4398 times.
✓ Branch 2 taken 4006 times.
✓ Branch 3 taken 26008 times.
30014 if isLhsUnsigned || isRhsUnsigned {
1436 26008 resultType.makeUnsigned();
1437 26008 }
1438 30014 return resultType;
1439 }
1440
1441 14371 f<QualType> OpRuleManager.validateUnaryOperation(const ASTNode* node, const UnaryOpRules& opRules, string name, const QualType& lhs) {
1442
2/2
✓ Branch 0 taken 31493 times.
✓ Branch 1 taken 2 times.
31495 for unsigned long i = 0l; i < opRules.getSize(); i++ {
1443 31493 const UnaryOpRule& rule = opRules[i];
1444
2/2
✓ Branch 0 taken 14369 times.
✓ Branch 1 taken 17124 times.
31493 if rule.lhsType == lhs.getSuperType() {
1445 14369 return applyIntegerSignedness(QualType(rule.resultType), lhs, lhs, false);
1446 }
1447 17124 }
1448 2 throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, getUnaryErrorMessage(name, lhs));
1449 4 return QualType(SuperType::TY_UNRESOLVED);
1450 2 }
1451
1452 154624 f<QualType> OpRuleManager.validateBinaryOperation(const ASTNode* node, const BinaryOpRules& opRules, string name, const QualType& lhs, const QualType& rhs, bool preserveQualifiersFromLhs, string customMessagePrefix) {
1453
2/2
✓ Branch 0 taken 1533206 times.
✓ Branch 1 taken 34 times.
1533240 for unsigned long i = 0l; i < opRules.getSize(); i++ {
1454 1533206 const BinaryOpRule& rule = opRules[i];
1455
4/4
✓ Branch 0 taken 1224241 times.
✓ Branch 1 taken 308965 times.
✓ Branch 2 taken 154590 times.
✓ Branch 3 taken 1378616 times.
1533206 if rule.lhsType == lhs.getSuperType() && rule.rhsType == rhs.getSuperType() {
1456 154590 QualType resultType = QualType(rule.resultType);
1457
2/2
✓ Branch 0 taken 72392 times.
✓ Branch 1 taken 82198 times.
154590 if preserveQualifiersFromLhs {
1458 82198 resultType.setQualifiers(lhs.qualifiers);
1459 82198 }
1460 154590 return resultType;
1461 }
1462 1378616 }
1463 34 throwSemanticError(node, SemanticErrorType::OPERATOR_WRONG_DATA_TYPE, getBinaryErrorMessage(name, lhs, rhs, customMessagePrefix));
1464 68 return QualType(SuperType::TY_UNRESOLVED);
1465 34 }
1466
1467 // Message of the semantic error for an invalid unary operator/type combination
1468 2 f<String> getUnaryErrorMessage(string name, const QualType& lhs) {
1469 4 return "Cannot apply '" + String(name) + "' operator on type " + lhs.getName(true);
1470 2 }
1471
1472 // Message of the semantic error for an invalid binary operator/type combination
1473 34 f<String> getBinaryErrorMessage(string name, const QualType& lhs, const QualType& rhs, string messagePrefix) {
1474 34 StringStream errorMsg;
1475 34 const String messagePrefixStr = String(messagePrefix);
1476
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 if !messagePrefixStr.isEmpty() {
1477 4 errorMsg << messagePrefix << ". Expected " << lhs.getName(true) << " but got " << rhs.getName(true);
1478 4 } else {
1479 30 errorMsg << "Cannot apply '" << name << "' operator on types " << lhs.getName(true) << " and " << rhs.getName(true);
1480 30 }
1481 68 return errorMsg.str();
1482 34 }
1483
1484 32 p OpRuleManager.ensureUnsafeAllowed(const ASTNode* node, string name, const QualType& lhs) {
1485
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if this.typeChecker.currentScope.doesAllowUnsafeOperations() {
1486 32 return;
1487 }
1488 // Print error message
1489 ✗ const String lhsName = lhs.getName(true);
1490 ✗ const String errorMsg = "Cannot apply '" + String(name) + "' operator on type " + lhsName + " as this is an unsafe operation. Please use unsafe blocks if you know what you are doing.";
1491 ✗ this.softError(node, SemanticErrorType::UNSAFE_OPERATION_IN_SAFE_CONTEXT, errorMsg);
1492 ✗ }
1493
1494 5923 p OpRuleManager.ensureUnsafeAllowed(const ASTNode* node, string name, const QualType& lhs, const QualType& rhs) {
1495
2/2
✓ Branch 0 taken 5920 times.
✓ Branch 1 taken 3 times.
5923 if this.typeChecker.currentScope.doesAllowUnsafeOperations() {
1496 5920 return;
1497 }
1498 // Print error message
1499 3 const String lhsName = lhs.getName(true);
1500 3 const String rhsName = rhs.getName(true);
1501 3 const String errorMsg = "Cannot apply '" + String(name) + "' operator on types " + lhsName + " and " + rhsName + " as this is an unsafe operation. Please use unsafe blocks if you know what you are doing.";
1502 3 this.softError(node, SemanticErrorType::UNSAFE_OPERATION_IN_SAFE_CONTEXT, errorMsg);
1503 3 }
1504
1505 121633 p OpRuleManager.ensureNoConstAssign(const ASTNode* node, const QualType& lhs, bool isDecl, bool isReturn) {
1506 // Check if we try to assign a constant value
1507 121633 const QualType lhsUnwrappedType = lhs.removeReferenceWrapper();
1508
6/6
✓ Branch 0 taken 12712 times.
✓ Branch 1 taken 108921 times.
✓ Branch 2 taken 12472 times.
✓ Branch 3 taken 240 times.
✓ Branch 4 taken 121613 times.
✓ Branch 5 taken 20 times.
121633 if lhsUnwrappedType.isConst() && !isDecl && !isReturn {
1509 20 const String errorMessage = "Trying to assign value to an immutable variable of type " + lhs.getName(true);
1510 20 this.softError(node, SemanticErrorType::REASSIGN_CONST_VARIABLE, errorMessage);
1511 20 }
1512 121633 }
1513
1514 // Add a soft error to the error list
1515 23 p OpRuleManager.softError(const ASTNode* node, SemanticErrorType errorType, const String& message) {
1516 23 ErrorManager& errorManager = this.typeChecker.resourceManager.getErrorManager();
1517 23 errorManager.addSoftError(node, errorType, message);
1518 23 }
1519