Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 64.1% 511 / 0 / 797
Functions: -% 0 / 1 / 1
Branches: 59.3% 319 / 0 / 538

OMCompiler/Compiler/NFFrontEnd/NFTypeCheck.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package NFTypeCheck
37 " file: NFTypeCheck.mo
38 package: NFTypeCheck
39 description: SCodeInst type checking.
40
41
42 Functions used by SCodeInst for type checking and type conversion where needed.
43 "
44
45 import Absyn;
46 import Dimension = NFDimension;
47 import Expression = NFExpression;
48 import NFInstNode.InstNode;
49 import NFInstNode;
50 import Binding = NFBinding;
51 import NFPrefixes.{Variability, Purity};
52 import Subscript = NFSubscript;
53
54 protected
55 import Error;
56 import Flags;
57 import List;
58 import Operator = NFOperator;
59 import Type = NFType;
60 import Class = NFClass;
61 import NFClassTree.ClassTree;
62 import Prefixes = NFPrefixes;
63 import Restriction = NFRestriction;
64 import ComplexType = NFComplexType;
65 import NFOperator.Op;
66 import NFFunction.Function;
67 import NFFunction.TypedArg;
68 import NFFunction.FunctionMatchKind;
69 import NFFunction.MatchedFunction;
70 import Call = NFCall;
71 import BuiltinCall = NFBuiltinCall;
72 import ComponentRef = NFComponentRef;
73 import ErrorExt;
74 import NFBuiltin;
75 import SimplifyExp = NFSimplifyExp;
76 import MetaModelica.Dangerous.*;
77 import OperatorOverloading = NFOperatorOverloading;
78 import ExpandExp = NFExpandExp;
79 import NFFunction.Slot;
80 import Util;
81 import Component = NFComponent;
82 import InstContext = NFInstContext;
83 import NFInstNode.InstNodeType;
84 import Array;
85 import Inline = NFInline;
86
87 public
88 type MatchKind = enumeration(
89 EXACT "Exact match",
90 CAST "Matched by casting, e.g. Integer to Real",
91 UNKNOWN_EXPECTED "The expected type was unknown",
92 UNKNOWN_ACTUAL "The actual type was unknown",
93 GENERIC "Matched with a generic type e.g. function F<T> input T i; end F; F(1)",
94 PLUG_COMPATIBLE "Component by component matching, e.g. class A R r; end A; is plug compatible with class B R r; end B;",
95 NOT_COMPATIBLE
96 );
97
98 function isCompatibleMatch
99 input MatchKind kind;
100 output Boolean isCompatible = kind <> MatchKind.NOT_COMPATIBLE;
101 end isCompatibleMatch;
102
103 function isIncompatibleMatch
104 input MatchKind kind;
105 output Boolean isIncompatible = kind == MatchKind.NOT_COMPATIBLE;
106 end isIncompatibleMatch;
107
108 function isExactMatch
109 input MatchKind kind;
110 output Boolean isCompatible = kind == MatchKind.EXACT;
111 end isExactMatch;
112
113 function isCastMatch
114 input MatchKind kind;
115 output Boolean isCast = kind == MatchKind.CAST;
116 end isCastMatch;
117
118 function isGenericMatch
119 input MatchKind kind;
120 output Boolean isCast = kind == MatchKind.GENERIC;
121 end isGenericMatch;
122
123 function isValidAssignmentMatch
124 input MatchKind kind;
125 output Boolean v = kind == MatchKind.EXACT
126 or kind == MatchKind.CAST
127 or kind == MatchKind.PLUG_COMPATIBLE;
128 end isValidAssignmentMatch;
129
130 function isValidArgumentMatch
131 input MatchKind kind;
132 output Boolean v = kind == MatchKind.EXACT
133 or kind == MatchKind.CAST
134 or kind == MatchKind.GENERIC
135 or kind == MatchKind.PLUG_COMPATIBLE;
136 end isValidArgumentMatch;
137
138 function isValidPlugCompatibleMatch
139 input MatchKind kind;
140 output Boolean v = kind == MatchKind.EXACT
141 or kind == MatchKind.PLUG_COMPATIBLE;
142 end isValidPlugCompatibleMatch;
143
144 type MatchOptions = Integer;
145 constant MatchOptions DEFAULT_OPTIONS = 0;
146 constant MatchOptions ALLOW_UNKNOWN = intBitLShift(1, 0);
147 constant MatchOptions IGNORE_DIMENSIONS = intBitLShift(1, 1);
148 constant MatchOptions IGNORE_DIMENSIONS_IN_RECORDS = intBitLShift(1, 2);
149
150 function setOption
151 input MatchOptions currentOptions;
152 input MatchOptions newOption;
153 output MatchOptions newOptions = intBitOr(currentOptions, newOption);
154 end setOption;
155
156 function getOption
157 input MatchOptions options;
158 input MatchOptions option;
159 output Boolean isSet = intBitAnd(options, option) > 0;
160 end getOption;
161
162 function checkBinaryOperation
163 input Expression exp1;
164 input Type type1;
165 input Variability var1;
166 input Operator operator;
167 input Expression exp2;
168 input Type type2;
169 input Variability var2;
170 input InstContext.Type context;
171 input SourceInfo info;
172 input Boolean retype "when retyping accept non elementwise operators for elementwise binaries";
173 output Expression binaryExp;
174 output Type resultType;
175 algorithm
176
2/4
✓ Branch 1 taken 613565 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 613565 times.
613565 if Type.isConditionalArray(type1) or Type.isConditionalArray(type2) then
177 ✗ (binaryExp, resultType) := checkConditionalBinaryOperator(exp1, type1, var1, operator, exp2, type2, var2, context, info, retype);
178 elseif Type.isComplex(Type.arrayElementType(type1)) or
179 Type.isComplex(Type.arrayElementType(type2)) then
180 1515 (binaryExp, resultType) := checkOverloadedBinaryOperator(exp1, type1, var1, operator, exp2, type2, var2, context, info);
181 elseif Type.isBoxed(type1) and Type.isBoxed(type2) then
182 ✗ (binaryExp, resultType) := checkBinaryOperationBoxed(exp1, type1, var1, operator, exp2, type2, var2, context, info, retype);
183 else
184 (binaryExp, resultType) := match operator.op
185 147317 case Op.ADD then checkBinaryOperationAdd(exp1, type1, exp2, type2, info);
186 61612 case Op.SUB then checkBinaryOperationSub(exp1, type1, exp2, type2, info);
187 342958 case Op.MUL then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
188 48298 case Op.DIV then checkBinaryOperationDiv(exp1, type1, exp2, type2, info, isElementWise = retype);
189 11604 case Op.POW then checkBinaryOperationPow(exp1, type1, exp2, type2, info);
190 10 case Op.ADD_EW then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.ADD, info);
191 3 case Op.SUB_EW then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.SUB, info);
192 123 case Op.MUL_EW then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.MUL, info);
193 69 case Op.DIV_EW then checkBinaryOperationDiv(exp1, type1, exp2, type2, info, isElementWise = true);
194 22 case Op.POW_EW then checkBinaryOperationPowEW(exp1, type1, exp2, type2, info);
195 // These operators should not occur in untyped expressions, but sometimes
196 // we want to retype already typed expressions due to changes in them.
197 ✗ case Op.ADD_SCALAR_ARRAY then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.ADD, info);
198 ✗ case Op.ADD_ARRAY_SCALAR then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.ADD, info);
199 1 case Op.SUB_SCALAR_ARRAY then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.SUB, info);
200 ✗ case Op.SUB_ARRAY_SCALAR then checkBinaryOperationEW(exp1, type1, exp2, type2, Op.SUB, info);
201 11 case Op.MUL_SCALAR_ARRAY then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
202 5 case Op.MUL_ARRAY_SCALAR then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
203 ✗ case Op.MUL_VECTOR_MATRIX then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
204 ✗ case Op.MUL_MATRIX_VECTOR then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
205 7 case Op.SCALAR_PRODUCT then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
206 ✗ case Op.MATRIX_PRODUCT then checkBinaryOperationMul(exp1, type1, exp2, type2, info);
207 ✗ case Op.DIV_SCALAR_ARRAY then checkBinaryOperationDiv(exp1, type1, exp2, type2, info, isElementWise = retype);
208 9 case Op.DIV_ARRAY_SCALAR then checkBinaryOperationDiv(exp1, type1, exp2, type2, info, isElementWise = retype);
209 ✗ case Op.POW_SCALAR_ARRAY then checkBinaryOperationPowEW(exp1, type1, exp2, type2, info);
210 1 case Op.POW_ARRAY_SCALAR then checkBinaryOperationPowEW(exp1, type1, exp2, type2, info);
211 ✗ case Op.POW_MATRIX then checkBinaryOperationPow(exp1, type1, exp2, type2, info);
212 end match;
213 end if;
214 end checkBinaryOperation;
215
216 public function checkOverloadedBinaryOperator
217 input Expression exp1;
218 input Type type1;
219 input Variability var1;
220 input Operator op;
221 input Expression exp2;
222 input Type type2;
223 input Variability var2;
224 input InstContext.Type context;
225 input SourceInfo info;
226 output Expression outExp;
227 output Type outType;
228 protected
229 String op_str;
230 list<Function> candidates;
231 Type ety1, ety2;
232 algorithm
233 1515 op_str := Operator.symbol(Operator.stripEW(op), "'");
234 1515 ety1 := Type.arrayElementType(type1);
235 1515 ety2 := Type.arrayElementType(type2);
236
237 1515 candidates := OperatorOverloading.lookupOperatorFunctionsInType(op_str, ety1);
238
239 // Only collect operators from both types if they're not the same type.
240
2/2
✓ Branch 1 taken 427 times.
✓ Branch 2 taken 1088 times.
1515 if not Type.isEqual(ety1, ety2) then
241 427 candidates := listAppend(OperatorOverloading.lookupOperatorFunctionsInType(op_str, ety2), candidates);
242 end if;
243
244 // Give up if no operator functions could be found.
245
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1514 times.
1515 if listEmpty(candidates) then
246 2 printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, type2}, info);
247 end if;
248
249
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1514 times.
1514 if Operator.isElementWise(op) then
250 ✗ (outExp, outType) := checkOverloadedBinaryArrayEW(
251 exp1, type1, var1, Operator.stripEW(op), exp2, type2, var2, candidates, context, info);
252 else
253 1514 (outExp, outType) := matchOverloadedBinaryOperator(
254 exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
255 end if;
256
257 1512 outExp := Inline.inlineCallExp(outExp);
258 end checkOverloadedBinaryOperator;
259
260 function matchOverloadedBinaryOperator
261 input Expression exp1;
262 input Type type1;
263 input Variability var1;
264 input Operator op;
265 input Expression exp2;
266 input Type type2;
267 input Variability var2;
268 input list<Function> candidates;
269 input InstContext.Type context;
270 input SourceInfo info;
271 input Boolean showErrors = true;
272 output Expression outExp;
273 output Type outType;
274 protected
275 list<TypedArg> args;
276 MatchedFunction matchedFunc;
277 list<MatchedFunction> matchedFunctions, exactMatches;
278 Function fn;
279 algorithm
280 1526 args := {
281 TypedArg.TYPED_ARG(NONE(), exp1, type1, var1, Purity.PURE),
282 TypedArg.TYPED_ARG(NONE(), exp2, type2, var2, Purity.PURE)
283 };
284 1526 matchedFunctions := Function.matchFunctionsSilent(candidates, args, {}, context, info);
285 // We only allow exact matches for operator overloading. e.g. no casting or generic matches.
286 1526 exactMatches := MatchedFunction.getExactMatches(matchedFunctions);
287
288
2/2
✓ Branch 0 taken 428 times.
✓ Branch 1 taken 1098 times.
1526 if listEmpty(exactMatches) then
289 // TODO: new error mentioning overloaded operators.
290 428 ErrorExt.setCheckpoint("NFTypeCheck:implicitConstruction");
291 try
292 428 (outExp, outType) := implicitConstructAndMatch(candidates, exp1, type1, op, exp2, type2, info);
293
294
1/2
✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
423 if showErrors then
295 423 ErrorExt.delCheckpoint("NFTypeCheck:implicitConstruction");
296 else
297 ✗ ErrorExt.rollBack("NFTypeCheck:implicitConstruction");
298 end if;
299 else
300 5 ErrorExt.rollBack("NFTypeCheck:implicitConstruction");
301
302
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
5 if Type.isArray(type1) or Type.isArray(type2) then
303 (outExp, outType) := match op.op
304 2 case Op.ADD then checkOverloadedBinaryArrayAddSub(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
305 2 case Op.SUB then checkOverloadedBinaryArrayAddSub(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
306 ✗ case Op.MUL then checkOverloadedBinaryArrayMul(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
307 ✗ case Op.DIV then checkOverloadedBinaryArrayDiv(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
308 else
309 algorithm
310 ✗ printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, type2}, info, showErrors);
311 ✗ then
312 fail();
313 end match;
314 else
315 2 printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, type2}, info, showErrors);
316 ✗ fail();
317 end if;
318 end try;
319 elseif listLength(exactMatches) == 1 then
320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1097 times.
1097 matchedFunc ::_ := exactMatches;
321 1097 fn := matchedFunc.func;
322 1097 outType := Function.returnType(fn);
323
4/4
✓ Branch 0 taken 2194 times.
✓ Branch 1 taken 1097 times.
✓ Branch 2 taken 2194 times.
✓ Branch 3 taken 1097 times.
3291 outExp := Expression.CALL(
324 Call.makeTypedCall(
325 matchedFunc.func,
326 list(a.value for a in matchedFunc.args),
327 Prefixes.variabilityMax(var1, var2),
328 Purity.PURE,
329 outType));
330 else
331
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if showErrors then
332
4/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
5 Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_OPERATOR_FUNCTIONS_NFINST,
333 {Expression.toString(Expression.BINARY(exp1, op, exp2)),
334 Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info);
335 end if;
336 1 fail();
337 end if;
338 end matchOverloadedBinaryOperator;
339
340 public function checkBinaryOperationBoxed
341 input Expression exp1;
342 input Type type1;
343 input Variability var1;
344 input Operator op;
345 input Expression exp2;
346 input Type type2;
347 input Variability var2;
348 input InstContext.Type context;
349 input SourceInfo info;
350 input Boolean retype;
351 output Expression outExp;
352 output Type outType;
353 protected
354 Expression e1, e2;
355 Type ty1, ty2;
356 algorithm
357 ✗ (e1, ty1) := matchTypes(type1, Type.unbox(type1), exp1);
358 ✗ (e2, ty2) := matchTypes(type2, Type.unbox(type2), exp2);
359 ✗ (outExp, outType) := checkBinaryOperation(e1, ty1, var1, op, e2, ty2, var2, context, info, retype);
360 end checkBinaryOperationBoxed;
361
362 protected
363 function checkConditionalBinaryOperator
364 input Expression exp1;
365 input Type type1;
366 input Variability var1;
367 input Operator op;
368 input Expression exp2;
369 input Type type2;
370 input Variability var2;
371 input InstContext.Type context;
372 input SourceInfo info;
373 input Boolean retype;
374 output Expression outExp;
375 output Type outType;
376 protected
377 Type tty1, fty1, tty2, fty2, ty1 = Type.UNKNOWN(), ty2 = Type.UNKNOWN();
378 Expression e1 = exp1, e2 = exp2;
379 Boolean valid1, valid2;
380 NFType.Branch branch;
381 algorithm
382 (tty1, fty1, tty2, fty2, branch) := match (type1, type2)
383 case (Type.CONDITIONAL_ARRAY(), _)
384 ✗ then (type1.trueType, type1.falseType, type2, type2, type1.matchedBranch);
385 case (_, Type.CONDITIONAL_ARRAY())
386 ✗ then (type1, type1, type2.trueType, type2.falseType, type2.matchedBranch);
387 end match;
388
389 ✗ ErrorExt.setCheckpoint(getInstanceName());
390 try
391 ✗ (e1, ty1) := checkBinaryOperation(exp1, tty1, var1, op, exp2, tty2, var2, context, info, retype);
392 valid1 := true;
393 else
394 valid1 := false;
395 end try;
396
397 try
398 ✗ (e2, ty2) := checkBinaryOperation(exp1, fty1, var1, op, exp2, fty2, var2, context, info, retype);
399 valid2 := true;
400 else
401 valid2 := false;
402 end try;
403 ✗ ErrorExt.rollBack(getInstanceName());
404
405 ✗ if valid1 and valid2 then
406 ✗ outType := Type.CONDITIONAL_ARRAY(ty1, ty2, branch);
407 ✗ outExp := e1;
408 elseif valid1 then
409 ✗ outType := Type.CONDITIONAL_ARRAY(ty1, Type.UNKNOWN(), NFType.Branch.TRUE);
410 ✗ outExp := e1;
411 elseif valid2 then
412 ✗ outType := Type.CONDITIONAL_ARRAY(Type.UNKNOWN(), ty2, NFType.Branch.FALSE);
413 ✗ outExp := e2;
414 else
415 ✗ printUnresolvableTypeError(exp1, {type1, type2}, info);
416 ✗ fail();
417 end if;
418
419 ✗ outExp := Expression.setType(outType, outExp);
420 end checkConditionalBinaryOperator;
421
422 function checkOverloadedBinaryArrayAddSub
423 input Expression exp1;
424 input Type type1;
425 input Variability var1;
426 input Operator op;
427 input Expression exp2;
428 input Type type2;
429 input Variability var2;
430 input list<Function> candidates;
431 input InstContext.Type context;
432 input SourceInfo info;
433 output Expression outExp;
434 output Type outType;
435 protected
436 Expression e1, e2;
437 MatchKind mk;
438 algorithm
439 // For addition or subtraction both sides must have the same type.
440 4 (e1, e2, _, mk) := matchExpressions(exp1, type1, exp2, type2, ALLOW_UNKNOWN);
441
442
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if not isCompatibleMatch(mk) then
443 ✗ printUnresolvableTypeError(Expression.BINARY(e1, op, e2), {type1, type2}, info);
444 end if;
445
446 4 e1 := ExpandExp.expand(e1);
447 4 e2 := ExpandExp.expand(e2);
448
449 4 (outExp, outType) :=
450 checkOverloadedBinaryArrayAddSub2(e1, type1, var1, op, e2, type2, var2, candidates, context, info);
451 end checkOverloadedBinaryArrayAddSub;
452
453 function checkOverloadedBinaryArrayAddSub2
454 input Expression exp1;
455 input Type type1;
456 input Variability var1;
457 input Operator op;
458 input Expression exp2;
459 input Type type2;
460 input Variability var2;
461 input list<Function> candidates;
462 input InstContext.Type context;
463 input SourceInfo info;
464 output Expression outExp;
465 output Type outType;
466 algorithm
467 (outExp, outType) := match (exp1, exp2)
468 local
469 Type ty, ty1, ty2;
470 Expression e, e1, e2;
471 array<Expression> arr, arr1, arr2;
472
473 case (Expression.ARRAY(elements = arr1), Expression.ARRAY(elements = arr2))
474 algorithm
475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 ty := Type.UNKNOWN();
476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if arrayEmpty(arr1) then
477 // If the arrays are empty, match against the element types to get the expected return type.
478 ✗ ty1 := Type.arrayElementType(type1);
479 ✗ ty2 := Type.arrayElementType(type2);
480 ✗ arr := listArray({});
481
482 try
483 ✗ (_, ty) := matchOverloadedBinaryOperator(
484 Expression.EMPTY(ty1), ty1, var1, op, Expression.EMPTY(ty2), ty2, var2, candidates, context, info, showErrors = false);
485 else
486 ✗ printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, type2}, info);
487 end try;
488 else
489 4 ty1 := Type.unliftArray(type1);
490
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 ty2 := Type.unliftArray(type2);
491
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 arr := arrayCreateNoInit(arrayLength(arr1), arr1[1]);
492
493
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
16 for i in 1:arrayLength(arr1) loop
494 12 e1 := arrayGetNoBoundsChecking(arr1, i);
495 12 e2 := arrayGetNoBoundsChecking(arr2, i);
496 12 (e, ty) := checkOverloadedBinaryArrayAddSub2(e1, ty1, var1, op, e2, ty2, var2, candidates, context, info);
497 arrayUpdateNoBoundsChecking(arr, i, e);
498 end for;
499 end if;
500
501 4 outType := Type.setArrayElementType(type1, ty);
502 4 outExp := Expression.makeArray(outType, arr);
503 4 then
504 (outExp, outType);
505
506 12 else matchOverloadedBinaryOperator(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
507 end match;
508 end checkOverloadedBinaryArrayAddSub2;
509
510 function checkOverloadedBinaryArrayMul
511 input Expression exp1;
512 input Type type1;
513 input Variability var1;
514 input Operator op;
515 input Expression exp2;
516 input Type type2;
517 input Variability var2;
518 input list<Function> candidates;
519 input InstContext.Type context;
520 input SourceInfo info;
521 output Expression outExp;
522 output Type outType;
523 protected
524 Boolean valid;
525 list<Dimension> dims1, dims2;
526 Dimension dim11, dim12, dim21;
527 algorithm
528 ✗ dims1 := Type.arrayDims(type1);
529 ✗ dims2 := Type.arrayDims(type2);
530
531 (valid, outExp) := match (dims1, dims2)
532 // scalar * array = array
533 case ({}, {_})
534 algorithm
535 ✗ outExp := checkOverloadedBinaryScalarArray(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
536 then
537 (true, outExp);
538 // array * scalar = array
539 case ({_}, {})
540 algorithm
541 ✗ outExp := checkOverloadedBinaryArrayScalar(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
542 then
543 (true, outExp);
544 // matrix[n, m] * vector[m] = vector[n]
545 case ({dim11, dim12}, {dim21})
546 algorithm
547 ✗ valid := Dimension.isEqual(dim12, dim21);
548 // TODO: Implement me!
549 ✗ outExp := Expression.BINARY(exp1, op, exp2);
550 valid := false;
551 then
552 (valid, outExp);
553 // matrix[n, m] * matrix[m, p] = vector[n, p]
554 case ({dim11, dim12}, {dim21, _})
555 algorithm
556 ✗ valid := Dimension.isEqual(dim12, dim21);
557 // TODO: Implement me!
558 ✗ outExp := Expression.BINARY(exp1, op, exp2);
559 valid := false;
560 then
561 (valid, outExp);
562 // scalar * scalar should never get here.
563 // vector * vector and vector * matrix are undefined for overloaded operators.
564 ✗ else (false, Expression.BINARY(exp1, op, exp2));
565 end match;
566
567 if not valid then
568 ✗ printUnresolvableTypeError(outExp, {type1, type2}, info);
569 end if;
570
571 ✗ outType := Expression.typeOf(outExp);
572 end checkOverloadedBinaryArrayMul;
573
574 function checkOverloadedBinaryScalarArray
575 input Expression exp1;
576 input Type type1;
577 input Variability var1;
578 input Operator op;
579 input Expression exp2;
580 input Type type2;
581 input Variability var2;
582 input list<Function> candidates;
583 input InstContext.Type context;
584 input SourceInfo info;
585 output Expression outExp;
586 output Type outType;
587 algorithm
588 ✗ (outExp, outType) := checkOverloadedBinaryScalarArray2(
589 exp1, type1, var1, op, ExpandExp.expand(exp2), type2, var2, candidates, context, info);
590 end checkOverloadedBinaryScalarArray;
591
592 function checkOverloadedBinaryScalarArray2
593 input Expression exp1;
594 input Type type1;
595 input Variability var1;
596 input Operator op;
597 input Expression exp2;
598 input Type type2;
599 input Variability var2;
600 input list<Function> candidates;
601 input InstContext.Type context;
602 input SourceInfo info;
603 output Expression outExp;
604 output Type outType;
605 protected
606 Type ty;
607 array<Expression> arr;
608 Expression e2;
609 algorithm
610 (outExp, outType) := match exp2
611 case Expression.ARRAY()
612 guard arrayEmpty(exp2.elements)
613 algorithm
614 try
615 ✗ ty := Type.unliftArray(type2);
616 ✗ (_, outType) := matchOverloadedBinaryOperator(
617 exp1, type1, var1, op, Expression.EMPTY(type2), ty, var2, candidates, context, info, showErrors = false);
618 else
619 ✗ printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, exp2.ty}, info);
620 ✗ fail();
621 end try;
622
623 ✗ outType := Type.setArrayElementType(exp2.ty, outType);
624 ✗ then
625 (Expression.makeEmptyArray(outType), outType);
626
627 case Expression.ARRAY()
628 algorithm
629 ✗ ty := Type.unliftArray(type2);
630 ✗ arr := arrayCreateNoInit(arrayLength(exp2.elements), exp2);
631
632 ✗ for i in 1:arrayLength(arr) loop
633 ✗ e2 := arrayGetNoBoundsChecking(exp2.elements, i);
634 ✗ arrayUpdateNoBoundsChecking(arr, i,
635 checkOverloadedBinaryScalarArray2(exp1, type1, var1, op, e2, ty, var2, candidates, context, info));
636 end for;
637
638 ✗ outType := Type.setArrayElementType(exp2.ty, Expression.typeOf(arr[1]));
639 ✗ then
640 (Expression.makeArray(outType, arr), outType);
641
642 ✗ else matchOverloadedBinaryOperator(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
643 end match;
644 end checkOverloadedBinaryScalarArray2;
645
646 function checkOverloadedBinaryArrayScalar
647 input Expression exp1;
648 input Type type1;
649 input Variability var1;
650 input Operator op;
651 input Expression exp2;
652 input Type type2;
653 input Variability var2;
654 input list<Function> candidates;
655 input InstContext.Type context;
656 input SourceInfo info;
657 output Expression outExp;
658 output Type outType;
659 algorithm
660 ✗ (outExp, outType) := checkOverloadedBinaryArrayScalar2(
661 ExpandExp.expand(exp1), type1, var1, op, exp2, type2, var2, candidates, context, info);
662 end checkOverloadedBinaryArrayScalar;
663
664 function checkOverloadedBinaryArrayScalar2
665 input Expression exp1;
666 input Type type1;
667 input Variability var1;
668 input Operator op;
669 input Expression exp2;
670 input Type type2;
671 input Variability var2;
672 input list<Function> candidates;
673 input InstContext.Type context;
674 input SourceInfo info;
675 output Expression outExp;
676 output Type outType;
677 protected
678 Expression e1;
679 Type ty;
680 array<Expression> arr;
681 algorithm
682 (outExp, outType) := match exp1
683 case Expression.ARRAY()
684 guard arrayEmpty(exp1.elements)
685 algorithm
686 try
687 ✗ ty := Type.unliftArray(type1);
688 ✗ (_, outType) := matchOverloadedBinaryOperator(
689 Expression.EMPTY(type1), ty, var1, op, exp2, type2, var2, candidates, context, info, showErrors = false);
690 else
691 ✗ printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, exp1.ty}, info);
692 ✗ fail();
693 end try;
694
695 ✗ outType := Type.setArrayElementType(exp1.ty, outType);
696 ✗ then
697 (Expression.makeEmptyArray(outType), outType);
698
699 case Expression.ARRAY()
700 algorithm
701 ✗ ty := Type.unliftArray(type1);
702 ✗ arr := arrayCreateNoInit(arrayLength(exp1.elements), exp1);
703
704 ✗ for i in 1:arrayLength(arr) loop
705 ✗ e1 := arrayGetNoBoundsChecking(exp1.elements, i);
706 ✗ arrayUpdateNoBoundsChecking(arr, i,
707 checkOverloadedBinaryArrayScalar2(e1, ty, var1, op, exp2, type2, var2, candidates, context, info));
708 end for;
709
710 ✗ outType := Type.setArrayElementType(exp1.ty, Expression.typeOf(arr[1]));
711 ✗ then
712 (Expression.makeArray(outType, arr), outType);
713
714 ✗ else matchOverloadedBinaryOperator(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
715 end match;
716 end checkOverloadedBinaryArrayScalar2;
717
718 function checkOverloadedBinaryArrayDiv
719 input Expression exp1;
720 input Type type1;
721 input Variability var1;
722 input Operator op;
723 input Expression exp2;
724 input Type type2;
725 input Variability var2;
726 input list<Function> candidates;
727 input InstContext.Type context;
728 input SourceInfo info;
729 output Expression outExp;
730 output Type outType;
731 algorithm
732 ✗ if Type.isArray(type1) and Type.isScalar(type2) then
733 ✗ (outExp, outType) := checkOverloadedBinaryArrayScalar(exp1, type1, var1, op, exp2, type2, var2, candidates, context, info);
734 else
735 ✗ printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, type2}, info);
736 ✗ fail();
737 end if;
738 end checkOverloadedBinaryArrayDiv;
739
740 function checkOverloadedBinaryArrayEW
741 input Expression exp1;
742 input Type type1;
743 input Variability var1;
744 input Operator op;
745 input Expression exp2;
746 input Type type2;
747 input Variability var2;
748 input list<Function> candidates;
749 input InstContext.Type context;
750 input SourceInfo info;
751 output Expression outExp;
752 output Type outType;
753 protected
754 Expression e1, e2;
755 MatchKind mk;
756 algorithm
757 ✗ if Type.isArray(type1) and Type.isArray(type2) then
758 ✗ (e1, e2, _, mk) := matchExpressions(exp1, type1, exp2, type2, ALLOW_UNKNOWN);
759 else
760 ✗ (e1, e2, _, mk) := matchExpressions(exp1, Type.arrayElementType(type1),
761 exp2, Type.arrayElementType(type2), ALLOW_UNKNOWN);
762 end if;
763
764 ✗ if not isCompatibleMatch(mk) then
765 ✗ printUnresolvableTypeError(Expression.BINARY(e1, op, e2), {type1, type2}, info);
766 end if;
767
768 ✗ e1 := ExpandExp.expand(exp1);
769 ✗ e2 := ExpandExp.expand(exp2);
770
771 ✗ (outExp, outType) := checkOverloadedBinaryArrayEW2(
772 e1, type1, var1, op, e2, type2, var2, candidates, context, info);
773 end checkOverloadedBinaryArrayEW;
774
775 function checkOverloadedBinaryArrayEW2
776 input Expression exp1;
777 input Type type1;
778 input Variability var1;
779 input Operator op;
780 input Expression exp2;
781 input Type type2;
782 input Variability var2;
783 input list<Function> candidates;
784 input InstContext.Type context;
785 input SourceInfo info;
786 output Expression outExp;
787 output Type outType;
788 protected
789 Expression e1, e2;
790 list<Expression> expl;
791 array<Expression> expl1, expl2;
792 Type ty = Type.UNKNOWN(), ty1, ty2;
793 Boolean is_array1, is_array2;
794 algorithm
795 ✗ is_array1 := Type.isArray(type1);
796 ✗ is_array2 := Type.isArray(type2);
797
798 ✗ if is_array1 or is_array2 then
799 ✗ expl := {};
800
801 ✗ if Expression.isEmptyArray(exp1) or Expression.isEmptyArray(exp2) then
802 ✗ ty1 := Type.arrayElementType(type1);
803 ✗ ty2 := Type.arrayElementType(type2);
804
805 try
806 ✗ (_, ty) := matchOverloadedBinaryOperator(
807 Expression.EMPTY(ty1), ty1, var1, op,
808 Expression.EMPTY(ty2), ty2, var2, candidates, context, info);
809 else
810 ✗ printUnresolvableTypeError(Expression.BINARY(exp1, op, exp2), {type1, type2}, info);
811 end try;
812 elseif is_array1 and is_array2 then
813 ✗ ty1 := Type.unliftArray(type1);
814 ✗ ty2 := Type.unliftArray(type2);
815 ✗ expl1 := Expression.arrayElements(exp1);
816 ✗ expl2 := Expression.arrayElements(exp2);
817
818 ✗ if arrayLength(expl1) > arrayLength(expl2) then
819 ✗ fail();
820 end if;
821
822 ✗ for i in 1:arrayLength(expl1) loop
823 ✗ e1 := arrayGetNoBoundsChecking(expl1, i);
824 ✗ e2 := arrayGetNoBoundsChecking(expl2, i);
825 ✗ (e1, ty) := checkOverloadedBinaryArrayEW2(e1, ty1, var1, op, e2, ty2, var2, candidates, context, info);
826 expl := e1 :: expl;
827 end for;
828 elseif is_array1 then
829 ✗ ty1 := Type.unliftArray(type1);
830 ✗ expl1 := Expression.arrayElements(exp1);
831
832 ✗ for e in expl1 loop
833 ✗ (e, ty) := checkOverloadedBinaryArrayEW2(e, ty1, var1, op, exp2, type2, var2, candidates, context, info);
834 expl := e :: expl;
835 end for;
836 elseif is_array2 then
837 ✗ ty2 := Type.unliftArray(type2);
838 ✗ expl2 := Expression.arrayElements(exp2);
839
840 ✗ for e in expl2 loop
841 ✗ (e, ty) := checkOverloadedBinaryArrayEW2(exp1, type1, var1, op, e, ty2, var2, candidates, context, info);
842 expl := e :: expl;
843 end for;
844 end if;
845
846 ✗ outType := Type.setArrayElementType(type1, ty);
847 ✗ outExp := Expression.makeArray(outType, listArray(listReverseInPlace(expl)));
848 else
849 ✗ (outExp, outType) := matchOverloadedBinaryOperator(
850 exp1, type1, var1, op,
851 exp2, type2, var2, candidates, context, info);
852 end if;
853 end checkOverloadedBinaryArrayEW2;
854
855 function implicitConstructAndMatch
856 input list<Function> candidates;
857 input Expression inExp1;
858 input Type inType1;
859 input Operator op;
860 input Expression inExp2;
861 input Type inType2;
862 input SourceInfo info;
863 output Expression outExp;
864 output Type outType;
865 protected
866 list<InstNode> inputs;
867 InstNode in1, in2;
868 Function operfn;
869 list<tuple<Function, list<Expression>, Variability>> matchedfuncs = {};
870 Expression exp1,exp2;
871 Type arg1_ty, arg2_ty;
872 Variability var;
873 Boolean matched;
874 SourceInfo arg1_info, arg2_info;
875 algorithm
876 exp1 := inExp1; exp2 := inExp2;
877
2/2
✓ Branch 0 taken 837 times.
✓ Branch 1 taken 427 times.
1264 for fn in candidates loop
878
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 834 times.
837 if listLength(fn.inputs) <> 2 then
879 3 continue;
880 end if;
881
882
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 834 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 834 times.
834 in1 :: in2 :: _ := fn.inputs;
883 834 arg1_ty := InstNode.getType(in1);
884 834 arg2_ty := InstNode.getType(in2);
885 834 arg1_info := InstNode.info(in1);
886 834 arg2_info := InstNode.info(in2);
887
888 // Try to implicitly construct a matching record from the first argument.
889 834 (matchedfuncs, matched) :=
890 implicitConstructAndMatch2(inExp1, inType1, inExp2, arg1_ty,
891 arg1_info, arg2_ty, arg2_info, InstNode.classScope(in2), fn, false, matchedfuncs);
892
893
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 635 times.
833 if matched then
894 198 continue;
895 end if;
896
897 // Try to implicitly construct a matching record from the second argument.
898 635 (matchedfuncs, matched) :=
899 implicitConstructAndMatch2(inExp2, inType2, inExp1, arg2_ty,
900 arg2_info, arg1_ty, arg1_info, InstNode.classScope(in1), fn, true, matchedfuncs);
901 end for;
902
903
2/2
✓ Branch 1 taken 423 times.
✓ Branch 2 taken 4 times.
427 if listLength(matchedfuncs) == 1 then
904
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 423 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 423 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 423 times.
423 (operfn, {exp1,exp2}, var)::_ := matchedfuncs;
905 423 outType := Function.returnType(operfn);
906 423 outExp := Expression.CALL(Call.makeTypedCall(operfn, {exp1, exp2}, var, Purity.PURE, outType));
907 else
908
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
12 Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_OPERATOR_FUNCTIONS_NFINST,
909 {Expression.toString(Expression.BINARY(exp1, op, exp2)),
910 Function.candidateFuncListString(list(Util.tuple31(fn) for fn in matchedfuncs))}, info);
911 4 fail();
912 end if;
913 end implicitConstructAndMatch;
914
915 function implicitConstructAndMatch2
916 input Expression exp1;
917 input Type type1;
918 input Expression exp2;
919 input Type paramType1;
920 input SourceInfo paramInfo1;
921 input Type paramType2;
922 input SourceInfo paramInfo2;
923 input InstNode scope;
924 input Function fn;
925 input Boolean reverseArgs;
926 input output list<tuple<Function, list<Expression>, Variability>> matchedFns;
927 output Boolean matched;
928 protected
929 ComponentRef fn_ref;
930 Expression e1, e2;
931 MatchKind mk;
932 Variability var;
933 Type ty;
934 algorithm
935 1469 (e1, _, mk) := matchTypes(paramType1, type1, exp1);
936
937 // We only want overloaded constructors when trying to implicitly construct.
938 // Default constructors are not considered.
939
2/2
✓ Branch 0 taken 424 times.
✓ Branch 1 taken 1045 times.
1469 if mk == MatchKind.EXACT then
940 424 fn_ref := Function.instFunction(Absyn.CREF_IDENT("'constructor'", {}),
941 scope, NFInstContext.NO_CONTEXT, paramInfo2);
942 423 e2 := Expression.CALL(Call.UNTYPED_CALL(fn_ref, {exp2}, {}, InstNode.scopeRef(scope)));
943 423 (e2, ty, var) := Call.typeCall(e2, 0, paramInfo1);
944 423 (_, _, mk) := matchTypes(paramType2, ty, e2);
945
946
1/2
✓ Branch 0 taken 423 times.
✗ Branch 1 not taken.
423 if mk == MatchKind.EXACT then
947
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 198 times.
846 matchedFns := (fn, if reverseArgs then {e2, e1} else {e1, e2}, var) :: matchedFns;
948 matched := true;
949 else
950 matched := false;
951 end if;
952 else
953 matched := false;
954 end if;
955 end implicitConstructAndMatch2;
956
957 function checkBinaryOperationAdd
958 input Expression exp1;
959 input Type type1;
960 input Expression exp2;
961 input Type type2;
962 input SourceInfo info;
963 output Expression binaryExp;
964 output Type resultType;
965 protected
966 Expression e1, e2;
967 MatchKind mk;
968 Boolean valid;
969 algorithm
970 147317 (e1, e2, resultType, mk) := matchExpressions(exp1, type1, exp2, type2, ALLOW_UNKNOWN);
971 147317 valid := isCompatibleMatch(mk);
972
973 valid := match Type.arrayElementType(resultType)
974 case Type.INTEGER() then valid;
975 case Type.REAL() then valid;
976 case Type.STRING() then valid;
977 else false;
978 end match;
979
980 147317 binaryExp := Expression.BINARY(e1, Operator.makeAdd(resultType), e2);
981
982
1/2
✓ Branch 0 taken 147317 times.
✗ Branch 1 not taken.
147317 if not valid then
983 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
984 end if;
985 end checkBinaryOperationAdd;
986
987 function checkBinaryOperationSub
988 input Expression exp1;
989 input Type type1;
990 input Expression exp2;
991 input Type type2;
992 input SourceInfo info;
993 output Expression binaryExp;
994 output Type resultType;
995 protected
996 Expression e1, e2;
997 MatchKind mk;
998 Boolean valid;
999 algorithm
1000 61612 (e1, e2, resultType, mk) := matchExpressions(exp1, type1, exp2, type2, ALLOW_UNKNOWN);
1001 61612 valid := isCompatibleMatch(mk);
1002
1003 valid := match Type.arrayElementType(resultType)
1004 case Type.INTEGER() then valid;
1005 case Type.REAL() then valid;
1006 else false;
1007 end match;
1008
1009 61612 binaryExp := Expression.BINARY(e1, Operator.makeSub(resultType), e2);
1010
1011
1/2
✓ Branch 0 taken 61612 times.
✗ Branch 1 not taken.
61612 if not valid then
1012 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
1013 end if;
1014 end checkBinaryOperationSub;
1015
1016 function checkBinaryOperationMul
1017 input Expression exp1;
1018 input Type type1;
1019 input Expression exp2;
1020 input Type type2;
1021 input SourceInfo info;
1022 output Expression binaryExp;
1023 output Type resultType;
1024 protected
1025 Expression e1, e2;
1026 Type ty1, ty2;
1027 list<Dimension> dims1, dims2;
1028 Dimension dim11, dim12, dim21, dim22;
1029 MatchKind mk;
1030 Op op;
1031 Boolean valid;
1032 algorithm
1033 342981 ty1 := Type.arrayElementType(type1);
1034 342981 ty2 := Type.arrayElementType(type2);
1035 342981 (e1, e2, resultType, mk) := matchExpressions(exp1, ty1, exp2, ty2, ALLOW_UNKNOWN);
1036 342981 valid := isCompatibleMatch(mk);
1037
1038 valid := match resultType
1039 case Type.INTEGER() then valid;
1040 case Type.REAL() then valid;
1041 else false;
1042 end match;
1043
1044 342981 dims1 := Type.arrayDims(type1);
1045 342981 dims2 := Type.arrayDims(type2);
1046
1047 (resultType, op) := match (dims1, dims2)
1048 // scalar * scalar = scalar
1049 318209 case ({}, {}) then (resultType, Op.MUL);
1050 // scalar * array = array
1051 2666 case ({}, _) then (Type.ARRAY(resultType, dims2), Op.MUL_SCALAR_ARRAY);
1052 // array * scalar = array
1053 1952 case (_, {}) then (Type.ARRAY(resultType, dims1), Op.MUL_ARRAY_SCALAR);
1054 // vector[n] * vector[n] = scalar
1055 case ({dim11}, {dim21})
1056 algorithm
1057 18573 valid := Dimension.isEqual(dim11, dim21);
1058 18573 then
1059 (resultType, Op.SCALAR_PRODUCT);
1060
1061 // vector[n] * matrix[n, m] = vector[m]
1062 case ({dim11}, {dim21, dim22})
1063 algorithm
1064 3 valid := Dimension.isEqual(dim11, dim21);
1065 3 then
1066 (Type.ARRAY(resultType, {dim22}), Op.MUL_VECTOR_MATRIX);
1067
1068 // matrix[n, m] * vector[m] = vector[n]
1069 case ({dim11, dim12}, {dim21})
1070 algorithm
1071 1134 valid := Dimension.isEqual(dim12, dim21);
1072 1134 then
1073 (Type.ARRAY(resultType, {dim11}), Op.MUL_MATRIX_VECTOR);
1074
1075 // matrix[n, m] * matrix[m, p] = vector[n, p]
1076 case ({dim11, dim12}, {dim21, dim22})
1077 algorithm
1078 444 valid := Dimension.isEqual(dim12, dim21);
1079 444 then
1080 (Type.ARRAY(resultType, {dim11, dim22}), Op.MATRIX_PRODUCT);
1081
1082 else
1083 algorithm
1084 valid := false;
1085 ✗ then
1086 (resultType, Op.MUL);
1087 end match;
1088
1089 342981 binaryExp := Expression.BINARY(e1, Operator.OPERATOR(resultType, op), e2);
1090
1091
1/2
✓ Branch 0 taken 342981 times.
✗ Branch 1 not taken.
342981 if not valid then
1092 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
1093 end if;
1094 end checkBinaryOperationMul;
1095
1096 function checkBinaryOperationDiv
1097 input Expression exp1;
1098 input Type type1;
1099 input Expression exp2;
1100 input Type type2;
1101 input SourceInfo info;
1102 input Boolean isElementWise;
1103 output Expression binaryExp;
1104 output Type resultType;
1105 protected
1106 Expression e1, e2;
1107 Type ty1, ty2;
1108 MatchKind mk;
1109 Boolean valid;
1110 Operator op;
1111 algorithm
1112 // Division always returns a Real value, so instead of checking if the types
1113 // are compatible with each other we check if each type is compatible with Real.
1114 48376 (e1, ty1, mk) := matchTypes(type1, Type.setArrayElementType(type1, Type.REAL()), exp1, ALLOW_UNKNOWN);
1115 48376 valid := isCompatibleMatch(mk);
1116 48376 (e2, ty2, mk) := matchTypes(type2, Type.setArrayElementType(type2, Type.REAL()), exp2, ALLOW_UNKNOWN);
1117
2/4
✓ Branch 0 taken 48376 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 48376 times.
48376 valid := valid and isCompatibleMatch(mk);
1118
1119 // Division is always element-wise, the only difference between / and ./ is
1120 // which operands they accept.
1121 (resultType, op) := match (Type.isArray(ty1), Type.isArray(ty2), isElementWise)
1122 // scalar / scalar or scalar ./ scalar
1123 46834 case (false, false, _ ) then (ty1, Operator.makeDiv(ty1));
1124 // array / scalar or array ./ scalar
1125 1477 case (_ , false, _ ) then (ty1, Operator.OPERATOR(ty1, Op.DIV_ARRAY_SCALAR));
1126 // scalar ./ array
1127 4 case (false, _ , true) then (ty2, Operator.OPERATOR(ty2, Op.DIV_SCALAR_ARRAY));
1128
1129 // array ./ array
1130 case (true , _ , true)
1131 algorithm
1132 // If both operands are arrays, check that their dimensions are compatible.
1133 61 (_, _, mk) := matchArrayTypes(ty1, ty2, e1, ALLOW_UNKNOWN);
1134
2/4
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 61 times.
61 valid := valid and isCompatibleMatch(mk);
1135 61 then
1136 (ty1, Operator.makeDiv(ty1));
1137
1138 // Anything else is an error.
1139 else
1140 algorithm
1141 valid := false;
1142 ✗ then
1143 (ty1, Operator.makeDiv(ty1));
1144 end match;
1145
1146 48376 binaryExp := Expression.BINARY(e1, op, e2);
1147
1148
1/2
✓ Branch 0 taken 48376 times.
✗ Branch 1 not taken.
48376 if not valid then
1149 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
1150 end if;
1151 end checkBinaryOperationDiv;
1152
1153 function checkBinaryOperationPow
1154 input Expression exp1;
1155 input Type type1;
1156 input Expression exp2;
1157 input Type type2;
1158 input SourceInfo info;
1159 output Expression binaryExp;
1160 output Type resultType;
1161 protected
1162 Expression e1, e2;
1163 MatchKind mk;
1164 Boolean valid;
1165 Operator op;
1166 algorithm
1167 // The first operand of ^ should be Real.
1168 11604 (e1, resultType, mk) := matchTypes(type1, Type.setArrayElementType(type1, Type.REAL()), exp1, ALLOW_UNKNOWN);
1169 11604 valid := isCompatibleMatch(mk);
1170
1171
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 11579 times.
11604 if Type.isArray(resultType) then
1172 // Real[n, n] ^ Integer
1173
2/4
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
25 valid := valid and Type.isSquareMatrix(resultType);
1174
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 valid := valid and Type.isInteger(type2);
1175
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 valid := valid and not Expression.isNegative(exp2); // invalid if we know it's negative, valid if we don't know.
1176 25 op := Operator.OPERATOR(resultType, Op.POW_MATRIX);
1177 e2 := exp2;
1178 else
1179 // Real ^ Real
1180 11579 (e2, _, mk) := matchTypes(type2, Type.REAL(), exp2, ALLOW_UNKNOWN);
1181
2/4
✓ Branch 0 taken 11579 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11579 times.
11579 valid := valid and isCompatibleMatch(mk);
1182 11579 op := Operator.OPERATOR(resultType, Op.POW);
1183 end if;
1184
1185 11604 binaryExp := Expression.BINARY(e1, op, e2);
1186
1187
1/2
✓ Branch 0 taken 11604 times.
✗ Branch 1 not taken.
11604 if not valid then
1188 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
1189 end if;
1190 end checkBinaryOperationPow;
1191
1192 function checkBinaryOperationPowEW
1193 input Expression exp1;
1194 input Type type1;
1195 input Expression exp2;
1196 input Type type2;
1197 input SourceInfo info;
1198 output Expression binaryExp;
1199 output Type resultType;
1200 protected
1201 Expression e1, e2;
1202 Type ty1, ty2;
1203 MatchKind mk;
1204 Boolean valid;
1205 Operator op;
1206 algorithm
1207 // Exponentiation always returns a Real value, so instead of checking if the types
1208 // are compatible with each other we check if each type is compatible with Real.
1209 23 (e1, ty1, mk) := matchTypes(type1, Type.setArrayElementType(type1, Type.REAL()), exp1, ALLOW_UNKNOWN);
1210 23 valid := isCompatibleMatch(mk);
1211 23 (e2, ty2, mk) := matchTypes(type2, Type.setArrayElementType(type2, Type.REAL()), exp2, ALLOW_UNKNOWN);
1212
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
23 valid := valid and isCompatibleMatch(mk);
1213
1214 (resultType, op) := match (Type.isArray(ty1), Type.isArray(ty2))
1215 // scalar .^ scalar
1216 1 case (false, false) then (ty1, Operator.makePow(ty1));
1217 // array .^ scalar
1218 20 case (_ , false) then (ty1, Operator.OPERATOR(ty1, Op.POW_ARRAY_SCALAR));
1219 // scalar .^ array
1220 2 case (false, _ ) then (ty2, Operator.OPERATOR(ty2, Op.POW_SCALAR_ARRAY));
1221 // array .^ array
1222 else
1223 algorithm
1224 // If both operands are arrays, check that their dimensions are compatible.
1225 ✗ (_, _, mk) := matchArrayTypes(ty1, ty2, e1, ALLOW_UNKNOWN);
1226 ✗ valid := valid and isCompatibleMatch(mk);
1227 ✗ then
1228 (ty1, Operator.makePow(ty1));
1229 end match;
1230
1231 23 binaryExp := Expression.BINARY(e1, op, e2);
1232
1233
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if not valid then
1234 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
1235 end if;
1236 end checkBinaryOperationPowEW;
1237
1238 function checkBinaryOperationEW
1239 input Expression exp1;
1240 input Type type1;
1241 input Expression exp2;
1242 input Type type2;
1243 input Op elemOp;
1244 input SourceInfo info;
1245 output Expression binaryExp;
1246 output Type resultType;
1247 protected
1248 Expression e1, e2;
1249 Type ty1, ty2;
1250 MatchKind mk;
1251 Boolean valid, is_arr1, is_arr2;
1252 Operator op;
1253 algorithm
1254 137 is_arr1 := Type.isArray(type1);
1255 137 is_arr2 := Type.isArray(type2);
1256
1257
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 26 times.
137 if is_arr1 and is_arr2 then
1258 // The expressions must be type compatible if they are both arrays.
1259 111 (e1, e2, resultType, mk) := matchExpressions(exp1, type1, exp2, type2, ALLOW_UNKNOWN);
1260 else
1261 // Otherwise it's enough if their element types are compatible.
1262 26 ty1 := Type.arrayElementType(type1);
1263 26 ty2 := Type.arrayElementType(type2);
1264 26 (e1, e2, resultType, mk) := matchExpressions(exp1, ty1, exp2, ty2, ALLOW_UNKNOWN);
1265 end if;
1266
1267 137 valid := isCompatibleMatch(mk);
1268
1269 // Check that the type is valid for the operation.
1270 valid := match (Type.arrayElementType(resultType), elemOp)
1271 case (Type.INTEGER(), _) then valid;
1272 case (Type.REAL(), _) then valid;
1273 case (Type.STRING(), Op.ADD) then valid;
1274 else false;
1275 end match;
1276
1277 (resultType, op) := match (is_arr1, is_arr2)
1278 // array * scalar => Op.{elemOp}_ARRAY_SCALAR.
1279 case (true, false)
1280 algorithm
1281 12 resultType := Type.copyDims(type1, resultType);
1282 12 op := Operator.makeArrayScalar(resultType, elemOp);
1283 12 then
1284 (resultType, op);
1285
1286 // scalar * array => Op.{elemOp}_SCALAR_ARRAY;
1287 case (false, true)
1288 algorithm
1289 13 resultType := Type.copyDims(type2, resultType);
1290 13 op := Operator.makeScalarArray(resultType, elemOp);
1291 13 then
1292 (resultType, op);
1293
1294 // array * array => Op.{elemOp}_EW
1295 case (true, true)
1296 111 then (resultType, Operator.makeEW(Operator.OPERATOR(resultType, elemOp)));
1297
1298 // scalar * scalar => Op.{elemOp}
1299 1 else (resultType, Operator.OPERATOR(resultType, elemOp));
1300 end match;
1301
1302 137 binaryExp := Expression.BINARY(e1, op, e2);
1303
1304
1/2
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
137 if not valid then
1305 ✗ printUnresolvableTypeError(binaryExp, {type1, type2}, info);
1306 end if;
1307 end checkBinaryOperationEW;
1308
1309 public function checkUnaryOperation
1310 input Expression exp1;
1311 input Type type1;
1312 input Variability var1;
1313 input Operator operator;
1314 input InstContext.Type context;
1315 input SourceInfo info;
1316 output Expression unaryExp;
1317 output Type unaryType;
1318 protected
1319 Operator op;
1320 algorithm
1321
2/2
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 35265 times.
35433 if Type.isComplex(Type.arrayElementType(type1)) then
1322 168 (unaryExp,unaryType) := checkOverloadedUnaryOperator(exp1, type1, var1, operator, context, info);
1323 168 return;
1324 end if;
1325
1326 35265 unaryType := type1;
1327 35265 op := Operator.setType(unaryType, operator);
1328
1329 unaryExp := match operator.op
1330 case Op.ADD then exp1; // + is a no-op for arithmetic unary operations.
1331 35265 else Expression.UNARY(op, exp1);
1332 end match;
1333
1334
1/2
✓ Branch 1 taken 35265 times.
✗ Branch 2 not taken.
35265 if not Type.isNumeric(type1) then
1335 ✗ printUnresolvableTypeError(unaryExp, {type1}, info);
1336 end if;
1337 end checkUnaryOperation;
1338
1339 public function checkOverloadedUnaryOperator
1340 input Expression inExp1;
1341 input Type inType1;
1342 input Variability var;
1343 input Operator inOp;
1344 input InstContext.Type context;
1345 input SourceInfo info;
1346 output Expression outExp;
1347 output Type outType;
1348 protected
1349 String opstr;
1350 list<Function> candidates;
1351 list<TypedArg> args;
1352 MatchedFunction matchedFunc;
1353 list<MatchedFunction> matchedFunctions = {}, exactMatches;
1354 algorithm
1355 168 opstr := Operator.symbol(inOp,"'");
1356 168 candidates := OperatorOverloading.lookupOperatorFunctionsInType(opstr, inType1);
1357
1358 //for fn in candidates loop
1359 // checkValidOperatorOverload(opstr, fn, node1);
1360 //end for;
1361
1362 168 args := {TypedArg.TYPED_ARG(NONE(), inExp1, inType1, var, Purity.PURE)};
1363 168 matchedFunctions := Function.matchFunctionsSilent(candidates, args, {}, context, info, vectorize = false);
1364
1365 // We only allow exact matches for operator overloading. e.g. no casting or generic matches.
1366 168 exactMatches := MatchedFunction.getExactMatches(matchedFunctions);
1367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
168 if listEmpty(exactMatches) then
1368 ✗ printUnresolvableTypeError(Expression.UNARY(inOp, inExp1), {inType1}, info);
1369 ✗ fail();
1370 end if;
1371
1372
1/2
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
168 if listLength(exactMatches) == 1 then
1373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
168 matchedFunc ::_ := exactMatches;
1374 168 outType := Function.returnType(matchedFunc.func);
1375
4/4
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 168 times.
336 outExp := Expression.CALL(
1376 Call.makeTypedCall(
1377 matchedFunc.func,
1378 list(a.value for a in matchedFunc.args),
1379 var,
1380 Purity.PURE,
1381 outType));
1382 else
1383 ✗ Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_OPERATOR_FUNCTIONS_NFINST,
1384 {Expression.toString(Expression.UNARY(inOp, inExp1)),
1385 Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info);
1386 ✗ fail();
1387 end if;
1388
1389 168 outExp := Inline.inlineCallExp(outExp);
1390 end checkOverloadedUnaryOperator;
1391
1392 function checkLogicalBinaryOperation
1393 input Expression exp1;
1394 input Type type1;
1395 input Variability var1;
1396 input Operator operator;
1397 input Expression exp2;
1398 input Type type2;
1399 input Variability var2;
1400 input InstContext.Type context;
1401 input SourceInfo info;
1402 output Expression outExp;
1403 output Type resultType;
1404 protected
1405 Expression e1, e2;
1406 MatchKind mk;
1407 algorithm
1408
2/4
✓ Branch 2 taken 9890 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9890 times.
9890 if Type.isComplex(Type.arrayElementType(type1)) or
1409 Type.isComplex(Type.arrayElementType(type2)) then
1410 ✗ (outExp,resultType) := checkOverloadedBinaryOperator(exp1, type1, var1, operator, exp2, type2, var2, context, info);
1411 ✗ return;
1412 end if;
1413
1414
1415 9890 (e1, e2, resultType, mk) := matchExpressions(exp1, type1, exp2, type2, ALLOW_UNKNOWN);
1416 9890 outExp := Expression.LBINARY(e1, Operator.setType(resultType, operator), e2);
1417
1418
2/4
✓ Branch 1 taken 9890 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 9890 times.
✗ Branch 6 not taken.
9890 if not isCompatibleMatch(mk) or
1419 not Type.isBoolean(Type.arrayElementType(resultType)) then
1420 ✗ printUnresolvableTypeError(outExp, {type1, type2}, info);
1421 end if;
1422 end checkLogicalBinaryOperation;
1423
1424 function checkLogicalUnaryOperation
1425 input Expression exp1;
1426 input Type type1;
1427 input Variability var1;
1428 input Operator operator;
1429 input InstContext.Type context;
1430 input SourceInfo info;
1431 output Expression outExp;
1432 output Type resultType = type1;
1433 algorithm
1434
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3668 times.
3668 if Type.isComplex(Type.arrayElementType(type1)) then
1435 ✗ (outExp,resultType) := checkOverloadedUnaryOperator(exp1, type1, var1, operator, context, info);
1436 ✗ return;
1437 end if;
1438
1439 3668 outExp := Expression.LUNARY(Operator.setType(type1, operator), exp1);
1440
1441
1/2
✓ Branch 2 taken 3668 times.
✗ Branch 3 not taken.
3668 if not Type.isBoolean(Type.arrayElementType(type1)) then
1442 ✗ printUnresolvableTypeError(outExp, {type1}, info);
1443 end if;
1444 end checkLogicalUnaryOperation;
1445
1446 function checkRelationOperation
1447 input Expression exp1;
1448 input Type type1;
1449 input Variability var1;
1450 input Operator operator;
1451 input Expression exp2;
1452 input Type type2;
1453 input Variability var2;
1454 input Integer index;
1455 input InstContext.Type context;
1456 input SourceInfo info;
1457 output Expression outExp;
1458 output Type resultType;
1459 protected
1460 Expression e1, e2;
1461 Type ty;
1462 MatchKind mk;
1463 Boolean valid;
1464 Op o;
1465 algorithm
1466
1467
2/4
✓ Branch 2 taken 30432 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 30432 times.
30432 if Type.isComplex(Type.arrayElementType(type1)) or
1468 Type.isComplex(Type.arrayElementType(type2)) then
1469 ✗ (outExp,resultType) := checkOverloadedBinaryOperator(exp1, type1, var1, operator, exp2, type2, var2, context, info);
1470 ✗ return;
1471 end if;
1472
1473 30432 (e1, e2, ty, mk) := matchExpressions(exp1, type1, exp2, type2);
1474 30432 valid := isCompatibleMatch(mk);
1475
1476 30432 resultType := Type.BOOLEAN();
1477 30432 outExp := Expression.RELATION(e1, Operator.setType(ty, operator), e2, index);
1478
1479 valid := match ty
1480 case Type.INTEGER() then valid;
1481 case Type.REAL()
1482 algorithm
1483 // Print a warning for == or <> with Real operands in a model.
1484 16351 o := operator.op;
1485
4/4
✓ Branch 1 taken 5991 times.
✓ Branch 2 taken 10360 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 5984 times.
16351 if not InstContext.inFunction(context) and (o == Op.EQUAL or o == Op.NEQUAL) then
1486 21 Error.addStrictMessage(Error.WARNING_RELATION_ON_REAL,
1487 {Expression.toString(outExp), Operator.symbol(operator, "")}, info);
1488 end if;
1489 then
1490 valid;
1491 case Type.STRING() then valid;
1492 case Type.BOOLEAN() then valid;
1493 case Type.ENUMERATION() then valid;
1494 else false;
1495 end match;
1496
1497
1/2
✓ Branch 0 taken 30432 times.
✗ Branch 1 not taken.
30432 if not valid then
1498 ✗ printUnresolvableTypeError(outExp, {type1, type2}, info);
1499 end if;
1500 end checkRelationOperation;
1501
1502 function printUnresolvableTypeError
1503 input Expression exp;
1504 input list<Type> types;
1505 input SourceInfo info;
1506 input Boolean printError = true;
1507 protected
1508 String exp_str, ty_str;
1509 algorithm
1510
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if printError then
1511 2 exp_str := Expression.toString(exp);
1512 2 ty_str := List.toStringCustom(types, Type.toString, "", "", ", ", "", false);
1513 2 Error.addSourceMessage(Error.UNRESOLVABLE_TYPE, {exp_str, ty_str, "<NO_COMPONENT>"}, info);
1514 end if;
1515
1516 2 fail();
1517 end printUnresolvableTypeError;
1518
1519 function matchExpressions
1520 input output Expression exp1;
1521 input Type type1;
1522 input output Expression exp2;
1523 input Type type2;
1524 input MatchOptions options = DEFAULT_OPTIONS;
1525 output Type compatibleType;
1526 output MatchKind matchKind;
1527 algorithm
1528 // Return true if the references are the same.
1529
2/2
✓ Branch 0 taken 436573 times.
✓ Branch 1 taken 338872 times.
775445 if referenceEq(type1, type2) then
1530 436573 compatibleType := type1;
1531 436573 matchKind := MatchKind.EXACT;
1532 436573 return;
1533 end if;
1534
1535 // Check if the types are different kinds of types.
1536
2/2
✓ Branch 0 taken 34211 times.
✓ Branch 1 taken 304661 times.
338872 if valueConstructor(type1) <> valueConstructor(type2) then
1537 // If the types are not of the same kind we might need to type cast one of
1538 // the expressions to make them compatible.
1539 34211 (exp1, exp2, compatibleType, matchKind) :=
1540 matchExpressions_cast(exp1, type1, exp2, type2, options);
1541 34211 return;
1542 end if;
1543
1544 // The types are of the same kind, so we only need to match on one of them.
1545
8/12
✓ Branch 0 taken 22143 times.
✓ Branch 1 taken 219285 times.
✓ Branch 2 taken 6228 times.
✓ Branch 3 taken 2232 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 41821 times.
✓ Branch 7 taken 203 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12725 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
304661 matchKind := MatchKind.EXACT;
1546 compatibleType := match type1
1547 case Type.INTEGER() then type1;
1548 case Type.REAL() then type1;
1549 case Type.STRING() then type1;
1550 case Type.BOOLEAN() then type1;
1551 case Type.CLOCK() then type1;
1552
1553 case Type.ENUMERATION()
1554 algorithm
1555 ✗ matchKind := matchEnumerationTypes(type1, type2);
1556 then
1557 type1;
1558
1559 case Type.ARRAY()
1560 algorithm
1561 41821 (exp1, exp2, compatibleType, matchKind) :=
1562 matchArrayExpressions(exp1, type1, exp2, type2, options);
1563 41821 then
1564 compatibleType;
1565
1566 case Type.TUPLE()
1567 algorithm
1568 203 (exp1, compatibleType, matchKind) :=
1569 matchTupleTypes(type1, type2, exp1, options);
1570 203 then
1571 compatibleType;
1572
1573 case Type.UNKNOWN()
1574 algorithm
1575 ✗ matchKind := if getOption(options, ALLOW_UNKNOWN) then MatchKind.EXACT else MatchKind.NOT_COMPATIBLE;
1576 then
1577 type1;
1578
1579 case Type.COMPLEX()
1580 algorithm
1581 // TODO: This needs more work to handle e.g. type casting of complex expressions.
1582 12725 (exp1, compatibleType, matchKind) :=
1583 matchComplexTypes(type1, type2, exp1, options);
1584 12725 then
1585 compatibleType;
1586
1587 case Type.METABOXED()
1588 algorithm
1589 ✗ (exp1, exp2, compatibleType, matchKind) :=
1590 matchBoxedExpressions(exp1, type1, exp2, type2, options);
1591 ✗ then
1592 compatibleType;
1593
1594 else
1595 algorithm
1596 ✗ Error.terminate(getInstanceName() + " got unknown type.", sourceInfo());
1597 ✗ then
1598 fail();
1599
1600 end match;
1601 end matchExpressions;
1602
1603 function matchTypes
1604 input Type actualType;
1605 input Type expectedType;
1606 input output Expression expression;
1607 input MatchOptions options = DEFAULT_OPTIONS;
1608 output Type compatibleType;
1609 output MatchKind matchKind;
1610 algorithm
1611 // Return true if the references are the same.
1612
2/2
✓ Branch 0 taken 556278 times.
✓ Branch 1 taken 1492356 times.
2048634 if referenceEq(actualType, expectedType) then
1613 556278 compatibleType := actualType;
1614 556278 matchKind := MatchKind.EXACT;
1615 556278 return;
1616 end if;
1617
1618 // Check if the types are different kinds of types.
1619
2/2
✓ Branch 0 taken 148513 times.
✓ Branch 1 taken 1343843 times.
1492356 if valueConstructor(actualType) <> valueConstructor(expectedType) then
1620 // If the types are not of the same kind we might need to type cast the
1621 // expression to make it compatible.
1622 148513 (expression, compatibleType, matchKind) :=
1623 matchTypes_cast(actualType, expectedType, expression, options);
1624 148513 return;
1625 end if;
1626
1627 // The types are of the same kind, so we only need to match on one of them.
1628
10/14
✓ Branch 0 taken 283492 times.
✓ Branch 1 taken 256813 times.
✓ Branch 2 taken 485276 times.
✓ Branch 3 taken 45620 times.
✓ Branch 4 taken 40 times.
✓ Branch 5 taken 9526 times.
✓ Branch 6 taken 233171 times.
✓ Branch 7 taken 748 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 29117 times.
✓ Branch 10 taken 40 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1343843 matchKind := MatchKind.EXACT;
1629 compatibleType := match actualType
1630 case Type.INTEGER() then actualType;
1631 case Type.REAL() then actualType;
1632 case Type.STRING() then actualType;
1633 case Type.BOOLEAN() then actualType;
1634 case Type.CLOCK() then actualType;
1635
1636 case Type.ENUMERATION()
1637 algorithm
1638
2/2
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 9483 times.
9526 if Type.isUnspecifiedEnumeration(expectedType) then
1639 43 matchKind := MatchKind.EXACT;
1640 else
1641 9483 matchKind := matchEnumerationTypes(actualType, expectedType);
1642 end if;
1643 then
1644 actualType;
1645
1646 case Type.ARRAY()
1647 algorithm
1648 233171 (expression, compatibleType, matchKind) :=
1649 matchArrayTypes(actualType, expectedType, expression, options);
1650 233171 then
1651 compatibleType;
1652
1653 case Type.TUPLE()
1654 algorithm
1655 748 (expression, compatibleType, matchKind) :=
1656 matchTupleTypes(actualType, expectedType, expression, options);
1657 748 then
1658 compatibleType;
1659
1660 case Type.UNKNOWN()
1661 algorithm
1662 ✗ matchKind := if getOption(options, ALLOW_UNKNOWN) then MatchKind.EXACT else MatchKind.NOT_COMPATIBLE;
1663 then
1664 actualType;
1665
1666 case Type.COMPLEX()
1667 algorithm
1668 29117 (expression, compatibleType, matchKind) :=
1669 matchComplexTypes(actualType, expectedType, expression, options);
1670 29117 then
1671 compatibleType;
1672
1673 case Type.FUNCTION()
1674 algorithm
1675 40 (expression, compatibleType, matchKind) :=
1676 matchFunctionTypes(actualType, expectedType, expression, options);
1677 40 then
1678 compatibleType;
1679
1680 case Type.METABOXED()
1681 algorithm
1682 ✗ (expression, compatibleType, matchKind) :=
1683 matchTypes(actualType.ty, Type.unbox(expectedType), Expression.unbox(expression), options);
1684 ✗ expression := Expression.box(expression);
1685 ✗ compatibleType := Type.box(compatibleType);
1686 then
1687 compatibleType;
1688
1689 case Type.CONDITIONAL_ARRAY()
1690 algorithm
1691 ✗ (expression, compatibleType, matchKind) :=
1692 matchConditionalArrayTypes(actualType, expectedType, expression, options);
1693 ✗ then
1694 compatibleType;
1695
1696 else
1697 algorithm
1698 ✗ Error.terminate(getInstanceName() + " got unknown type.", sourceInfo());
1699 ✗ then
1700 fail();
1701
1702 end match;
1703 end matchTypes;
1704
1705 function matchExpressions_cast
1706 input output Expression exp1;
1707 input Type type1;
1708 input output Expression exp2;
1709 input Type type2;
1710 input MatchOptions options;
1711 output Type compatibleType;
1712 output MatchKind matchKind;
1713 protected
1714 Expression before = exp1;
1715 algorithm
1716 (compatibleType, matchKind) := match (type1, type2)
1717 // Integer can be cast to Real.
1718 case (Type.INTEGER(), Type.REAL())
1719 algorithm
1720 19915 exp1 := Expression.typeCast(exp1, type2);
1721 then
1722 (type2, MatchKind.CAST);
1723
1724 // Integer can be cast to Enum on certain occasions
1725 case (Type.ENUMERATION(), Type.INTEGER()) guard Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "nonStdEnumerationAsIntegers")
1726 algorithm
1727 ✗ exp1 := Expression.typeCast(exp1, type2);
1728 ✗ Error.addCompilerWarning("Allowing casting of enumeration expression: " + Expression.toString(before) + " to Integer: "+ Expression.toString(exp1) +". This is non-standard Modelica, use Integer(" + Expression.toString(before) + ") instead!");
1729 then
1730 (type2, MatchKind.CAST);
1731
1732 case (Type.INTEGER(), Type.ENUMERATION()) guard Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "nonStdIntegersAsEnumeration")
1733 algorithm
1734 ✗ exp1 := Expression.typeCast(exp1, type2);
1735 ✗ Error.addCompilerWarning("Allowing casting of Integer expression: " + Expression.toString(before) + " to enumeration: " + Expression.toString(exp1) + ". This is non-standard Modelica, use the actual enumeration instead!");
1736 then
1737 (type2, MatchKind.CAST);
1738
1739 case (Type.REAL(), Type.INTEGER())
1740 algorithm
1741 14222 exp2 := Expression.typeCast(exp2, type1);
1742 then
1743 (type1, MatchKind.CAST);
1744
1745 // Boolean can be cast to Real (only if -d=nfAPI is on)
1746 // as there are annotations having expressions such as Boolean x > 0.5
1747 case (Type.BOOLEAN(), Type.REAL()) guard Flags.isSet(Flags.NF_API)
1748 algorithm
1749 ✗ Error.addCompilerWarning("Allowing casting of Boolean expression: " + Expression.toString(exp1) + " to Real.");
1750 ✗ exp1 := Expression.typeCast(exp1, type2);
1751 then
1752 (type2, MatchKind.CAST);
1753
1754 case (Type.REAL(), Type.BOOLEAN()) guard Flags.isSet(Flags.NF_API)
1755 algorithm
1756 ✗ Error.addCompilerWarning("Allowing casting of Boolean expression: " + Expression.toString(exp2) + " to Real.");
1757 ✗ exp2 := Expression.typeCast(exp2, type1);
1758 then
1759 (type1, MatchKind.CAST);
1760
1761 // This case takes care of equations where the lhs is a non-tuple and the rhs a
1762 // function call returning a tuple, in which case only the first element of the
1763 // tuple is used. exp1 should never be a tuple here, since any tuple expression
1764 // not alone on the rhs of an equation is "tuple subscripted" by Typing.typeExp.
1765 case (Type.TUPLE(types = compatibleType :: _), _)
1766 algorithm
1767 14 exp1 := Expression.tupleElement(exp1, 1);
1768 14 (exp1, compatibleType, matchKind) :=
1769 matchTypes(compatibleType, type2, exp1, options);
1770
1771
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 if isCompatibleMatch(matchKind) then
1772 14 matchKind := MatchKind.CAST;
1773 end if;
1774 14 then
1775 (compatibleType, matchKind);
1776
1777 case (Type.UNKNOWN(), _)
1778
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 then (type2, if getOption(options, ALLOW_UNKNOWN) then MatchKind.EXACT else MatchKind.NOT_COMPATIBLE);
1779
1780 case (_, Type.UNKNOWN())
1781
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
54 then (type1, if getOption(options, ALLOW_UNKNOWN) then MatchKind.EXACT else MatchKind.NOT_COMPATIBLE);
1782
1783 case (Type.METABOXED(), _)
1784 algorithm
1785 ✗ (exp1, exp2, compatibleType, matchKind) :=
1786 matchExpressions(Expression.unbox(exp1), type1.ty, exp2, type2, options);
1787 ✗ then
1788 (compatibleType, matchKind);
1789
1790 case (_, Type.METABOXED())
1791 algorithm
1792 ✗ (exp1, exp2, compatibleType, matchKind) :=
1793 matchExpressions(exp1, type1, Expression.unbox(exp2), type2.ty, options);
1794 ✗ then
1795 (compatibleType, matchKind);
1796
1797 case (_, Type.POLYMORPHIC())
1798 algorithm
1799 ✗ exp1 := Expression.box(exp1);
1800 ✗ then
1801 (Type.box(type1), MatchKind.GENERIC);
1802
1803 case (Type.POLYMORPHIC(), _)
1804 algorithm
1805 ✗ exp2 := Expression.box(exp2);
1806 ✗ then
1807 (Type.box(type2), MatchKind.GENERIC);
1808
1809 case (Type.CONDITIONAL_ARRAY(), _)
1810 algorithm
1811 ✗ (exp1, exp2, compatibleType, matchKind) :=
1812 matchConditionalArrayExp(exp1, type1, exp2, type2, options);
1813 ✗ then
1814 (compatibleType, matchKind);
1815
1816 case (_, Type.CONDITIONAL_ARRAY())
1817 algorithm
1818 ✗ (exp2, exp1, compatibleType, matchKind) :=
1819 matchConditionalArrayExp(exp2, type2, exp1, type1, options);
1820 ✗ then
1821 (compatibleType, matchKind);
1822
1823 else (Type.UNKNOWN(), MatchKind.NOT_COMPATIBLE);
1824 end match;
1825 end matchExpressions_cast;
1826
1827 function matchComplexTypes
1828 input Type actualType;
1829 input Type expectedType;
1830 input output Expression expression;
1831 input MatchOptions options;
1832 output Type compatibleType = actualType;
1833 output MatchKind matchKind = MatchKind.NOT_COMPATIBLE;
1834 protected
1835 Class cls1, cls2;
1836 ClassTree ctree;
1837 InstNode anode, enode;
1838 array<InstNode> comps1, comps2;
1839 Type ty;
1840 ComplexType cty1, cty2;
1841 list<Expression> matched_elements = {};
1842 array<Expression> elem_arr;
1843 MatchOptions opt = options;
1844 list<Dimension> dims;
1845 algorithm
1846 41842 anode := Type.complexNode(actualType);
1847 41842 enode := Type.complexNode(expectedType);
1848
1849
2/2
✓ Branch 1 taken 35212 times.
✓ Branch 2 taken 6630 times.
41842 if InstNode.isSame(anode, enode) then
1850 35212 matchKind := MatchKind.EXACT;
1851 35212 return;
1852 end if;
1853
1854 6630 cls1 := InstNode.getClass(anode);
1855 6630 cls2 := InstNode.getClass(enode);
1856
1857
2/2
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 6489 times.
6630 if getOption(opt, IGNORE_DIMENSIONS_IN_RECORDS) then
1858 141 opt := setOption(opt, IGNORE_DIMENSIONS);
1859 end if;
1860
1861 () := match (cls1, actualType, cls2, expectedType)
1862 case (_, Type.COMPLEX(complexTy = cty1 as ComplexType.CONNECTOR()), _, Type.COMPLEX(complexTy = cty2 as ComplexType.CONNECTOR()))
1863 algorithm
1864 4831 matchKind := matchComponentList(cty1.potentials, cty2.potentials, options);
1865
2/2
✓ Branch 0 taken 4830 times.
✓ Branch 1 taken 1 time.
4831 if matchKind <> MatchKind.NOT_COMPATIBLE then
1866 4830 matchKind := matchComponentList(cty1.flows, cty2.flows, options);
1867
1/2
✓ Branch 0 taken 4830 times.
✗ Branch 1 not taken.
4830 if matchKind <> MatchKind.NOT_COMPATIBLE then
1868 4830 matchKind := matchComponentList(cty1.streams, cty2.streams, options);
1869 end if;
1870 end if;
1871
1872
2/2
✓ Branch 0 taken 4830 times.
✓ Branch 1 taken 1 time.
4831 if matchKind <> MatchKind.NOT_COMPATIBLE then
1873 4830 matchKind := MatchKind.PLUG_COMPATIBLE;
1874 end if;
1875 then
1876 ();
1877
1878 case (Class.INSTANCED_CLASS(elements = ctree as ClassTree.FLAT_TREE(components = comps1)), _, Class.INSTANCED_CLASS(elements = ClassTree.FLAT_TREE(components = comps2)), _)
1879 algorithm
1880 // Both types must contain the same number of components.
1881
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 1670 times.
1799 if arrayLength(comps1) <> arrayLength(comps2) then
1882 129 matchKind := MatchKind.NOT_COMPATIBLE;
1883 129 return;
1884 end if;
1885
1886 1670 matchKind := MatchKind.PLUG_COMPATIBLE;
1887
1888 // Create an array of record element expressions.
1889 elem_arr := match expression
1890 20 case Expression.RECORD() then listArray(expression.elements);
1891 else
1892 algorithm
1893 1650 elem_arr := arrayCreateNoInit(arrayLength(comps1), Expression.INTEGER(0));
1894 1650 dims := Type.arrayDims(Expression.typeOf(expression));
1895
1896
1/2
✓ Branch 0 taken 1650 times.
✗ Branch 1 not taken.
28832 for i in arrayLength(comps1):-1:1 loop
1897 27182 ty := Component.getType(InstNode.component(comps1[i]));
1898 27182 ty := Type.liftArrayRightList(ty, dims);
1899 27182 elem_arr[i] := Expression.RECORD_ELEMENT(expression, i, InstNode.name(comps1[i]), ty);
1900 end for;
1901 then
1902 elem_arr;
1903 end match;
1904
1905 // Match the expressions against the expected component types.
1906 1670 (matched_elements, matchKind) := matchComplexComponents(comps1, comps2, elem_arr, ctree, opt);
1907
1908 // Cast the result to the expected record type if necessary.
1909
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1665 times.
1670 if matchKind == MatchKind.CAST then
1910 5 expression := typeCastRecord(matched_elements, enode, expectedType, expression);
1911 end if;
1912 then
1913 ();
1914
1915 else
1916 algorithm
1917 ✗ matchKind := MatchKind.NOT_COMPATIBLE;
1918 then
1919 ();
1920
1921 end match;
1922 end matchComplexTypes;
1923
1924 function matchComplexComponents
1925 input array<InstNode> actualComponents;
1926 input array<InstNode> expectedComponents;
1927 input array<Expression> expressions;
1928 input ClassTree classTree;
1929 input MatchOptions options;
1930 output list<Expression> matchedExpressions = {};
1931 output MatchKind matchKind = MatchKind.PLUG_COMPATIBLE;
1932 protected
1933 InstNode anode, enode;
1934 Component acomp, ecomp;
1935 Integer idx;
1936 Expression e;
1937 MatchKind mk;
1938 algorithm
1939
2/4
✓ Branch 0 taken 1670 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1670 times.
3340 if arrayLength(actualComponents) <> arrayLength(expectedComponents) or
1940 arrayLength(actualComponents) <> arrayLength(expressions) then
1941 matchKind := MatchKind.NOT_COMPATIBLE;
1942 ✗ return;
1943 end if;
1944
1945
1/2
✓ Branch 0 taken 1670 times.
✗ Branch 1 not taken.
28933 for i in 1:arrayLength(actualComponents) loop
1946 27275 enode := expectedComponents[i];
1947 27275 ecomp := InstNode.component(enode);
1948 27275 anode := actualComponents[i];
1949
1950 // The records must have the same named components, but they don't need to
1951 // be in the same order.
1952
4/4
✓ Branch 2 taken 27256 times.
✓ Branch 3 taken 19 times.
✓ Branch 7 taken 27250 times.
✓ Branch 8 taken 6 times.
27275 if InstNode.name(anode) == InstNode.name(enode) then
1953 // If the names match we can use the index as is.
1954 27250 idx := i;
1955 else
1956 // Otherwise look the index of the component up in the actual type.
1957 try
1958 25 idx := ClassTree.lookupComponentIndex(InstNode.name(enode), classTree);
1959 else
1960 // The records do not have the same named components and are incompatible.
1961 matchKind := MatchKind.NOT_COMPATIBLE;
1962 12 return;
1963 end try;
1964
1965 13 anode := actualComponents[idx];
1966 end if;
1967
1968 // If the components aren't in the same order then we need to type cast
1969 // the record expression to the expected record type.
1970
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 27250 times.
27263 if i <> idx then
1971 matchKind := MatchKind.CAST;
1972 end if;
1973
1974 // Match the type of the component to the expected type.
1975 27263 acomp := InstNode.component(anode);
1976 27263 e := expressions[idx];
1977 27263 (e, _, mk) := matchTypes(Component.getType(acomp), Component.getType(ecomp), e, options);
1978 27263 matchedExpressions := e :: matchedExpressions;
1979
1980
2/2
✓ Branch 0 taken 27261 times.
✓ Branch 1 taken 2 times.
27263 if mk == MatchKind.CAST then
1981 matchKind := mk;
1982 elseif not isValidPlugCompatibleMatch(mk) then
1983 matchKind := MatchKind.NOT_COMPATIBLE;
1984 break;
1985 end if;
1986 end for;
1987
1988 1658 matchedExpressions := listReverseInPlace(matchedExpressions);
1989 end matchComplexComponents;
1990
1991 function typeCastRecord
1992 input list<Expression> expressions;
1993 input InstNode node;
1994 input Type expectedType;
1995 input output Expression expression;
1996 protected
1997 Type ty;
1998 list<Dimension> dims;
1999 list<Expression> ranges;
2000 InstNode iter;
2001 list<InstNode> iters;
2002 Subscript sub;
2003 list<Subscript> subs;
2004 Integer i;
2005 algorithm
2006 5 ty := Expression.typeOf(expression);
2007
2008
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
5 if Type.isArray(ty) then
2009 3 dims := Type.arrayDims(ty);
2010 ranges := {};
2011 iters := {};
2012 subs := {};
2013 i := 1;
2014
2015
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 for d in listReverse(dims) loop
2016
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if Dimension.isUnknown(d) then
2017 ✗ ranges := Expression.RANGE(Type.INTEGER(), Expression.INTEGER(1),
2018 NONE(), Expression.SIZE(expression, SOME(Expression.INTEGER(i)))) :: ranges;
2019 else
2020 3 ranges := Dimension.toRange(d) :: ranges;
2021 end if;
2022
2023 3 iter := InstNode.newUniqueIterator(InstNode.info(node));
2024 iters := iter :: iters;
2025 3 sub := Subscript.INDEX(Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER())));
2026 subs := sub :: subs;
2027 3 i := i + 1;
2028 end for;
2029
2030
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3 times.
8 expression := Expression.RECORD(InstNode.scopePath(node), expectedType,
2031 list(Expression.applySubscripts(subs, e) for e in expressions));
2032
7/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
6 expression := Expression.CALL(Call.TYPED_ARRAY_CONSTRUCTOR(ty,
2033 Expression.variability(expression), Expression.purity(expression), expression,
2034 list((i, r) threaded for i in iters, r in ranges)));
2035 else
2036 2 expression := Expression.RECORD(InstNode.scopePath(node), expectedType, expressions);
2037 end if;
2038 end typeCastRecord;
2039
2040 function matchComponentList
2041 input list<NFInstNode.ScopeRef> comps1;
2042 input list<NFInstNode.ScopeRef> comps2;
2043 input MatchOptions options;
2044 output MatchKind matchKind;
2045 protected
2046 InstNode c1, c2;
2047 NFInstNode.ScopeRef c2_ref;
2048 list<NFInstNode.ScopeRef> rest_c2 = comps2;
2049 Expression dummy = Expression.INTEGER(0);
2050 algorithm
2051
2/2
✓ Branch 2 taken 14490 times.
✓ Branch 3 taken 1 time.
14491 if listLength(comps1) <> listLength(comps2) then
2052 matchKind := MatchKind.NOT_COMPATIBLE;
2053 else
2054
2/2
✓ Branch 0 taken 13274 times.
✓ Branch 1 taken 14489 times.
27763 for c1_ref in comps1 loop
2055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13274 times.
13274 c2_ref :: rest_c2 := rest_c2;
2056 13274 c1 := InstNode.borrow(c1_ref);
2057 13274 c2 := InstNode.borrow(c2_ref);
2058
2059
3/4
✓ Branch 2 taken 13273 times.
✓ Branch 3 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 13273 times.
13274 if InstNode.name(c1) <> InstNode.name(c2) then
2060 1 matchKind := MatchKind.NOT_COMPATIBLE;
2061 1 return;
2062 end if;
2063
2064 13273 (_, _, matchKind) := matchTypes(InstNode.getType(c1), InstNode.getType(c2), dummy, options);
2065
2066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13273 times.
13273 if matchKind == MatchKind.NOT_COMPATIBLE then
2067 ✗ return;
2068 end if;
2069 end for;
2070 end if;
2071
2072 14490 matchKind := MatchKind.PLUG_COMPATIBLE;
2073 end matchComponentList;
2074
2075 function matchFunctionTypes
2076 input Type actualType;
2077 input Type expectedType;
2078 input output Expression expression;
2079 input MatchOptions options;
2080 output Type compatibleType = actualType;
2081 output MatchKind matchKind = MatchKind.EXACT;
2082 protected
2083 list<InstNode> inputs1, inputs2;
2084 list<NFInstNode.NodeHandle> outputs1, outputs2;
2085 list<Slot> slots1, slots2;
2086 Slot slot1, slot2;
2087 algorithm
2088
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
40 Type.FUNCTION(fn =
2089 Function.FUNCTION(inputs = inputs1, outputs = outputs1, slots = slots1)) := actualType;
2090
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
40 Type.FUNCTION(fn =
2091 Function.FUNCTION(inputs = inputs2, outputs = outputs2, slots = slots2)) := expectedType;
2092
2093 // The functions must have the same number of outputs.
2094
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
40 if listLength(outputs1) <> listLength(outputs2) then
2095 matchKind := MatchKind.NOT_COMPATIBLE;
2096 ✗ return;
2097 end if;
2098
2099
10/10
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 40 times.
✓ Branch 5 taken 40 times.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 40 times.
✓ Branch 8 taken 40 times.
✓ Branch 11 taken 1 time.
✓ Branch 12 taken 39 times.
120 if not matchFunctionParameters(list(InstNode.fromHandle(o) for o in outputs1),
2100 list(InstNode.fromHandle(o) for o in outputs2), options) then
2101 matchKind := MatchKind.NOT_COMPATIBLE;
2102 1 return;
2103 end if;
2104
2105
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 if not matchFunctionParameters(inputs1, inputs2, options) then
2106 matchKind := MatchKind.NOT_COMPATIBLE;
2107 ✗ return;
2108 end if;
2109
2110 // An input in the actual type must have a default argument if the
2111 // corresponding input in the expected type has one.
2112
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 39 times.
78 for i in inputs2 loop
2113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 slot1 :: slots1 := slots1;
2114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 slot2 :: slots2 := slots2;
2115
2116
2/8
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
39 if isSome(slot2.default) and isNone(slot1.default) then
2117 matchKind := MatchKind.NOT_COMPATIBLE;
2118 ✗ return;
2119 end if;
2120 end for;
2121
2122 // The actual type can have more inputs than expected if the extra inputs have
2123 // default arguments.
2124
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 39 times.
40 for slot in slots1 loop
2125
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 if isNone(slot.default) then
2126 matchKind := MatchKind.NOT_COMPATIBLE;
2127 ✗ return;
2128 end if;
2129 end for;
2130 end matchFunctionTypes;
2131
2132 function matchFunctionParameters
2133 input list<InstNode> params1;
2134 input list<InstNode> params2;
2135 input MatchOptions options;
2136 output Boolean matching = true;
2137 protected
2138 list<InstNode> pl1 = params1, pl2 = params2;
2139 InstNode p1;
2140 Expression dummy = Expression.INTEGER(0);
2141 MatchKind mk;
2142 algorithm
2143
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 78 times.
157 for p2 in pl2 loop
2144
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if listEmpty(pl1) then
2145 matching := false;
2146 break;
2147 end if;
2148
2149 79 p1 :: pl1 := pl1;
2150
2151
2/4
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 7 taken 79 times.
✗ Branch 8 not taken.
79 if InstNode.name(p1) <> InstNode.name(p2) then
2152 matching := false;
2153 break;
2154 end if;
2155
2156 79 (_, _, mk) := matchTypes(Type.unbox(InstNode.getType(p1)),
2157 Type.unbox(InstNode.getType(p2)), dummy, options);
2158
2159
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1 time.
79 if mk <> MatchKind.EXACT then
2160 matching := false;
2161 break;
2162 end if;
2163 end for;
2164 end matchFunctionParameters;
2165
2166 function matchEnumerationTypes
2167 input Type type1;
2168 input Type type2;
2169 output MatchKind matchKind;
2170 protected
2171 list<String> lits1, lits2;
2172 algorithm
2173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9483 times.
9483 Type.ENUMERATION(literals = lits1) := type1;
2174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9483 times.
9483 Type.ENUMERATION(literals = lits2) := type2;
2175
2176
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9483 times.
9483 matchKind := if List.isEqualOnTrue(lits1, lits2, stringEqual)
2177 then MatchKind.EXACT else MatchKind.NOT_COMPATIBLE;
2178 end matchEnumerationTypes;
2179
2180 function matchArrayExpressions
2181 input output Expression exp1;
2182 input Type type1;
2183 input output Expression exp2;
2184 input Type type2;
2185 input MatchOptions options;
2186 output Type compatibleType;
2187 output MatchKind matchKind;
2188 protected
2189 Type ety1, ety2;
2190 list<Dimension> dims1, dims2;
2191 algorithm
2192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41821 times.
41821 Type.ARRAY(elementType = ety1, dimensions = dims1) := type1;
2193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41821 times.
41821 Type.ARRAY(elementType = ety2, dimensions = dims2) := type2;
2194
2195 // Check that the element types are compatible.
2196 41821 (exp1, exp2, compatibleType, matchKind) :=
2197 matchExpressions(exp1, ety1, exp2, ety2, options);
2198
2199 // If the element types are compatible, check the dimensions too.
2200 41821 (compatibleType, matchKind) := matchArrayDims(dims1, dims2, compatibleType, matchKind, options);
2201
2202
2/2
✓ Branch 1 taken 865 times.
✓ Branch 2 taken 40956 times.
41821 if isCompatibleMatch(matchKind) then
2203 40956 exp1 := setRangeSize(exp1, compatibleType);
2204 40956 exp2 := setRangeSize(exp2, compatibleType);
2205 end if;
2206 end matchArrayExpressions;
2207
2208 function matchArrayTypes
2209 input Type arrayType1;
2210 input Type arrayType2;
2211 input output Expression expression;
2212 input MatchOptions options;
2213 output Type compatibleType;
2214 output MatchKind matchKind;
2215 protected
2216 Type ety1, ety2;
2217 list<Dimension> dims1, dims2;
2218 algorithm
2219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 233232 times.
233232 Type.ARRAY(elementType = ety1, dimensions = dims1) := arrayType1;
2220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 233232 times.
233232 Type.ARRAY(elementType = ety2, dimensions = dims2) := arrayType2;
2221
2222 // Check that the element types are compatible.
2223 233232 (expression, compatibleType, matchKind) :=
2224 matchTypes(ety1, ety2, expression, options);
2225
2226 // If the element types are compatible, check the dimensions too.
2227 233232 (compatibleType, matchKind) := matchArrayDims(dims1, dims2, compatibleType, matchKind, options);
2228
2229
2/2
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 233141 times.
233232 if isCompatibleMatch(matchKind) then
2230 233141 expression := setRangeSize(expression, compatibleType);
2231 end if;
2232 end matchArrayTypes;
2233
2234 function keepRangeSize
2235 "Recomputing a range's type from its bounds cannot find a size that
2236 setRangeSize gave it, so keep the old one rather than fall back to the
2237 symbolic size."
2238 input output Type ty;
2239 input Type oldTy;
2240 algorithm
2241
4/6
✗ Branch 1 not taken.
✓ Branch 2 taken 14438 times.
✓ Branch 4 taken 6480 times.
✓ Branch 5 taken 7958 times.
✓ Branch 7 taken 7958 times.
✗ Branch 8 not taken.
14438 if Type.isArray(oldTy) and Type.hasKnownSize(oldTy) and not Type.hasKnownSize(ty) then
2242 ✗ ty := Type.setArrayElementType(oldTy, Type.arrayElementType(ty));
2243 end if;
2244 end keepRangeSize;
2245
2246 function setRangeSize
2247 "A range whose bounds are not literals, like x:dx:x+4*dx, is sized by an
2248 expression that cannot be evaluated. Giving it the size it was matched
2249 against lets it be expanded when the equation is scalarized."
2250 input output Expression exp;
2251 input Type ty;
2252 algorithm
2253 exp := match exp
2254 case Expression.RANGE()
2255 guard Type.hasKnownSize(ty) and not Type.hasKnownSize(exp.ty)
2256 algorithm
2257 2 exp.ty := Type.setArrayElementType(ty, Type.arrayElementType(exp.ty));
2258 then
2259 exp;
2260
2261 else exp;
2262 end match;
2263 end setRangeSize;
2264
2265 function matchArrayDims
2266 input list<Dimension> dims1;
2267 input list<Dimension> dims2;
2268 input output Type ty;
2269 input output MatchKind matchKind;
2270 input MatchOptions options;
2271 protected
2272 list<Dimension> rest_dims2 = dims2, cdims = {};
2273 Dimension dim2;
2274 Boolean compat;
2275 MatchKind match_kind;
2276 algorithm
2277
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 276778 times.
276782 if not isCompatibleMatch(matchKind) then
2278 4 return;
2279 end if;
2280
2281 // The array types must have the same number of dimensions.
2282
2/2
✓ Branch 2 taken 276775 times.
✓ Branch 3 taken 3 times.
276778 if listLength(dims1) <> listLength(dims2) then
2283 matchKind := MatchKind.NOT_COMPATIBLE;
2284 3 return;
2285 end if;
2286
2287 // The dimensions of both array types must be compatible.
2288
2/2
✓ Branch 0 taken 367367 times.
✓ Branch 1 taken 275749 times.
643116 for dim1 in dims1 loop
2289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 367367 times.
367367 dim2 :: rest_dims2 := rest_dims2;
2290 367367 (dim1, compat) := matchDimensions(dim1, dim2);
2291
2292
3/4
✓ Branch 0 taken 1026 times.
✓ Branch 1 taken 366341 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1026 times.
367367 if not compat and not getOption(options, IGNORE_DIMENSIONS) then
2293 matchKind := MatchKind.NOT_COMPATIBLE;
2294 break;
2295 end if;
2296
2297 cdims := dim1 :: cdims;
2298 end for;
2299
2300 276775 ty := Type.ARRAY(ty, listReverseInPlace(cdims));
2301 end matchArrayDims;
2302
2303 function matchDimensions
2304 input Dimension dim1;
2305 input Dimension dim2;
2306 output Dimension compatibleDim;
2307 output Boolean compatible = true;
2308 algorithm
2309
2/2
✓ Branch 1 taken 35656 times.
✓ Branch 2 taken 331711 times.
367367 if Dimension.isEqualKnown(dim1, dim2) then
2310 compatibleDim := dim1;
2311 else
2312
2/2
✓ Branch 1 taken 32073 times.
✓ Branch 2 taken 3583 times.
35656 if not Dimension.isKnown(dim1) then
2313 compatibleDim := dim2;
2314 elseif not Dimension.isKnown(dim2) then
2315 compatibleDim := dim1;
2316 elseif Dimension.isResizable(dim1) and Dimension.isResizable(dim2) then
2317 compatibleDim := dim1;
2318 else
2319 compatibleDim := dim1;
2320 compatible := false;
2321 end if;
2322 end if;
2323 end matchDimensions;
2324
2325 function matchTupleTypes
2326 input Type tupleType1;
2327 input Type tupleType2;
2328 input output Expression expression;
2329 input MatchOptions options;
2330 output Type compatibleType = tupleType1;
2331 output MatchKind matchKind = MatchKind.EXACT;
2332 protected
2333 list<Type> tyl1, tyl2;
2334 Type ty1;
2335 algorithm
2336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 951 times.
951 Type.TUPLE(types = tyl1) := tupleType1;
2337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 951 times.
951 Type.TUPLE(types = tyl2) := tupleType2;
2338
2339
1/2
✓ Branch 2 taken 951 times.
✗ Branch 3 not taken.
951 if listLength(tyl1) < listLength(tyl2) then
2340 ✗ matchKind := MatchKind.NOT_COMPATIBLE;
2341 ✗ return;
2342 end if;
2343
2344
2/2
✓ Branch 0 taken 2096 times.
✓ Branch 1 taken 916 times.
3012 for ty2 in tyl2 loop
2345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2096 times.
2096 ty1 :: tyl1 := tyl1;
2346
2347 // Skip matching if the rhs is _.
2348
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2092 times.
2096 if Type.isUnknown(ty2) then
2349 4 continue;
2350 end if;
2351
2352 2092 (_, _, matchKind) := matchTypes(ty1, ty2, expression, options);
2353
2354
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2057 times.
2092 if matchKind <> MatchKind.EXACT then
2355 break;
2356 end if;
2357 end for;
2358 end matchTupleTypes;
2359
2360 function matchBoxedExpressions
2361 input output Expression exp1;
2362 input Type type1;
2363 input output Expression exp2;
2364 input Type type2;
2365 input MatchOptions options;
2366 output Type compatibleType;
2367 output MatchKind matchKind;
2368 protected
2369 Expression e1, e2;
2370 algorithm
2371 ✗ e1 := Expression.unbox(exp1);
2372 ✗ e2 := Expression.unbox(exp2);
2373
2374 ✗ (e1, e2, compatibleType, matchKind) :=
2375 matchExpressions(e1, Type.unbox(type1), e2, Type.unbox(type2), options);
2376
2377 ✗ if isCastMatch(matchKind) then
2378 ✗ exp1 := Expression.box(e1);
2379 ✗ exp2 := Expression.box(e2);
2380 end if;
2381
2382 ✗ compatibleType := Type.box(compatibleType);
2383 end matchBoxedExpressions;
2384
2385 function matchConditionalArrayExp
2386 input output Expression condExp;
2387 input Type condType;
2388 input output Expression otherExp;
2389 input Type otherType;
2390 input MatchOptions options;
2391 output Type compatibleType;
2392 output MatchKind matchKind;
2393 protected
2394 Type true_ty, false_ty, cond_ty, comp_ty1, comp_ty2;
2395 Expression e1_1, e2_1, e1_2, e2_2;
2396 NFType.Branch branch;
2397 MatchKind mk1, mk2;
2398 Boolean compat1, compat2;
2399 algorithm
2400 ✗ Type.CONDITIONAL_ARRAY(trueType = true_ty, falseType = false_ty, matchedBranch = branch) := condType;
2401
2402 ✗ if branch == NFType.Branch.NONE then
2403 // If no branch has already been selected as the correct branch, check both of them.
2404 ✗ (e1_1, e2_1, comp_ty1, mk1) :=
2405 matchExpressions(condExp, true_ty, otherExp, otherType, options);
2406
2407 ✗ (e1_2, e2_2, comp_ty2, mk2) :=
2408 matchExpressions(condExp, false_ty, otherExp, otherType, options);
2409
2410 ✗ compat1 := isCompatibleMatch(mk1);
2411 ✗ compat2 := isCompatibleMatch(mk2);
2412
2413 (compatibleType, otherExp, matchKind) := match (isCompatibleMatch(mk1), isCompatibleMatch(mk2))
2414 // Both branches matched, one of them is probably itself of a conditional
2415 // array type since the types should otherwise have different dimensions.
2416 case (true, true)
2417 algorithm
2418 ✗ cond_ty := Type.CONDITIONAL_ARRAY(comp_ty1, comp_ty2, NFType.Branch.NONE);
2419 ✗ condExp := Expression.typeCast(condExp, cond_ty);
2420 ✗ then
2421 (comp_ty1, otherExp, mk1);
2422
2423 // Only the first branch matches, mark it as the correct branch.
2424 case (true, _)
2425 algorithm
2426 ✗ cond_ty := Type.CONDITIONAL_ARRAY(comp_ty1, comp_ty2, NFType.Branch.TRUE);
2427 ✗ condExp := Expression.typeCast(e1_1, cond_ty);
2428 ✗ then
2429 (comp_ty1, e2_1, mk1);
2430
2431 // Only the second branch matches, mark it as the correct branch.
2432 case (_, true)
2433 algorithm
2434 ✗ comp_ty1 := Type.setArrayElementType(comp_ty1, Type.arrayElementType(comp_ty2));
2435 ✗ cond_ty := Type.CONDITIONAL_ARRAY(comp_ty1, comp_ty2, NFType.Branch.FALSE);
2436 ✗ condExp := Expression.typeCast(e1_2, cond_ty);
2437 ✗ then
2438 (comp_ty2, e2_2, mk2);
2439
2440 ✗ else (condType, condExp, mk1);
2441 end match;
2442 else
2443 ✗ if branch == NFType.Branch.TRUE then
2444 ✗ (condExp, otherExp, compatibleType, matchKind) :=
2445 matchExpressions(condExp, true_ty, otherExp, otherType, options);
2446 ✗ cond_ty := Type.CONDITIONAL_ARRAY(compatibleType, false_ty, branch);
2447 else
2448 ✗ (condExp, otherExp, compatibleType, matchKind) :=
2449 matchExpressions(condExp, false_ty, otherExp, otherType, options);
2450 ✗ true_ty := Type.setArrayElementType(true_ty, Type.arrayElementType(compatibleType));
2451 ✗ cond_ty := Type.CONDITIONAL_ARRAY(true_ty, compatibleType, branch);
2452 end if;
2453
2454 ✗ if isCompatibleMatch(matchKind) then
2455 ✗ condExp := Expression.typeCast(condExp, cond_ty);
2456 end if;
2457 end if;
2458 end matchConditionalArrayExp;
2459
2460 function matchConditionalArrayTypes
2461 input Type actualType;
2462 input Type expectedType;
2463 input output Expression exp;
2464 input MatchOptions options;
2465 output Type compatibleType;
2466 output MatchKind matchKind;
2467 protected
2468 Type actual_true_ty, actual_false_ty;
2469 Type expected_true_ty, expected_false_ty;
2470 Type true_ty, false_ty;
2471 Expression true_exp, false_exp;
2472 algorithm
2473 ✗ Type.CONDITIONAL_ARRAY(trueType = actual_true_ty, falseType = actual_false_ty) := actualType;
2474 ✗ Type.CONDITIONAL_ARRAY(trueType = expected_true_ty, falseType = expected_false_ty) := expectedType;
2475
2476 () := match exp
2477 case Expression.IF()
2478 algorithm
2479 ✗ (true_exp, true_ty, matchKind) :=
2480 matchTypes(actual_true_ty, expected_true_ty, exp.trueBranch, options);
2481
2482 ✗ if not isCompatibleMatch(matchKind) then
2483 compatibleType := actualType;
2484 ✗ return;
2485 end if;
2486
2487 ✗ (false_exp, false_ty, matchKind) :=
2488 matchTypes(actual_false_ty, expected_false_ty, exp.falseBranch, options);
2489
2490 ✗ if not isCompatibleMatch(matchKind) then
2491 compatibleType := actualType;
2492 ✗ return;
2493 end if;
2494
2495 ✗ compatibleType := Type.CONDITIONAL_ARRAY(true_ty, false_ty, NFType.Branch.NONE);
2496 ✗ exp := Expression.IF(compatibleType, exp.condition, true_exp, false_exp);
2497 then
2498 ();
2499 end match;
2500 end matchConditionalArrayTypes;
2501
2502 function matchConditionalArrayTypes_cast
2503 input Type condType;
2504 input Type expectedType;
2505 input output Expression exp;
2506 input MatchOptions options;
2507 output Type compatibleType;
2508 output MatchKind matchKind;
2509 protected
2510 Type true_ty, false_ty, cond_ty, comp_ty1, comp_ty2;
2511 Expression e1, e2;
2512 NFType.Branch branch;
2513 MatchKind mk1, mk2;
2514 algorithm
2515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 Type.CONDITIONAL_ARRAY(trueType = true_ty, falseType = false_ty, matchedBranch = branch) := condType;
2516
2517
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
51 if branch == NFType.Branch.NONE then
2518 // If no branch has already been selected as the correct branch, check both of them.
2519 51 (e1, comp_ty1, mk1) := matchTypes(true_ty, expectedType, exp, options);
2520 51 (e2, comp_ty2, mk2) := matchTypes(false_ty, expectedType, exp, options);
2521
2522 (compatibleType, matchKind) := match (isCompatibleMatch(mk1), isCompatibleMatch(mk2))
2523 // Both branches matched, one of them is probably itself of a conditional
2524 // array type since the types should otherwise have different dimensions.
2525 case (true, true)
2526 algorithm
2527 1 cond_ty := Type.CONDITIONAL_ARRAY(comp_ty1, comp_ty2, NFType.Branch.NONE);
2528 1 exp := Expression.typeCast(exp, cond_ty);
2529 1 then
2530 (comp_ty1, mk1);
2531
2532 // Only the first branch matches, mark it as the correct branch.
2533 case (true, _)
2534 algorithm
2535 47 cond_ty := Type.CONDITIONAL_ARRAY(comp_ty1, false_ty, NFType.Branch.TRUE);
2536 47 exp := Expression.typeCast(e1, cond_ty);
2537 47 then
2538 (comp_ty1, mk1);
2539
2540 // Only the second branch matches, mark it as the correct branch. The cast
2541 // takes the element type from the true branch, so it gets the matched one.
2542 case (_, true)
2543 algorithm
2544 3 true_ty := Type.setArrayElementType(true_ty, Type.arrayElementType(comp_ty2));
2545 3 cond_ty := Type.CONDITIONAL_ARRAY(true_ty, comp_ty2, NFType.Branch.FALSE);
2546 3 exp := Expression.typeCast(e2, cond_ty);
2547 3 then
2548 (comp_ty2, mk2);
2549
2550 ✗ else (condType, mk1);
2551 end match;
2552 else
2553 ✗ if branch == NFType.Branch.TRUE then
2554 ✗ (exp, compatibleType, matchKind) := matchTypes(true_ty, expectedType, exp, options);
2555 ✗ cond_ty := Type.CONDITIONAL_ARRAY(compatibleType, false_ty, branch);
2556 else
2557 ✗ (exp, compatibleType, matchKind) := matchTypes(false_ty, expectedType, exp, options);
2558 ✗ true_ty := Type.setArrayElementType(true_ty, Type.arrayElementType(compatibleType));
2559 ✗ cond_ty := Type.CONDITIONAL_ARRAY(true_ty, compatibleType, branch);
2560 end if;
2561
2562 ✗ if isCompatibleMatch(matchKind) then
2563 ✗ exp := Expression.typeCast(exp, cond_ty);
2564 end if;
2565 end if;
2566 end matchConditionalArrayTypes_cast;
2567
2568 function matchTypes_cast
2569 input Type actualType;
2570 input Type expectedType;
2571 input output Expression expression;
2572 input MatchOptions options = DEFAULT_OPTIONS;
2573 output Type compatibleType;
2574 output MatchKind matchKind;
2575 protected
2576 Expression before = expression;
2577 algorithm
2578 (compatibleType, matchKind) := match(actualType, expectedType)
2579 // Integer can be cast to Real.
2580 case (Type.INTEGER(), Type.REAL())
2581 algorithm
2582 119648 expression := Expression.typeCast(expression, expectedType);
2583 then
2584 (expectedType, MatchKind.CAST);
2585
2586 // Allow using enumeration as Integer without the explicit cast
2587 case (Type.ENUMERATION(), Type.INTEGER()) guard Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "nonStdEnumerationAsIntegers")
2588 algorithm
2589 ✗ expression := Expression.typeCast(expression, expectedType);
2590 ✗ Error.addCompilerWarning("Allowing usage of enumeration expression: " + Expression.toString(before) + " as Integer: "+ Expression.toString(expression) +". This is non-standard Modelica, use Integer(" + Expression.toString(before) + ") instead!");
2591 then
2592 (expectedType, MatchKind.CAST);
2593
2594 // Allow using enumeration as Integer without the explicit cast
2595 case (Type.INTEGER(), Type.ENUMERATION()) guard Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "nonStdIntegersAsEnumeration")
2596 algorithm
2597 ✗ expression := Expression.typeCast(expression, expectedType);
2598 ✗ Error.addCompilerWarning("Allowing usage of Integer expression: " + Expression.toString(before) + " as enumeration: " + Expression.toString(expression) + ". This is non-standard Modelica, use the actual enumeration instead!");
2599 then
2600 (expectedType, MatchKind.CAST);
2601
2602 // If the actual type is a tuple but the expected type isn't,
2603 // try to use the first type in the tuple.
2604 case (Type.TUPLE(types = _ :: _), _)
2605 algorithm
2606 101 (expression, compatibleType, matchKind) :=
2607 matchTypes(listHead(actualType.types), expectedType, expression, options);
2608
2609
1/2
✓ Branch 1 taken 101 times.
✗ Branch 2 not taken.
101 if isCompatibleMatch(matchKind) then
2610 expression := match expression
2611 ✗ case Expression.TUPLE() then listHead(expression.elements);
2612 101 else Expression.TUPLE_ELEMENT(expression, 1,
2613 Type.setArrayElementType(Expression.typeOf(expression), compatibleType));
2614 end match;
2615
2616 101 matchKind := MatchKind.CAST;
2617 end if;
2618 101 then
2619 (compatibleType, matchKind);
2620
2621 // Allow unknown types in some cases, e.g. () has type METALIST(UNKNOWN)
2622 case (Type.UNKNOWN(), _)
2623 ✗ then (expectedType,
2624 if getOption(options, ALLOW_UNKNOWN) then MatchKind.UNKNOWN_ACTUAL else MatchKind.NOT_COMPATIBLE);
2625
2626 case (_, Type.UNKNOWN())
2627
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2603 times.
2603 then (actualType,
2628 if getOption(options, ALLOW_UNKNOWN) then MatchKind.UNKNOWN_EXPECTED else MatchKind.NOT_COMPATIBLE);
2629
2630 case (Type.METABOXED(), _)
2631 algorithm
2632 ✗ expression := Expression.unbox(expression);
2633 ✗ (expression, compatibleType, matchKind) :=
2634 matchTypes(actualType.ty, expectedType, expression, options);
2635 ✗ then
2636 (compatibleType, if isCompatibleMatch(matchKind) then MatchKind.CAST else matchKind);
2637
2638 case (_, Type.METABOXED())
2639 algorithm
2640 69 (expression, compatibleType, matchKind) :=
2641 matchTypes(actualType, expectedType.ty, expression, options);
2642 69 expression := Expression.box(expression);
2643 69 compatibleType := Type.box(compatibleType);
2644
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
69 then
2645 (compatibleType, if isCompatibleMatch(matchKind) then MatchKind.CAST else matchKind);
2646
2647 case (_, Type.POLYMORPHIC())
2648 algorithm
2649 4294 (expression, compatibleType, matchKind) :=
2650 matchPolymorphic(expectedType.name, actualType, expression);
2651 4294 then
2652 (compatibleType, matchKind);
2653
2654 case (Type.POLYMORPHIC(), _)
2655 algorithm
2656 // expression := Expression.unbox(expression);
2657 // matchKind := MatchKind.GENERIC(expectedType.b,actualType);
2658 then
2659 (expectedType, MatchKind.GENERIC);
2660
2661 // Expected type is any, any actual type matches.
2662 case (_, Type.ANY()) then (expectedType, MatchKind.EXACT);
2663
2664 case (Type.CONDITIONAL_ARRAY(), _)
2665 algorithm
2666 51 (expression, compatibleType, matchKind) :=
2667 matchConditionalArrayTypes_cast(actualType, expectedType, expression, options);
2668 51 then
2669 (compatibleType, matchKind);
2670
2671 // Anything else is not compatible.
2672 else (Type.UNKNOWN(), MatchKind.NOT_COMPATIBLE);
2673 end match;
2674 end matchTypes_cast;
2675
2676 function matchPolymorphic
2677 input String polymorphicName;
2678 input Type actualType;
2679 input output Expression exp;
2680 output Type compatibleType;
2681 output MatchKind matchKind;
2682 algorithm
2683 (compatibleType, matchKind) := match polymorphicName
2684 // Any type, used when we don't want the expression to be boxed.
2685 case "__Any" then (actualType, MatchKind.GENERIC);
2686
2687 // Any scalar type.
2688 case "__Scalar"
2689 algorithm
2690
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 109 times.
109 matchKind := if Type.isScalar(actualType) then MatchKind.GENERIC else MatchKind.NOT_COMPATIBLE;
2691 then
2692 (actualType, matchKind);
2693
2694 // Any array type.
2695 case "__Array"
2696 algorithm
2697
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1700 times.
1700 matchKind := if Type.isArray(actualType) then MatchKind.GENERIC else MatchKind.NOT_COMPATIBLE;
2698 then
2699 (actualType, matchKind);
2700
2701 case "__Connector"
2702 algorithm
2703
2/4
✓ Branch 1 taken 2354 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2354 times.
2354 matchKind := if Type.isScalar(actualType) and Expression.isConnector(exp) then
2704 MatchKind.GENERIC else MatchKind.NOT_COMPATIBLE;
2705 then
2706 (actualType, matchKind);
2707
2708 case "__ComponentExpression"
2709 algorithm
2710
3/4
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
48 matchKind := if Type.isScalar(actualType) and Expression.isComponentExpression(exp) then
2711 MatchKind.GENERIC else MatchKind.NOT_COMPATIBLE;
2712 then
2713 (actualType, matchKind);
2714
2715 case "__Block"
2716 algorithm
2717
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 matchKind := if Type.isComplex(actualType) then MatchKind.GENERIC else MatchKind.NOT_COMPATIBLE;
2718 then
2719 (actualType, matchKind);
2720
2721 else
2722 algorithm
2723 12 exp := Expression.box(exp);
2724 12 then
2725 (Type.METABOXED(actualType), MatchKind.GENERIC);
2726
2727 end match;
2728 end matchPolymorphic;
2729
2730 function getRangeType
2731 input Expression startExp;
2732 input Option<Expression> stepExp;
2733 input Expression stopExp;
2734 input Type rangeElemType;
2735 input SourceInfo info;
2736 output Type rangeType;
2737 protected
2738 Dimension dim;
2739 algorithm
2740 dim := match rangeElemType
2741 28485 case Type.INTEGER() then getRangeTypeInt(startExp, stepExp, stopExp, info);
2742 150 case Type.REAL() then getRangeTypeReal(startExp, stepExp, stopExp, info);
2743
2744 case Type.BOOLEAN()
2745 algorithm
2746
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if isSome(stepExp) then
2747 ✗ Error.addSourceMessageAndFail(Error.RANGE_INVALID_STEP,
2748 {Type.toString(rangeElemType)}, info);
2749 end if;
2750 4 then
2751 getRangeTypeBool(startExp, stopExp);
2752
2753 case Type.ENUMERATION()
2754 algorithm
2755
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
123 if isSome(stepExp) then
2756 ✗ Error.addSourceMessageAndFail(Error.RANGE_INVALID_STEP,
2757 {Type.toString(rangeElemType)}, info);
2758 end if;
2759 123 then
2760 getRangeTypeEnum(startExp, stopExp);
2761
2762 else
2763 algorithm
2764 ✗ Error.addSourceMessage(Error.RANGE_INVALID_TYPE,
2765 {Type.toString(rangeElemType)}, info);
2766 ✗ then
2767 fail();
2768 end match;
2769
2770 28760 rangeType := Type.ARRAY(rangeElemType, {dim});
2771 end getRangeType;
2772
2773 function getRangeTypeInt
2774 input Expression startExp;
2775 input Option<Expression> stepExp;
2776 input Expression stopExp;
2777 input SourceInfo info;
2778 output Dimension dim;
2779 algorithm
2780 dim := match (startExp, stepExp, stopExp)
2781 local
2782 Integer step;
2783 Expression step_exp, dim_exp;
2784 Variability var;
2785 Purity pur;
2786
2787 case (Expression.INTEGER(), NONE(), Expression.INTEGER())
2788 19376 then Dimension.fromInteger(max(stopExp.value - startExp.value + 1, 0));
2789
2790 case (Expression.INTEGER(), SOME(Expression.INTEGER(value = step)), Expression.INTEGER())
2791 algorithm
2792 // Don't allow infinite ranges.
2793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 if step == 0 then
2794 ✗ Error.addSourceMessageAndFail(Error.RANGE_TOO_SMALL_STEP, {String(step)}, info);
2795 end if;
2796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89 times.
89 then
2797 Dimension.fromInteger(max(intDiv(stopExp.value - startExp.value, step) + 1, 0));
2798
2799 // Ranges like 1:n have size n.
2800 case (Expression.INTEGER(1), NONE(), _)
2801 algorithm
2802 6879 dim_exp := SimplifyExp.simplify(stopExp);
2803 6879 then
2804 Dimension.fromExp(dim_exp, Expression.variability(dim_exp));
2805
2806 // Ranges like n:n have size 1.
2807 case (_, NONE(), _)
2808 guard Expression.isEqual(startExp, stopExp)
2809 1 then Dimension.fromInteger(1);
2810
2811 // For other ranges, create the appropriate expression as dimension.
2812 // max(stop - start + 1, 0) or max(((stop - start) / step) + 1, 0)
2813 else
2814 algorithm
2815 2140 dim_exp := Expression.BINARY(stopExp, Operator.makeSub(Type.INTEGER()), startExp);
2816 2140 var := Prefixes.variabilityMax(Expression.variability(stopExp),
2817 Expression.variability(startExp));
2818 2140 pur := Prefixes.purityMin(Expression.purity(stopExp),
2819 Expression.purity(startExp));
2820
2821
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2140 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2124 times.
2140 if isSome(stepExp) then
2822 16 SOME(step_exp) := stepExp;
2823 16 var := Prefixes.variabilityMax(var, Expression.variability(step_exp));
2824 16 pur := Prefixes.purityMin(pur, Expression.purity(step_exp));
2825 32 dim_exp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.DIV_INT, {dim_exp, step_exp}, var, pur));
2826 end if;
2827
2828 2140 dim_exp := Expression.BINARY(dim_exp, Operator.makeAdd(Type.INTEGER()), Expression.INTEGER(1));
2829 4280 dim_exp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.MAX_INT, {dim_exp, Expression.INTEGER(0)}, var, pur));
2830 2140 dim_exp := SimplifyExp.simplify(dim_exp);
2831 2140 then
2832 Dimension.fromExp(dim_exp, var);
2833
2834 end match;
2835 end getRangeTypeInt;
2836
2837 function getRangeTypeReal
2838 input Expression startExp;
2839 input Option<Expression> stepExp;
2840 input Expression stopExp;
2841 input SourceInfo info;
2842 output Dimension dim;
2843 algorithm
2844 dim := match (startExp, stepExp, stopExp)
2845 local
2846 Real start, step;
2847 Expression dim_exp, step_exp;
2848 Variability var;
2849 Purity pur;
2850
2851 case (Expression.REAL(), NONE(), Expression.REAL())
2852 21 then Dimension.fromInteger(Util.realRangeSize(startExp.value, 1.0, stopExp.value));
2853
2854 case (Expression.REAL(value = start), SOME(Expression.REAL(value = step)), Expression.REAL())
2855 algorithm
2856 // Check that adding step to start actually produces a different value,
2857 // otherwise the step size is too small.
2858
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 109 times.
111 if start == start + step then
2859 4 Error.addSourceMessageAndFail(Error.RANGE_TOO_SMALL_STEP, {String(step)}, info);
2860 end if;
2861 109 then
2862 Dimension.fromInteger(Util.realRangeSize(startExp.value, step, stopExp.value));
2863
2864 case (_, NONE(), _)
2865 guard Expression.isEqual(startExp, stopExp)
2866 ✗ then Dimension.fromInteger(1);
2867
2868 else
2869 algorithm
2870 18 dim_exp := Expression.BINARY(stopExp, Operator.makeSub(Type.REAL()), startExp);
2871 18 var := Prefixes.variabilityMax(Expression.variability(stopExp),
2872 Expression.variability(startExp));
2873 18 pur := Prefixes.purityMin(Expression.purity(stopExp), Expression.purity(startExp));
2874
2875
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 4 times.
18 if isSome(stepExp) then
2876 14 SOME(step_exp) := stepExp;
2877 14 var := Prefixes.variabilityMax(var, Expression.variability(step_exp));
2878 14 pur := Prefixes.purityMin(pur, Expression.purity(step_exp));
2879 14 dim_exp := Expression.BINARY(dim_exp, Operator.makeDiv(Type.REAL()), step_exp);
2880 14 dim_exp := Expression.BINARY(dim_exp, Operator.makeAdd(Type.REAL()), Expression.REAL(5e-15));
2881 end if;
2882
2883 36 dim_exp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.FLOOR, {dim_exp}, var, pur));
2884 36 dim_exp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.INTEGER_REAL, {dim_exp}, var, pur));
2885 18 dim_exp := Expression.BINARY(dim_exp, Operator.makeAdd(Type.INTEGER()), Expression.INTEGER(1));
2886 18 dim_exp := SimplifyExp.simplify(dim_exp);
2887 18 then
2888 Dimension.fromExp(dim_exp, var);
2889
2890 end match;
2891 end getRangeTypeReal;
2892
2893 function getRangeTypeBool
2894 input Expression startExp;
2895 input Expression stopExp;
2896 output Dimension dim;
2897 algorithm
2898 dim := match (startExp, stopExp)
2899 local
2900 Integer sz;
2901 Expression dim_exp;
2902 Variability var;
2903
2904 case (Expression.BOOLEAN(), Expression.BOOLEAN())
2905 algorithm
2906
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 sz := if startExp.value == stopExp.value then 1
2907 elseif startExp.value < stopExp.value then 2
2908 else 0;
2909 4 then
2910 Dimension.fromInteger(sz);
2911
2912 else
2913 algorithm
2914 ✗ if Expression.isEqual(startExp, stopExp) then
2915 ✗ dim := Dimension.fromInteger(1);
2916 else
2917 ✗ var := Prefixes.variabilityMax(Expression.variability(startExp),
2918 Expression.variability(stopExp));
2919 // [if start == stop then 1 else if start < stop then 2 else 0]
2920 ✗ dim_exp := Expression.IF(
2921 Type.INTEGER(),
2922 Expression.RELATION(startExp, Operator.makeEqual(Type.BOOLEAN()), stopExp, -1),
2923 Expression.INTEGER(1),
2924 Expression.IF(
2925 Type.INTEGER(),
2926 Expression.RELATION(startExp, Operator.makeLess(Type.BOOLEAN()), stopExp, -1),
2927 Expression.INTEGER(2),
2928 Expression.INTEGER(0)));
2929
2930 ✗ dim_exp := SimplifyExp.simplify(dim_exp);
2931 ✗ dim := Dimension.fromExp(dim_exp, var);
2932 end if;
2933 then
2934 dim;
2935
2936 end match;
2937 end getRangeTypeBool;
2938
2939 function getRangeTypeEnum
2940 input Expression startExp;
2941 input Expression stopExp;
2942 output Dimension dim;
2943 algorithm
2944 dim := match (startExp, stopExp)
2945 local
2946 Expression dim_exp;
2947 Variability var;
2948
2949 case (Expression.ENUM_LITERAL(), Expression.ENUM_LITERAL())
2950 123 then Dimension.fromInteger(max(stopExp.index - startExp.index + 1, 0));
2951
2952 case (Expression.ENUM_LITERAL(index = 1), _)
2953 ✗ then Dimension.fromExp(stopExp, Expression.variability(stopExp));
2954
2955 else
2956 algorithm
2957 ✗ if Expression.isEqual(startExp, stopExp) then
2958 ✗ dim := Dimension.fromInteger(1);
2959 else
2960 ✗ var := Prefixes.variabilityMax(Expression.variability(startExp),
2961 Expression.variability(stopExp));
2962
2963 ✗ dim_exp := Expression.BINARY(
2964 Expression.enumIndexExp(startExp),
2965 Operator.makeSub(Type.INTEGER()),
2966 Expression.enumIndexExp(stopExp));
2967
2968 ✗ dim_exp := Expression.BINARY(
2969 dim_exp,
2970 Operator.makeAdd( Type.INTEGER()),
2971 Expression.INTEGER(1));
2972
2973 ✗ dim_exp := SimplifyExp.simplify(dim_exp);
2974 ✗ dim := Dimension.fromExp(dim_exp, var);
2975 end if;
2976 then
2977 dim;
2978
2979 end match;
2980 end getRangeTypeEnum;
2981
2982 function matchBinding
2983 input output Binding binding;
2984 input Type componentType;
2985 input String name;
2986 input InstNode component;
2987 input InstContext.Type context;
2988 algorithm
2989 () := match binding
2990 local
2991 MatchKind ty_match;
2992 Expression exp;
2993 Type ty, bind_ty, comp_ty;
2994
2995 case Binding.TYPED_BINDING(bindingExp = exp)
2996 algorithm
2997 822326 (bind_ty, comp_ty) := elaborateBindingType(exp, component, binding.bindingType, componentType);
2998 822326 (exp, ty, ty_match) := matchTypes(bind_ty, comp_ty, exp, ALLOW_UNKNOWN);
2999
3000
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 822318 times.
822326 if not isValidAssignmentMatch(ty_match) then
3001 8 binding.bindingExp := Expression.expandSplitIndices(exp);
3002 8 printBindingTypeError(name, binding, comp_ty, bind_ty, component, context);
3003
3004
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 time.
8 if not InstContext.inInstanceAPI(context) then
3005 7 fail();
3006 end if;
3007 elseif isCastMatch(ty_match) then
3008 83115 binding := Binding.TYPED_BINDING(exp, ty, binding.variability, binding.purity, binding.eachType,
3009 binding.evalState, binding.isFlattened, binding.source, binding.confidence, binding.info);
3010 end if;
3011 then
3012 ();
3013
3014 case Binding.UNBOUND() then ();
3015
3016 else
3017 algorithm
3018 ✗ Error.terminate(getInstanceName() + " got untyped binding " + Binding.toString(binding), sourceInfo());
3019 ✗ then
3020 fail();
3021 end match;
3022 end matchBinding;
3023
3024 function elaborateBindingType
3025 "If the binding expression comes from a modifier, returns the type of the
3026 actual binding expression and adds dimensions to the component type to match.
3027 This is done so that modifiers are type checked properly, i.e.:
3028
3029 model A
3030 Real x;
3031 end A;
3032
3033 model B
3034 A a[3](x = {1, 2});
3035 end B;
3036
3037 means the bindingExp will be {1, 2}[<x, 1>] and result in [2] being added to
3038 the binding type and [3] to the component type such that the type mismatch is
3039 detected."
3040 input Expression bindingExp;
3041 input InstNode component;
3042 input output Type bindingType;
3043 input output Type componentType;
3044 protected
3045 list<Dimension> dims;
3046
3047 function isParent
3048 input InstNode parent;
3049 input InstNode node;
3050 output Boolean res;
3051 protected
3052 InstNode n = InstNode.getDerivedNode(node);
3053 NFInstNode.ScopeRef p;
3054 algorithm
3055 res := match n
3056 case InstNode.COMPONENT_NODE(nodeType = InstNodeType.REDECLARED_COMP(parent = p))
3057
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✗ Branch 6 not taken.
2 then InstNode.refEqual(parent, n) or isParent(parent, InstNode.borrow(p));
3058 case InstNode.COMPONENT_NODE()
3059
3/4
✓ Branch 1 taken 1722 times.
✓ Branch 2 taken 90640 times.
✓ Branch 5 taken 1722 times.
✗ Branch 6 not taken.
92362 then InstNode.refEqual(parent, n) or isParent(parent, InstNode.parent(n));
3060 else false;
3061 end match;
3062 end isParent;
3063
3064 algorithm
3065 () := match bindingExp
3066 case Expression.SUBSCRIPTED_EXP()
3067 algorithm
3068 86258 bindingType := Expression.typeOf(bindingExp.exp);
3069
3070 dims := {};
3071
2/2
✓ Branch 0 taken 88631 times.
✓ Branch 1 taken 86258 times.
174889 for s in bindingExp.subscripts loop
3072 dims := match s
3073 case Subscript.SPLIT_INDEX()
3074 algorithm
3075
1/2
✓ Branch 2 taken 88630 times.
✗ Branch 3 not taken.
88630 if isParent(InstNode.borrow(s.node), component) then
3076 88630 dims := Type.nthDimension(InstNode.getType(InstNode.borrow(s.node)), s.dimIndex) :: dims;
3077 end if;
3078 then
3079 dims;
3080
3081 else Dimension.UNKNOWN() :: dims;
3082 end match;
3083 end for;
3084
3085 86258 dims := listReverseInPlace(dims);
3086 86258 componentType := Type.liftArrayLeftList(componentType, dims);
3087 then
3088 ();
3089
3090 case Expression.CREF()
3091 algorithm
3092 54869 bindingType := ComponentRef.getSubscriptedType(ComponentRef.expandSplitSubscripts(bindingExp.cref));
3093
3094 dims := {};
3095
2/2
✓ Branch 1 taken 3556 times.
✓ Branch 2 taken 54869 times.
58425 for s in ComponentRef.subscriptsAllFlat(bindingExp.cref) loop
3096 dims := match s
3097 case Subscript.SPLIT_INDEX()
3098 algorithm
3099
1/2
✓ Branch 2 taken 2011 times.
✗ Branch 3 not taken.
2011 if isParent(InstNode.borrow(s.node), component) then
3100 2011 dims := Type.nthDimension(InstNode.getType(InstNode.borrow(s.node)), s.dimIndex) :: dims;
3101 end if;
3102 then
3103 dims;
3104
3105 else dims;
3106 end match;
3107 end for;
3108
3109 54869 dims := listReverseInPlace(dims);
3110 54869 componentType := Type.liftArrayLeftList(componentType, dims);
3111 then
3112 ();
3113
3114 else ();
3115 end match;
3116 end elaborateBindingType;
3117
3118 function printBindingTypeError
3119 input String name;
3120 input Binding binding;
3121 input Type componentType;
3122 input Type bindingType;
3123 input InstNode component;
3124 input InstContext.Type context;
3125 protected
3126 SourceInfo binding_info, comp_info;
3127 MatchKind mk;
3128 algorithm
3129 8 binding_info := Binding.getInfo(binding);
3130 8 comp_info := InstNode.info(component);
3131
3132
4/4
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 3 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 3 times.
8 if Type.isScalar(bindingType) and Type.isArray(componentType) then
3133 4 Error.addMultiSourceMessage(Error.MODIFIER_NON_ARRAY_TYPE_ERROR,
3134 {Binding.toString(binding), name}, {binding_info, comp_info});
3135 else
3136 6 (_, _, mk) := matchTypes(Type.arrayElementType(bindingType),
3137 Type.arrayElementType(componentType),
3138 Expression.EMPTY(bindingType), ALLOW_UNKNOWN);
3139
3140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if not InstContext.inAnnotation(context) then // forget errors when handling annotations
3141
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if isValidAssignmentMatch(mk) then
3142 12 Error.addMultiSourceMessage(Error.VARIABLE_BINDING_DIMS_MISMATCH,
3143 {name, Binding.toString(binding),
3144 Dimension.toStringList(Type.arrayDims(componentType)),
3145 Dimension.toStringList(Type.arrayDims(bindingType))},
3146 {binding_info, comp_info});
3147 else
3148 12 Error.addMultiSourceMessage(Error.VARIABLE_BINDING_TYPE_MISMATCH,
3149 {name, Binding.toString(binding), Type.toString(componentType),
3150 Type.toString(bindingType)}, {binding_info, comp_info});
3151 end if;
3152 end if;
3153 end if;
3154 end printBindingTypeError;
3155
3156 function checkDimensionType
3157 "Checks that an expression used as a dimension has a valid type for a
3158 dimension, otherwise prints an error and fails."
3159 input Expression exp;
3160 input Type ty;
3161 input SourceInfo info;
3162 algorithm
3163
2/2
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 86765 times.
86819 if not Type.isInteger(ty) then
3164 () := match exp
3165 case Expression.TYPENAME(ty = Type.ARRAY(elementType = Type.BOOLEAN())) then ();
3166 case Expression.TYPENAME(ty = Type.ARRAY(elementType = Type.ENUMERATION())) then ();
3167 else
3168 algorithm
3169 3 Error.addSourceMessage(Error.INVALID_DIMENSION_TYPE,
3170 {Expression.toString(exp), Type.toString(ty)}, info);
3171 1 then
3172 fail();
3173 end match;
3174 end if;
3175 end checkDimensionType;
3176
3177 function checkReductionType
3178 input Type ty;
3179 input Absyn.Path name;
3180 input Expression exp;
3181 input SourceInfo info;
3182 protected
3183 String err;
3184 algorithm
3185 err := match name
3186 case Absyn.Path.IDENT("sum")
3187 then
3188 match Type.arrayElementType(ty)
3189 case Type.INTEGER() then "";
3190 case Type.REAL() then "";
3191 case Type.COMPLEX() guard checkSumComplexType(ty, exp, info) then "";
3192 else "Integer or Real, or operator record";
3193 end match;
3194
3195 case Absyn.Path.IDENT("product")
3196 then
3197 match ty
3198 case Type.INTEGER() then "";
3199 case Type.REAL() then "";
3200 else "scalar Integer or Real";
3201 end match;
3202
3203 case Absyn.Path.IDENT("min")
3204 then
3205 match ty
3206 case Type.INTEGER() then "";
3207 case Type.REAL() then "";
3208 case Type.BOOLEAN() then "";
3209 case Type.ENUMERATION() then "";
3210 else "scalar enumeration, Boolean, Integer, or Real";
3211 end match;
3212
3213 case Absyn.Path.IDENT("max")
3214 then
3215 match ty
3216 case Type.INTEGER() then "";
3217 case Type.REAL() then "";
3218 case Type.BOOLEAN() then "";
3219 case Type.ENUMERATION() then "";
3220 else "scalar enumeration, Boolean, Integer, or Real";
3221 end match;
3222
3223 else "";
3224 end match;
3225
3226
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 2 times.
300 if not stringEmpty(err) then
3227 8 Error.addSourceMessageAndFail(Error.INVALID_REDUCTION_TYPE,
3228 {Expression.toString(exp), Type.toString(ty), AbsynUtil.pathString(name), err}, info);
3229 end if;
3230 end checkReductionType;
3231
3232 function checkSumComplexType
3233 input Type ty;
3234 input Expression exp;
3235 input SourceInfo info;
3236 output Boolean valid = true;
3237 protected
3238 InstNode cls_node;
3239 Class cls;
3240 algorithm
3241 1 cls_node := Type.complexNode(ty);
3242 1 cls := InstNode.getClass(cls_node);
3243
3244
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for op in {"'+'", "'0'"} loop
3245
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if not Class.hasOperator(op, cls) then
3246 ✗ Error.addSourceMessage(Error.OPERATOR_RECORD_MISSING_OPERATOR,
3247 {Type.toString(ty), Expression.toString(exp), "sum", op}, info);
3248 valid := false;
3249 end if;
3250 end for;
3251 end checkSumComplexType;
3252
3253 function matchIfBranches
3254 "Matches the types of the branches of an if-expression. The branches must have
3255 the same element type and number of dimensions, but might have different
3256 dimensions as long as the condition can be evaluated later to select one of
3257 the branches."
3258 input output Expression trueBranch;
3259 input Type trueType;
3260 input output Expression falseBranch;
3261 input Type falseType;
3262 input InstContext.Type context;
3263 input MatchOptions options = DEFAULT_OPTIONS;
3264 output Type compatibleType;
3265 output MatchKind matchKind;
3266 algorithm
3267 (compatibleType, matchKind) := match (trueType, falseType)
3268 case (Type.ARRAY(), Type.ARRAY())
3269 algorithm
3270 // Check that both branches have the same element type.
3271 1729 (trueBranch, falseBranch, compatibleType, matchKind) :=
3272 matchExpressions(trueBranch, trueType.elementType,
3273 falseBranch, falseType.elementType, options);
3274
3275
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1729 times.
1729 if isIncompatibleMatch(matchKind) then
3276 ✗ return;
3277 end if;
3278
3279 // Check that both branches have the same dimensions.
3280 1729 (compatibleType, matchKind) :=
3281 matchArrayDims(trueType.dimensions, falseType.dimensions, compatibleType, matchKind, options);
3282
3283
5/6
✓ Branch 2 taken 1729 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1652 times.
✓ Branch 6 taken 77 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 1646 times.
1729 if listLength(trueType.dimensions) == listLength(falseType.dimensions) and
3284 (isIncompatibleMatch(matchKind) or
3285 not List.isEqualOnTrue(trueType.dimensions, falseType.dimensions, Dimension.isSame)) then
3286 // The branches are allowed to have different array dimensions as long as
3287 // they have compatible element types and the same number of dimensions.
3288
4/4
✓ Branch 1 taken 81 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 73 times.
83 if InstContext.inSubexpression(context) or InstContext.inFunction(context) then
3289 // Unify the types if the if-expression is part of a larger expression or we're in
3290 // a function, because we can't really handle conditional array sizes in that case.
3291 10 compatibleType := Type.unifyArrays(Type.copyElementType(trueType, compatibleType),
3292 Type.copyElementType(falseType, compatibleType));
3293 else
3294 // Otherwise, create a conditional array type to allow determining the actual type later.
3295 73 compatibleType := Type.CONDITIONAL_ARRAY(Type.copyElementType(trueType, compatibleType),
3296 Type.copyElementType(falseType, compatibleType),
3297 NFType.Branch.NONE);
3298 end if;
3299
3300 83 matchKind := MatchKind.EXACT;
3301 end if;
3302 1729 then
3303 (compatibleType, matchKind);
3304
3305 case (_, _)
3306 guard Type.isConditionalArray(trueType) or Type.isConditionalArray(falseType)
3307 algorithm
3308 ✗ (trueBranch, falseBranch, compatibleType, matchKind) :=
3309 matchExpressions(trueBranch, Type.arrayElementType(trueType),
3310 falseBranch, Type.arrayElementType(falseType), options);
3311
3312 ✗ if isIncompatibleMatch(matchKind) then
3313 ✗ return;
3314 end if;
3315
3316 ✗ compatibleType := Type.CONDITIONAL_ARRAY(Type.copyElementType(trueType, compatibleType),
3317 Type.copyElementType(falseType, compatibleType),
3318 NFType.Branch.NONE);
3319 ✗ then
3320 (compatibleType, matchKind);
3321
3322 else
3323 algorithm
3324 12496 (trueBranch, falseBranch, compatibleType, matchKind) :=
3325 matchExpressions(trueBranch, trueType, falseBranch, falseType, options);
3326 12496 then
3327 (compatibleType, matchKind);
3328
3329 end match;
3330 end matchIfBranches;
3331
3332 annotation(__OpenModelica_Interface="nf_frontend");
3333 end NFTypeCheck;
3334