Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.7% 39 / 0 / 45
Functions: -% 0 / 1 / 1
Branches: 90.0% 18 / 0 / 20

OMCompiler/Compiler/NFFrontEnd/NFOperatorOverloading.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 NFOperatorOverloading
37 import Absyn;
38 import AbsynUtil;
39 import NFInstNode.InstNode;
40 import NFFunction.Function;
41 import Type = NFType;
42
43 protected
44 import Record = NFRecord;
45 import ComponentRef = NFComponentRef;
46 import NFClassTree.ClassTree;
47 import Class = NFClass;
48 import Component = NFComponent;
49 import Binding = NFBinding;
50 import Expression = NFExpression;
51 import Call = NFCall;
52 import SCodeUtil;
53 import InstContext = NFInstContext;
54
55 public
56 function instConstructor
57 input Absyn.Path path;
58 input output InstNode recordNode;
59 input InstContext.Type context;
60 input SourceInfo info;
61 protected
62 ComponentRef ctor_ref = ComponentRef.EMPTY();
63 Absyn.Path ctor_path;
64 Boolean ctor_overloaded;
65 InstNode ctor_node;
66 algorithm
67 // Check if the operator record has an overloaded constructor declared.
68 try
69 250 ctor_ref := Function.lookupFunctionSimple("'constructor'", recordNode, context);
70 ctor_overloaded := true;
71 else
72 ctor_overloaded := false;
73 end try;
74
75
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 13 times.
250 if ctor_overloaded then
76 // If it has an overloaded constructor, instantiate it and add the
77 // function(s) to the record node.
78 237 (_, ctor_node) := Function.instFunctionRef(ctor_ref, context, info);
79 237 ctor_path := InstNode.fullPath(ctor_node);
80
81
2/2
✓ Branch 1 taken 237 times.
✓ Branch 2 taken 236 times.
710 for f in Function.getCachedFuncs(ctor_node) loop
82 237 checkOperatorConstructorOutput(f, Class.lastBaseClass(recordNode), ctor_path, info);
83 236 recordNode := InstNode.cacheAddFunc(recordNode, f, false);
84 end for;
85 end if;
86
87 249 recordNode := Record.instDefaultConstructor(path, recordNode, context, info);
88 end instConstructor;
89
90 function instOperatorFunctions
91 input output InstNode node;
92 input InstContext.Type context;
93 input SourceInfo info;
94 protected
95 ClassTree tree;
96 array<InstNode> mclss;
97 list<Function> allfuncs = {}, funcs;
98 algorithm
99 135 checkOperatorRestrictions(node);
100 135 tree := Class.classTree(InstNode.getClass(node));
101
102 () := match tree
103 case ClassTree.FLAT_TREE(classes = mclss)
104 algorithm
105
2/2
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 135 times.
337 for op in mclss loop
106 202 Function.instFunctionNode(op, context, info);
107 202 funcs := Function.getCachedFuncs(op);
108 202 allfuncs := listAppend(funcs, allfuncs);
109 end for;
110
111
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 135 times.
337 for f in allfuncs loop
112 202 node := InstNode.cacheAddFunc(node, f, false);
113 end for;
114 then
115 ();
116
117 else
118 algorithm
119 ✗ Error.terminate(getInstanceName() + " got non-instantiated function", sourceInfo());
120 ✗ then
121 fail();
122
123 end match;
124 end instOperatorFunctions;
125
126 function checkOperatorRestrictions
127 input InstNode operatorNode;
128 algorithm
129
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 173 times.
173 if not SCodeUtil.isElementEncapsulated(InstNode.definition(operatorNode)) then
130 ✗ Error.addSourceMessage(Error.OPERATOR_NOT_ENCAPSULATED,
131 {AbsynUtil.pathString(InstNode.fullPath(operatorNode))},
132 InstNode.info(operatorNode));
133 ✗ fail();
134 end if;
135 end checkOperatorRestrictions;
136
137 function lookupOperatorFunctionsInType
138 input String operatorName;
139 input Type ty;
140 output list<Function> functions;
141 protected
142 InstNode node;
143 Type elem_ty;
144 ComponentRef fn_ref = ComponentRef.EMPTY();
145 Boolean is_defined;
146 algorithm
147 functions := match Type.arrayElementType(ty)
148 case elem_ty as Type.COMPLEX()
149 algorithm
150 1683 node := Type.complexNode(elem_ty);
151
152 try
153 1683 fn_ref := Function.lookupFunctionSimple(operatorName, node, NFInstContext.NO_CONTEXT);
154 is_defined := true;
155 else
156 is_defined := false;
157 end try;
158
159
2/2
✓ Branch 0 taken 1682 times.
✓ Branch 1 taken 1 time.
1683 if is_defined then
160 1682 fn_ref := Function.instFunctionRef(fn_ref, NFInstContext.NO_CONTEXT, InstNode.info(node));
161 1682 functions := Function.typeRefCache(fn_ref);
162 else
163 functions := {};
164 end if;
165 then
166 functions;
167
168 else {};
169 end match;
170 end lookupOperatorFunctionsInType;
171
172 function patchOperatorRecordConstructorBinding
173 "Patches operator record constructors to avoid recursive binding.
174
175 They often have outputs declared as:
176 output RecordType result = RecordType(args)
177
178 The binding in such cases causes a recursive definition of the constructor,
179 so to avoid that we rewrite any calls to the constructor in the binding as
180 record expressions."
181 input output Function fn;
182 protected
183 InstNode output_node;
184 Component output_comp;
185 Binding output_binding;
186 algorithm
187 // Due to how this function is used it might also be called on destructors,
188 // which we just ignore.
189
2/2
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 4514 times.
4578 if listLength(fn.outputs) <> 1 then
190 64 return;
191 end if;
192
193 4514 output_node := InstNode.fromHandle(listHead(fn.outputs));
194 4514 output_comp := InstNode.component(output_node);
195 4514 output_binding := Component.getBinding(output_comp);
196
197
2/2
✓ Branch 1 taken 4508 times.
✓ Branch 2 taken 6 times.
4514 if not Binding.isBound(output_binding) then
198 4508 return;
199 end if;
200
201 6 output_binding := Binding.mapExp(output_binding,
202 function patchOperatorRecordConstructorBinding_traverser(constructorFn = fn));
203 6 output_comp := Component.setBinding(output_binding, output_comp);
204 6 output_node := InstNode.updateComponent(output_comp, output_node);
205 end patchOperatorRecordConstructorBinding;
206
207 protected
208 function checkOperatorConstructorOutput
209 input Function fn;
210 input InstNode recordNode;
211 input Absyn.Path path;
212 input SourceInfo info;
213 protected
214 InstNode output_node, output_ty;
215 algorithm
216
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 236 times.
237 if listLength(fn.outputs) <> 1 then
217 2 Error.addSourceMessage(Error.OPERATOR_OVERLOADING_ONE_OUTPUT_ERROR,
218 {AbsynUtil.pathString(path)}, info);
219 1 fail();
220 end if;
221
222 236 output_node := InstNode.fromHandle(listHead(fn.outputs));
223 236 output_ty := InstNode.classScope(output_node);
224
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
236 if not InstNode.isSame(output_ty, recordNode) then
225 ✗ Error.addSourceMessage(Error.OPERATOR_OVERLOADING_INVALID_OUTPUT_TYPE,
226 {InstNode.name(output_node), AbsynUtil.pathString(path),
227 InstNode.name(recordNode), InstNode.name(output_ty)}, info);
228 ✗ fail();
229 end if;
230 end checkOperatorConstructorOutput;
231
232 function patchOperatorRecordConstructorBinding_traverser
233 input Expression exp;
234 input Function constructorFn;
235 output Expression outExp;
236 protected
237 Function fn;
238 list<Expression> args;
239 Type ty;
240 algorithm
241 outExp := match exp
242 case Expression.CALL(call = Call.TYPED_CALL(fn = fn, ty = ty, arguments = args))
243 guard referenceEq(InstNode.fromHandle(constructorFn.node), InstNode.fromHandle(fn.node))
244 4 then Expression.makeRecord(Function.name(constructorFn), ty, args);
245
246 else exp;
247 end match;
248 end patchOperatorRecordConstructorBinding_traverser;
249
250 annotation(__OpenModelica_Interface="nf_frontend");
251 end NFOperatorOverloading;
252