Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.0% 945 / 0 / 1074
Functions: -% 0 / 1 / 1
Branches: 81.2% 559 / 0 / 688

OMCompiler/Compiler/NFFrontEnd/NFTyping.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 NFTyping
37 " file: NFTyping.mo
38 package: NFTyping
39 description: NFInst typing.
40
41
42 Functions used by NFInst for typing.
43 "
44
45 import Binding = NFBinding;
46 import Component = NFComponent;
47 import NFComponent.ComponentState;
48 import Dimension = NFDimension;
49 import Equation = NFEquation;
50 import Class = NFClass;
51 import Expression = NFExpression;
52 import NFInstNode.InstNode;
53 import NFInstNode;
54 import NFModifier.Modifier;
55 import SimplifyExp = NFSimplifyExp;
56 import Statement = NFStatement;
57 import NFType.Type;
58 import Operator = NFOperator;
59 import NFPrefixes.{Variability, Purity, ConnectorType};
60 import Prefixes = NFPrefixes;
61 import Connector = NFConnector;
62 import Connection = NFConnection;
63 import Algorithm = NFAlgorithm;
64 import Record = NFRecord;
65 import InstContext = NFInstContext;
66
67 protected
68 import Absyn;
69 import Attributes = NFAttributes;
70 import Builtin = NFBuiltin;
71 import BuiltinCall = NFBuiltinCall;
72 import Ceval = NFCeval;
73 import Config;
74 import ComponentRef = NFComponentRef;
75 import Origin = NFComponentRef.Origin;
76 import ExecStat.execStat;
77 import Lookup = NFLookup;
78 import MatchKind = NFTypeCheck.MatchKind;
79 import Call = NFCall;
80 import DAE;
81 import NFClassTree.ClassTree;
82 import Subscript = NFSubscript;
83 import TypeCheck = NFTypeCheck;
84 import NFSections.Sections;
85 import List;
86 import MetaModelica.Dangerous.listReverseInPlace;
87 import ComplexType = NFComplexType;
88 import Restriction = NFRestriction;
89 import NFModifier.ModTable;
90 import Package = NFPackage;
91 import NFFunction.Function;
92 import NFInstNode.CachedData;
93 import Direction = NFPrefixes.Direction;
94 import ElementSource;
95 import System;
96 import ErrorExt;
97 import ErrorTypes;
98 import OperatorOverloading = NFOperatorOverloading;
99 import Structural = NFStructural;
100 import Array;
101
102 public
103 uniontype TypingError
104 record NO_ERROR end NO_ERROR;
105
106 record OUT_OF_BOUNDS
107 Integer upperBound;
108 end OUT_OF_BOUNDS;
109
110 record UNKNOWN_TYPE end UNKNOWN_TYPE;
111
112 function isError
113 input TypingError error;
114 output Boolean isError;
115 algorithm
116 isError := match error
117 case NO_ERROR() then false;
118 else true;
119 end match;
120 end isError;
121 end TypingError;
122
123 // Used by typeDimension for catching cyclic dimension involving :
124 constant Expression WHOLEDIM_CREF = Expression.CREF(Type.UNKNOWN(),
125 ComponentRef.CREF(InstNode.NAME_NODE(":"), {}, Type.UNKNOWN(), NFComponentRef.Origin.CREF, ComponentRef.EMPTY()));
126
127 public
128 function typeClass
129 input InstNode cls;
130 input InstContext.Type context;
131 protected
132 InstContext.Type next_context;
133 algorithm
134 1712 next_context := InstContext.set(context, NFInstContext.CLASS);
135 1712 typeClassType(cls, NFBinding.EMPTY_BINDING, next_context, cls);
136 1712 typeComponents(cls, next_context);
137 1702 execStat("NFTyping.typeComponents");
138 1702 typeBindings(cls, next_context);
139 1654 execStat("NFTyping.typeBindings");
140 1654 typeClassSections(cls, next_context);
141 1621 execStat("NFTyping.typeClassSections");
142 end typeClass;
143
144 function typeComponents
145 input InstNode cls;
146 input InstContext.Type context;
147 input Boolean preserveDerived = false;
148 protected
149 Class c = InstNode.getClass(cls), c2;
150 ClassTree cls_tree;
151 NFInstNode.ScopeRef con, de;
152 NFInstNode.ScopeRef rec_con;
153 algorithm
154 () := match c
155 case Class.INSTANCED_CLASS(restriction = Restriction.TYPE()) then ();
156
157 case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE())
158 algorithm
159
2/2
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 80951 times.
81033 if InstContext.inInstanceAPI(context) then
160
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
✓ Branch 3 taken 105 times.
✓ Branch 4 taken 82 times.
269 for c in cls_tree.components loop
161 105 typeComponentTry(c, context);
162 end for;
163 else
164
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 80951 times.
✓ Branch 3 taken 513907 times.
✓ Branch 4 taken 80939 times.
675797 for c in cls_tree.components loop
165 513907 typeComponent(c, context);
166 end for;
167 end if;
168
169 () := match c.ty
170 case Type.COMPLEX(complexTy = ComplexType.RECORD(constructor = rec_con))
171 algorithm
172 28914 typeStructor(InstNode.borrow(rec_con));
173 then
174 ();
175
176 else ();
177 end match;
178 then
179 ();
180
181 // For derived types with dimensions we keep them as they are, because we
182 // need to preserve the dimensions.
183 case Class.TYPED_DERIVED()
184 guard preserveDerived or Type.isArray(c.ty)
185 algorithm
186 5077 typeComponents(c.baseClass, context);
187 then
188 ();
189
190 // Derived types without dimensions can be collapsed.
191 case Class.TYPED_DERIVED()
192 algorithm
193 328137 typeComponents(c.baseClass, context);
194
195 // Only collapse for the normal instantiation, for the instance API we
196 // need the derived class chains.
197
2/2
✓ Branch 1 taken 328127 times.
✓ Branch 2 taken 10 times.
328137 if not InstContext.inInstanceAPI(context) then
198 328127 c2 := InstNode.getClass(c.baseClass);
199 328127 c2 := Class.setRestriction(c.restriction, c2);
200 328127 InstNode.updateClass(c2, cls);
201 end if;
202 then
203 ();
204
205 case Class.INSTANCED_BUILTIN(ty = Type.COMPLEX(complexTy =
206 ComplexType.EXTERNAL_OBJECT(constructor = con, destructor = de)))
207 algorithm
208 337 typeStructor(InstNode.borrow(con));
209 337 typeStructor(InstNode.borrow(de));
210 then
211 ();
212
213 case Class.INSTANCED_BUILTIN() then ();
214
215 else
216 algorithm
217 ✗ Error.terminate(getInstanceName() + " got uninstantiated class " + InstNode.name(cls), sourceInfo());
218 ✗ then
219 fail();
220
221 end match;
222 end typeComponents;
223
224 function typeStructor
225 input InstNode node;
226 protected
227 CachedData cache;
228 list<Function> fnl;
229 InstContext.Type context;
230 algorithm
231 29588 cache := InstNode.getFuncCache(node);
232
233 () := match cache
234 case CachedData.FUNCTION(funcs = fnl, typed = false)
235 algorithm
236 4406 context := InstContext.set(NFInstContext.FUNCTION, NFInstContext.RELAXED);
237
4/4
✓ Branch 0 taken 4578 times.
✓ Branch 1 taken 4406 times.
✓ Branch 2 taken 4578 times.
✓ Branch 3 taken 4406 times.
8984 fnl := list(Function.typeFunction(fn, context) for fn in fnl);
238
4/4
✓ Branch 0 taken 4578 times.
✓ Branch 1 taken 4406 times.
✓ Branch 2 taken 4578 times.
✓ Branch 3 taken 4406 times.
8984 fnl := list(OperatorOverloading.patchOperatorRecordConstructorBinding(fn) for fn in fnl);
239 4406 InstNode.setFuncCache(node, CachedData.FUNCTION(fnl, true, cache.specialBuiltin));
240 then
241 ();
242
243 else ();
244 end match;
245 end typeStructor;
246
247 function typeClassType
248 input InstNode clsNode;
249 input Binding componentBinding;
250 input InstContext.Type context;
251 input InstNode instanceNode;
252 output Type ty;
253 protected
254 Class cls, ty_cls;
255 InstNode ty_node;
256 NFInstNode.ScopeRef node;
257 Type cls_ty;
258 Function fn;
259 Boolean is_expandable;
260 algorithm
261 855999 cls := InstNode.getClass(clsNode);
262
263 ty := match cls
264 case Class.INSTANCED_CLASS(restriction = Restriction.CONNECTOR(isExpandable = is_expandable))
265 algorithm
266 15210 ty := Type.COMPLEX(InstNode.identityCell(clsNode), makeConnectorType(cls.elements, is_expandable));
267 15210 cls.ty := ty;
268 15210 InstNode.updateClass(cls, clsNode);
269 then
270 ty;
271
272 case Class.INSTANCED_CLASS(ty = cls_ty as Type.COMPLEX(complexTy = ComplexType.RECORD(constructor = node)))
273 algorithm
274 28918 ty_node := Type.complexNode(cls_ty);
275 28918 ty := Type.COMPLEX(InstNode.identityCell(ty_node), makeRecordType(node));
276 28918 cls.ty := ty;
277 28918 InstNode.updateClass(cls, clsNode);
278 then
279 ty;
280
281 // A long class declaration of a type extending from a type has the type of the base class.
282 case Class.INSTANCED_CLASS(ty = Type.COMPLEX(complexTy = ComplexType.EXTENDS_TYPE(node)))
283 algorithm
284 14104 ty := typeClassType(InstNode.borrow(node), componentBinding, context, instanceNode);
285 14104 cls.ty := ty;
286 14104 InstNode.updateClass(cls, clsNode);
287 then
288 ty;
289
290 // A component of function type, i.e. a functional input parameter.
291 case Class.INSTANCED_CLASS(restriction = Restriction.FUNCTION())
292 guard InstNode.isComponent(instanceNode)
293 algorithm
294
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 fn :: _ := Function.typeNodeCache(clsNode);
295 30 ty := Type.FUNCTION(fn, NFType.FunctionType.FUNCTIONAL_PARAMETER);
296 30 cls.ty := ty;
297 30 InstNode.updateClass(cls, clsNode);
298 then
299 ty;
300
301 39574 case Class.INSTANCED_CLASS() then cls.ty;
302
303 case Class.EXPANDED_DERIVED()
304 algorithm
305 335880 typeDimensions(cls.dims, clsNode, componentBinding, context, InstNode.info(clsNode));
306 335880 ty := typeClassType(cls.baseClass, componentBinding, context, instanceNode);
307 335880 ty := Type.liftArrayLeftList(ty, arrayList(cls.dims));
308 335880 ty_cls := Class.TYPED_DERIVED(ty, cls.baseClass, cls.restriction);
309 335880 InstNode.updateClass(ty_cls, clsNode);
310 then
311 ty;
312
313 422283 case Class.INSTANCED_BUILTIN() then cls.ty;
314 ✗ case Class.TYPED_DERIVED() then cls.ty;
315
316 else
317 algorithm
318 ✗ Error.terminate(getInstanceName() + " got noninstantiated class " +
319 InstNode.name(clsNode), sourceInfo());
320 ✗ then
321 fail();
322
323 end match;
324 end typeClassType;
325
326 function makeConnectorType
327 input ClassTree ctree;
328 input Boolean isExpandable;
329 output ComplexType connectorTy;
330 protected
331 list<NFInstNode.ScopeRef> pots = {}, flows = {}, streams = {}, exps = {};
332 ConnectorType.Type cty;
333 algorithm
334
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 15209 times.
15250 if isExpandable then
335
2/2
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 41 times.
243 for c in ClassTree.enumerateComponents(ctree) loop
336 202 cty := Component.connectorType(InstNode.component(InstNode.resolveInner(c)));
337
338
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 184 times.
202 if intBitAnd(cty, ConnectorType.EXPANDABLE) > 0 then
339 18 exps := InstNode.scopeRef(c) :: exps;
340 else
341 184 pots := InstNode.scopeRef(c) :: pots;
342 end if;
343 end for;
344
345 41 connectorTy := ComplexType.EXPANDABLE_CONNECTOR(pots, exps);
346 else
347
2/2
✓ Branch 1 taken 41476 times.
✓ Branch 2 taken 15209 times.
56685 for c in ClassTree.enumerateComponents(ctree) loop
348 41476 cty := Component.connectorType(InstNode.component(InstNode.resolveInner(c)));
349
350
2/2
✓ Branch 0 taken 16577 times.
✓ Branch 1 taken 24899 times.
41476 if intBitAnd(cty, ConnectorType.FLOW) > 0 then
351 16577 flows := InstNode.scopeRef(c) :: flows;
352 elseif intBitAnd(cty, ConnectorType.STREAM) > 0 then
353 969 streams := InstNode.scopeRef(c) :: streams;
354 elseif intBitAnd(cty, ConnectorType.POTENTIAL) > 0 then
355 23930 pots := InstNode.scopeRef(c) :: pots;
356 else
357 ✗ Error.addInternalError("Invalid connector type on component " + InstNode.name(c), InstNode.info(c));
358 ✗ fail();
359 end if;
360 end for;
361
362 15209 connectorTy := ComplexType.CONNECTOR(pots, flows, streams);
363
364
2/2
✓ Branch 0 taken 14818 times.
✓ Branch 1 taken 391 times.
15209 if not listEmpty(streams) then
365 391 System.setHasStreamConnectors(true);
366 end if;
367 end if;
368 end makeConnectorType;
369
370 function checkConnectorTypeBalance
371 input InstNode component;
372 protected
373 Integer pots, flows, streams;
374 Boolean known_size;
375 Component comp;
376 InstNode parent;
377 algorithm
378 475129 comp := InstNode.component(component);
379
380
2/2
✓ Branch 2 taken 454912 times.
✓ Branch 3 taken 20217 times.
475129 if not ConnectorType.isConnector(Component.connectorType(comp)) then
381 454912 return;
382 end if;
383
384 20217 parent := InstNode.instanceParent(component);
385
4/4
✓ Branch 1 taken 20004 times.
✓ Branch 2 taken 213 times.
✓ Branch 5 taken 1221 times.
✓ Branch 6 taken 18783 times.
20217 if InstNode.isComponent(parent) and Component.isConnector(InstNode.component(parent)) then
386 1221 return;
387 end if;
388
389 18996 (pots, flows, streams, known_size) := Component.countConnectorVars(comp);
390
391
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 18995 times.
18996 if not known_size then
392 1 return;
393 end if;
394
395 // Modelica 3.2 section 9.3.1:
396 // For each non-partial connector class the number of flow variables shall
397 // be equal to the number of variables that are neither parameter, constant,
398 // input, output, stream nor flow.
399
3/4
✓ Branch 0 taken 496 times.
✓ Branch 1 taken 18499 times.
✓ Branch 3 taken 496 times.
✗ Branch 4 not taken.
18995 if pots <> flows and not Flags.isConfigFlagSet(Flags.ALLOW_NON_STANDARD_MODELICA, "unbalancedModel") then
400 1488 Error.addStrictMessage(Error.UNBALANCED_CONNECTOR,
401 {InstNode.name(component), String(pots), String(flows)}, InstNode.info(component));
402 end if;
403
404 // Modelica 3.2 section 15.1:
405 // A stream connector must have exactly one scalar variable with the flow prefix.
406
3/4
✓ Branch 0 taken 390 times.
✓ Branch 1 taken 18605 times.
✓ Branch 2 taken 390 times.
✗ Branch 3 not taken.
18995 if streams > 0 and flows <> 1 then
407 ✗ Error.addSourceMessage(Error.MISMATCHED_FLOW_IN_STREAM_CONNECTOR,
408 {InstNode.name(component), String(flows)}, InstNode.info(component));
409 ✗ fail();
410 end if;
411 end checkConnectorTypeBalance;
412
413 function makeRecordType
414 input NFInstNode.ScopeRef constructor;
415 output ComplexType recordTy;
416 protected
417 CachedData cache;
418 Function fn;
419 array<Record.Field> fields;
420 UnorderedMap<String, Integer> indexMap;
421 algorithm
422 28918 cache := InstNode.getFuncCache(InstNode.borrow(constructor));
423
424 recordTy := matchcontinue cache
425 case CachedData.FUNCTION()
426 algorithm
427 28918 fn := List.find(cache.funcs, Function.isDefaultRecordConstructor);
428 28918 (fields, indexMap) := Record.collectRecordFields(InstNode.fromHandle(fn.node));
429 28918 then
430 ComplexType.RECORD(constructor, fields, indexMap);
431
432 else
433 algorithm
434 ✗ Error.terminate(getInstanceName() +
435 " got record type without constructor", sourceInfo());
436 ✗ then
437 fail();
438 end matchcontinue;
439 end makeRecordType;
440
441 function typeComponent
442 input InstNode component;
443 input InstContext.Type context;
444 input Boolean typeChildren = true;
445 output Type ty;
446 protected
447 InstNode node;
448 Component c;
449 Boolean is_deleted;
450 array<Dimension> dims;
451 Binding binding;
452 algorithm
453
4/4
✓ Branch 1 taken 1813159 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 1532 times.
✓ Branch 5 taken 1811627 times.
1813164 if InstNode.isEmpty(component) or InstNode.isOnlyOuter(component) then
454 1537 return;
455 end if;
456
457 1811627 node := InstNode.resolveOuter(component);
458 1811627 c := InstNode.component(node);
459
460 ty := match c
461 // An untyped component, type it.
462 case Component.COMPONENT(ty = Type.UNTYPED(dimensions = dims))
463 algorithm
464 // Type the component's dimensions.
465 478112 typeDimensions(dims, node, c.binding, context, c.info);
466
467 // Construct the type of the component and update the node with it.
468
2/2
✓ Branch 1 taken 478100 times.
✓ Branch 2 taken 3 times.
478103 if InstNode.isEmpty(c.classInst) then
469 ty := Type.UNKNOWN();
470 else
471 478100 ty := typeClassType(c.classInst, c.binding, context, component);
472 end if;
473 478103 ty := Type.liftArrayLeftList(ty, arrayList(dims));
474
475
2/2
✓ Branch 1 taken 5560 times.
✓ Branch 2 taken 472543 times.
478103 if Binding.isBound(c.condition) then
476 5560 c.condition := typeComponentCondition(c.condition, context, evaluate = true);
477 5559 is_deleted := Expression.isFalse(Binding.getExp(c.condition));
478 else
479 is_deleted := false;
480 end if;
481
482
2/2
✓ Branch 0 taken 478101 times.
✓ Branch 1 taken 1 time.
478102 if typeChildren then
483 478101 c.ty := ty;
484 478101 c.state := ComponentState.Typed;
485 478101 InstNode.updateComponent(c, node);
486
487
4/4
✓ Branch 0 taken 475134 times.
✓ Branch 1 taken 2967 times.
✓ Branch 3 taken 475131 times.
✓ Branch 4 taken 3 times.
478101 if not is_deleted and not InstNode.isEmpty(c.classInst) then
488 // Check that flow/stream variables are Real.
489 475131 checkComponentStreamAttribute(c.attributes.connectorType, ty, component);
490
491 // Type the component's children.
492 475131 typeComponents(c.classInst, context);
493
494 475129 checkConnectorTypeBalance(node);
495 end if;
496 end if;
497 then
498 ty;
499
500 // A component that has already been typed, skip it.
501 1317623 case Component.COMPONENT() then c.ty;
502 15892 case Component.ITERATOR() then c.ty;
503 case Component.ENUM_LITERAL(literal = Expression.ENUM_LITERAL(ty = ty)) then ty;
504 ✗ case Component.INVALID_COMPONENT() then Component.getType(c);
505
506 // Any other type of component shouldn't show up here.
507 else
508 algorithm
509 ✗ Error.terminate(getInstanceName() + " got noninstantiated component " + InstNode.name(component), sourceInfo());
510 ✗ then
511 fail();
512
513 end match;
514 end typeComponent;
515
516 function typeComponentTry
517 input InstNode componentNode;
518 input InstContext.Type context;
519 protected
520 Component comp;
521 algorithm
522 105 ErrorExt.setCheckpoint(getInstanceName());
523 try
524 105 typeComponent(componentNode, context);
525 else
526 ✗ comp := InstNode.component(componentNode);
527 ✗ comp := Component.INVALID_COMPONENT(comp, ErrorExt.printCheckpointMessagesStr());
528 ✗ InstNode.updateComponent(comp, componentNode);
529 end try;
530 105 ErrorExt.delCheckpoint(getInstanceName());
531 end typeComponentTry;
532
533 function checkComponentStreamAttribute
534 input ConnectorType.Type cty;
535 input Type ty;
536 input InstNode component;
537 protected
538 Type ety;
539 algorithm
540
2/2
✓ Branch 1 taken 457724 times.
✓ Branch 2 taken 17407 times.
475131 if ConnectorType.isFlowOrStream(cty) then
541 17407 ety := Type.arrayElementType(ty);
542
543
3/4
✓ Branch 1 taken 16913 times.
✓ Branch 2 taken 494 times.
✓ Branch 4 taken 494 times.
✗ Branch 5 not taken.
17407 if not (Type.isReal(ety) or Type.isComplex(ety)) then
544 ✗ Error.addSourceMessageAndFail(Error.NON_REAL_FLOW_OR_STREAM,
545 {ConnectorType.toString(cty), InstNode.name(component)}, InstNode.info(component));
546 end if;
547 end if;
548 end checkComponentStreamAttribute;
549
550 function typeIterator
551 input InstNode iterator;
552 input Expression range;
553 input InstContext.Type context;
554 input Boolean structural "If the iteration range must be a parameter expression or not.";
555 output Expression outRange;
556 output Type ty;
557 output Variability var;
558 output Purity purity;
559 protected
560 Component c = InstNode.component(iterator);
561 Expression exp;
562 SourceInfo info;
563 algorithm
564 (outRange, ty, var) := match c
565 case Component.ITERATOR(info = info)
566 algorithm
567 3836 (exp, ty, var, purity) := typeExp(range, InstContext.set(context, NFInstContext.ITERATION_RANGE), info);
568
569 // If the iteration range is structural, it must be a parameter expression (unless we don't scalarize and it is a non structural parameter).
570
7/8
✓ Branch 0 taken 2835 times.
✓ Branch 1 taken 1001 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 2820 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
3836 if structural and var > Variability.PARAMETER and (not var == Variability.NON_STRUCTURAL_PARAMETER or Flags.isSet(Flags.NF_SCALARIZE)) then
571 2 Error.addSourceMessageAndFail(Error.NON_PARAMETER_ITERATOR_RANGE,
572 {Expression.toString(exp)}, info);
573 end if;
574
575 // The iteration range must be a vector expression.
576
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3835 times.
3835 if not Type.isVector(ty) then
577 ✗ Error.addSourceMessageAndFail(Error.FOR_EXPRESSION_TYPE_ERROR,
578 {Expression.toString(exp), Type.toString(ty)}, info);
579 end if;
580
581 // The type of the iterator is the element type of the range expression.
582 3835 c := Component.ITERATOR(Type.arrayElementType(ty), var, info);
583 3835 InstNode.updateComponent(c, iterator);
584
2/2
✓ Branch 0 taken 1354 times.
✓ Branch 1 taken 2481 times.
3835 then
585 (exp, ty, var);
586
587 else
588 algorithm
589 ✗ Error.terminate(getInstanceName() + " got non-iterator " + InstNode.name(iterator), sourceInfo());
590 ✗ then
591 fail();
592
593 end match;
594 end typeIterator;
595
596 function typeDimensions
597 input output array<Dimension> dimensions;
598 input InstNode component;
599 input Binding binding;
600 input InstContext.Type context;
601 input SourceInfo info;
602 algorithm
603
2/2
✓ Branch 0 taken 735791 times.
✓ Branch 1 taken 78201 times.
906867 for i in 1:arrayLength(dimensions) loop
604 92884 typeDimension(dimensions, i, component, binding, context, info);
605 end for;
606 end typeDimensions;
607
608 function typeDimension
609 input array<Dimension> dimensions;
610 input Integer index;
611 input InstNode component;
612 input Binding binding;
613 input InstContext.Type context;
614 input SourceInfo info;
615 output Dimension dimension = dimensions[index];
616 algorithm
617 dimension := match dimension
618 local
619 Expression exp;
620 Variability var;
621 Dimension dim;
622 Binding b;
623 Type ty;
624 TypingError ty_err;
625 Integer parent_dims;
626 Ceval.EvalTarget target;
627
628 // A dimension that we're already trying to type.
629 case Dimension.UNTYPED(isProcessing = true)
630 algorithm
631
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 5 times.
13 if InstContext.inFunction(context) then
632 // If we are in a functions we allow e.g. size expression of unknown dimensions.
633 dim := Dimension.UNKNOWN();
634 8 arrayUpdate(dimensions, index, dim);
635 else
636 // Otherwise leave the dimension as it is, which is sometimes fine if
637 // the dimension isn't used or generates an error in typeCrefDim.
638 dim := dimension;
639 end if;
640 then
641 dim;
642
643 // If the dimension is not typed, type it.
644 case Dimension.UNTYPED()
645 algorithm
646 86821 arrayUpdate(dimensions, index, Dimension.UNTYPED(dimension.dimension, true));
647
648 86821 (exp, ty, var) := typeExp(dimension.dimension, InstContext.set(context, NFInstContext.DIMENSION), info);
649 86819 TypeCheck.checkDimensionType(exp, ty, info);
650
651
2/2
✓ Branch 1 taken 56525 times.
✓ Branch 2 taken 30293 times.
86818 if not InstContext.inFunction(context) then
652 // Dimensions must be parameter expressions in a non-function class.
653
2/2
✓ Branch 0 taken 56500 times.
✓ Branch 1 taken 25 times.
56525 if var <= Variability.PARAMETER then
654
2/2
✓ Branch 1 taken 28961 times.
✓ Branch 2 taken 27539 times.
56500 if InstContext.inRelaxed(context) then
655 28961 exp := Ceval.tryEvalExp(exp);
656 else
657 55078 target := Ceval.EvalTarget.new(info, context,
658 SOME(Ceval.EvalTargetData.DIMENSION_DATA(component, index, exp)));
659 27539 exp := Ceval.tryEvalExpResizable(exp, target);
660 end if;
661 elseif not var == Variability.NON_STRUCTURAL_PARAMETER then
662 ✗ Error.addSourceMessage(Error.DIMENSION_NOT_KNOWN, {Expression.toString(exp)}, info);
663 ✗ fail();
664 end if;
665 else
666 // For functions, only evaluate constant and structural parameter expressions.
667
3/4
✓ Branch 0 taken 29170 times.
✓ Branch 1 taken 1123 times.
✓ Branch 3 taken 29170 times.
✗ Branch 4 not taken.
30293 if var <= Variability.STRUCTURAL_PARAMETER and
668 not Expression.contains(exp, Expression.isFunctionInputCref) then
669 29170 exp := Ceval.tryEvalExp(exp);
670 end if;
671 end if;
672
673 86815 exp := subscriptDimExp(exp, component);
674 86815 dim := Dimension.fromExp(exp, var);
675 86815 arrayUpdate(dimensions, index, dim);
676 then
677 dim;
678
679 // Dimensions in a function can be flexible (non-input component with no
680 // binding) or determined by the call arguments (input component), keep the
681 // dimension unknown for these cases.
682 case Dimension.UNKNOWN() guard InstContext.inFunction(context) and
683 ((Binding.isUnbound(binding) and InstNode.isOutput(component)) or
684 not InstNode.isOutput(component))
685 then dimension;
686
687 // A dimension of a function output parameter that depends on e.g. an input
688 // can't be determined here, leave it unknown and let the call typing handle it.
689 // TODO: This assumes any binding that contains crefs can't be evaluated to
690 // avoid e.g. using the default value of an input parameter, but some
691 // cases such as an output dimension depending on another output
692 // dimension could be fine.
693 case Dimension.UNKNOWN() guard InstContext.inFunction(context) and
694 Binding.hasExp(binding) and
695 Expression.contains(Binding.getExp(binding), Expression.isCref)
696 then dimension;
697
698 // If the dimension is unknown in a class, try to infer it from the components binding.
699 case Dimension.UNKNOWN()
700 algorithm
701 b := binding;
702 1042 parent_dims := 0;
703 // Update the dimension as processing, using a : cref to get the correct
704 // error message if there are cycles.
705 1042 arrayUpdate(dimensions, index, Dimension.UNTYPED(WHOLEDIM_CREF, true));
706
707
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1022 times.
1042 if Binding.isUnbound(binding) then
708 // If the component has no binding, try to use its parent's binding
709 // (i.e. for record fields where the record instance has a binding).
710 20 (b, parent_dims) := getRecordElementBinding(component, context);
711
712
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 16 times.
20 if Binding.isUnbound(b) then
713 // If the component still doesn't have a binding, try to use the start attribute instead.
714 // TODO: Any attribute should actually be fine to use here.
715 4 parent_dims := 0;
716 4 b := Class.lookupAttributeBinding("start", InstNode.getClass(component));
717 4 b := Binding.mapExp(b, function Expression.filterSplitIndices(node = component));
718 end if;
719 end if;
720
721 (dim, ty_err) := match b
722 // Print an error if there's no binding.
723 case Binding.UNBOUND()
724 guard not InstContext.inRelaxed(context)
725 algorithm
726 2 Error.addSourceMessage(Error.FAILURE_TO_DEDUCE_DIMS_NO_MOD,
727 {String(index), InstNode.name(component)}, info);
728 1 then
729 fail();
730
731 case Binding.UNTYPED_BINDING()
732 1023 then deduceDimensionFromExp(b.bindingExp, NONE(), index, parent_dims, component, context, info);
733
734 case Binding.TYPED_BINDING()
735 16 then deduceDimensionFromExp(b.bindingExp, SOME(b.bindingType), index, parent_dims, component, context, info);
736 2 else (dimension, TypingError.NO_ERROR());
737 end match;
738
739 () := match ty_err
740 case TypingError.OUT_OF_BOUNDS()
741 guard not InstContext.inRelaxed(context)
742 algorithm
743 3 Error.addSourceMessage(Error.DIMENSION_DEDUCTION_FROM_BINDING_FAILURE,
744 {String(index), InstNode.name(component), Binding.toString(b)}, info);
745 1 then
746 fail();
747
748 else ();
749 end match;
750
751 // Make sure the dimension is constant evaluated, and also mark it as structural.
752 dim := match dim
753 case Dimension.EXP(exp = exp)
754 algorithm
755 1 Structural.markExp(exp);
756
757
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if InstContext.inRelaxed(context) then
758 ✗ exp := Ceval.tryEvalExp(exp);
759 else
760 2 target := Ceval.EvalTarget.new(info, context,
761 SOME(Ceval.EvalTargetData.DIMENSION_DATA(component, index, exp)));
762 1 exp := Ceval.evalExp(exp, target);
763 end if;
764
765 1 exp := subscriptDimExp(exp, component);
766 1 then
767 Dimension.fromExp(exp, dim.var);
768
769 case Dimension.UNKNOWN()
770 guard not InstContext.inRelaxed(context)
771 algorithm
772 ✗ Error.addInternalError(getInstanceName() + " returned unknown dimension in a non-function context", info);
773 ✗ then
774 fail();
775
776 else dim;
777 end match;
778
779 1037 arrayUpdate(dimensions, index, dim);
780 then
781 dim;
782
783 // Other kinds of dimensions are already typed.
784 else dimension;
785 end match;
786 end typeDimension;
787
788 function deduceDimensionFromExp
789 input Expression exp;
790 input Option<Type> ty;
791 input Integer index;
792 input Integer parentDims;
793 input InstNode component;
794 input InstContext.Type context;
795 input SourceInfo info;
796 output Dimension dim;
797 output TypingError error;
798 protected
799 Option<Expression> oe;
800 Expression e;
801 Integer dim_index;
802 algorithm
803 // If the binding expression comes from a parent of the component rather than
804 // the component iself the dimension index needs to be offset by the number of
805 // dimensions of the parent(s).
806 1039 dim_index := index + parentDims;
807
808
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1023 times.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
1039 if isSome(ty) and not Type.isConditionalArray(Util.getOption(ty)) then
809 // If the type is known, take the dimension directly from it.
810 16 (dim, error) := nthDimensionBoundsChecked(Util.getOption(ty), dim_index);
811
812
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 9 times.
16 if Dimension.isUnknown(dim) then
813 // Fall back to typing the expression if the dimension we got from the
814 // type is unknown, which can happen when the type of the binding isn't
815 // fully typed yet due to cyclic dependencies.
816 7 (dim, oe, error) := typeExpDim(exp, dim_index,
817 InstContext.set(context, NFInstContext.DIMENSION), info);
818 else
819 9 oe := NONE();
820 end if;
821 else
822 // If the type is unknown, try to type the expression only as much as is
823 // needed to get the dimension we're looking for.
824 1023 (dim, oe, error) := typeExpDim(exp, dim_index,
825 InstContext.set(context, NFInstContext.DIMENSION), info);
826 end if;
827
828 // If the deduced dimension is unknown, evaluate the binding and try again.
829
4/4
✓ Branch 1 taken 1026 times.
✓ Branch 2 taken 10 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 9 times.
1036 if Dimension.isUnknown(dim) and not TypingError.isError(error) then
830 // Use the typed expression from typeExpDim if it was returned.
831
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 e := if isSome(oe) then Util.getOption(oe) else exp;
832
833
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
9 if InstContext.inRelaxed(context) then
834 6 e := Ceval.tryEvalExp(e);
835 else
836 6 e := Ceval.evalExp(e, Ceval.EvalTarget.new(info, context,
837 SOME(Ceval.EvalTargetData.DIMENSION_DATA(component, index, e))));
838 end if;
839
840 9 (dim, error) := nthDimensionBoundsChecked(Expression.typeOf(e), dim_index);
841 end if;
842 end deduceDimensionFromExp;
843
844 function subscriptDimExp
845 "Tries to fix dimension expressions that are lacking subscripts after having
846 been evaluated."
847 input output Expression dimExp;
848 input InstNode component;
849 protected
850 Integer exp_dims, parent_dims;
851 InstNode parent;
852 list<Subscript> subs;
853 algorithm
854 86816 exp_dims := Expression.dimensionCount(dimExp, true);
855
856
1/2
✓ Branch 0 taken 86816 times.
✗ Branch 1 not taken.
86816 if exp_dims == 0 then
857 // If the expression is a scalar like it should we don't need to do anything.
858 86816 return;
859 end if;
860
861 // If the expression has too many dimensions, add split subscripts based on
862 // the component's parent's dimensions until we get a scalar expression.
863 subs := {};
864 ✗ parent := InstNode.instanceParent(component);
865
866 ✗ while exp_dims > 0 and not InstNode.isEmpty(parent) loop
867 ✗ parent_dims := InstNode.dimensionCount(parent);
868
869 ✗ for i in parent_dims:-1:1 loop
870 ✗ subs := Subscript.makeSplitIndex(parent, i) :: subs;
871 ✗ exp_dims := exp_dims - 1;
872
873 ✗ if exp_dims == 0 then
874 break;
875 end if;
876 end for;
877
878 ✗ parent := InstNode.instanceParent(parent);
879 end while;
880
881 ✗ dimExp := Expression.applySubscripts(subs, dimExp);
882 end subscriptDimExp;
883
884 function simplifyDimExp
885 input output Expression dimExp;
886 protected
887 Expression exp;
888 algorithm
889 dimExp := match dimExp
890 case Expression.ARRAY()
891 guard Expression.arrayAllEqual(dimExp)
892 ✗ then Expression.arrayFirstScalar(dimExp);
893
894 case Expression.SUBSCRIPTED_EXP(split = true)
895 guard Expression.isArray(dimExp.exp) and Expression.arrayAllEqual(dimExp.exp)
896 1 then Expression.arrayFirstScalar(dimExp.exp);
897
898 else dimExp;
899 end match;
900 end simplifyDimExp;
901
902 function makeDimension
903 input Expression dimExp;
904 input Expression unevaledExp;
905 input Variability variability;
906 output Dimension outDimension;
907 protected
908 Expression exp = dimExp;
909 algorithm
910 ✗ if Expression.isArray(exp) then
911 ✗ if Expression.arrayAllEqual(exp) then
912 ✗ exp := Expression.arrayFirstScalar(exp);
913 else
914
915 end if;
916 end if;
917
918 ✗ outDimension := Dimension.fromExp(exp, variability);
919 end makeDimension;
920
921 function getRecordElementBinding
922 "Tries to fetch the binding for a given record field by using the binding of
923 the record instance."
924 input InstNode component;
925 input InstContext.Type context;
926 output Binding binding;
927 output Integer parentDims = 0;
928 protected
929 InstNode parent;
930 Component comp;
931 Binding parent_binding;
932 algorithm
933 31 parent := InstNode.instanceParent(component);
934
935
2/2
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 4 times.
31 if InstNode.isComponent(parent) then
936 // Get the binding of the component's parent.
937 27 comp := InstNode.component(parent);
938 27 parent_binding := Component.getBinding(comp);
939
940
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 16 times.
27 if Binding.isUnbound(parent_binding) then
941 // If the parent has no binding, try the parent's parent.
942 11 (binding, parentDims) := getRecordElementBinding(parent, context);
943 else
944 // Otherwise type the binding, so we can safely look up the field name.
945 16 binding := typeBinding(parent_binding, InstContext.set(context, NFInstContext.DIMENSION));
946
947 // If the binding wasn't typed before, update the parent component with it
948 // so we don't have to type it again.
949
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 if not referenceEq(parent_binding, binding) then
950 10 InstNode.componentApply(parent, Component.setBinding, binding);
951 end if;
952 end if;
953
954 27 parentDims := parentDims + Component.dimensionCount(comp);
955
956 // If we found a binding, get the binding for the field from it.
957
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1 time.
27 if Binding.isBound(binding) then
958 26 binding := Binding.recordFieldBinding(component, binding);
959 end if;
960 else
961 binding := NFBinding.EMPTY_BINDING;
962 end if;
963 end getRecordElementBinding;
964
965 function typeBindings
966 input InstNode cls;
967 input InstContext.Type context;
968 protected
969 Class c;
970 ClassTree cls_tree;
971 algorithm
972 534237 c := InstNode.getClass(cls);
973
974 () := match c
975 case Class.INSTANCED_CLASS(elements = cls_tree as ClassTree.FLAT_TREE())
976 algorithm
977
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 71259 times.
✓ Branch 3 taken 513447 times.
✓ Branch 4 taken 71210 times.
655916 for c in cls_tree.components loop
978 513447 typeComponentBinding(c, context);
979 end for;
980 then
981 ();
982
983 case Class.INSTANCED_BUILTIN(elements = cls_tree as ClassTree.FLAT_TREE())
984 algorithm
985
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 455565 times.
✓ Branch 3 taken 4743108 times.
✓ Branch 4 taken 455559 times.
5654232 for c in cls_tree.components loop
986 4743108 typeComponentBinding(c, context);
987 end for;
988 then
989 ();
990
991 case Class.INSTANCED_BUILTIN() then ();
992
993 case Class.TYPED_DERIVED()
994 algorithm
995 5396 typeBindings(c.baseClass, context);
996 then
997 ();
998
999 else
1000 algorithm
1001 ✗ Error.terminate(getInstanceName() + " got uninstantiated class " + InstNode.name(cls), sourceInfo());
1002 ✗ then
1003 fail();
1004
1005 end match;
1006 end typeBindings;
1007
1008 function typeComponentBinding
1009 input InstNode component;
1010 input InstContext.Type context;
1011 input Boolean typeChildren = true;
1012 protected
1013 InstNode node;
1014 Component c;
1015 Binding binding;
1016 String name;
1017 Variability comp_var;
1018 Attributes attrs;
1019 Type ty;
1020 algorithm
1021
4/4
✓ Branch 1 taken 5571297 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 1532 times.
✓ Branch 5 taken 5569765 times.
5571302 if InstNode.isEmpty(component) or InstNode.isOnlyOuter(component) then
1022 1537 return;
1023 end if;
1024
1025 5569765 node := InstNode.resolveOuter(component);
1026 5569765 c := InstNode.component(node);
1027
1028 () := match c
1029 case Component.COMPONENT()
1030 guard Component.isDeleted(c) or Component.isInvalid(c)
1031 then ();
1032
1033 case Component.COMPONENT(binding = Binding.UNTYPED_BINDING(), attributes = attrs)
1034 guard c.state == ComponentState.Typed
1035 algorithm
1036 142061 name := InstNode.name(component);
1037 142061 binding := c.binding;
1038
1039 142061 ErrorExt.setCheckpoint(getInstanceName());
1040 try
1041 142061 binding := typeBinding(binding, InstContext.set(context, NFInstContext.BINDING));
1042
1043
3/8
✗ Branch 1 not taken.
✓ Branch 2 taken 142020 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 9 taken 142018 times.
✓ Branch 10 taken 2 times.
142020 if not (InstContext.inAnnotation(context) and stringEq(name, "graphics") or
1044 InstNode.isEmpty(c.classInst)) then
1045 142018 binding := TypeCheck.matchBinding(binding, c.ty, name, node, context);
1046 end if;
1047
1048 142017 comp_var := checkComponentBindingVariability(node, c, binding, context);
1049
1050
2/2
✓ Branch 0 taken 4839 times.
✓ Branch 1 taken 137175 times.
142014 if comp_var <> attrs.variability then
1051 4839 attrs.variability := comp_var;
1052 4839 c.attributes := attrs;
1053 end if;
1054 else
1055
3/4
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 46 times.
47 if Binding.isBound(c.condition) or InstContext.inInstanceAPI(context) then
1056 1 binding := Binding.INVALID_BINDING(binding, ErrorExt.getCheckpointMessages());
1057 else
1058 46 ErrorExt.delCheckpoint(getInstanceName());
1059 46 fail();
1060 end if;
1061 end try;
1062 142015 ErrorExt.delCheckpoint(getInstanceName());
1063
1064 142015 c.binding := binding;
1065 142015 c.state := ComponentState.TypeChecked;
1066
1067 142015 InstNode.updateComponent(c, node);
1068
1069
4/4
✓ Branch 0 taken 128164 times.
✓ Branch 1 taken 13851 times.
✓ Branch 3 taken 128162 times.
✓ Branch 4 taken 2 times.
142015 if typeChildren and not InstNode.isEmpty(c.classInst) then
1070 128162 typeBindings(c.classInst, context);
1071 end if;
1072 then
1073 ();
1074
1075 // A component without a binding, or with a binding that's already been typed.
1076 case Component.COMPONENT()
1077 guard c.state >= ComponentState.Typed
1078 algorithm
1079 // Type check the binding if it hasn't already been checked.
1080
2/2
✓ Branch 0 taken 329375 times.
✓ Branch 1 taken 234988 times.
564363 if c.state == ComponentState.Typed then
1081
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 329333 times.
329375 if Binding.isTyped(c.binding) then
1082 42 c.binding := TypeCheck.matchBinding(c.binding, c.ty, InstNode.name(component), node, context);
1083 42 checkComponentBindingVariability(component, c, c.binding, context);
1084 end if;
1085
1086 329375 c.state := ComponentState.TypeChecked;
1087 329375 InstNode.updateComponent(c, node);
1088 end if;
1089
1090
4/4
✓ Branch 0 taken 398904 times.
✓ Branch 1 taken 165459 times.
✓ Branch 3 taken 398903 times.
✓ Branch 4 taken 1 time.
564363 if typeChildren and not InstNode.isEmpty(c.classInst) then
1091 398903 typeBindings(c.classInst, context);
1092 end if;
1093 then
1094 ();
1095
1096 // An untyped component with a binding. This might happen when typing a
1097 // dimension and having to evaluate the binding of a not yet typed
1098 // component. Type only the binding and let the case above handle the rest.
1099 case Component.COMPONENT(binding = Binding.UNTYPED_BINDING(), attributes = attrs)
1100 guard c.state < ComponentState.Typed
1101 algorithm
1102 ✗ binding := typeBinding(c.binding, InstContext.set(context, NFInstContext.BINDING));
1103 ✗ comp_var := checkComponentBindingVariability(component, c, binding, context);
1104
1105 ✗ if comp_var <> attrs.variability then
1106 ✗ attrs.variability := comp_var;
1107 ✗ c.attributes := attrs;
1108 end if;
1109
1110 ✗ c.binding := binding;
1111 ✗ InstNode.updateComponent(c, node);
1112 then
1113 ();
1114
1115 // An untyped component without a binding or an already type checked component, do nothing.
1116 case Component.COMPONENT() then ();
1117
1118 case Component.ENUM_LITERAL() then ();
1119 case Component.TYPE_ATTRIBUTE(modifier = Modifier.NOMOD()) then ();
1120
1121 case Component.TYPE_ATTRIBUTE()
1122 algorithm
1123 763293 c.modifier := typeTypeAttribute(c.modifier, c.ty, component, context);
1124 763287 InstNode.updateComponent(c, node);
1125 then
1126 ();
1127
1128 case Component.INVALID_COMPONENT() then ();
1129
1130 else
1131 algorithm
1132 ✗ Error.terminate(getInstanceName() + " got invalid node " + InstNode.name(node), sourceInfo());
1133 ✗ then
1134 fail();
1135
1136 end match;
1137 end typeComponentBinding;
1138
1139 function checkComponentBindingVariability
1140 input InstNode node;
1141 input Component component;
1142 input Binding binding;
1143 input InstContext.Type context;
1144 output Variability var;
1145 protected
1146 Variability comp_eff_var, bind_var, bind_eff_var;
1147 algorithm
1148 142059 var := Component.variability(component);
1149 142059 comp_eff_var := Prefixes.effectiveVariability(var);
1150 142059 bind_var := Binding.variability(binding);
1151 142059 bind_eff_var := Prefixes.effectiveVariability(bind_var);
1152
1153
4/4
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 141797 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 258 times.
142059 if bind_eff_var > comp_eff_var and not InstContext.inFunction(context) then
1154 16 Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING, {
1155 InstNode.name(node),
1156 Prefixes.variabilityString(comp_eff_var),
1157 "'" + Binding.toString(Component.getBinding(component)) + "'",
1158 Prefixes.variabilityString(bind_eff_var)
1159 },
1160 Binding.getInfo(binding));
1161
1162
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
4 if not InstContext.inRelaxed(context) then
1163 3 fail();
1164 end if;
1165 end if;
1166
1167
2/2
✓ Branch 0 taken 103067 times.
✓ Branch 1 taken 38989 times.
142056 if var == Variability.PARAMETER then
1168
6/6
✓ Branch 0 taken 24547 times.
✓ Branch 1 taken 14442 times.
✓ Branch 3 taken 22204 times.
✓ Branch 4 taken 2343 times.
✓ Branch 6 taken 19833 times.
✓ Branch 7 taken 2371 times.
38989 if bind_var <= Variability.STRUCTURAL_PARAMETER and
1169 (InstNode.isInheritedProtected(node) or Component.isFinal(component)) then
1170 // A protected or final parameter with a structural parameter binding should also be evaluated.
1171 var := Variability.STRUCTURAL_PARAMETER;
1172 elseif bind_var == Variability.NON_STRUCTURAL_PARAMETER then
1173 // A parameter with a non-structural parameter binding should not be evaluated.
1174 var := Variability.NON_STRUCTURAL_PARAMETER;
1175 end if;
1176 end if;
1177 end checkComponentBindingVariability;
1178
1179 function typeBinding
1180 input output Binding binding;
1181 input InstContext.Type context;
1182 algorithm
1183 binding := match binding
1184 local
1185 Expression exp;
1186 Type ty;
1187 Variability var;
1188 Purity purity;
1189 SourceInfo info;
1190
1191 case Binding.UNTYPED_BINDING(bindingExp = exp)
1192 algorithm
1193 822403 info := Binding.getInfo(binding);
1194 822403 (exp, ty, var, purity) := typeExp(exp, context, info);
1195 822362 then
1196 Binding.TYPED_BINDING(exp, ty, var, purity, binding.eachType,
1197 Mutable.create(NFBinding.EvalState.NOT_EVALUATED), false,
1198 binding.source, binding.confidence, binding.info);
1199
1200 case Binding.TYPED_BINDING() then binding;
1201 case Binding.UNBOUND() then binding;
1202
1203 else
1204 algorithm
1205 ✗ Error.terminate(getInstanceName() + " got uninstantiated binding", sourceInfo());
1206 ✗ then
1207 fail();
1208
1209 end match;
1210 end typeBinding;
1211
1212 function typeComponentCondition
1213 input output Binding condition;
1214 input InstContext.Type context;
1215 input Boolean evaluate = false;
1216 algorithm
1217 condition := match condition
1218 local
1219 Expression exp;
1220 Type ty;
1221 Variability var;
1222 Purity purity;
1223 SourceInfo info;
1224 MatchKind mk;
1225 NFBinding.EvalState eval_state;
1226 InstContext.Type next_context;
1227
1228 case Binding.UNTYPED_BINDING(bindingExp = exp)
1229 algorithm
1230 5560 next_context := InstContext.set(context, NFInstContext.CONDITION);
1231 5560 info := Binding.getInfo(condition);
1232 5560 (exp, ty, var, purity) := typeExp(exp, next_context, info);
1233 5560 (exp, _, mk) := TypeCheck.matchTypes(ty, Type.BOOLEAN(), exp);
1234
1235
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5559 times.
5560 if TypeCheck.isIncompatibleMatch(mk) then
1236 3 Error.addSourceMessage(Error.IF_CONDITION_TYPE_ERROR,
1237 {Expression.toString(exp), Type.toString(ty)}, info);
1238 1 fail();
1239 end if;
1240
1241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5559 times.
5559 if var > Variability.PARAMETER then
1242 ✗ Error.addSourceMessage(Error.COMPONENT_CONDITION_VARIABILITY,
1243 {Expression.toString(exp)}, info);
1244 ✗ fail();
1245 end if;
1246
1247 5559 eval_state := NFBinding.EvalState.NOT_EVALUATED;
1248
1249
1/2
✓ Branch 0 taken 5559 times.
✗ Branch 1 not taken.
5559 if evaluate then
1250 5559 ErrorExt.setCheckpoint(getInstanceName());
1251 try
1252 5559 exp := Ceval.evalExp(exp, Ceval.EvalTarget.new(info, next_context));
1253 5559 exp := simplifyDimExp(exp);
1254 eval_state := NFBinding.EvalState.EVALUATED;
1255 else
1256 end try;
1257 5559 ErrorExt.rollBack(getInstanceName());
1258 end if;
1259 5559 then
1260 Binding.TYPED_BINDING(exp, ty, var, purity, NFBinding.EachType.NOT_EACH,
1261 Mutable.create(eval_state), false, condition.source, condition.confidence, info);
1262
1263 end match;
1264 end typeComponentCondition;
1265
1266 function typeTypeAttribute
1267 input output Modifier attribute;
1268 input Type attrType;
1269 input InstNode component;
1270 input InstContext.Type context;
1271 protected
1272 String name;
1273 Binding binding;
1274 InstNode parent;
1275 algorithm
1276 attribute := match attribute
1277 // Modifier with submodifier, e.g. Real x(start(y = 1)), is an error.
1278 case Modifier.MODIFIER()
1279 guard not ModTable.isEmpty(attribute.subModifiers)
1280 algorithm
1281 // Print an error for the first submodifier. The builtin attributes
1282 // don't have types as such, so for the error message to make sense we
1283 // join the attribute name and submodifier name together (e.g. start.y).
1284 1 name := attribute.name + "." + Util.tuple21(listHead(ModTable.toList(attribute.subModifiers)));
1285 2 Error.addSourceMessage(Error.MISSING_MODIFIED_ELEMENT,
1286 {name, Type.toString(attrType)}, attribute.info);
1287 1 then
1288 fail();
1289
1290 // Modifier with no binding, e.g. Real x(final start).
1291 // Remove it so we don't have to deal with it in later.
1292 case Modifier.MODIFIER()
1293 guard Binding.isUnbound(attribute.binding)
1294 then
1295 NFModifier.NOMOD();
1296
1297 // Modifier that has already been typed.
1298 case Modifier.MODIFIER(binding = Binding.TYPED_BINDING())
1299 then attribute;
1300
1301 // Normal modifier with no submodifiers.
1302 case Modifier.MODIFIER(name = name, binding = binding)
1303 algorithm
1304 // Type and type check the attribute.
1305
1/2
✓ Branch 1 taken 680266 times.
✗ Branch 2 not taken.
680266 if Binding.isBound(binding) then
1306 680266 binding := typeBinding(binding, context);
1307 680266 parent := InstNode.parent(component);
1308 680266 binding := TypeCheck.matchBinding(binding, attrType, name, parent, context);
1309
1310 // Check the variability. All builtin attributes have parameter variability,
1311 // unless we're in a function in which case we don't care.
1312
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 680261 times.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
680262 if Binding.variability(binding) >= Variability.DISCRETE and not InstContext.inFunction(context) then
1313 3 Error.addSourceMessage(Error.HIGHER_VARIABILITY_BINDING,
1314 {name, Prefixes.variabilityString(Variability.PARAMETER),
1315 "'" + Binding.toString(binding) + "'", Prefixes.variabilityString(Binding.variability(binding))},
1316 Binding.getInfo(binding));
1317 1 fail();
1318 end if;
1319
1320 680261 attribute.binding := binding;
1321 end if;
1322 then
1323 attribute;
1324
1325 end match;
1326 end typeTypeAttribute;
1327
1328 function typeExp
1329 "Types an untyped expression, returning the typed expression itself along with
1330 its type and variability."
1331 input output Expression exp;
1332 input InstContext.Type context;
1333 input SourceInfo info;
1334 input Boolean retype = false;
1335 output Type ty;
1336 output Variability variability;
1337 output Purity purity;
1338 algorithm
1339 (exp, ty, variability, purity) := match exp
1340 local
1341 Expression e1, e2;
1342 Variability var1, var2;
1343 Purity pur1, pur2;
1344 Type ty1, ty2;
1345 InstContext.Type next_context;
1346
1347 341211 case Expression.INTEGER() then (exp, Type.INTEGER(), Variability.CONSTANT, Purity.PURE);
1348 299418 case Expression.REAL() then (exp, Type.REAL(), Variability.CONSTANT, Purity.PURE);
1349 498238 case Expression.STRING() then (exp, Type.STRING(), Variability.CONSTANT, Purity.PURE);
1350 44969 case Expression.BOOLEAN() then (exp, Type.BOOLEAN(), Variability.CONSTANT, Purity.PURE);
1351 19862 case Expression.ENUM_LITERAL() then (exp, exp.ty, Variability.CONSTANT, Purity.PURE);
1352 1052462 case Expression.CREF() then typeCrefExp(exp.cref, context, info);
1353
1354 case Expression.TYPENAME()
1355 algorithm
1356
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 55 times.
56 if not InstContext.inValidTypenameScope(context) then
1357 // Typenames may only be used as iteration ranges or dimensions.
1358 2 Error.addSourceMessage(Error.INVALID_TYPENAME_USE,
1359 {Type.typenameString(Type.arrayElementType(exp.ty))}, info);
1360 1 fail();
1361 end if;
1362 55 then
1363 (exp, exp.ty, Variability.CONSTANT, Purity.PURE);
1364
1365 23840 case Expression.ARRAY() then typeArray(exp.elements, exp.literal, exp.ty, context, info);
1366 2174 case Expression.MATRIX() then typeMatrix(exp.elements, context, info);
1367 9854 case Expression.RANGE() then typeRange(exp, context, info);
1368 955 case Expression.TUPLE() then typeTuple(exp.elements, context, info);
1369 2034 case Expression.SIZE() then typeSize(exp, context, info);
1370
1371 case Expression.END()
1372 algorithm
1373 // end is replaced in subscripts before we get here, so any end still
1374 // left should be outside a subscript and thus illegal.
1375 ✗ Error.addSourceMessage(Error.END_ILLEGAL_USE_ERROR, {}, info);
1376 ✗ then
1377 fail();
1378
1379 case Expression.BINARY()
1380 algorithm
1381 613566 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1382 613566 (e1, ty1, var1, pur1) := typeExp(exp.exp1, next_context, info);
1383 613566 (e2, ty2, var2, pur2) := typeExp(exp.exp2, next_context, info);
1384 613565 (exp, ty) := TypeCheck.checkBinaryOperation(e1, ty1, var1, exp.operator, e2, ty2, var2, context, info, retype);
1385 613562 then
1386 (exp, ty, Prefixes.variabilityMax(var1, var2), Prefixes.purityMin(pur1, pur2));
1387
1388 case Expression.UNARY()
1389 algorithm
1390 35433 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1391 35433 (e1, ty1, var1, pur1) := typeExp(exp.exp, next_context, info);
1392 35433 (exp, ty) := TypeCheck.checkUnaryOperation(e1, ty1, var1, exp.operator, context, info);
1393 35433 then
1394 (exp, ty, var1, pur1);
1395
1396 case Expression.LBINARY()
1397 algorithm
1398 9890 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1399 9890 (e1, ty1, var1, pur1) := typeExp(exp.exp1, next_context, info);
1400 9890 (e2, ty2, var2, pur2) := typeExp(exp.exp2, next_context, info);
1401 9890 (exp, ty) := TypeCheck.checkLogicalBinaryOperation(e1, ty1, var1, exp.operator, e2, ty2, var2, context, info);
1402 9890 then
1403 (exp, ty, Prefixes.variabilityMax(var1, var2), Prefixes.purityMin(pur1, pur2));
1404
1405 case Expression.LUNARY()
1406 algorithm
1407 3668 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1408 3668 (e1, ty1, var1, pur1) := typeExp(exp.exp, next_context, info);
1409 3668 (exp, ty) := TypeCheck.checkLogicalUnaryOperation(e1, ty1, var1, exp.operator, context, info);
1410 3668 then
1411 (exp, ty, var1, pur1);
1412
1413 case Expression.RELATION()
1414 algorithm
1415 30433 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1416 30433 (e1, ty1, var1, pur1) := typeExp(exp.exp1, next_context, info);
1417 30432 (e2, ty2, var2, pur2) := typeExp(exp.exp2, next_context, info);
1418 30432 (exp, ty) := TypeCheck.checkRelationOperation(e1, ty1, var1, exp.operator, e2, ty2, var2, exp.index, context, info);
1419 30432 variability := Prefixes.variabilityMax(var1, var2);
1420 30432 purity := Prefixes.purityMin(pur1, pur2);
1421
1422 // A relation involving continuous expressions which is not inside
1423 // noEvent is a discrete expression.
1424
4/4
✓ Branch 1 taken 29524 times.
✓ Branch 2 taken 908 times.
✓ Branch 3 taken 3354 times.
✓ Branch 4 taken 26170 times.
30432 if not InstContext.inNoEvent(context) and variability == Variability.CONTINUOUS then
1425 3354 variability := Variability.DISCRETE;
1426 end if;
1427 30432 then
1428 (exp, ty, variability, purity);
1429
1430 14225 case Expression.IF() then typeIfExpression(exp, context, info);
1431 54 case Expression.RECORD() then typeRecordExp(exp, context, info);
1432
1433 case Expression.CALL()
1434 algorithm
1435 103303 (e1, ty, var1, pur1) := Call.typeCall(exp, context, info, retype);
1436 // If the call has multiple outputs and isn't alone on either side of an
1437 // equation/algorithm, select the first output.
1438
4/4
✓ Branch 1 taken 1132 times.
✓ Branch 2 taken 102133 times.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 1067 times.
103265 if Type.isTuple(ty) and not InstContext.isSingleExpression(context) then
1439 65 ty := Type.firstTupleType(ty);
1440 65 e1 := Expression.tupleElement(e1, 1);
1441 end if;
1442 103265 then
1443 (e1, ty, var1, pur1);
1444
1445 case Expression.CAST()
1446 algorithm
1447 36 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1448 36 (e1, ty, variability, purity) := typeExp(exp.exp, next_context, info, retype);
1449 36 exp.exp := e1;
1450 36 exp.ty := Type.copyDims(ty, exp.ty);
1451 36 then
1452 (exp, exp.ty, variability, purity);
1453
1454 case Expression.SUBSCRIPTED_EXP()
1455 711102 then typeSubscriptedExp(exp, context, info);
1456
1457 case Expression.RECORD_ELEMENT(ty = Type.UNKNOWN())
1458 ✗ then typeRecordElement(exp, context, info);
1459
1460 case Expression.MUTABLE()
1461 algorithm
1462 1 e1 := Mutable.access(exp.exp);
1463 1 (e1, ty, variability, purity) := typeExp(e1, context, info, retype);
1464 1 exp.exp := Mutable.create(e1);
1465 1 then
1466 (exp, ty, variability, purity);
1467
1468 case Expression.PARTIAL_FUNCTION_APPLICATION()
1469 27 then Function.typePartialApplication(exp, context, info);
1470
1471 ✗ case Expression.FILENAME() then (exp, Type.STRING(), Variability.CONSTANT, Purity.PURE);
1472
1473 412 case Expression.MULTARY() then typeExp(SimplifyExp.splitMultary(exp), context, info, retype);
1474
1475 14 else (exp, Expression.typeOf(exp), Expression.variability(exp), Expression.purity(exp));
1476
1477 end match;
1478
1479 // Expressions inside when-clauses and initial sections are discrete.
1480
4/4
✓ Branch 1 taken 1681394 times.
✓ Branch 2 taken 2135779 times.
✓ Branch 3 taken 1517721 times.
✓ Branch 4 taken 618058 times.
3817173 if InstContext.inDiscreteScope(context) and variability == Variability.CONTINUOUS then
1481 618058 variability := Variability.DISCRETE;
1482 end if;
1483 end typeExp;
1484
1485 function typeExpl
1486 input list<Expression> expl;
1487 input InstContext.Type context;
1488 input SourceInfo info;
1489 output list<Expression> explTyped = {};
1490 output list<Type> tyl = {};
1491 output list<Variability> varl = {};
1492 protected
1493 Expression exp;
1494 Variability var;
1495 Type ty;
1496 algorithm
1497
2/2
✓ Branch 1 taken 2200 times.
✓ Branch 2 taken 954 times.
3154 for e in listReverse(expl) loop
1498 2200 (exp, ty, var) := typeExp(e, context, info);
1499 explTyped := exp :: explTyped;
1500 2200 tyl := ty :: tyl;
1501 2200 varl := var :: varl;
1502 end for;
1503 end typeExpl;
1504
1505 function typeRecordExp
1506 input output Expression exp;
1507 input InstContext.Type context;
1508 input SourceInfo info;
1509 output Type ty;
1510 output Variability variability = Variability.CONSTANT;
1511 output Purity purity = Purity.PURE;
1512 protected
1513 Absyn.Path path;
1514 list<Expression> elems, ty_elems = {};
1515 Variability var;
1516 Purity pur;
1517 InstContext.Type next_context;
1518 algorithm
1519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 Expression.RECORD(path, ty, elems) := exp;
1520 54 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
1521
1522
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 54 times.
200 for e in elems loop
1523 146 (e, _, var, pur) := typeExp(e, context, info);
1524 146 variability := Prefixes.variabilityMax(var, variability);
1525 146 purity := Prefixes.purityMin(pur, purity);
1526 ty_elems := e :: ty_elems;
1527 end for;
1528
1529 54 exp := Expression.makeRecord(path, ty, listReverseInPlace(ty_elems));
1530 end typeRecordExp;
1531
1532 function typeRecordElement
1533 input Expression exp;
1534 input InstContext.Type context;
1535 input SourceInfo info;
1536 output Expression outExp;
1537 output Type ty;
1538 output Variability variability;
1539 output Purity purity;
1540 protected
1541 Expression rec_exp;
1542 Type rec_ty;
1543 String name;
1544 Boolean found;
1545 algorithm
1546 ✗ Expression.RECORD_ELEMENT(recordExp = rec_exp, fieldName = name) := exp;
1547 ✗ (rec_exp, rec_ty, variability, purity) :=
1548 typeExp(rec_exp, InstContext.set(context, NFInstContext.SUBEXPRESSION), info);
1549
1550 ✗ found := Type.isRecord(Type.arrayElementType(rec_ty));
1551 ✗ if found then
1552 try
1553 ✗ _ := Class.lookupComponentIndex(name,
1554 InstNode.getClass(Type.complexNode(Type.arrayElementType(rec_ty))));
1555 else
1556 found := false;
1557 end try;
1558 end if;
1559
1560 ✗ if not found then
1561 ✗ Error.addSourceMessage(Error.RECORD_ELEMENT_NOT_FOUND,
1562 {Expression.toString(rec_exp), Type.toString(rec_ty), name}, info);
1563 ✗ fail();
1564 end if;
1565
1566 ✗ outExp := Expression.recordElement(name, rec_exp);
1567 ✗ ty := Expression.typeOf(outExp);
1568 end typeRecordElement;
1569
1570 function typeSubscriptedExp
1571 input output Expression exp;
1572 input InstContext.Type context;
1573 input SourceInfo info;
1574 output Type ty;
1575 output Variability variability;
1576 output Purity purity;
1577 protected
1578 Expression e;
1579 list<Subscript> subs, expanded_subs;
1580 list<Expression> fill_dims;
1581 Boolean split;
1582 Variability subs_var;
1583 algorithm
1584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 711102 times.
711102 Expression.SUBSCRIPTED_EXP(e, subs, ty, split) := exp;
1585
1586 // split = true means the expression is subscripted because it came from a
1587 // modifier that was propagated down. In this case it should have proxy
1588 // subscripts that we need to deal with.
1589
2/2
✓ Branch 0 taken 711088 times.
✓ Branch 1 taken 14 times.
711102 if split then
1590 // Expand proxy subscripts into split index subscripts.
1591 711088 (expanded_subs, fill_dims) := expandProxySubscripts(subs, context);
1592
1593 // Type the expression that's being subscripted.
1594 //(exp, ty, variability, purity) := typeExp(e, context, info);
1595 711088 (exp, ty, variability, purity) := typeSubscriptedExp2(e, expanded_subs, context, info);
1596
1597 // If we have fill dimensions, use them to create a fill call.
1598
2/2
✓ Branch 0 taken 80862 times.
✓ Branch 1 taken 630226 times.
711088 if not listEmpty(fill_dims) then
1599 80862 fill_dims := listReverseInPlace(fill_dims);
1600
4/4
✓ Branch 0 taken 83226 times.
✓ Branch 1 taken 80862 times.
✓ Branch 2 taken 83226 times.
✓ Branch 3 taken 80862 times.
164088 ty := Type.liftArrayLeftList(ty, list(Dimension.fromExp(d, Variability.CONSTANT) for d in fill_dims));
1601 80862 exp := Expression.CALL(
1602 Call.makeTypedCall(NFBuiltinFuncs.FILL_FUNC, exp :: fill_dims, variability, purity, ty));
1603 end if;
1604
1605 // If we have any subscripts after expanding the proxies we create a new
1606 // subscripted expression. Otherwise we can just return the typed expression
1607 // as it is.
1608
2/2
✓ Branch 0 taken 88407 times.
✓ Branch 1 taken 622681 times.
711088 if not listEmpty(expanded_subs) then
1609 // Subscripting the expression might not be possible if the type is wrong,
1610 // but we ignore it here so we can handle it during type checking instead
1611 // when we can give better error messages.
1612 88407 ty := Type.subscript(ty, expanded_subs, failOnError = false);
1613
1614
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 88405 times.
88407 if Type.isUnknown(ty) then
1615 2 exp := Expression.SUBSCRIPTED_EXP(exp, expanded_subs, ty, true);
1616 else
1617 88405 exp := Expression.applySubscripts(expanded_subs, exp);
1618 end if;
1619
1620 // Take the purity and variability of the subscripts into consideration.
1621
2/2
✓ Branch 0 taken 88207 times.
✓ Branch 1 taken 200 times.
88407 if purity == Purity.PURE then
1622 88207 purity := Subscript.purityList(expanded_subs);
1623 end if;
1624
1625
2/2
✓ Branch 0 taken 87481 times.
✓ Branch 1 taken 926 times.
88407 if variability <> Variability.CONTINUOUS then
1626 87481 variability := Prefixes.variabilityMax(variability,
1627 Subscript.variabilityList(expanded_subs));
1628 end if;
1629 end if;
1630 else
1631 14 (e, ty, variability, purity) := typeExp(e, context, info);
1632 14 (subs, subs_var) := typeSubscripts(subs, ty, exp, context, info);
1633 14 ty := Type.subscript(ty, subs);
1634 14 exp := Expression.SUBSCRIPTED_EXP(e, subs, ty, false);
1635 end if;
1636 end typeSubscriptedExp;
1637
1638 function expandProxySubscripts
1639 "Expand proxy subscripts into split index subscripts. A proxy subscript
1640 generates as many index subscripts as the number of dimensions on the
1641 element it refers to (which might be none if the element is a scalar)."
1642 input list<Subscript> subscripts;
1643 input InstContext.Type context;
1644 output list<Subscript> outSubscripts = {};
1645 output list<Expression> fillDimensions = {};
1646 protected
1647 Integer dim_count;
1648 Expression cr_exp;
1649 Type ty;
1650 list<Dimension> dims;
1651 Dimension dim;
1652 algorithm
1653
2/2
✓ Branch 0 taken 724283 times.
✓ Branch 1 taken 711088 times.
1435371 for s in subscripts loop
1654 outSubscripts := match s
1655 case Subscript.SPLIT_PROXY()
1656 algorithm
1657 // Count the number of dimensions on the parent the subscript came
1658 // from, and add that many split index subscripts to the list.
1659 724282 dim_count := InstNode.dimensionCount(InstNode.borrow(s.parent));
1660
1661
2/2
✓ Branch 0 taken 88408 times.
✓ Branch 1 taken 635874 times.
815061 for i in 1:dim_count loop
1662 90779 outSubscripts := Subscript.makeSplitIndex(InstNode.borrow(s.parent), i) :: outSubscripts;
1663 end for;
1664
1665 // If the origin and parent of the subscript is not the same it
1666 // means the expression comes from a class modifier, like
1667 // type T = Real[3](start = {1, 2, 3}).
1668 // In this case we might need to add dimensions when applying the
1669 // binding expression to a component. For a component like
1670 // T x[1, 2]
1671 // we then have origin = T and parent = x and generate
1672 // T x[1, 2](start = fill({1, 2, 3}, size(x, 1), size(x, 2))).
1673
2/2
✓ Branch 3 taken 556982 times.
✓ Branch 4 taken 167300 times.
724282 if not InstNode.refEqual(InstNode.borrow(s.origin), InstNode.borrow(s.parent)) then
1674 // The number of fill dimensions is size(parent) - size(origin).
1675 556982 dim_count := dim_count - InstNode.dimensionCount(InstNode.borrow(s.origin));
1676
1677 // Add size expressions to the list of fill dimensions.
1678
2/2
✓ Branch 0 taken 80862 times.
✓ Branch 1 taken 476120 times.
556982 if dim_count > 0 then
1679 80862 ty := InstNode.getType(InstNode.borrow(s.parent));
1680 80862 cr_exp := Expression.fromCref(ComponentRef.fromNode(InstNode.borrow(s.parent), ty));
1681 80862 dims := Type.arrayDims(ty);
1682
1683 164088 for i in 1:dim_count loop
1684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83226 times.
83226 dim :: dims := dims;
1685
1686
2/2
✓ Branch 1 taken 81837 times.
✓ Branch 2 taken 1389 times.
83226 if Dimension.isKnown(dim, allowExp = true) then
1687 81837 fillDimensions := Dimension.sizeExp(dim) :: fillDimensions;
1688 else
1689 2778 fillDimensions := Expression.SIZE(cr_exp, SOME(Expression.INTEGER(i))) :: fillDimensions;
1690 end if;
1691 end for;
1692 end if;
1693 end if;
1694 then
1695 outSubscripts;
1696
1697 else s :: outSubscripts;
1698 end match;
1699 end for;
1700
1701 711088 outSubscripts := List.trim(outSubscripts, Subscript.isWhole);
1702 711088 outSubscripts := listReverseInPlace(outSubscripts);
1703 end expandProxySubscripts;
1704
1705 function typeSubscriptedExp2
1706 input Expression exp;
1707 input list<Subscript> splitSubs;
1708 input InstContext.Type context;
1709 input SourceInfo info;
1710 output Expression outExp;
1711 output Type ty = Type.UNKNOWN();
1712 output Variability variability;
1713 output Purity purity;
1714 protected
1715 list<Expression> expl;
1716 algorithm
1717 (outExp, ty, variability, purity) := match exp
1718 case Expression.ARRAY()
1719 guard not listEmpty(splitSubs) and not arrayEmpty(exp.elements)
1720 algorithm
1721 expl := {};
1722 3728 variability := Variability.CONSTANT;
1723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3728 times.
3728 purity := Purity.PURE;
1724
1725
2/2
✓ Branch 1 taken 11173 times.
✓ Branch 2 taken 3728 times.
14901 for e in exp.elements loop
1726 11173 (e, ty, variability, purity) := typeSubscriptedExp2(e, listRest(splitSubs), context, info);
1727 expl := e :: expl;
1728 end for;
1729
1730 3728 expl := listReverseInPlace(expl);
1731 3728 ty := Type.liftArrayLeft(ty, Dimension.fromInteger(listLength(expl)));
1732 3728 outExp := Expression.makeArray(ty, listArray(expl), exp.literal);
1733 3728 then
1734 (outExp, ty, variability, purity);
1735
1736 718533 else typeExp(exp, context, info);
1737 end match;
1738 end typeSubscriptedExp2;
1739
1740 function typeExpDim
1741 "Returns the requested dimension of the given expression, while doing as
1742 little typing as possible. This function returns TypingError.OUT_OF_BOUNDS if
1743 the given index doesn't refer to a valid dimension, in which case the
1744 returned dimension is undefined."
1745 input Expression exp;
1746 input Integer dimIndex;
1747 input InstContext.Type context;
1748 input SourceInfo info;
1749 output Dimension dim;
1750 output Option<Expression> typedExp = NONE();
1751 output TypingError error;
1752 protected
1753 Type ty;
1754 Expression e;
1755 InstContext.Type next_context;
1756 algorithm
1757 7359 ty := Expression.typeOf(exp);
1758
1759 // If the expression has already been typed, just get the dimension from the type.
1760
2/2
✓ Branch 1 taken 4241 times.
✓ Branch 2 taken 3118 times.
7359 if Type.isKnown(ty) then
1761 4241 (dim, error) := nthDimensionBoundsChecked(ty, dimIndex);
1762 typedExp := SOME(exp);
1763
1764
2/2
✓ Branch 1 taken 4109 times.
✓ Branch 2 taken 132 times.
4241 if not Dimension.isUnknown(dim) then
1765 4109 return;
1766 end if;
1767 end if;
1768
1769 // Clear any scope flags. For dimensions we only really care about if we're
1770 // in a class or function and other flags shouldn't influence the typing.
1771 3250 next_context := InstContext.clearExpFlags(context);
1772
1773 // Otherwise we try to type as little as possible of the expression to get
1774 // the dimension we need, to avoid introducing unnecessary cycles.
1775 (dim, error) := match exp
1776 // An untyped array, use typeArrayDim to get the dimension.
1777 case Expression.ARRAY(ty = Type.UNKNOWN())
1778 150 then typeArrayDim(exp, dimIndex);
1779
1780 // A cref, use typeCrefDim to get the dimension.
1781 case Expression.CREF()
1782 2223 then typeCrefDim(exp.cref, dimIndex, next_context, info);
1783
1784 // Any other expression, type the whole expression and get the dimension
1785 // from the type.
1786 else
1787 algorithm
1788 877 (e, ty, _) := typeExp(exp, next_context, info);
1789
1790
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 874 times.
874 if Type.isTuple(ty) then
1791 ✗ ty := Type.firstTupleType(ty);
1792 ✗ e := Expression.tupleElement(e, 1);
1793 end if;
1794
1795
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 852 times.
874 if Type.isConditionalArray(ty) then
1796 22 e := Expression.map(e,
1797 function evaluateArrayIf(target = Ceval.EvalTarget.new(info, next_context)));
1798 22 (e, ty, _) := typeExp(e, next_context, info);
1799 end if;
1800
1801 typedExp := SOME(e);
1802 874 then
1803 nthDimensionBoundsChecked(ty, dimIndex);
1804
1805 end match;
1806 end typeExpDim;
1807
1808 function evaluateArrayIf
1809 input Expression exp;
1810 input Ceval.EvalTarget target;
1811 output Expression outExp;
1812 algorithm
1813 outExp := match exp
1814 local
1815 Expression cond;
1816
1817 case Expression.IF() guard Type.isConditionalArray(exp.ty)
1818 algorithm
1819 22 cond := Ceval.evalExp(exp.condition, target);
1820
1821
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 1 time.
22 if Expression.isTrue(cond) then
1822 21 outExp := exp.trueBranch;
1823 elseif Expression.isFalse(cond) then
1824 1 outExp := exp.falseBranch;
1825 else
1826 ✗ Error.addInternalError(getInstanceName() + " failed on " +
1827 Expression.toString(exp), Ceval.EvalTarget.getInfo(target));
1828 ✗ fail();
1829 end if;
1830 then
1831 outExp;
1832
1833 else exp;
1834 end match;
1835 end evaluateArrayIf;
1836
1837 function typeArrayDim
1838 "Returns the requested dimension of an array dimension. This function is meant
1839 to be used on an untyped array, for a typed array it's better to just use
1840 e.g. nthDimensionBoundsChecked on its type."
1841 input Expression arrayExp;
1842 input Integer dimIndex;
1843 output Dimension dim;
1844 output TypingError error;
1845 algorithm
1846 // We don't yet know the number of dimensions, but the index must at least be 1.
1847
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 150 times.
150 if dimIndex < 1 then
1848 dim := Dimension.UNKNOWN();
1849 ✗ error := TypingError.OUT_OF_BOUNDS(Expression.dimensionCount(arrayExp, true));
1850 else
1851 150 (dim, error) := typeArrayDim2(arrayExp, dimIndex);
1852 end if;
1853 end typeArrayDim;
1854
1855 function typeArrayDim2
1856 input Expression arrayExp;
1857 input Integer dimIndex;
1858 input Integer dimCount = 0;
1859 output Dimension dim;
1860 output TypingError error;
1861 algorithm
1862 (dim, error) := match (arrayExp, dimIndex)
1863 case (Expression.ARRAY(), 1)
1864 149 then (Dimension.fromExpArray(arrayExp.elements), TypingError.NO_ERROR());
1865
1866 // Modelica arrays are non-ragged and only the last dimension of an array
1867 // expression can be empty, so just traverse into the first element.
1868 case (Expression.ARRAY(), _)
1869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 then typeArrayDim2(arrayGet(arrayExp.elements, 1), dimIndex - 1, dimCount + 1);
1870
1871 else
1872 algorithm
1873 dim := Dimension.UNKNOWN();
1874 1 error := TypingError.OUT_OF_BOUNDS(dimCount);
1875 then
1876 (dim, error);
1877
1878 end match;
1879 end typeArrayDim2;
1880
1881 function typeCrefDim
1882 input ComponentRef cref;
1883 input Integer dimIndex;
1884 input InstContext.Type context;
1885 input SourceInfo info;
1886 output Dimension dim;
1887 output TypingError error = TypingError.NO_ERROR();
1888 protected
1889 list<ComponentRef> crl;
1890 Integer index, dim_count, dim_total = 0;
1891 InstNode node;
1892 Component c;
1893 Type ty;
1894 array<Dimension> dims;
1895 algorithm
1896 // TODO: If the cref has subscripts it becomes trickier to correctly calculate
1897 // the dimension. For now we take the easy way out and just type the
1898 // whole cref, but doing so might introduce unnecessary cycles.
1899
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2218 times.
2223 if ComponentRef.hasSubscripts(cref) then
1900 5 (_, ty) := typeCref(cref, context, info);
1901 5 (dim, error) := nthDimensionBoundsChecked(ty, dimIndex);
1902 5 return;
1903 end if;
1904
1905 // Loop through the cref in reverse, reducing the index by the number of
1906 // dimensions each component has until we find a component that the index is
1907 // valid for. This is done even if the index is 0 or negative, since the loop
1908 // also sums up the total number of dimensions which is needed to give a good
1909 // error message.
1910 2218 crl := ComponentRef.toListReverse(cref, includeScope = false);
1911 index := dimIndex;
1912
1913
2/2
✓ Branch 0 taken 2240 times.
✓ Branch 1 taken 1 time.
2241 for cr in crl loop
1914 () := match cr
1915 case ComponentRef.CREF(subscripts = _)
1916 guard InstNode.isComponent(ComponentRef.node(cr))
1917 algorithm
1918 2236 node := InstNode.resolveOuter(ComponentRef.node(cr));
1919 2236 c := InstNode.component(node);
1920
1921 // If the component is untyped it might have an array type whose dimensions
1922 // we need to take into consideration. To avoid making this more complicated
1923 // than it already is we make sure that the component is typed in that case.
1924
2/2
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2235 times.
2236 if Class.hasDimensions(InstNode.getClass(Component.classInstance(c))) then
1925 1 typeComponent(node, context);
1926 1 c := InstNode.component(node);
1927 end if;
1928
1929 dim_count := match c
1930 case Component.COMPONENT(ty = Type.UNTYPED(dimensions = dims))
1931 algorithm
1932 dim_count := arrayLength(dims);
1933
1934
2/2
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 1 time.
182 if index <= dim_count and index > 0 then
1935 181 dim := typeDimension(dims, index, node, c.binding, context, c.info);
1936 179 checkCyclicDimension(dim, node, index, c.info);
1937 175 return;
1938 end if;
1939 then
1940 dim_count;
1941
1942 case Component.COMPONENT()
1943 algorithm
1944 2054 dim_count := Type.dimensionCount(c.ty);
1945
1946
2/2
✓ Branch 0 taken 2036 times.
✓ Branch 1 taken 18 times.
2054 if index <= dim_count and index > 0 then
1947 2036 dim := Type.nthDimension(c.ty, index);
1948 2036 return;
1949 end if;
1950 then
1951 dim_count;
1952
1953 else 0;
1954 end match;
1955
1956 19 index := index - dim_count;
1957 19 dim_total := dim_total + dim_count;
1958 then
1959 ();
1960
1961 else ();
1962 end match;
1963 end for;
1964
1965 dim := Dimension.UNKNOWN();
1966 1 error := TypingError.OUT_OF_BOUNDS(dim_total);
1967 end typeCrefDim;
1968
1969 function checkCyclicDimension
1970 input Dimension dim;
1971 input InstNode component;
1972 input Integer index;
1973 input SourceInfo info;
1974 algorithm
1975 () := match dim
1976 case Dimension.UNTYPED(isProcessing = true)
1977 algorithm
1978 // TODO: Tell the user which variables are involved in the loop (can be
1979 // found with DFS on the dimension expression. Maybe have a limit
1980 // on the output in case there's a lot of dimensions involved.
1981 12 Error.addSourceMessage(Error.CYCLIC_DIMENSIONS,
1982 {String(index), InstNode.name(component), Expression.toString(dim.dimension)}, info);
1983 4 then
1984 fail();
1985
1986 else ();
1987 end match;
1988 end checkCyclicDimension;
1989
1990 function nthDimensionBoundsChecked
1991 "Returns the requested dimension from the given type, along with a TypingError
1992 indicating whether the index was valid or not."
1993 input Type ty;
1994 input Integer dimIndex;
1995 input Integer offset = 0 "The number of dimensions to skip due to subscripts.";
1996 output Dimension dim;
1997 output TypingError error;
1998 protected
1999 Integer dim_size = Type.dimensionCount(ty);
2000 Integer index = dimIndex + offset;
2001 algorithm
2002 // Check that the dimension index is within bounds.
2003
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5142 times.
5145 if index < 1 or index > dim_size then
2004 dim := Dimension.UNKNOWN();
2005 3 error := TypingError.OUT_OF_BOUNDS(dim_size - offset);
2006 else
2007 try
2008 5142 dim := Type.nthDimension(ty, index);
2009 error := TypingError.NO_ERROR();
2010 else
2011 // Type.nthDimension doesn't work for e.g. conditional arrays that don't have a
2012 // selected branch yet. Return an error in that case instead of just failing.
2013 dim := Dimension.UNKNOWN();
2014 error := TypingError.UNKNOWN_TYPE();
2015 end try;
2016 end if;
2017 end nthDimensionBoundsChecked;
2018
2019 function typeCrefExp
2020 input ComponentRef cref;
2021 input InstContext.Type context;
2022 input SourceInfo info;
2023 output Expression exp;
2024 output Type ty;
2025 output Variability variability;
2026 output Purity purity;
2027 protected
2028 ComponentRef cr;
2029 Variability node_var, subs_var;
2030 algorithm
2031 1052462 (cr, ty, node_var, subs_var) := typeCref(cref, context, info);
2032 1052458 exp := Expression.CREF(ty, cr);
2033 1052458 variability := Prefixes.variabilityMax(node_var, subs_var);
2034 1052458 purity := ComponentRef.purity(cref);
2035 end typeCrefExp;
2036
2037 function typeCref
2038 input output ComponentRef cref;
2039 input InstContext.Type context;
2040 input SourceInfo info;
2041 output Type ty;
2042 output Variability nodeVariability;
2043 output Variability subsVariability;
2044 algorithm
2045 // Check that time isn't used in a function context.
2046 // TODO: Fix NFBuiltin.TIME_CREF so that the compiler treats it like an actual
2047 // constant, then maybe we can use referenceEq here instead.
2048
4/4
✓ Branch 1 taken 668307 times.
✓ Branch 2 taken 385439 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 668306 times.
1053746 if InstContext.inFunction(context) and
2049 ComponentRef.isTime(cref) then
2050 1 Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"time"}, info);
2051 1 fail();
2052 end if;
2053
2054 1053745 (cref, subsVariability) := typeCref2(cref, context, info);
2055
2056 // Fill all implicit array subscripts with explicit `:`
2057
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1053732 times.
1053742 if ComponentRef.hasImplicitTrailingIndex(cref) then
2058 10 cref := ComponentRef.fillSubscripts(cref);
2059 end if;
2060
2061 1053742 ty := ComponentRef.getSubscriptedType(cref);
2062 1053742 nodeVariability := ComponentRef.nodeVariability(cref);
2063 end typeCref;
2064
2065 function typeCref2
2066 input output ComponentRef cref;
2067 input InstContext.Type context;
2068 input SourceInfo info;
2069 input Boolean firstPart = true;
2070 output Variability subsVariability;
2071
2072 import NFComponentRef.Origin;
2073 protected
2074 InstNode cr_node;
2075 algorithm
2076 (cref, subsVariability) := match cref
2077 local
2078 ComponentRef rest_cr;
2079 Type node_ty;
2080 list<Subscript> subs;
2081 Variability subs_var, rest_var;
2082 Function fn;
2083
2084 case ComponentRef.CREF(origin = Origin.SCOPE)
2085 algorithm
2086 646583 cref.ty := InstNode.getType(ComponentRef.node(cref));
2087 646583 cref.restCref := typeCref2(cref.restCref, context, info, false);
2088 then
2089 (cref, Variability.CONSTANT);
2090
2091 case ComponentRef.CREF() guard InstNode.isComponent(ComponentRef.node(cref))
2092 algorithm
2093 1299151 cr_node := ComponentRef.node(cref);
2094 // The context used when typing a component node depends on where the
2095 // component was declared, not where it's used. This can be different to
2096 // the given context, e.g. for package constants used in a function.
2097
4/4
✓ Branch 0 taken 248598 times.
✓ Branch 1 taken 1050553 times.
✓ Branch 3 taken 248586 times.
✓ Branch 4 taken 12 times.
1547737 node_ty := typeComponent(cr_node, InstContext.nodeContext(cr_node, context), typeChildren = firstPart or not InstContext.inDimension(context));
2098
2099 1299151 (subs, subs_var) := typeSubscripts(cref.subscripts, node_ty, Expression.CREF(node_ty, cref), context, info);
2100 1299148 (rest_cr, rest_var) := typeCref2(cref.restCref, context, info, false);
2101 1299148 subsVariability := Prefixes.variabilityMax(subs_var, rest_var);
2102 1299148 then
2103 (ComponentRef.CREF(cref.node, subs, node_ty, cref.origin, rest_cr), subsVariability);
2104
2105 case ComponentRef.CREF()
2106 guard InstNode.isClass(ComponentRef.node(cref)) and firstPart and
2107 InstNode.isFunction(ComponentRef.node(cref))
2108 algorithm
2109
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
14 fn :: _ := Function.typeNodeCache(ComponentRef.node(cref));
2110 28 cref.ty := Type.FUNCTION(fn, NFType.FunctionType.FUNCTION_REFERENCE);
2111 14 cref.restCref := typeCref2(cref.restCref, context, info, false);
2112 then
2113 (cref, Variability.CONSTANT);
2114
2115 case ComponentRef.CREF() guard InstNode.isClass(ComponentRef.node(cref))
2116 algorithm
2117 42306 cref.ty := InstNode.getType(ComponentRef.node(cref));
2118 then
2119 (cref, Variability.CONSTANT);
2120
2121 case ComponentRef.CREF() guard InstNode.isName(ComponentRef.node(cref))
2122 algorithm
2123 58 (_, subs_var) := typeSubscripts(cref.subscripts, cref.ty,
2124 Expression.CREF(cref.ty, cref), context, info, checkSubscripts = false);
2125 58 (rest_cr, rest_var) := typeCref2(cref.restCref, context, info, false);
2126 58 cref.restCref := rest_cr;
2127 58 subsVariability := Prefixes.variabilityMax(subs_var, rest_var);
2128 58 then
2129 (cref, rest_var);
2130
2131 else (cref, Variability.CONSTANT);
2132 end match;
2133 end typeCref2;
2134
2135 function typeSubscripts
2136 input list<Subscript> subscripts;
2137 input Type crefType;
2138 input Expression subscriptedExp;
2139 input InstContext.Type context;
2140 input SourceInfo info;
2141 input Boolean checkSubscripts = true;
2142 output list<Subscript> typedSubs;
2143 output Variability variability = Variability.CONSTANT;
2144 protected
2145 list<Dimension> dims;
2146 Dimension dim;
2147 Integer next_context, i;
2148 Subscript sub;
2149 Variability var;
2150 algorithm
2151
2/2
✓ Branch 0 taken 1050749 times.
✓ Branch 1 taken 248474 times.
1299223 if listEmpty(subscripts) then
2152 typedSubs := subscripts;
2153 1050749 return;
2154 end if;
2155
2156 248474 dims := Type.arrayDims(crefType);
2157 typedSubs := {};
2158 248474 next_context := InstContext.set(context, NFInstContext.SUBSCRIPT);
2159 i := 1;
2160
2161
3/4
✓ Branch 2 taken 248472 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
248474 if listLength(subscripts) > listLength(dims) and checkSubscripts then
2162 6 Error.addSourceMessage(Error.WRONG_NUMBER_OF_SUBSCRIPTS,
2163 {Expression.toString(subscriptedExp), String(listLength(subscripts)), String(listLength(dims))}, info);
2164 2 fail();
2165 end if;
2166
2167
2/2
✓ Branch 0 taken 295085 times.
✓ Branch 1 taken 248471 times.
543556 for s in subscripts loop
2168
1/2
✓ Branch 0 taken 295085 times.
✗ Branch 1 not taken.
295085 if checkSubscripts then
2169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 295085 times.
295085 dim :: dims := dims;
2170 else
2171 dim := Dimension.UNKNOWN();
2172 end if;
2173
2174 295085 (sub, var) := typeSubscript(s, dim, subscriptedExp, i, next_context, info, checkSubscripts);
2175 typedSubs := sub :: typedSubs;
2176 295084 variability := Prefixes.variabilityMax(variability, var);
2177 295084 i := i + 1;
2178
2179 // Mark parameter subscripts as structural so that they're evaluated.
2180 // TODO: Ideally this shouldn't be needed, but the old frontend does it and
2181 // the backend relies on it.
2182
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 295065 times.
295084 if var == Variability.PARAMETER then
2183 19 Structural.markSubscript(sub);
2184 end if;
2185 end for;
2186
2187 248471 typedSubs := listReverseInPlace(typedSubs);
2188 end typeSubscripts;
2189
2190 function typeSubscript
2191 input Subscript subscript;
2192 input Dimension dimension;
2193 input Expression subscriptedExp;
2194 input Integer index;
2195 input InstContext.Type context;
2196 input SourceInfo info;
2197 input Boolean checkSubscript;
2198 output Subscript outSubscript = subscript;
2199 output Variability variability = Variability.CONSTANT;
2200 protected
2201 Expression e = Expression.EMPTY(Type.UNKNOWN());
2202 Type ty, matched_ty;
2203 algorithm
2204 (ty, variability) := match subscript
2205 // An untyped subscript, type the expression and create a typed subscript.
2206 case Subscript.UNTYPED()
2207 algorithm
2208 24599 e := evaluateEnd(subscript.exp, dimension, subscriptedExp, index, context, info);
2209 24599 (e, ty, variability) := typeExp(e, context, info);
2210
2211 // A slice over a resizable parameter keeps its size symbolic.
2212
5/6
✓ Branch 1 taken 5877 times.
✓ Branch 2 taken 18722 times.
✓ Branch 4 taken 5325 times.
✓ Branch 5 taken 552 times.
✓ Branch 7 taken 5325 times.
✗ Branch 8 not taken.
24599 if Type.isArray(ty) and InstContext.inEquation(context) and
2213 not Expression.contains(e, Expression.isResizableCref) then
2214 5325 Structural.markExp(e);
2215 5325 e := Ceval.tryEvalExp(e);
2216 5325 ty := Expression.typeOf(e);
2217 end if;
2218
2219
1/2
✓ Branch 0 taken 24599 times.
✗ Branch 1 not taken.
24599 if checkSubscript then
2220 24599 (e, matched_ty) := checkSubscriptType(e, Type.arrayElementType(ty), dimension, info);
2221 else
2222 ✗ matched_ty := ty;
2223 end if;
2224
2225
2/2
✓ Branch 1 taken 5877 times.
✓ Branch 2 taken 18721 times.
24598 outSubscript := if Type.isArray(ty) then Subscript.SLICE(e) else Subscript.INDEX(e);
2226 24598 then
2227 (matched_ty, variability);
2228
2229 // Other subscripts have already been typed, but still need to be type checked.
2230 case Subscript.INDEX(index = e)
2231 algorithm
2232
1/2
✓ Branch 0 taken 230764 times.
✗ Branch 1 not taken.
230764 if checkSubscript then
2233 230764 (e, ty) := checkSubscriptType(e, Expression.typeOf(e), dimension, info);
2234 else
2235 ✗ ty := Expression.typeOf(e);
2236 end if;
2237
2238 230764 outSubscript := Subscript.INDEX(e);
2239 230764 then
2240 (ty, Expression.variability(e));
2241
2242 case Subscript.SLICE(slice = e)
2243 algorithm
2244 ✗ if checkSubscript then
2245 ✗ (e, ty) := checkSubscriptType(e, Type.unliftArray(Expression.typeOf(e)), dimension, info);
2246 else
2247 ✗ ty := Type.unliftArray(Expression.typeOf(e));
2248 end if;
2249
2250 ✗ outSubscript := Subscript.SLICE(e);
2251 ✗ then
2252 (ty, Expression.variability(e));
2253
2254 39722 case Subscript.WHOLE() then (Type.UNKNOWN(), Dimension.variability(dimension));
2255
2256 else
2257 algorithm
2258 ✗ Error.terminate(getInstanceName() + " got unknown subscript", sourceInfo());
2259 ✗ then
2260 fail();
2261 end match;
2262 end typeSubscript;
2263
2264 function checkSubscriptType
2265 input output Expression subscriptExp;
2266 input Type subscriptType;
2267 input Dimension dimension;
2268 input SourceInfo info;
2269 output Type outType;
2270 protected
2271 Type expected_ty;
2272 MatchKind mk;
2273 algorithm
2274 255363 expected_ty := Dimension.subscriptType(dimension);
2275 255363 (subscriptExp, outType, mk) := TypeCheck.matchTypes(subscriptType,
2276 expected_ty, subscriptExp, NFTypeCheck.ALLOW_UNKNOWN);
2277
2278
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 255362 times.
255363 if TypeCheck.isIncompatibleMatch(mk) then
2279 4 Error.addSourceMessage(Error.SUBSCRIPT_TYPE_MISMATCH,
2280 {Expression.toString(subscriptExp), Type.toString(subscriptType), Type.toString(expected_ty)}, info);
2281 1 fail();
2282 end if;
2283 end checkSubscriptType;
2284
2285 function typeArray
2286 input array<Expression> elements;
2287 input Boolean isLiteral;
2288 input Type ty;
2289 input InstContext.Type context;
2290 input SourceInfo info;
2291 output Expression arrayExp;
2292 output Type arrayType = Type.UNKNOWN();
2293 output Variability variability = Variability.CONSTANT;
2294 output Purity purity = Purity.PURE;
2295 protected
2296 Expression exp;
2297 list<Expression> expl = {}, expl2 = {};
2298 Variability var;
2299 Purity pur;
2300 Type ty1 = Type.UNKNOWN(), ty2, ty3;
2301 list<Type> tys = {};
2302 MatchKind mk;
2303 Integer array_len, idx;
2304 InstContext.Type next_context;
2305 algorithm
2306 23840 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
2307 array_len := arrayLength(elements);
2308
2309
2/2
✓ Branch 0 taken 23836 times.
✓ Branch 1 taken 4 times.
23840 if array_len > 0 then
2310 23836 (exp, ty1, variability, purity) := typeExp(arrayGet(elements, 1), next_context, info);
2311 expl := exp :: expl;
2312 23836 tys := ty1 :: tys;
2313
2314
2/2
✓ Branch 0 taken 22458 times.
✓ Branch 1 taken 1378 times.
100492 for i in 2:array_len loop
2315 76656 (exp, ty2, var, pur) := typeExp(arrayGet(elements, i), next_context, info);
2316 76656 variability := Prefixes.variabilityMax(var, variability);
2317 76656 purity := Prefixes.purityMin(pur, purity);
2318
2319 76656 (, ty3, mk) := TypeCheck.matchTypes(ty2, ty1, exp, NFTypeCheck.IGNORE_DIMENSIONS_IN_RECORDS);
2320
2/2
✓ Branch 1 taken 896 times.
✓ Branch 2 taken 75760 times.
76656 if TypeCheck.isIncompatibleMatch(mk) then
2321 // Try the other way around to get the super-type of the array
2322 896 (, ty3, mk) := TypeCheck.matchTypes(ty1, ty2, exp, NFTypeCheck.IGNORE_DIMENSIONS_IN_RECORDS);
2323
2/2
✓ Branch 1 taken 849 times.
✓ Branch 2 taken 47 times.
896 if TypeCheck.isCompatibleMatch(mk) then
2324 849 ty1 := ty3;
2325 end if;
2326 else
2327 75760 ty1 := ty3;
2328 end if;
2329 expl := exp :: expl;
2330 76656 tys := ty2 :: tys;
2331 end for;
2332 else
2333 // If the array is empty it probably already has a type, since empty arrays
2334 // can't be created in Modelica without evaluating some expression. So use
2335 // that type instead of an unknown type so we don't lose it.
2336 4 ty1 := Type.arrayElementType(ty);
2337 end if;
2338
2339 // Give the actual error-messages here after we got the super-type of the array
2340 idx := array_len;
2341
2/2
✓ Branch 0 taken 100492 times.
✓ Branch 1 taken 23840 times.
124332 for e in expl loop
2342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100492 times.
100492 ty2::tys := tys;
2343 100492 (exp, , mk) := TypeCheck.matchTypes(ty2, ty1, e, NFTypeCheck.IGNORE_DIMENSIONS_IN_RECORDS);
2344 expl2 := exp::expl2;
2345
2/2
✓ Branch 1 taken 98602 times.
✓ Branch 2 taken 1890 times.
100492 if not InstContext.inAnnotation(context) then // forget errors when handling annotations
2346
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98602 times.
98602 if TypeCheck.isIncompatibleMatch(mk) then
2347 ✗ Error.addSourceMessage(Error.NF_ARRAY_TYPE_MISMATCH, {String(idx), Expression.toString(exp), Type.toString(ty2), Type.toString(ty1)}, info);
2348 ✗ fail();
2349 end if;
2350 end if;
2351 100492 idx := idx-1;
2352 end for;
2353
2354 23840 arrayType := Type.liftArrayLeft(ty1, Dimension.fromExpList(expl2));
2355 23840 arrayExp := Expression.makeArray(arrayType, listArray(expl2), isLiteral);
2356 end typeArray;
2357
2358 function typeMatrix "The array concatenation operator"
2359 input list<list<Expression>> elements;
2360 input InstContext.Type context;
2361 input SourceInfo info;
2362 output Expression arrayExp;
2363 output Type arrayType = Type.UNKNOWN();
2364 output Variability variability = Variability.CONSTANT;
2365 output Purity purity = Purity.PURE;
2366 protected
2367 Expression exp;
2368 list<Expression> expl = {}, res = {};
2369 Variability var;
2370 Purity pur;
2371 Type ty = Type.UNKNOWN();
2372 list<Type> tys = {}, resTys = {};
2373 Integer n = 2;
2374 InstContext.Type next_context = InstContext.set(context, NFInstContext.SUBEXPRESSION);
2375 algorithm
2376
2/2
✓ Branch 1 taken 2011 times.
✓ Branch 2 taken 163 times.
2174 if listLength(elements) > 1 then
2377
2/2
✓ Branch 0 taken 6504 times.
✓ Branch 1 taken 2011 times.
8515 for el in elements loop
2378 6504 (exp, ty, var, pur) := typeMatrixComma(el, next_context, info);
2379 6504 variability := Prefixes.variabilityMax(var, variability);
2380 6504 purity := Prefixes.purityMin(pur, purity);
2381 expl := exp :: expl;
2382 6504 tys := ty :: tys;
2383 6504 n := max(n, Type.dimensionCount(ty));
2384 end for;
2385
2/2
✓ Branch 0 taken 6504 times.
✓ Branch 1 taken 2011 times.
8515 for e in expl loop
2386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6504 times.
6504 ty::tys := tys;
2387 6504 (e,ty) := Expression.promote(e, ty, n);
2388 6504 resTys := ty::resTys;
2389 res := e::res;
2390 end for;
2391 2011 (arrayExp, arrayType) := BuiltinCall.makeCatExp(1, res, resTys, variability, purity, info);
2392 else
2393 163 (arrayExp, arrayType, variability, purity) := typeMatrixComma(listHead(elements), next_context, info);
2394
2/2
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 9 times.
163 if Type.dimensionCount(arrayType) < 2 then
2395 9 (arrayExp, arrayType) := Expression.promote(arrayExp, arrayType, n);
2396 end if;
2397 end if;
2398 end typeMatrix;
2399
2400 function typeMatrixComma
2401 input list<Expression> elements;
2402 input InstContext.Type context;
2403 input SourceInfo info;
2404 output Expression arrayExp;
2405 output Type arrayType;
2406 output Variability variability = Variability.CONSTANT;
2407 output Purity purity = Purity.PURE;
2408 protected
2409 Expression exp;
2410 list<Expression> expl = {}, res = {};
2411 Variability var;
2412 Purity pur;
2413 Type ty = Type.UNKNOWN(), ty1, ty2, ty3;
2414 list<Type> tys = {}, tys2;
2415 Integer n = 2, pos;
2416 TypeCheck.MatchKind mk;
2417 algorithm
2418 6667 Error.assertion(not listEmpty(elements), getInstanceName() + " expected non-empty arguments", sourceInfo());
2419
2/2
✓ Branch 1 taken 5806 times.
✓ Branch 2 taken 861 times.
6667 if listLength(elements) > 1 then
2420
2/2
✓ Branch 0 taken 17511 times.
✓ Branch 1 taken 5806 times.
23317 for e in elements loop
2421 17511 (exp, ty1, var, pur) := typeExp(e, context, info);
2422 expl := exp :: expl;
2423
2/2
✓ Branch 1 taken 5806 times.
✓ Branch 2 taken 11705 times.
17511 if Type.isEqual(ty, Type.UNKNOWN()) then
2424 5806 ty := ty1;
2425 else
2426 11705 (,,ty2,mk) := TypeCheck.matchExpressions(Expression.INTEGER(0), Type.arrayElementType(ty1), Expression.INTEGER(0), Type.arrayElementType(ty));
2427
1/2
✓ Branch 1 taken 11705 times.
✗ Branch 2 not taken.
11705 if TypeCheck.isCompatibleMatch(mk) then
2428 11705 ty := ty2;
2429 end if;
2430 end if;
2431 17511 tys := ty1 :: tys;
2432 17511 variability := Prefixes.variabilityMax(variability, var);
2433 17511 purity := Prefixes.purityMin(purity, pur);
2434 17511 n := max(n, Type.dimensionCount(ty));
2435 end for;
2436 tys2 := {};
2437 res := {};
2438 5806 pos := n+1;
2439
2/2
✓ Branch 0 taken 17511 times.
✓ Branch 1 taken 5806 times.
23317 for e in expl loop
2440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17511 times.
17511 ty1::tys := tys;
2441 17511 pos := pos-1;
2442
1/2
✓ Branch 1 taken 17511 times.
✗ Branch 2 not taken.
17511 if Type.dimensionCount(ty1) <> n then
2443 17511 (e,ty1) := Expression.promote(e, ty1, n);
2444 end if;
2445 17511 ty2 := Type.setArrayElementType(ty1, ty);
2446 17511 (e, ty3, mk) := TypeCheck.matchTypes(ty1, ty2, e);
2447
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17511 times.
17511 if TypeCheck.isIncompatibleMatch(mk) then
2448 ✗ Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, {String(pos), "matrix constructor ", "arg", Expression.toString(e), Type.toString(ty1), Type.toString(ty2)}, info);
2449 end if;
2450 res := e :: res;
2451 17511 tys2 := ty3 :: tys2;
2452 end for;
2453 5806 (arrayExp, arrayType) := BuiltinCall.makeCatExp(2, res, tys2, variability, purity, info);
2454 else
2455 861 (arrayExp, arrayType, variability) := typeExp(listHead(elements), context, info);
2456 end if;
2457 end typeMatrixComma;
2458
2459 function typeRange
2460 input output Expression rangeExp;
2461 input InstContext.Type context;
2462 input SourceInfo info;
2463 output Type rangeType;
2464 output Variability variability;
2465 output Purity purity;
2466 protected
2467 Expression start_exp, step_exp, stop_exp;
2468 Type start_ty, step_ty, stop_ty;
2469 Option<Expression> ostep_exp;
2470 Option<Type> ostep_ty;
2471 Variability start_var, step_var, stop_var;
2472 Purity start_pur, step_pur, stop_pur;
2473 TypeCheck.MatchKind ty_match;
2474 InstContext.Type next_context = InstContext.set(context, NFInstContext.SUBEXPRESSION);
2475 algorithm
2476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9854 times.
9854 Expression.RANGE(start = start_exp, step = ostep_exp, stop = stop_exp) := rangeExp;
2477
2478 // Type start and stop.
2479 9854 (start_exp, start_ty, start_var, start_pur) := typeExp(start_exp, next_context, info);
2480 9854 (stop_exp, stop_ty, stop_var, stop_pur) := typeExp(stop_exp, next_context, info);
2481 9854 variability := Prefixes.variabilityMax(start_var, stop_var);
2482 9854 purity := Prefixes.purityMin(start_pur, stop_pur);
2483
2484 // Type check start and stop.
2485 9854 (start_exp, stop_exp, rangeType, ty_match) :=
2486 TypeCheck.matchExpressions(start_exp, start_ty, stop_exp, stop_ty);
2487
2488
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9854 times.
9854 if TypeCheck.isIncompatibleMatch(ty_match) then
2489 ✗ printRangeTypeError(start_exp, start_ty, stop_exp, stop_ty, info);
2490 end if;
2491
2492
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9854 times.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 9756 times.
9854 if isSome(ostep_exp) then
2493 // Type step.
2494 98 SOME(step_exp) := ostep_exp;
2495 98 (step_exp, step_ty, step_var, step_pur) := typeExp(step_exp, next_context, info);
2496 98 variability := Prefixes.variabilityMax(step_var, variability);
2497 98 purity := Prefixes.purityMin(step_pur, purity);
2498
2499 // Type check start and step.
2500 98 (start_exp, step_exp, rangeType, ty_match) :=
2501 TypeCheck.matchExpressions(start_exp, start_ty, step_exp, step_ty);
2502
2503
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 97 times.
98 if TypeCheck.isIncompatibleMatch(ty_match) then
2504 1 printRangeTypeError(start_exp, start_ty, step_exp, step_ty, info);
2505 end if;
2506
2507 // We've checked start-stop and start-step now, so step-stop must also be
2508 // type compatible. Stop might need to be type cast here though.
2509 97 stop_exp := TypeCheck.matchTypes_cast(stop_ty, rangeType, stop_exp);
2510
2511 97 ostep_exp := SOME(step_exp);
2512 97 ostep_ty := SOME(step_ty);
2513 else
2514 ostep_exp := NONE();
2515 ostep_ty := NONE();
2516 end if;
2517
2518 9853 rangeType := TypeCheck.getRangeType(start_exp, ostep_exp, stop_exp, rangeType, info);
2519 9851 rangeExp := Expression.RANGE(rangeType, start_exp, ostep_exp, stop_exp);
2520
2521
4/4
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 9311 times.
✓ Branch 3 taken 497 times.
✓ Branch 4 taken 8814 times.
9851 if variability <= Variability.PARAMETER and
2522 purity == Purity.PURE and
2523 not InstContext.inFunction(context) then
2524 8814 Structural.markExp(rangeExp);
2525 end if;
2526 end typeRange;
2527
2528 function typeTuple
2529 input list<Expression> elements;
2530 input InstContext.Type context;
2531 input SourceInfo info;
2532 output Expression tupleExp;
2533 output Type tupleType;
2534 output Variability variability;
2535 output Purity purity = Purity.PURE;
2536 protected
2537 list<Expression> expl;
2538 list<Type> tyl;
2539 list<Variability> valr;
2540 InstContext.Type next_context;
2541 algorithm
2542 // Tuples are only allowed on the lhs side of an equality/assignment,
2543 // and only if they are alone and not part of a larger expression.
2544
3/4
✓ Branch 1 taken 954 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 954 times.
955 if not InstContext.onLHS(context) or InstContext.inSubexpression(context) then
2545 2 Error.addSourceMessage(Error.RHS_TUPLE_EXPRESSION,
2546 {Expression.toString(Expression.TUPLE(Type.UNKNOWN(), elements))}, info);
2547 1 fail();
2548 end if;
2549
2550 954 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
2551 954 (expl, tyl, valr) := typeExpl(elements, next_context, info);
2552 954 tupleType := Type.TUPLE(tyl, NONE());
2553 954 tupleExp := Expression.TUPLE(tupleType, expl);
2554
2555 // Tuples may only contain component references.
2556
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 953 times.
954 if not List.all(expl, Expression.isCref) then
2557 2 Error.addSourceMessage(Error.TUPLE_ASSIGN_CREFS_ONLY,
2558 {Expression.toString(tupleExp)}, info);
2559 1 fail();
2560 end if;
2561
2562
1/2
✓ Branch 0 taken 953 times.
✗ Branch 1 not taken.
953 variability := if listEmpty(valr) then Variability.CONSTANT else listHead(valr);
2563 end typeTuple;
2564
2565 function printRangeTypeError
2566 input Expression exp1;
2567 input Type ty1;
2568 input Expression exp2;
2569 input Type ty2;
2570 input SourceInfo info;
2571 algorithm
2572 5 Error.addSourceMessage(Error.RANGE_TYPE_MISMATCH,
2573 {Expression.toString(exp1), Type.toString(ty1),
2574 Expression.toString(exp2), Type.toString(ty2)}, info);
2575 1 fail();
2576 end printRangeTypeError;
2577
2578 function typeSize
2579 "Types a size expression. If evaluate is true the size expression is also
2580 evaluated if the dimension is known and the index is a parameter expression,
2581 otherwise a typed size expression is returned."
2582 input output Expression sizeExp;
2583 input InstContext.Type context;
2584 input SourceInfo info;
2585 input Boolean evaluate = true;
2586 output Type sizeType;
2587 output Variability variability;
2588 output Purity purity;
2589 protected
2590 Expression exp, index;
2591 Type exp_ty, index_ty;
2592 TypeCheck.MatchKind ty_match;
2593 Integer iindex;
2594 Dimension dim;
2595 TypingError ty_err;
2596 Option<Expression> oexp;
2597 InstContext.Type next_context = InstContext.set(context, NFInstContext.SUBEXPRESSION);
2598 array<Expression> expl;
2599 algorithm
2600 (sizeExp, sizeType, variability, purity) := match sizeExp
2601 case Expression.SIZE(exp = exp, dimIndex = SOME(index))
2602 algorithm
2603 2178 (index, index_ty, variability, purity) := typeExp(index, next_context, info);
2604
2605 // The second argument must be an Integer.
2606 2178 (index, _, ty_match) :=
2607 TypeCheck.matchTypes(index_ty, Type.INTEGER(), index);
2608
2609
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2177 times.
2178 if TypeCheck.isIncompatibleMatch(ty_match) then
2610 3 Error.addSourceMessage(Error.ARG_TYPE_MISMATCH,
2611 {"2", "size ", "dim", Expression.toString(index), Type.toString(index_ty), "Integer"}, info);
2612 1 fail();
2613 end if;
2614
2615
4/4
✓ Branch 0 taken 2175 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2174 times.
✓ Branch 3 taken 1 time.
2177 if variability <= Variability.STRUCTURAL_PARAMETER and purity == Purity.PURE then
2616 // Evaluate the index if it's a constant.
2617 2174 index := Ceval.evalExp(index, NFCeval.noTarget);
2618
2619 // TODO: Print an error if the index couldn't be evaluated to an int.
2620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2174 times.
2174 Expression.INTEGER(iindex) := index;
2621
2622 // Get the iindex'd dimension of the expression.
2623 2174 (dim, oexp, ty_err) := typeExpDim(exp, iindex, next_context, info);
2624 2168 checkSizeTypingError(ty_err, exp, iindex, info);
2625
2626
4/4
✓ Branch 1 taken 675 times.
✓ Branch 2 taken 1490 times.
✓ Branch 3 taken 672 times.
✓ Branch 4 taken 3 times.
2165 if Dimension.isKnown(dim) and evaluate then
2627 // If the dimension size is known, return its size.
2628 672 exp := Dimension.sizeExp(dim);
2629 else
2630 // If the dimension size is unknown (e.g. in a function) or
2631 // evaluation is disabled, return a size expression instead.
2632
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1493 times.
✓ Branch 2 taken 1431 times.
✓ Branch 3 taken 62 times.
1493 if isSome(oexp) then
2633 62 SOME(exp) := oexp;
2634 else
2635 1431 exp := typeExp(exp, next_context, info);
2636 end if;
2637
2638 1493 exp := Expression.SIZE(exp, SOME(index));
2639 end if;
2640
2641
4/4
✓ Branch 1 taken 1506 times.
✓ Branch 2 taken 659 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 1490 times.
2165 if not InstContext.inFunction(context) or Dimension.isKnown(dim) then
2642 // size is constant outside functions, or for known dimensions inside functions.
2643 675 variability := Variability.CONSTANT;
2644 else
2645 // size is discrete for : in functions.
2646 1490 variability := Variability.DISCRETE;
2647 1490 purity := Purity.IMPURE;
2648 end if;
2649 else
2650 // If the index is not a constant, type the whole expression.
2651 3 (exp, exp_ty, _, purity) := typeExp(sizeExp.exp, next_context, info);
2652
2653 // Check that it's an array.
2654
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if not Type.isArray(exp_ty) then
2655 ✗ Error.addSourceMessage(Error.INVALID_ARGUMENT_TYPE_FIRST_ARRAY, {"size"}, info);
2656 ✗ fail();
2657 end if;
2658
2659
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
3 if Type.isEmptyArray(exp_ty) and not InstContext.inFunction(context) then
2660 // If the expression has any dimensions that are 0 it might not be safe to generate
2661 // a size expression with it, since it might be either a variable that's no longer
2662 // present in the flat model or an array expression that doesn't have enough
2663 // dimensions (e.g. Real[0, 2] => {}). In that case make an array with the dimension
2664 // sizes of the expression and index that instead.
2665 1 expl := Array.mapList(Type.arrayDims(exp_ty), Dimension.sizeExp);
2666 1 exp := Expression.makeExpArray(expl, Type.INTEGER());
2667 2 exp := Expression.makeSubscriptedExp({Subscript.makeIndex(index)}, exp);
2668 else
2669 // Since we don't know which dimension to take the size of, return a size expression.
2670 2 exp := Expression.SIZE(exp, SOME(index));
2671 end if;
2672 end if;
2673 2168 then
2674 (exp, Type.INTEGER(), variability, purity);
2675
2676 case Expression.SIZE()
2677 algorithm
2678 6 (exp, exp_ty, _) := typeExp(sizeExp.exp, next_context, info);
2679 6 sizeType := Type.sizeType(exp_ty);
2680 6 then
2681 (Expression.SIZE(exp, NONE()), sizeType, Variability.PARAMETER, Purity.PURE);
2682
2683 end match;
2684 end typeSize;
2685
2686 function checkSizeTypingError
2687 input TypingError typingError;
2688 input Expression exp;
2689 input Integer index;
2690 input SourceInfo info;
2691 algorithm
2692 () := match typingError
2693 case NO_ERROR() then ();
2694
2695 // The first argument wasn't an array.
2696 case OUT_OF_BOUNDS(0)
2697 algorithm
2698 1 Error.addSourceMessage(Error.INVALID_ARGUMENT_TYPE_FIRST_ARRAY, {"size"}, info);
2699 1 then
2700 fail();
2701
2702 // The index referred to an invalid dimension.
2703 case OUT_OF_BOUNDS()
2704 algorithm
2705 6 Error.addSourceMessage(Error.INVALID_SIZE_INDEX,
2706 {String(index), Expression.toString(exp), String(typingError.upperBound)}, info);
2707 2 then
2708 fail();
2709 end match;
2710 end checkSizeTypingError;
2711
2712 function evaluateEnd
2713 input Expression exp;
2714 input Dimension dim;
2715 input Expression subscriptedExp;
2716 input Integer index;
2717 input InstContext.Type context;
2718 input SourceInfo info;
2719 output Expression outExp;
2720 algorithm
2721 outExp := match exp
2722 local
2723
2724 26 case Expression.END() then Dimension.endExp(dim, subscriptedExp, index);
2725
2726 // Stop when encountering a cref, any 'end' in a cref expression refers to
2727 // the cref's dimensions and will be evaluated when the cref is typed.
2728 case Expression.CREF() then exp;
2729
2730 23377 else Expression.mapShallow(exp,
2731 function evaluateEnd(dim = dim, subscriptedExp = subscriptedExp, index = index, info = info, context = context));
2732
2733 end match;
2734 end evaluateEnd;
2735
2736 function typeIfExpression
2737 input output Expression ifExp;
2738 input InstContext.Type context;
2739 input SourceInfo info;
2740 output Type ty;
2741 output Variability var;
2742 output Purity purity;
2743 protected
2744 Expression cond, tb, fb, tb2, fb2;
2745 InstContext.Type next_context;
2746 Type cond_ty, tb_ty, fb_ty;
2747 Variability cond_var, tb_var, fb_var;
2748 Purity cond_pur, tb_pur, fb_pur;
2749 MatchKind ty_match;
2750 algorithm
2751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14225 times.
14225 Expression.IF(condition = cond, trueBranch = tb, falseBranch = fb) := ifExp;
2752 14225 next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);
2753
2754 14225 (cond, cond_ty, cond_var, cond_pur) := typeExp(cond, next_context, info);
2755
2756 // The condition must be a scalar boolean.
2757 14225 (cond, _, ty_match) := TypeCheck.matchTypes(cond_ty, Type.BOOLEAN(), cond);
2758
2759
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14225 times.
14225 if TypeCheck.isIncompatibleMatch(ty_match) then
2760 ✗ Error.addSourceMessage(Error.IF_CONDITION_TYPE_ERROR,
2761 {Expression.toString(cond), Type.toString(cond_ty)}, info);
2762 ✗ fail();
2763 end if;
2764
2765 14225 (tb, tb_ty, tb_var, tb_pur) := typeExp(tb, next_context, info);
2766 14225 (fb, fb_ty, fb_var, fb_pur) := typeExp(fb, next_context, info);
2767 // Type match the branches, using the context for the whole if-expression rather than the branches.
2768 14225 (tb2, fb2, ty, ty_match) := TypeCheck.matchIfBranches(tb, tb_ty, fb, fb_ty, context);
2769
2770
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14225 times.
14225 if TypeCheck.isIncompatibleMatch(ty_match) then
2771 ✗ Error.addSourceMessage(Error.TYPE_MISMATCH_IF_EXP,
2772 {"", Expression.toString(tb), Type.toString(tb_ty),
2773 Expression.toString(fb), Type.toString(fb_ty)}, info);
2774 ✗ fail();
2775 end if;
2776
2777 // Evaluate the if-expression if exactly one branch contains a der call,
2778 // since this can affect the number of state variables.
2779
4/6
✓ Branch 6 taken 1041 times.
✓ Branch 7 taken 13184 times.
✓ Branch 9 taken 1041 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 1041 times.
✗ Branch 14 not taken.
14225 if Expression.contains(tb2, function Expression.isCallNamed(name = "der")) <>
2780 Expression.contains(fb2, function Expression.isCallNamed(name = "der")) and
2781 Flags.getConfigString(Flags.EVALUATE_STRUCTURAL_PARAMETERS) == "all" then
2782 1041 Structural.markExp(cond);
2783 end if;
2784
2785 14225 ifExp := Expression.IF(ty, cond, tb2, fb2);
2786 14225 var := Prefixes.variabilityMax(cond_var, Prefixes.variabilityMax(tb_var, fb_var));
2787 14225 purity := Prefixes.purityMin(cond_pur, Prefixes.purityMin(tb_pur, fb_pur));
2788 end typeIfExpression;
2789
2790 function typeClassSections
2791 input InstNode classNode;
2792 input InstContext.Type context;
2793 protected
2794 Class cls, typed_cls;
2795 array<InstNode> components;
2796 Sections sections;
2797 SourceInfo info;
2798 InstContext.Type initial_context;
2799 algorithm
2800 263285 cls := InstNode.getClass(classNode);
2801
2802 () := match cls
2803 case Class.INSTANCED_CLASS() guard Type.isBasic(Type.arrayElementType(cls.ty)) then ();
2804
2805 case Class.INSTANCED_CLASS(elements = ClassTree.FLAT_TREE(components = components),
2806 sections = sections)
2807 algorithm
2808 sections := match sections
2809 case Sections.SECTIONS()
2810 algorithm
2811 9040 initial_context := InstContext.set(context, NFInstContext.INITIAL);
2812 9040 then
2813 Sections.map(sections,
2814 function typeEquation(context = InstContext.set(context, NFInstContext.EQUATION)),
2815 function typeAlgorithm(context = InstContext.set(context, NFInstContext.ALGORITHM)),
2816 function typeEquation(context = InstContext.set(initial_context, NFInstContext.EQUATION)),
2817 function typeAlgorithm(context = InstContext.set(initial_context, NFInstContext.ALGORITHM)));
2818
2819 case Sections.EXTERNAL()
2820 algorithm
2821 ✗ Error.addSourceMessage(Error.TRANS_VIOLATION,
2822 {InstNode.name(classNode), Restriction.toString(cls.restriction), "external declaration"},
2823 InstNode.info(classNode));
2824 ✗ then
2825 fail();
2826
2827 else sections;
2828 end match;
2829
2830 37208 typed_cls := Class.setSections(sections, cls);
2831
2832
2/2
✓ Branch 1 taken 261380 times.
✓ Branch 2 taken 37208 times.
298588 for c in components loop
2833 261380 typeComponentSections(InstNode.resolveOuter(c), context);
2834 end for;
2835
2836 37208 InstNode.updateClass(typed_cls, classNode);
2837 then
2838 ();
2839
2840 case Class.INSTANCED_BUILTIN() then ();
2841
2842 case Class.TYPED_DERIVED()
2843 algorithm
2844 4724 typeClassSections(cls.baseClass, context);
2845 then
2846 ();
2847
2848 else
2849 algorithm
2850 ✗ Error.terminate(getInstanceName() + " got uninstantiated class " + InstNode.name(classNode), sourceInfo());
2851 ✗ then
2852 fail();
2853 end match;
2854 end typeClassSections;
2855
2856 function typeFunctionSections
2857 input InstNode classNode;
2858 input InstContext.Type context;
2859 protected
2860 Class cls, typed_cls;
2861 Sections sections;
2862 SourceInfo info;
2863 Algorithm alg;
2864 algorithm
2865 26155 cls := InstNode.getClass(classNode);
2866
2867 () := match cls
2868 case Class.INSTANCED_CLASS(sections = sections)
2869 algorithm
2870 sections := match sections
2871 case Sections.SECTIONS({}, {}, {alg}, {})
2872 algorithm
2873 31509 sections.algorithms := {typeAlgorithm(alg, InstContext.set(context, NFInstContext.ALGORITHM))};
2874 then
2875 sections;
2876
2877 case Sections.SECTIONS()
2878 algorithm
2879 2 Error.addSourceMessage(Error.MULTIPLE_SECTIONS_IN_FUNCTION,
2880 {InstNode.name(classNode)}, InstNode.info(classNode));
2881 1 then
2882 fail();
2883
2884 case Sections.EXTERNAL(explicit = true)
2885 algorithm
2886 1232 info := InstNode.info(classNode);
2887
4/4
✓ Branch 0 taken 2824 times.
✓ Branch 1 taken 1231 times.
✓ Branch 2 taken 2824 times.
✓ Branch 3 taken 1231 times.
5286 sections.args := list(typeExternalArg(arg, info, classNode) for arg in sections.args);
2888 1231 sections.outputRef := typeCref(sections.outputRef, context, info);
2889 1231 checkExternalCallResult(sections.outputRef, info);
2890 then
2891 sections;
2892
2893 case Sections.EXTERNAL()
2894 4735 then makeDefaultExternalCall(sections, classNode);
2895
2896 else sections;
2897 end match;
2898
2899 26148 typed_cls := Class.setSections(sections, cls);
2900 26148 InstNode.updateClass(typed_cls, classNode);
2901 then
2902 ();
2903
2904 case Class.TYPED_DERIVED()
2905 algorithm
2906 1 typeFunctionSections(cls.baseClass, context);
2907 then
2908 ();
2909
2910 else
2911 algorithm
2912 ✗ Error.terminate(getInstanceName() + " got uninstantiated class " + InstNode.name(classNode), sourceInfo());
2913 ✗ then
2914 fail();
2915 end match;
2916 end typeFunctionSections;
2917
2918 function typeExternalArg
2919 input Expression arg;
2920 input SourceInfo info;
2921 input InstNode node;
2922 output Expression outArg;
2923 protected
2924 Type ty;
2925 Variability var;
2926 Expression index;
2927 algorithm
2928 outArg := match arg
2929 case Expression.SIZE(dimIndex = SOME(_))
2930 algorithm
2931 150 outArg := typeSize(arg, NFInstContext.FUNCTION, info, evaluate = false);
2932
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 150 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 150 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 150 times.
150 Expression.SIZE(dimIndex = SOME(index)) := outArg;
2933
2934 // Size expression must have a constant dimension index.
2935
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 149 times.
150 if not Expression.isInteger(index) then
2936 2 Error.addSourceMessage(Error.EXTERNAL_ARG_NONCONSTANT_SIZE_INDEX,
2937 {Expression.toString(arg)}, info);
2938 1 fail();
2939 end if;
2940 then
2941 outArg;
2942
2943 else
2944 algorithm
2945 2674 (outArg, ty, var) := typeExp(arg, NFInstContext.FUNCTION, info);
2946 2674 Call.updateExternalRecordArgsInType(ty);
2947 then
2948 match arg
2949 // All kinds of crefs are allowed.
2950 case Expression.CREF() then outArg;
2951 else
2952 algorithm
2953 // The only other kind of expression that's allowed is scalar constants.
2954
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
7 if Type.isScalarBuiltin(ty) and var == Variability.CONSTANT then
2955 7 outArg := Ceval.evalExp(outArg, Ceval.EvalTarget.new(info, NFInstContext.FUNCTION));
2956 else
2957 ✗ Error.addSourceMessage(Error.EXTERNAL_ARG_WRONG_EXP,
2958 {Expression.toString(outArg)}, info);
2959 ✗ fail();
2960 end if;
2961 then
2962 outArg;
2963 end match;
2964 end match;
2965 end typeExternalArg;
2966
2967 function makeDefaultExternalCall
2968 "Constructs a default external call for an external function. If only one
2969 output exists a call 'output = func(input1, input2, ...)' is generated,
2970 otherwise a call 'func(param1, param2, ...)' is generated from the function's
2971 formal parameters and local variables."
2972 input output Sections extDecl;
2973 input InstNode fnNode;
2974 algorithm
2975 extDecl := match extDecl
2976 local
2977 list<Expression> args;
2978 Function fn;
2979 Boolean single_output;
2980 array<InstNode> comps;
2981 Component comp;
2982 Type ty;
2983 InstNode node;
2984 NFInstNode.NodeHandle out_cell;
2985 Expression exp;
2986
2987 case Sections.EXTERNAL()
2988 algorithm
2989 // An explicit function call isn't needed for builtin calls.
2990
3/4
✓ Branch 0 taken 4730 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 4730 times.
✗ Branch 4 not taken.
4735 if extDecl.language == "builtin" then
2991 4730 return;
2992 end if;
2993
2994 // Fetch the cached function.
2995
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
5 CachedData.FUNCTION(funcs = {fn}) := InstNode.getFuncCache(fnNode);
2996 // Check whether we have a single output or not.
2997 5 single_output := listLength(fn.outputs) == 1;
2998
2999 // When there's a single array output we can't generate a call on the
3000 // 'output = func(inputs)' form, so print a warning and treat is as
3001 // though it's not a single output.
3002
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 3 times.
5 if single_output and Type.isArray(Function.returnType(fn)) then
3003 single_output := false;
3004 1 Error.addSourceMessage(Error.EXT_FN_SINGLE_RETURN_ARRAY,
3005 {extDecl.language}, InstNode.info(fnNode));
3006 end if;
3007
3008 // If we have a single output, set the external declaration's output to
3009 // be a reference to the function's output. Otherwise leave it as empty.
3010
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
4 if single_output then
3011
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 {out_cell} := fn.outputs;
3012 3 node := InstNode.fromHandle(out_cell);
3013 3 ty := InstNode.getType(node);
3014 3 extDecl.outputRef := ComponentRef.fromNode(node, ty);
3015 end if;
3016
3017 // Generate function arguments from the function's components.
3018 5 comps := ClassTree.getComponents(Class.classTree(InstNode.getClass(InstNode.fromHandle(fn.node))));
3019
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if arrayLength(comps) > 0 then
3020 args := {};
3021
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 5 times.
18 for c in comps loop
3022 13 comp := InstNode.component(c);
3023
3024 // Skip outputs if there's only a single output.
3025
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 3 times.
13 if not single_output or Component.direction(comp) <> Direction.OUTPUT then
3026 // Generate a cref for the component and add it to the list of arguments.
3027 10 ty := Component.getType(comp);
3028 10 exp := Expression.CREF(ty, ComponentRef.fromNode(c, ty));
3029 args := exp :: args;
3030
3031 // If the component is an array, generate a size expression for
3032 // each dimension too.
3033
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 9 times.
11 for i in 1:Type.dimensionCount(ty) loop
3034 2 args := Expression.SIZE(exp, SOME(Expression.INTEGER(i))) :: args;
3035 end for;
3036 end if;
3037 end for;
3038
3039 5 extDecl.args := listReverse(args);
3040 end if;
3041 then
3042 extDecl;
3043
3044 end match;
3045 end makeDefaultExternalCall;
3046
3047 function checkExternalCallResult
3048 input ComponentRef result;
3049 input SourceInfo info;
3050 protected
3051 Type ty;
3052 algorithm
3053
2/2
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 1089 times.
1231 if not ComponentRef.isCref(result) then
3054 142 return;
3055 end if;
3056
3057 1089 ty := ComponentRef.nodeType(result);
3058
3059
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1088 times.
1089 if Type.isArray(ty) then
3060 2 Error.addSourceMessage(Error.EXTERNAL_FUNCTION_RESULT_ARRAY_TYPE,
3061 {Type.toString(ty)}, info);
3062 1 fail();
3063 end if;
3064
3065
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1088 times.
1088 if ComponentRef.variability(result) < Variability.DISCRETE then
3066 ✗ Error.addSourceMessage(Error.EXTERNAL_FUNCTION_RESULT_NOT_VAR, {}, info);
3067 ✗ fail();
3068 end if;
3069 end checkExternalCallResult;
3070
3071 function typeComponentSections
3072 input InstNode component;
3073 input InstContext.Type context;
3074 protected
3075 Component comp;
3076 algorithm
3077
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 261375 times.
261380 if InstNode.isEmpty(component) then
3078 5 return;
3079 end if;
3080
3081 261375 comp := InstNode.component(component);
3082
3083
4/4
✓ Branch 1 taken 258435 times.
✓ Branch 2 taken 2940 times.
✓ Branch 4 taken 1528 times.
✓ Branch 5 taken 256907 times.
261375 if Component.isDeleted(comp) or InstNode.isOnlyOuter(component) then
3084 4468 return;
3085 end if;
3086
3087 () := match comp
3088 case Component.COMPONENT()
3089 guard comp.state >= ComponentState.TypeChecked
3090 algorithm
3091 256907 typeClassSections(comp.classInst, context);
3092 then
3093 ();
3094
3095 else
3096 algorithm
3097 ✗ Error.terminate(getInstanceName() + " got uninstantiated component " + InstNode.name(component), sourceInfo());
3098 ✗ then
3099 fail();
3100
3101 end match;
3102 end typeComponentSections;
3103
3104 function typeEquation
3105 input output Equation eq;
3106 input InstContext.Type context;
3107 algorithm
3108 eq := match eq
3109 local
3110 Expression e1, e2, e3;
3111 list<Equation> body;
3112 InstNode iterator;
3113 Integer next_context;
3114 SourceInfo info;
3115 Variability var;
3116
3117 57444 case Equation.EQUALITY() then typeEqualityEquation(eq.lhs, eq.rhs, context, eq.scope, eq.source);
3118 13136 case Equation.CONNECT() then typeConnect(eq.lhs, eq.rhs, context, eq.scope, eq.source);
3119 1558 case Equation.FOR() then typeForEquation(eq, context);
3120 6903 case Equation.IF() then typeIfEquation(eq.branches, context, eq.scope, eq.source);
3121 359 case Equation.WHEN() then typeWhenEquation(eq.branches, context, eq.scope, eq.source);
3122
3123 case Equation.ASSERT()
3124 algorithm
3125 3523 info := ElementSource.getInfo(eq.source);
3126 3523 (e1, e2, e3) := typeAssert(eq.condition, eq.message, eq.level, context, info);
3127 3521 then
3128 Equation.ASSERT(e1, e2, e3, eq.scope, eq.source);
3129
3130 case Equation.TERMINATE()
3131 algorithm
3132 9 info := ElementSource.getInfo(eq.source);
3133 9 e1 := typeOperatorArg(eq.message, Type.STRING(), context, "terminate", "message", 1, info);
3134 9 then
3135 Equation.TERMINATE(e1, eq.scope, eq.source);
3136
3137 case Equation.REINIT()
3138 algorithm
3139 43 (e1, e2) := typeReinit(eq.cref, eq.reinitExp, context, eq.source);
3140 40 then
3141 Equation.REINIT(e1, e2, eq.scope, eq.source);
3142
3143 case Equation.NORETCALL()
3144 algorithm
3145 1316 e1 := typeExp(eq.exp, context, ElementSource.getInfo(eq.source));
3146 1315 then
3147 Equation.NORETCALL(e1, eq.scope, eq.source);
3148
3149 else eq;
3150 end match;
3151 end typeEquation;
3152
3153 function typeConnect
3154 input Expression lhsConn;
3155 input Expression rhsConn;
3156 input InstContext.Type context;
3157 input NFInstNode.ScopeRef scope;
3158 input DAE.ElementSource source;
3159 output Equation connEq;
3160 protected
3161 Expression lhs, rhs;
3162 Type lhs_ty, rhs_ty;
3163 MatchKind mk;
3164 InstContext.Type next_context;
3165 SourceInfo info;
3166 Boolean lhs_deleted, rhs_deleted;
3167 algorithm
3168 13136 info := ElementSource.getInfo(source);
3169
3170 // Connections may not be used in if-equations or for-equations unless the
3171 // conditions are evaluable expressions.
3172 // TODO: Also check for cardinality etc. as per 8.3.3.
3173
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13136 times.
13136 if InstContext.inNonexpandable(context) then
3174 ✗ Error.addSourceMessage(Error.IN_NON_EVALUABLE_IF_OR_FOR, {"connect"}, info);
3175 ✗ fail();
3176 end if;
3177
3178 13136 next_context := InstContext.set(context, NFInstContext.CONNECT);
3179 13136 (lhs, lhs_ty, lhs_deleted) := typeConnector(lhsConn, next_context, info);
3180 13131 (rhs, rhs_ty, rhs_deleted) := typeConnector(rhsConn, next_context, info);
3181
3182 // Check that the connectors have matching types, but only if they're not expandable.
3183 // Expandable connectors can only be type checked after they've been augmented during
3184 // the connection handling.
3185
7/8
✓ Branch 0 taken 12300 times.
✓ Branch 1 taken 831 times.
✓ Branch 2 taken 11944 times.
✓ Branch 3 taken 356 times.
✓ Branch 6 taken 11934 times.
✓ Branch 7 taken 10 times.
✓ Branch 10 taken 11934 times.
✗ Branch 11 not taken.
13131 if not (lhs_deleted or rhs_deleted) and
3186 not (Type.isExpandableConnector(Type.arrayElementType(lhs_ty)) or
3187 Type.isExpandableConnector(Type.arrayElementType(rhs_ty))) then
3188 11934 (lhs, rhs, _, mk) := TypeCheck.matchExpressions(lhs, lhs_ty, rhs, rhs_ty, NFTypeCheck.ALLOW_UNKNOWN);
3189
3190
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 11933 times.
11934 if TypeCheck.isIncompatibleMatch(mk) then
3191 // TODO: Better error message.
3192 3 Error.addSourceMessage(Error.CONNECT_TYPE_MISMATCH,
3193 {Expression.toString(lhsConn), Expression.toString(rhsConn)}, info);
3194 1 fail();
3195 end if;
3196 end if;
3197
3198 13130 connEq := Equation.CONNECT(lhs, rhs, scope, source);
3199 end typeConnect;
3200
3201 function typeConnector
3202 input output Expression connExp;
3203 input InstContext.Type context;
3204 input SourceInfo info;
3205 output Type ty;
3206 output Boolean deleted;
3207 algorithm
3208 26267 (connExp, ty, _) := typeExp(connExp, context, info);
3209 26267 deleted := checkConnector(connExp, info);
3210 end typeConnector;
3211
3212 function checkConnector
3213 input Expression connExp;
3214 input SourceInfo info;
3215 output Boolean deleted;
3216 protected
3217 ComponentRef cr;
3218 list<Subscript> subs;
3219 algorithm
3220 () := match connExp
3221 case Expression.CREF(cref = cr as ComponentRef.CREF(origin = Origin.CREF))
3222 algorithm
3223
2/2
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 26264 times.
26267 if not InstNode.isConnector(ComponentRef.node(cr)) then
3224 6 Error.addSourceMessageAndFail(Error.INVALID_CONNECTOR_TYPE,
3225 {ComponentRef.toString(cr)}, info);
3226 end if;
3227
3228
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 26263 times.
26264 if not checkConnectorForm(cr) then
3229 2 Error.addSourceMessageAndFail(Error.INVALID_CONNECTOR_FORM,
3230 {ComponentRef.toString(cr)}, info);
3231 end if;
3232
3233 // subscripts that depend on resizable parameters are allowed
3234
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 26262 times.
26263 if ComponentRef.subscriptsVariability(cr) > Variability.NON_STRUCTURAL_PARAMETER then
3235 1 subs := ComponentRef.subscriptsAllFlat(cr);
3236
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 for sub in subs loop
3237
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 if Subscript.variability(sub) > Variability.NON_STRUCTURAL_PARAMETER then
3238 3 Error.addSourceMessage(Error.CONNECTOR_NON_PARAMETER_SUBSCRIPT,
3239 {Expression.toString(connExp), Subscript.toString(sub)}, info);
3240 1 fail();
3241 end if;
3242 end for;
3243 end if;
3244
3245 26262 deleted := ComponentRef.isDeleted(cr);
3246 then
3247 ();
3248
3249 else
3250 algorithm
3251 ✗ Error.addSourceMessage(Error.INVALID_CONNECTOR_TYPE,
3252 {Expression.toString(connExp)}, info);
3253 ✗ then
3254 fail();
3255 end match;
3256 end checkConnector;
3257
3258 function checkConnectorForm
3259 "Helper function for checkConnector. Checks that a connector cref uses the
3260 correct form, i.e. either c1.c2...cn or m.c."
3261 input ComponentRef cref;
3262 input Boolean isConnector = true;
3263 output Boolean valid;
3264 algorithm
3265 valid := match cref
3266 // The only part of the connector reference allowed to not be a
3267 // non-connector is the very last part.
3268 case ComponentRef.CREF(origin = Origin.CREF)
3269
2/2
✓ Branch 0 taken 45672 times.
✓ Branch 1 taken 1 time.
45673 then if isConnector then
3270 checkConnectorForm(cref.restCref, InstNode.isConnector(ComponentRef.node(cref))) else false;
3271
3272 else true;
3273 end match;
3274 end checkConnectorForm;
3275
3276 function checkLhsInWhen
3277 input Expression exp;
3278 output Boolean isValid;
3279 algorithm
3280 isValid := match exp
3281 case Expression.CREF() then true;
3282 case Expression.TUPLE()
3283 algorithm
3284
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for e in exp.elements loop
3285 12 checkLhsInWhen(e);
3286 end for;
3287 then
3288 true;
3289 else false;
3290 end match;
3291 end checkLhsInWhen;
3292
3293 function typeAssert
3294 input output Expression condition;
3295 input output Expression message;
3296 input output Expression level;
3297 input InstContext.Type context;
3298 input SourceInfo info;
3299 protected
3300 InstContext.Type next_context;
3301 Variability level_var;
3302 algorithm
3303 6178 next_context := InstContext.set(context, NFInstContext.ASSERT);
3304
3305 6178 condition := typeOperatorArg(condition, Type.BOOLEAN(),
3306 InstContext.set(next_context, NFInstContext.CONDITION), "assert", "condition", 1, info);
3307 6178 message := typeOperatorArg(message, Type.STRING(),
3308 next_context, "assert", "message", 2, info);
3309 6177 (level, level_var) := typeOperatorArg(level, NFBuiltin.ASSERTIONLEVEL_TYPE,
3310 next_context, "assert", "level", 3, info);
3311
3312
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 6176 times.
6177 if level_var > Variability.PARAMETER then
3313 3 Error.addSourceMessage(Error.FUNCTION_SLOT_VARIABILITY,
3314 {"level", Expression.toString(level), "assert",
3315 Prefixes.variabilityString(level_var), "parameter"}, info);
3316 1 fail();
3317 end if;
3318
3319 6176 Structural.markExp(level);
3320 end typeAssert;
3321
3322 function typeAlgorithm
3323 input output Algorithm alg;
3324 input InstContext.Type context;
3325 algorithm
3326
4/4
✓ Branch 0 taken 70634 times.
✓ Branch 1 taken 15947 times.
✓ Branch 2 taken 70634 times.
✓ Branch 3 taken 15947 times.
86581 alg.statements := list(typeStatement(s, context) for s in alg.statements);
3327 end typeAlgorithm;
3328
3329 function typeStatements
3330 input output list<Statement> alg;
3331 input InstContext.Type context;
3332 algorithm
3333
4/4
✓ Branch 0 taken 888 times.
✓ Branch 1 taken 624 times.
✓ Branch 2 taken 888 times.
✓ Branch 3 taken 624 times.
1512 alg := list(typeStatement(stmt, context) for stmt in alg);
3334 end typeStatements;
3335
3336 function typeStatement
3337 input output Statement st;
3338 input InstContext.Type context;
3339 algorithm
3340 st := match st
3341 local
3342 Expression cond, e1, e2, e3;
3343 Type ty1, ty2;
3344 list<Statement> sts1, body;
3345 list<tuple<Expression, list<Statement>>> tybrs;
3346 InstNode iterator;
3347 MatchKind mk;
3348 InstContext.Type next_context, cond_context;
3349 SourceInfo info;
3350 Variability var;
3351
3352 case Statement.ASSIGNMENT()
3353 algorithm
3354 105178 info := ElementSource.getInfo(st.source);
3355 105178 (e1, ty1, var) := typeExp(st.lhs, InstContext.set(context, NFInstContext.LHS), info);
3356 105178 (e2, ty2) := typeExp(st.rhs, InstContext.set(context, NFInstContext.RHS), info);
3357
3358 // TODO: Should probably only be allowUnknown = true if in a function.
3359 105176 (e2, _, mk) := TypeCheck.matchTypes(ty2, ty1, e2, NFTypeCheck.ALLOW_UNKNOWN);
3360
3361
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 105175 times.
105176 if TypeCheck.isIncompatibleMatch(mk) then
3362 5 Error.addSourceMessage(Error.ASSIGN_TYPE_MISMATCH_ERROR,
3363 {Expression.toString(e1), Expression.toString(e2),
3364 Type.toString(ty1), Type.toString(ty2)}, info);
3365 1 fail();
3366 end if;
3367
3368 105175 checkAssignment(e1, e2, var, context, info);
3369
3370
2/2
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 105077 times.
105174 if Expression.isExternalCall(e2) then
3371 97 Call.updateExternalRecordArgs(Expression.tupleElements(e1));
3372 end if;
3373 105174 then
3374 Statement.ASSIGNMENT(e1, e2, ty1, st.source);
3375
3376 case Statement.FOR()
3377 algorithm
3378 624 info := ElementSource.getInfo(st.source);
3379
3380
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 624 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 621 times.
624 if isSome(st.range) then
3381 621 SOME(e1) := st.range;
3382 else
3383 3 e1 := deduceIterationRangeStmt(st, st.iterator, info);
3384 end if;
3385
3386 624 e1 := typeIterator(st.iterator, e1, context, structural = false);
3387 624 next_context := InstContext.set(context, NFInstContext.FOR);
3388 624 body := typeStatements(st.body, next_context);
3389 624 then
3390 Statement.FOR(st.iterator, SOME(e1), body, st.forType, st.source, st.sub_iters);
3391
3392 case Statement.IF()
3393 algorithm
3394 5777 next_context := InstContext.set(context, NFInstContext.IF);
3395 5777 cond_context := InstContext.set(next_context, NFInstContext.CONDITION);
3396
3397
4/4
✓ Branch 0 taken 12239 times.
✓ Branch 1 taken 5777 times.
✓ Branch 2 taken 12239 times.
✓ Branch 3 taken 5777 times.
18016 tybrs := list(
3398 match br case(cond, body)
3399 algorithm
3400 12239 e1 := typeCondition(cond, cond_context, st.source, Error.IF_CONDITION_TYPE_ERROR);
3401
4/4
✓ Branch 0 taken 40877 times.
✓ Branch 1 taken 12239 times.
✓ Branch 2 taken 40877 times.
✓ Branch 3 taken 12239 times.
53116 sts1 := list(typeStatement(bst, next_context) for bst in body);
3402 12239 then (e1, sts1);
3403 end match
3404 for br in st.branches);
3405 5777 then
3406 Statement.IF(tybrs, st.source);
3407
3408 case Statement.WHEN()
3409 algorithm
3410 79 next_context := InstContext.set(context, NFInstContext.WHEN);
3411
3412
4/4
✓ Branch 0 taken 113 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 78 times.
191 tybrs := list(
3413 match br case(cond, body)
3414 algorithm
3415 113 e1 := typeWhenCondition(cond, context, st.source, allowClock = false);
3416
4/4
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 112 times.
289 sts1 := list(typeStatement(bst, next_context) for bst in body);
3417 112 then (e1, sts1);
3418 end match
3419 for br in st.branches);
3420 78 then
3421 Statement.WHEN(tybrs, st.source);
3422
3423 case Statement.ASSERT()
3424 algorithm
3425 2655 info := ElementSource.getInfo(st.source);
3426 2655 (e1, e2, e3) := typeAssert(st.condition, st.message, st.level, context, info);
3427 2655 then
3428 Statement.ASSERT(e1, e2, e3, st.source);
3429
3430 case Statement.TERMINATE()
3431 algorithm
3432 2 info := ElementSource.getInfo(st.source);
3433
3434 // terminate is not allowed in a function context.
3435
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 if InstContext.inFunction(context) then
3436 1 Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"terminate"}, info);
3437 1 fail();
3438 end if;
3439
3440 1 e1 := typeOperatorArg(st.message, Type.STRING(), context, "terminate", "message", 1, info);
3441 1 then
3442 Statement.TERMINATE(e1, st.source);
3443
3444 case Statement.REINIT()
3445 algorithm
3446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if InstContext.inFunction(context) then
3447 ✗ Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"reinit"},
3448 ElementSource.getInfo(st.source));
3449 ✗ fail();
3450 end if;
3451
3452 4 (e1, e2) := typeReinit(st.cref, st.reinitExp, context, st.source);
3453 4 then
3454 Statement.REINIT(e1, e2, st.source);
3455
3456 case Statement.NORETCALL()
3457 algorithm
3458 111 e1 := typeExp(st.exp, context, ElementSource.getInfo(st.source));
3459 111 then
3460 Statement.NORETCALL(e1, st.source);
3461
3462 case Statement.WHILE()
3463 algorithm
3464 288 e1 := typeCondition(st.condition, context, st.source, Error.WHILE_CONDITION_TYPE_ERROR);
3465
4/4
✓ Branch 0 taken 2155 times.
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 2155 times.
✓ Branch 3 taken 288 times.
2443 sts1 := list(typeStatement(bst, context) for bst in st.body);
3466 288 then
3467 Statement.WHILE(e1, sts1, st.source);
3468
3469 case Statement.FAILURE()
3470 algorithm
3471 ✗ sts1 := list(typeStatement(bst, context) for bst in st.body);
3472 ✗ then
3473 Statement.FAILURE(sts1, st.source);
3474
3475 else st;
3476 end match;
3477 end typeStatement;
3478
3479 function checkAssignment
3480 input Expression lhsExp;
3481 input Expression rhsExp;
3482 input Variability lhsVar;
3483 input InstContext.Type context;
3484 input SourceInfo info;
3485 algorithm
3486
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 106840 times.
106840 if InstContext.inInstanceAPI(context) then
3487 ✗ return;
3488 end if;
3489
3490 () := match lhsExp
3491 local
3492 Integer i;
3493
3494 case Expression.TUPLE()
3495 algorithm
3496 i := 1;
3497
2/2
✓ Branch 0 taken 1665 times.
✓ Branch 1 taken 748 times.
2413 for e in lhsExp.elements loop
3498 1665 checkAssignment(e, Expression.tupleElement(rhsExp, i), Expression.variability(e), context, info);
3499 1665 i := i + 1;
3500 end for;
3501 then
3502 ();
3503
3504 case Expression.CREF() guard InstContext.inFunction(context)
3505 algorithm
3506 // Give an error if trying to assign to an input inside a function.
3507
4/4
✓ Branch 1 taken 105540 times.
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 105539 times.
105541 if ComponentRef.isCref(lhsExp.cref) and InstNode.isInput(ComponentRef.node(lhsExp.cref)) then
3508 2 Error.addSourceMessage(Error.ASSIGN_READONLY_ERROR,
3509 {"input", ComponentRef.toString(lhsExp.cref)}, info);
3510 1 fail();
3511 end if;
3512 then
3513 ();
3514
3515 else
3516 algorithm
3517 // Give an error if assigning to a constant, or a parameter that's not
3518 // inside an initial algorithm.
3519
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 500 times.
551 if lhsVar < Variability.DISCRETE then
3520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if lhsVar == Variability.CONSTANT then
3521 ✗ Error.addSourceMessage(Error.ASSIGN_CONSTANT_ERROR,
3522 {Expression.toString(lhsExp), Expression.toString(rhsExp)}, info);
3523 ✗ fail();
3524 elseif not InstContext.inInitial(context) then
3525 ✗ Error.addSourceMessage(Error.ASSIGN_PARAM_ERROR,
3526 {Expression.toString(lhsExp), Expression.toString(rhsExp)}, info);
3527 ✗ fail();
3528 end if;
3529 end if;
3530 then
3531 ();
3532 end match;
3533 end checkAssignment;
3534
3535 function typeEqualityEquation
3536 input Expression lhsExp;
3537 input Expression rhsExp;
3538 input InstContext.Type context;
3539 input NFInstNode.ScopeRef scope;
3540 input DAE.ElementSource source;
3541 output Equation eq;
3542 protected
3543 SourceInfo info = ElementSource.getInfo(source);
3544 Expression e1, e2;
3545 Type ty1, ty2, ty;
3546 MatchKind mk;
3547 algorithm
3548
3/4
✓ Branch 1 taken 462 times.
✓ Branch 2 taken 56982 times.
✓ Branch 4 taken 462 times.
✗ Branch 5 not taken.
57444 if InstContext.inWhen(context) and not InstContext.inClocked(context) then
3549
2/2
✓ Branch 1 taken 461 times.
✓ Branch 2 taken 1 time.
462 if checkLhsInWhen(lhsExp) then
3550 461 Structural.markSubscriptsInExp(lhsExp);
3551 else
3552 2 Error.addSourceMessage(Error.WHEN_EQ_LHS, {Expression.toString(lhsExp)}, info);
3553 1 fail();
3554 end if;
3555 end if;
3556
3557 57443 (e1, ty1) := typeExp(lhsExp, InstContext.set(context, NFInstContext.LHS), info);
3558 57441 (e2, ty2) := typeExp(rhsExp, InstContext.set(context, NFInstContext.RHS), info);
3559 57433 (e2, e1, ty, mk) := TypeCheck.matchExpressions(e2, ty2, e1, ty1);
3560
3561
2/2
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57376 times.
57433 if TypeCheck.isIncompatibleMatch(mk) then
3562 114 Error.addSourceMessage(Error.EQUATION_TYPE_MISMATCH_ERROR,
3563 {Expression.toString(lhsExp) + " = " + Expression.toString(rhsExp),
3564 Type.toString(ty1) + " = " + Type.toString(ty2)}, info);
3565 57 fail();
3566 end if;
3567
3568 57376 eq := Equation.EQUALITY(e1, e2, ty, scope, source, NFEquation.ScalarizeMode.NO_PREFERENCE);
3569
3570
2/2
✓ Branch 1 taken 57320 times.
✓ Branch 2 taken 56 times.
57376 if Expression.isExternalCall(e2) then
3571 56 Call.updateExternalRecordArgs(Expression.tupleElements(e1));
3572 end if;
3573 end typeEqualityEquation;
3574
3575 function typeCondition
3576 input output Expression condition;
3577 input InstContext.Type context;
3578 input DAE.ElementSource source;
3579 input ErrorTypes.Message errorMsg;
3580 input Boolean allowVector = false;
3581 input Boolean allowClock = false;
3582 output Type ty;
3583 output Variability variability;
3584 protected
3585 SourceInfo info;
3586 Type ety;
3587 algorithm
3588 26027 info := ElementSource.getInfo(source);
3589 26027 (condition, ty, variability) := typeExp(condition, context, info);
3590
3591
4/4
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 25516 times.
✓ Branch 3 taken 76 times.
✓ Branch 4 taken 434 times.
26026 if allowVector and Type.isArray(ty) then
3592 76 ety := Type.unliftArray(ty);
3593 else
3594 25950 ety := ty;
3595 end if;
3596
3597
4/6
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 25989 times.
✓ Branch 3 taken 37 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
26026 if not (Type.isBoolean(ety) or (allowClock and Type.isClock(ety))) then
3598 ✗ Error.addSourceMessage(errorMsg,
3599 {Expression.toString(condition), Type.toString(ty)}, info);
3600 ✗ fail();
3601 end if;
3602 end typeCondition;
3603
3604 function typeForEquation
3605 input Equation eq;
3606 input InstContext.Type context;
3607 output Equation forEq;
3608 protected
3609 InstNode iterator;
3610 Option<Expression> range;
3611 list<Equation> body;
3612 NFInstNode.ScopeRef scope;
3613 DAE.ElementSource src;
3614 SourceInfo info;
3615 Expression range_exp;
3616 Variability range_var;
3617 InstContext.Type next_context;
3618 algorithm
3619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1558 times.
1558 Equation.FOR(iterator, range, body, scope, src) := eq;
3620
3621
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1558 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1553 times.
1558 if isSome(range) then
3622 1553 SOME(range_exp) := range;
3623 else
3624 5 range_exp := deduceIterationRangeEq(eq, iterator, ElementSource.getInfo(src));
3625 end if;
3626
3627 1557 (range_exp, _, range_var) := typeIterator(iterator, range_exp, context, structural = true);
3628 1556 next_context := InstContext.set(context, NFInstContext.FOR);
3629
3630 // A range with resizable parameters is still expandable, its bounds are evaluated to resolve connections.
3631
2/4
✓ Branch 0 taken 1556 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1556 times.
1556 if range_var > Variability.NON_STRUCTURAL_PARAMETER or Structural.isExpressionNotFixed(range_exp, maxDepth = 100) then
3632 ✗ next_context := InstContext.set(context, NFInstContext.NONEXPANDABLE);
3633 end if;
3634
3635
4/4
✓ Branch 0 taken 2484 times.
✓ Branch 1 taken 1555 times.
✓ Branch 2 taken 2484 times.
✓ Branch 3 taken 1555 times.
4039 body := list(typeEquation(e, next_context) for e in body);
3636 1555 forEq := Equation.FOR(iterator, SOME(range_exp), body, scope, src);
3637 end typeForEquation;
3638
3639 function typeIfEquation
3640 input list<Equation.Branch> branches;
3641 input InstContext.Type context;
3642 input NFInstNode.ScopeRef scope;
3643 input DAE.ElementSource source;
3644 output Equation ifEq;
3645 protected
3646 Expression cond;
3647 list<Equation> eql;
3648 Variability accum_var = Variability.CONSTANT, var;
3649 list<Equation.Branch> bl = {}, bl2 = {};
3650 InstContext.Type next_context = InstContext.set(context, NFInstContext.IF);
3651 InstContext.Type cond_context = InstContext.set(next_context, NFInstContext.CONDITION);
3652 algorithm
3653 // Type the conditions of all the branches.
3654
2/2
✓ Branch 0 taken 12989 times.
✓ Branch 1 taken 6903 times.
19892 for b in branches loop
3655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12989 times.
12989 Equation.Branch.BRANCH(cond, _, eql) := b;
3656 12989 (cond, _, var) := typeCondition(cond, cond_context, source, Error.IF_CONDITION_TYPE_ERROR);
3657
3658 // Conditions on resizable parameters (and iterators over them) are resolved with the connections.
3659
7/8
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 12710 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 278 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✓ Branch 8 taken 1061 times.
✓ Branch 9 taken 11649 times.
12989 if (var > Variability.PARAMETER and not (var == Variability.NON_STRUCTURAL_PARAMETER and
3660 Flags.getConfigBool(Flags.RESIZABLE_ARRAYS))) or Structural.isExpressionNotFixed(cond, maxDepth = 100) then
3661 // If the condition doesn't fulfill the requirements for allowing
3662 // connections in the branch, mark the context so we can check that when
3663 // typing the body of the branch.
3664 1340 next_context := InstContext.set(next_context, NFInstContext.NONEXPANDABLE);
3665 elseif var == Variability.PARAMETER and
3666 (accum_var <= Variability.PARAMETER or Equation.containsList(eql, Equation.isConnection)) then
3667 // If all conditions up to and including this one are parameter
3668 // expressions, consider the condition to be structural.
3669 1482 var := Variability.STRUCTURAL_PARAMETER;
3670 end if;
3671
3672 12989 accum_var := Prefixes.variabilityMax(accum_var, var);
3673 12989 bl := Equation.Branch.BRANCH(cond, var, eql) :: bl;
3674 end for;
3675
3676 // Type the bodies of all the branches.
3677
2/2
✓ Branch 0 taken 12989 times.
✓ Branch 1 taken 6903 times.
19892 for b in bl loop
3678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12989 times.
12989 Equation.Branch.BRANCH(cond, var, eql) := b;
3679
3680 12989 ErrorExt.setCheckpoint(getInstanceName());
3681 try
3682
4/4
✓ Branch 0 taken 23361 times.
✓ Branch 1 taken 12934 times.
✓ Branch 2 taken 23361 times.
✓ Branch 3 taken 12934 times.
36295 eql := list(typeEquation(e, next_context) for e in eql);
3683 12934 bl2 := Equation.makeBranch(cond, eql, var) :: bl2;
3684 else
3685 55 bl2 := Equation.INVALID_BRANCH(Equation.makeBranch(cond, eql, var),
3686 ErrorExt.getCheckpointMessages()) :: bl2;
3687 end try;
3688 12989 ErrorExt.delCheckpoint(getInstanceName());
3689 end for;
3690
3691 6903 ifEq := Equation.IF(bl2, scope, source);
3692 end typeIfEquation;
3693
3694 function typeWhenEquation
3695 input list<Equation.Branch> branches;
3696 input InstContext.Type context;
3697 input NFInstNode.ScopeRef scope;
3698 input DAE.ElementSource source;
3699 output Equation whenEq;
3700 protected
3701 InstContext.Type next_context = InstContext.set(context, NFInstContext.WHEN);
3702 list<Equation.Branch> accum_branches = {};
3703 Expression cond;
3704 list<Equation> body;
3705 Type ty;
3706 Variability var;
3707 algorithm
3708
2/2
✓ Branch 0 taken 399 times.
✓ Branch 1 taken 352 times.
751 for branch in branches loop
3709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 399 times.
399 Equation.Branch.BRANCH(cond, _, body) := branch;
3710 399 (cond, ty, var) := typeWhenCondition(cond, context, source, allowClock = true);
3711
3712
2/2
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 360 times.
397 if Type.isClock(ty) then
3713
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 36 times.
37 if listLength(branches) <> 1 then
3714
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if referenceEq(branch, listHead(branches)) then
3715 ✗ Error.addSourceMessage(Error.ELSE_WHEN_CLOCK, {}, ElementSource.getInfo(source));
3716 else
3717 1 Error.addSourceMessage(Error.CLOCKED_WHEN_BRANCH, {}, ElementSource.getInfo(source));
3718 end if;
3719
3720 1 fail();
3721 else
3722 36 next_context := InstContext.set(context, NFInstContext.CLOCKED);
3723 end if;
3724 end if;
3725
3726
4/4
✓ Branch 0 taken 570 times.
✓ Branch 1 taken 392 times.
✓ Branch 2 taken 570 times.
✓ Branch 3 taken 392 times.
962 body := list(typeEquation(eq, next_context) for eq in body);
3727 392 accum_branches := Equation.makeBranch(cond, body, var) :: accum_branches;
3728 end for;
3729
3730 352 whenEq := Equation.WHEN(listReverseInPlace(accum_branches), scope, source);
3731 end typeWhenEquation;
3732
3733 function typeWhenCondition
3734 input Expression condition;
3735 input InstContext.Type context;
3736 input DAE.ElementSource source;
3737 input Boolean allowClock;
3738 output Expression outCondition;
3739 output Type ty;
3740 output Variability variability;
3741 algorithm
3742
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 511 times.
512 if InstContext.inNonexpandable(context) then
3743 1 Error.addSourceMessage(Error.IN_NON_EVALUABLE_IF_OR_FOR, {"when"}, ElementSource.getInfo(source));
3744 1 fail();
3745 end if;
3746
3747 511 (outCondition, ty, variability) := typeCondition(condition, context, source,
3748 Error.WHEN_CONDITION_TYPE_ERROR, allowVector = true, allowClock = allowClock);
3749
3750
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 496 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 13 times.
510 if variability > Variability.IMPLICITLY_DISCRETE and not Type.isClock(ty) then
3751 2 Error.addSourceMessage(Error.NON_DISCRETE_WHEN_CONDITION,
3752 {Expression.toString(condition)}, ElementSource.getInfo(source));
3753 1 fail();
3754 end if;
3755
3756
1/2
✓ Branch 1 taken 509 times.
✗ Branch 2 not taken.
509 if not checkWhenInitial(outCondition) then
3757 ✗ Error.addSourceMessage(Error.INITIAL_CALL_WARNING,
3758 {Expression.toString(condition)}, ElementSource.getInfo(source));
3759 end if;
3760 end typeWhenCondition;
3761
3762 function checkWhenInitial
3763 "Checks that initial() is only used as either initial() or
3764 {..., initial(), ...} in a when-equation condition."
3765 input Expression condition;
3766 output Boolean invalid;
3767 algorithm
3768 invalid := match condition
3769 case Expression.ARRAY()
3770 algorithm
3771
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✓ Branch 3 taken 69 times.
✗ Branch 4 not taken.
138 for e in condition.elements loop
3772
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 if checkWhenInitial(e) then
3773 invalid := true;
3774 69 return;
3775 end if;
3776 end for;
3777 then
3778 false;
3779
3780 509 else not Expression.containsShallow(condition,
3781 function Expression.contains(func = function Expression.isCallNamed(name = "initial")));
3782
3783 end match;
3784 end checkWhenInitial;
3785
3786 function typeOperatorArg
3787 input output Expression arg;
3788 input Type expectedType;
3789 input InstContext.Type context;
3790 input String operatorName;
3791 input String argName;
3792 input Integer argIndex;
3793 input SourceInfo info;
3794 output Variability var;
3795 protected
3796 Type ty;
3797 MatchKind mk;
3798 algorithm
3799 18543 (arg, ty, var) := typeExp(arg, context, info);
3800 18543 (arg, _, mk) := TypeCheck.matchTypes(ty, expectedType, arg);
3801
3802
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 18542 times.
18543 if TypeCheck.isIncompatibleMatch(mk) then
3803 5 Error.addSourceMessage(Error.ARG_TYPE_MISMATCH,
3804 {intString(argIndex), operatorName, argName, Expression.toString(arg),
3805 Type.toString(ty), Type.toString(expectedType)}, info);
3806 1 fail();
3807 end if;
3808 end typeOperatorArg;
3809
3810 function typeReinit
3811 input output Expression crefExp;
3812 input output Expression exp;
3813 input InstContext.Type context;
3814 input DAE.ElementSource source;
3815 protected
3816 MatchKind mk;
3817 Type ty1, ty2;
3818 ComponentRef cref;
3819 SourceInfo info;
3820 algorithm
3821 47 info := ElementSource.getInfo(source);
3822 47 (crefExp, ty1, _) := typeExp(crefExp, context, info);
3823 47 (exp, ty2, _) := typeExp(exp, context, info);
3824
3825 // The first argument must be a cref.
3826 cref := match crefExp
3827 case Expression.CREF()
3828 algorithm
3829
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 46 times.
47 if ComponentRef.isIterator(crefExp.cref) then
3830 2 Error.addSourceMessage(Error.ASSIGN_ITERATOR_ERROR,
3831 {ComponentRef.toString(crefExp.cref)}, info);
3832 1 fail();
3833 end if;
3834 46 then
3835 crefExp.cref;
3836
3837 else
3838 algorithm
3839 ✗ Error.addSourceMessage(Error.REINIT_MUST_BE_VAR_OR_ARRAY, {}, info);
3840 ✗ then
3841 fail();
3842 end match;
3843
3844 // The first argument must be a continuous time variable.
3845 // Check the variability of the cref instead of the variability returned by
3846 // typeExp, since expressions in when-equations count as discrete.
3847
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 45 times.
46 if ComponentRef.nodeVariability(cref) < Variability.IMPLICITLY_DISCRETE then
3848 3 Error.addSourceMessage(Error.REINIT_MUST_BE_VAR,
3849 {Expression.toString(crefExp),
3850 Prefixes.variabilityString(ComponentRef.nodeVariability(cref))}, info);
3851 1 fail();
3852 end if;
3853
3854 // The first argument must be a subtype of Real.
3855 45 (_, _, mk) := TypeCheck.matchTypes(Type.arrayElementType(ty1), Type.REAL(), crefExp);
3856
3857
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
45 if TypeCheck.isIncompatibleMatch(mk) then
3858 ✗ Error.addSourceMessage(Error.REINIT_MUST_BE_REAL,
3859 {Expression.toString(crefExp), Type.toString(Type.arrayElementType(ty1))}, info);
3860 ✗ fail();
3861 end if;
3862
3863 // The second argument must be type compatible with the first.
3864 45 (exp, _, mk) := TypeCheck.matchTypes(ty2, ty1, exp);
3865
3866
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 44 times.
45 if TypeCheck.isIncompatibleMatch(mk) then
3867 4 Error.addSourceMessage(Error.ARG_TYPE_MISMATCH,
3868 {"2", "reinit", "", Expression.toString(exp), Type.toString(ty2), Type.toString(ty1)}, info);
3869 1 fail();
3870 end if;
3871 end typeReinit;
3872
3873 function deduceIterationRangeEq
3874 input Equation eq;
3875 input InstNode iterator;
3876 input SourceInfo info;
3877 output Expression iterationRange;
3878 protected
3879 list<tuple<ComponentRef, Integer>> crefs;
3880 algorithm
3881 5 crefs := Equation.foldExp(eq, function collectIteratorCrefs(iterator = iterator), {});
3882 5 iterationRange := deduceIterationRange(crefs, iterator, info);
3883 end deduceIterationRangeEq;
3884
3885 function deduceIterationRangeStmt
3886 input Statement stmt;
3887 input InstNode iterator;
3888 input SourceInfo info;
3889 output Expression iterationRange;
3890 protected
3891 list<tuple<ComponentRef, Integer>> crefs;
3892 algorithm
3893 3 crefs := Statement.foldExp(stmt, function collectIteratorCrefs(iterator = iterator), {});
3894 3 iterationRange := deduceIterationRange(crefs, iterator, info);
3895 end deduceIterationRangeStmt;
3896
3897 function deduceIterationRangeExp
3898 input Expression exp;
3899 input InstNode iterator;
3900 input SourceInfo info;
3901 output Expression iterationRange;
3902 protected
3903 list<tuple<ComponentRef, Integer>> crefs;
3904 algorithm
3905 2 crefs := Expression.fold(exp, function collectIteratorCrefs2(iterator = iterator), {});
3906 2 iterationRange := deduceIterationRange(crefs, iterator, info);
3907 end deduceIterationRangeExp;
3908
3909 function deduceIterationRange
3910 "Deduces the range of an iterator given a list of crefs and dimension indices
3911 that the iterator was used to index."
3912 input list<tuple<ComponentRef, Integer>> crefs;
3913 input InstNode iterator;
3914 input SourceInfo info;
3915 output Expression iterationRange;
3916 protected
3917 tuple<ComponentRef, Integer> range_cr;
3918 ComponentRef cr;
3919 Integer dim_index;
3920 Dimension dim;
3921 Expression start_exp, stop_exp;
3922 algorithm
3923 // The iterator needs to be used in a subscript somewhere to be able to deduce it.
3924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if listEmpty(crefs) then
3925 ✗ Error.addSourceMessage(Error.IMPLICIT_ITERATOR_NOT_FOUND_IN_LOOP_BODY,
3926 {InstNode.name(iterator)}, info);
3927 ✗ fail();
3928 end if;
3929
3930 // Check that the dimensions are all the same.
3931 10 range_cr := List.reduce(crefs, function deduceIterationRange2(info = info));
3932 9 (cr, dim_index) := range_cr;
3933
3934 // Deduced iteration range is 1:size(cr, dim_index)
3935 9 dim := Type.nthDimension(InstNode.getType(ComponentRef.node(cr)), dim_index);
3936 9 start_exp := Dimension.lowerBoundExp(dim);
3937 9 stop_exp := Dimension.endExp(dim, Expression.CREF(Type.UNKNOWN(), cr), dim_index);
3938 9 iterationRange := Expression.RANGE(Type.UNKNOWN(), start_exp, NONE(), stop_exp);
3939 end deduceIterationRange;
3940
3941 function collectIteratorCrefs
3942 "Traverses an expression and return a list of crefs that the given iterator
3943 was used as a subscript in, as well as the index of the dimension that the
3944 subscripts are indexing."
3945 input Expression exp;
3946 input InstNode iterator;
3947 input output list<tuple<ComponentRef, Integer>> crefs;
3948 algorithm
3949 16 crefs := Expression.fold(exp, function collectIteratorCrefs2(iterator = iterator), crefs);
3950 end collectIteratorCrefs;
3951
3952 function collectIteratorCrefs2
3953 "Helper function to collectIteratorCrefs, collects the iterator crefs in an
3954 expression."
3955 input Expression exp;
3956 input InstNode iterator;
3957 input output list<tuple<ComponentRef, Integer>> crefs;
3958 protected
3959 ComponentRef cref;
3960 Integer index;
3961 list<Subscript> subs;
3962 algorithm
3963 () := match exp
3964 case Expression.CREF(cref = cref)
3965 algorithm
3966
2/2
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 37 times.
78 while ComponentRef.isCref(cref) loop
3967 41 (cref, subs) := ComponentRef.stripSubscripts(cref);
3968 index := 1;
3969
3970
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 41 times.
57 for sub in subs loop
3971
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 if Subscript.equalsIterator(sub, iterator) then
3972 16 crefs := (cref, index) :: crefs;
3973 end if;
3974
3975 16 index := index + 1;
3976 end for;
3977
3978 41 cref := ComponentRef.rest(cref);
3979 end while;
3980 then
3981 ();
3982
3983 else ();
3984 end match;
3985 end collectIteratorCrefs2;
3986
3987 function deduceIterationRange2
3988 "Helper function to deduceIterationRange, check that two dimensions are the same."
3989 input tuple<ComponentRef, Integer> range1;
3990 input tuple<ComponentRef, Integer> range2;
3991 input SourceInfo info;
3992 output tuple<ComponentRef, Integer> range = range2;
3993 protected
3994 ComponentRef cref1, cref2;
3995 Integer index1, index2;
3996 InstNode node1, node2;
3997 Dimension dim1, dim2;
3998 algorithm
3999 6 (cref1, index1) := range1;
4000 6 (cref2, index2) := range2;
4001 6 node1 := ComponentRef.node(cref1);
4002 6 node2 := ComponentRef.node(cref2);
4003
4004 // Skip the check if they refer to the same dimension.
4005
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 5 times.
6 if index1 == index2 and InstNode.refEqual(node1, node2) then
4006 1 return;
4007 end if;
4008
4009 // The crefs are probably untyped here, so use the type of the instance nodes instead.
4010 5 dim1 := Type.nthDimension(InstNode.getType(node1), index1);
4011 5 dim2 := Type.nthDimension(InstNode.getType(node2), index2);
4012
4013
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 4 times.
5 if not Dimension.isEqualKnownSize(dim1, node1, index1, dim2, node2, index2) then
4014 3 Error.addSourceMessage(Error.INCOMPATIBLE_IMPLICIT_RANGES,
4015 {String(index1), ComponentRef.toString(cref1),
4016 String(index2), ComponentRef.toString(cref2)}, info);
4017 1 fail();
4018 end if;
4019 end deduceIterationRange2;
4020
4021 annotation(__OpenModelica_Interface="nf_frontend");
4022 end NFTyping;
4023