Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 81.1% 522 / 0 / 644
Functions: -% 0 / 1 / 1
Branches: 72.1% 202 / 0 / 280

OMCompiler/Compiler/FrontEnd/Patternm.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 Patternm
37 " file: Patternm.mo
38 package: Patternm
39 description: Patternmatching
40
41
42 This module contains the patternmatch algorithm for the MetaModelica
43 matchcontinue expression."
44
45 import Absyn;
46 import AbsynUtil;
47 import Ceval;
48 import ClassInf;
49 import ConnectionGraph;
50 import DAE;
51 import FCore;
52 import HashTableStringToPath;
53 import SCode;
54 import Dump;
55 import InnerOuter;
56 import Types;
57 import UnitAbsyn;
58
59 protected
60
61 import Algorithm;
62 import AvlSetString;
63 import BaseHashTable;
64 import ComponentReference;
65 protected import ComponentReferenceBasics;
66 import DAE.Connect;
67 import ElementSource;
68 import Expression;
69 import ExpressionDump;
70 import Error;
71 import ErrorExt;
72 import Flags;
73 import FGraph;
74 import Inst;
75 import InstSection;
76 import InstTypes;
77 import InstUtil;
78 import List;
79 import Lookup;
80 import MetaModelica.Dangerous;
81 import AbsynToSCode;
82 import SCodeUtil;
83 import Static;
84 import System;
85 import Util;
86 import SCodeDump;
87 import ExpressionBasics;
88
89 protected function generatePositionalArgs "author: KS
90 This function is used in the following cases:
91 v := matchcontinue (x)
92 case REC(a=1,b=2)
93 ...
94 The named arguments a=1 and b=2 must be sorted and transformed into
95 positional arguments (a,b is not necessarely the correct order).
96 "
97 input list<Absyn.Ident> fieldNameList;
98 input list<Absyn.NamedArg> namedArgList;
99 input list<Absyn.Exp> accList;
100 output list<Absyn.Exp> outList;
101 output list<Absyn.NamedArg> outInvalidNames;
102 algorithm
103 (outList,outInvalidNames) := match (fieldNameList,namedArgList,accList)
104 local
105 list<Absyn.Exp> localAccList;
106 list<Absyn.Ident> restFieldNames;
107 Absyn.Ident firstFieldName;
108 Absyn.Exp exp;
109 list<Absyn.NamedArg> localNamedArgList;
110 5298 case ({},_,localAccList) then (listReverse(localAccList),namedArgList);
111 case (firstFieldName :: restFieldNames,localNamedArgList,localAccList)
112 algorithm
113 8529 (exp,localNamedArgList) := findFieldExpInList(firstFieldName,localNamedArgList);
114 8529 (localAccList,localNamedArgList) := generatePositionalArgs(restFieldNames,localNamedArgList,exp::localAccList);
115 then (localAccList,localNamedArgList);
116 end match;
117 end generatePositionalArgs;
118
119 protected function findFieldExpInList "author: KS
120 Helper function to generatePositionalArgs
121 "
122 input Absyn.Ident firstFieldName;
123 input list<Absyn.NamedArg> namedArgList;
124 output Absyn.Exp outExp;
125 output list<Absyn.NamedArg> outNamedArgList;
126 algorithm
127 (outExp,outNamedArgList) := match (firstFieldName,namedArgList)
128 local
129 Absyn.Exp e;
130 Absyn.Ident localFieldName,aName;
131 list<Absyn.NamedArg> rest;
132 Absyn.NamedArg first;
133 case (_,{}) then (Absyn.CREF(Absyn.WILD()),{});
134 case (localFieldName,Absyn.NAMEDARG(aName,e) :: rest) guard stringEq(localFieldName,aName)
135 4117 then (e,rest);
136 case (localFieldName,first::rest)
137 algorithm
138 1497 (e,rest) := findFieldExpInList(localFieldName,rest);
139 1497 then (e,first::rest);
140 end match;
141 end findFieldExpInList;
142
143 protected function checkInvalidPatternNamedArgs
144 "Checks that there are no invalid named arguments in the pattern"
145 input list<Absyn.NamedArg> args;
146 input list<String> fieldNameList;
147 input Util.Status status;
148 input SourceInfo info;
149 output Util.Status outStatus;
150 algorithm
151 outStatus := match args
152 local
153 list<String> argsNames;
154 String str1,str2;
155 case {} then status;
156 else
157 algorithm
158 2 (argsNames,_) := AbsynUtil.getNamedFuncArgNamesAndValues(args);
159 2 str1 := stringDelimitList(argsNames, ",");
160 2 str2 := stringDelimitList(fieldNameList, ",");
161 2 Error.addSourceMessage(Error.META_INVALID_PATTERN_NAMED_FIELD, {str1,str2}, info);
162 then Util.FAILURE();
163 end match;
164 end checkInvalidPatternNamedArgs;
165
166 public function elabPatternCheckDuplicateBindings
167 input FCore.Cache cache;
168 input FCore.Graph env;
169 input Absyn.Exp lhs;
170 input DAE.Type ty;
171 input SourceInfo info;
172 output FCore.Cache outCache;
173 output DAE.Pattern pattern;
174 algorithm
175 675 (outCache,pattern) := elabPattern2(cache,env,lhs,ty,info,Error.getNumErrorMessages());
176 667 checkPatternsDuplicateAsBindings(pattern::{}, info);
177 end elabPatternCheckDuplicateBindings;
178
179 protected function elabPattern
180 input FCore.Cache cache;
181 input FCore.Graph env;
182 input Absyn.Exp lhs;
183 input DAE.Type ty;
184 input SourceInfo info;
185 output FCore.Cache outCache;
186 output DAE.Pattern pattern;
187 algorithm
188 22940 (outCache,pattern) := elabPattern2(cache,env,lhs,ty,info,Error.getNumErrorMessages());
189 end elabPattern;
190
191 protected function checkPatternsDuplicateAsBindings
192 input list<DAE.Pattern> patterns;
193 input SourceInfo info;
194 protected
195 list<String> usedVariables;
196 algorithm
197 5836 (_, usedVariables) := traversePatternList(patterns, findBoundVariables, {});
198 5836 usedVariables := List.sortedUniqueOnlyDuplicates(List.sort(usedVariables, Util.strcmpBool), stringEq);
199
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5831 times.
5836 if not listEmpty(usedVariables) then
200 10 Error.addSourceMessage(Error.DUPLICATE_DEFINITION, {stringDelimitList(usedVariables, ", ")}, info);
201 5 fail();
202 end if;
203 end checkPatternsDuplicateAsBindings;
204
205 protected function findBoundVariables
206 input DAE.Pattern pat;
207 input list<String> boundVars;
208 output DAE.Pattern outPat=pat;
209 output list<String> outBoundVars;
210 algorithm
211 outBoundVars := match pat
212 8099 case DAE.PAT_AS() then pat.id::boundVars;
213 11 case DAE.PAT_AS_FUNC_PTR() then pat.id::boundVars;
214 else boundVars;
215 end match;
216 end findBoundVariables;
217
218 protected function elabPattern2
219 input FCore.Cache inCache;
220 input FCore.Graph env;
221 input Absyn.Exp inLhs;
222 input DAE.Type ty;
223 input SourceInfo info;
224 input Integer numError;
225 output FCore.Cache outCache;
226 output DAE.Pattern pattern;
227 algorithm
228 (outCache,pattern) := matchcontinue (inCache, inLhs, ty)
229 local
230 list<Absyn.Exp> exps;
231 list<DAE.Type> tys;
232 list<DAE.Pattern> patterns;
233 Absyn.Exp exp,head,tail;
234 String id,s,str;
235 Integer i;
236 Real r;
237 Boolean b;
238 DAE.Type ty1,ty2,tyHead,tyTail;
239 Option<DAE.Type> et;
240 DAE.Pattern patternHead,patternTail;
241 Absyn.ComponentRef fcr;
242 Absyn.FunctionArgs fargs;
243 Absyn.Path utPath;
244 FCore.Cache cache;
245 Absyn.Exp lhs;
246 DAE.Attributes attr;
247 DAE.Exp elabExp;
248 DAE.Const const;
249 Values.Value val;
250 SCode.Variability variability;
251
252 case (cache, Absyn.INTEGER(i), _)
253 algorithm
254 155 et := validPatternType(ty,DAE.T_INTEGER_DEFAULT,inLhs,info);
255 155 then (cache,DAE.PAT_CONSTANT(et,DAE.ICONST(i)));
256
257 case (cache, Absyn.REAL(str), _)
258 algorithm
259 15 et := validPatternType(ty,DAE.T_REAL_DEFAULT,inLhs,info);
260 15 r := stringReal(str);
261 15 then (cache,DAE.PAT_CONSTANT(et,DAE.RCONST(r)));
262
263 case (cache, Absyn.UNARY(Absyn.UMINUS(),Absyn.INTEGER(i)), _)
264 algorithm
265 8 et := validPatternType(ty,DAE.T_INTEGER_DEFAULT,inLhs,info);
266 8 i := -i;
267 8 then (cache,DAE.PAT_CONSTANT(et,DAE.ICONST(i)));
268
269 case (cache, Absyn.UNARY(Absyn.UMINUS(),Absyn.REAL(str)), _)
270 algorithm
271 1 et := validPatternType(ty,DAE.T_REAL_DEFAULT,inLhs,info);
272 1 r := stringReal(str);
273 1 r := realNeg(r);
274 1 then (cache,DAE.PAT_CONSTANT(et,DAE.RCONST(r)));
275
276 case (cache, Absyn.STRING(s), _)
277 algorithm
278 303 et := validPatternType(ty,DAE.T_STRING_DEFAULT,inLhs,info);
279 303 s := System.unescapedString(s);
280 303 then (cache,DAE.PAT_CONSTANT(et,DAE.SCONST(s)));
281
282 case (cache, Absyn.BOOL(b), _)
283 algorithm
284 707 et := validPatternType(ty,DAE.T_BOOL_DEFAULT,inLhs,info);
285
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 482 times.
932 then (cache,DAE.PAT_CONSTANT(et,DAE.BCONST(b)));
286
287 case (cache, Absyn.ARRAY({}), _)
288 algorithm
289 583 et := validPatternType(ty,DAE.T_METALIST_DEFAULT,inLhs,info);
290 581 then (cache,DAE.PAT_CONSTANT(et,DAE.LIST({})));
291
292 case (cache, Absyn.ARRAY(exps as _::_), _)
293 algorithm
294 323 lhs := List.fold(listReverse(exps), AbsynUtil.makeCons, Absyn.ARRAY({}));
295 323 (cache,pattern) := elabPattern(cache,env,lhs,ty,info);
296 then (cache,pattern);
297
298 case (cache, Absyn.CALL(Absyn.CREF_IDENT("NONE",{}),Absyn.FUNCTIONARGS({},{})), _)
299 algorithm
300 83 validPatternType(ty,DAE.T_NONE_DEFAULT,inLhs,info);
301 83 then (cache,DAE.PAT_CONSTANT(NONE(),DAE.META_OPTION(NONE())));
302
303 case (cache, Absyn.CALL(Absyn.CREF_IDENT("SOME",{}),Absyn.FUNCTIONARGS({exp},{})), DAE.T_METAOPTION(ty = ty2))
304 algorithm
305 152 (cache,pattern) := elabPattern(cache,env,exp,ty2,info);
306 152 then (cache,DAE.PAT_SOME(pattern));
307
308 case (cache, Absyn.CONS(head,tail), tyTail as DAE.T_METALIST(ty = tyHead))
309 algorithm
310 756 tyHead := Types.boxIfUnboxedType(tyHead);
311 756 (cache,patternHead) := elabPattern(cache,env,head,tyHead,info);
312 756 (cache,patternTail) := elabPattern(cache,env,tail,tyTail,info);
313 756 then (cache,DAE.PAT_CONS(patternHead,patternTail));
314
315 case (cache, Absyn.TUPLE({exp}), _)
316 algorithm
317 168 (cache,pattern) := elabPattern2(cache,env,exp,ty,info,numError);
318 then (cache,pattern);
319
320 case (cache, Absyn.TUPLE(exps), DAE.T_METATUPLE(types = tys))
321 algorithm
322 162 tys := List.map(tys, Types.boxIfUnboxedType);
323 162 (cache,patterns) := elabPatternTuple(cache,env,exps,tys,info,inLhs);
324 162 then (cache,DAE.PAT_META_TUPLE(patterns));
325
326 case (cache, Absyn.TUPLE(exps), DAE.T_TUPLE(types = tys))
327 algorithm
328 24 (cache,patterns) := elabPatternTuple(cache,env,exps,tys,info,inLhs);
329 24 then (cache,DAE.PAT_CALL_TUPLE(patterns));
330
331 case (cache, lhs as Absyn.CALL(fcr,fargs), DAE.T_COMPLEX(complexClassType = ClassInf.RECORD(utPath)))
332 algorithm
333 30 (cache,pattern) := elabPatternCall(cache,env,AbsynUtil.crefToPath(fcr),fargs,utPath,info,lhs);
334 then (cache,pattern);
335
336 case (cache, lhs as Absyn.CALL(fcr,fargs), DAE.T_METAUNIONTYPE(path = utPath))
337 algorithm
338 5265 (cache,pattern) := elabPatternCall(cache,env,AbsynUtil.crefToPath(fcr),fargs,utPath,info,lhs);
339 then (cache,pattern);
340
341 case (cache, lhs as Absyn.CALL(fcr,fargs), DAE.T_METARECORD(utPath = utPath))
342 algorithm
343 3 (cache,pattern) := elabPatternCall(cache,env,AbsynUtil.crefToPath(fcr),fargs,utPath,info,lhs);
344 then (cache,pattern);
345
346 case (cache, Absyn.CREF(), ty1)
347 guard
348 Types.isBoxedType(ty1) or
349 (match Types.unboxedType(ty1)
350 case DAE.T_ENUMERATION() then true;
351 case DAE.T_INTEGER() then true;
352 case DAE.T_REAL() then true;
353 case DAE.T_STRING() then true;
354 case DAE.T_BOOL() then true;
355 else false;
356 end match)
357 algorithm
358
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 14687 times.
14688 (cache,elabExp,DAE.PROP(type_=ty2, constFlag=const)) := Static.elabExp(cache,env,inLhs,false,false,DAE.NOPRE(),info);
359 14687 et := validPatternType(ty1,ty2,inLhs,info);
360
2/2
✓ Branch 1 taken 14679 times.
✓ Branch 2 taken 6 times.
14685 true := Types.isConstant(const);
361 6 (cache, val) := Ceval.ceval(cache, env, elabExp, false, inMsg = Absyn.MSG(info));
362 6 elabExp := ValuesUtil.valueExp(val);
363 6 then (cache, DAE.PAT_CONSTANT(et, elabExp));
364
365 case (cache, Absyn.AS(id,exp), ty2)
366 algorithm
367 350 (cache,DAE.TYPES_VAR(ty = ty1, attributes = attr),_,_,_,_) := Lookup.lookupIdent(cache,env,id);
368 350 lhs := Absyn.CREF(Absyn.CREF_IDENT(id, {}));
369 350 Static.checkAssignmentToInput(lhs, attr, env, false, info);
370 350 et := validPatternType(ty2,ty1,inLhs,info);
371 346 (cache,pattern) := elabPattern(cache,env,exp,ty2,info);
372
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 346 times.
346 pattern := if Types.isFunctionType(ty2) then DAE.PAT_AS_FUNC_PTR(id,pattern) else DAE.PAT_AS(id,et,attr,pattern);
373 346 then (cache,pattern);
374
375 case (cache, Absyn.CREF(Absyn.CREF_IDENT(id,{})), ty2)
376 algorithm
377 7769 (cache,DAE.TYPES_VAR(ty = ty1, attributes = attr as DAE.ATTR(variability=variability)),_,_,_,_) := Lookup.lookupIdent(cache,env,id);
378
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7768 times.
7768 if SCodeUtil.isParameterOrConst(variability) then
379 ✗ Error.addSourceMessage(Error.PATTERN_VAR_NOT_VARIABLE, {id, SCodeDump.unparseVariability(variability)}, info);
380 ✗ fail();
381 end if;
382 7768 Static.checkAssignmentToInput(inLhs, attr, env, false, info);
383 7766 et := validPatternType(ty2,ty1,inLhs,info);
384
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 7753 times.
7764 pattern := if Types.isFunctionType(ty2) then DAE.PAT_AS_FUNC_PTR(id,DAE.PAT_WILD()) else DAE.PAT_AS(id,et,attr,DAE.PAT_WILD());
385 7764 then (cache,pattern);
386
387 case (cache, Absyn.AS(id,_), _)
388 algorithm
389
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 failure(Lookup.lookupIdent(cache,env,id));
390 ✗ Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR,{id,""},info);
391 ✗ then fail();
392
393 case (cache, Absyn.CREF(Absyn.CREF_IDENT("NONE",{})), _)
394 algorithm
395
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 failure(Lookup.lookupIdent(cache,env,"NONE"));
396 1 Error.addSourceMessage(Error.META_NONE_CREF,{},info);
397 1 then fail();
398
399 case (cache, Absyn.CREF(Absyn.CREF_IDENT(id,{})), _)
400 algorithm
401
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 failure(Lookup.lookupIdent(cache,env,id));
402
2/4
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
1 false := "NONE" == id;
403 ✗ Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR,{id,""},info);
404 ✗ then fail();
405
406 6918 case (cache, Absyn.CREF(Absyn.WILD()), _) then (cache,DAE.PAT_WILD());
407
408 case (cache, Absyn.EXPRESSIONCOMMENT(), _)
409 algorithm
410 218 (cache,pattern) := elabPattern2(cache,env,inLhs.exp,ty,info,numError);
411 then (cache,pattern);
412
413 case (_, lhs, _)
414 algorithm
415
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 2 times.
21 true := numError == Error.getNumErrorMessages();
416 2 str := Dump.printExpStr(lhs) + " of type " + TypesDump.unparseType(ty);
417 2 Error.addSourceMessage(Error.META_INVALID_PATTERN, {str}, info);
418 2 then fail();
419
420 end matchcontinue;
421 end elabPattern2;
422
423 protected function elabPatternTuple
424 input FCore.Cache inCache;
425 input FCore.Graph env;
426 input list<Absyn.Exp> inExps;
427 input list<DAE.Type> inTys;
428 input SourceInfo info;
429 input Absyn.Exp lhs "for error messages";
430 output FCore.Cache outCache;
431 output list<DAE.Pattern> patterns;
432 algorithm
433 (outCache,patterns) := match (inCache, inExps, inTys)
434 local
435 Absyn.Exp exp;
436 String s;
437 DAE.Pattern pattern;
438 DAE.Type ty;
439 FCore.Cache cache;
440 list<Absyn.Exp> exps;
441 list<DAE.Type> tys;
442
443 case (cache, {}, {}) then (cache,{});
444
445 case (cache, exp::exps, ty::tys)
446 algorithm
447 20607 (cache,pattern) := elabPattern(cache,env,exp,ty,info);
448 20598 (cache,patterns) := elabPatternTuple(cache,env,exps,tys,info,lhs);
449 20598 then (cache,pattern::patterns);
450
451 else
452 algorithm
453 ✗ s := Dump.printExpStr(lhs);
454 ✗ s := "pattern " + s;
455 ✗ Error.addSourceMessage(Error.WRONG_NO_OF_ARGS, {s}, info);
456 ✗ then fail();
457 end match;
458 end elabPatternTuple;
459
460 protected function elabPatternCall
461 input FCore.Cache inCache;
462 input FCore.Graph env;
463 input Absyn.Path callPath;
464 input Absyn.FunctionArgs fargs;
465 input Absyn.Path utPath;
466 input SourceInfo info;
467 input Absyn.Exp lhs "for error messages";
468 output FCore.Cache outCache;
469 output DAE.Pattern pattern;
470 algorithm
471 (outCache,pattern) := matchcontinue (inCache, fargs, utPath)
472 local
473 String s;
474 Absyn.Path utPath1,utPath2,fqPath;
475 Integer index,numPosArgs;
476 list<Absyn.NamedArg> namedArgList,invalidArgs;
477 list<Absyn.Exp> funcArgsNamedFixed,funcArgs, funcArgs2;
478 list<String> fieldNameList,fieldNamesNamed;
479 list<DAE.Type> fieldTypeList, typeVars;
480 list<DAE.Var> fieldVarList;
481 list<DAE.Pattern> patterns;
482 list<tuple<DAE.Pattern,String,DAE.Type>> namedPatterns;
483 Boolean knownSingleton;
484 FCore.Cache cache;
485 Boolean allWild;
486
487 case (_, Absyn.FUNCTIONARGS(_::_,_::_), _)
488 algorithm
489 10 Error.addSourceMessage(Error.PATTERN_MIXED_POS_NAMED, {AbsynUtil.pathString(callPath)}, info);
490 5 then fail();
491
492 case (cache, Absyn.FUNCTIONARGS(funcArgs,namedArgList), utPath2)
493 algorithm
494 5298 (cache,_,_) :=
495 Lookup.lookupType(cache, env, callPath, NONE());
496
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 5268 times.
5300 (cache,DAE.T_METARECORD(utPath=utPath1,index=index,fields=fieldVarList,typeVars=typeVars,knownSingleton = knownSingleton,path = fqPath),_) :=
497 Lookup.lookupType(cache, env, callPath, NONE());
498 5268 validUniontype(utPath1,utPath2,info,lhs);
499
500 5268 fieldTypeList := List.map(fieldVarList, Types.getVarType);
501 5268 fieldNameList := List.map(fieldVarList, TypesDump.getVarName);
502
503
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5268 times.
5268 if Flags.isSet(Flags.PATTERNM_ALL_INFO) then
504 ✗ for namedArg in namedArgList loop
505 () := match namedArg
506 case Absyn.NAMEDARG(argValue=Absyn.CREF(Absyn.WILD()))
507 algorithm
508 ✗ Error.addSourceMessage(Error.META_EMPTY_CALL_PATTERN, {namedArg.argName}, info);
509 then ();
510 else ();
511 end match;
512 end for;
513 ✗ if listEmpty(namedArgList) and not listEmpty(funcArgs) then
514 allWild := true;
515 ✗ for arg in funcArgs loop
516 allWild := match arg
517 case Absyn.CREF(Absyn.WILD()) then true;
518 else false;
519 end match;
520 if not allWild then
521 break;
522 end if;
523 end for;
524 ✗ if allWild then
525 ✗ Error.addSourceMessage(Error.META_ALL_EMPTY, {AbsynUtil.pathString(callPath)}, info);
526 end if;
527 end if;
528 end if;
529
530 5268 (funcArgs,namedArgList) := checkForAllWildCall(funcArgs,namedArgList,listLength(fieldNameList));
531
532 5268 numPosArgs := listLength(funcArgs);
533 5268 (_,fieldNamesNamed) := List.split(fieldNameList, numPosArgs);
534 5268 checkMissingArgs(fqPath,numPosArgs,fieldNamesNamed,listLength(namedArgList),info);
535 5268 (funcArgsNamedFixed,invalidArgs) := generatePositionalArgs(fieldNamesNamed,namedArgList,{});
536 5268 funcArgs2 := listAppend(funcArgs,funcArgsNamedFixed);
537
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5266 times.
5268 Util.SUCCESS() := checkInvalidPatternNamedArgs(invalidArgs,fieldNameList,Util.SUCCESS(),info);
538 5266 (cache,patterns) := elabPatternTuple(cache,env,funcArgs2,fieldTypeList,info,lhs);
539
2/2
✓ Branch 0 taken 4984 times.
✓ Branch 1 taken 280 times.
10248 then (cache,DAE.PAT_CALL(fqPath,index,patterns,fieldVarList,typeVars,knownSingleton));
540
541 case (cache, Absyn.FUNCTIONARGS(funcArgs,namedArgList), utPath2)
542 algorithm
543
4/6
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30 times.
34 (cache,DAE.T_FUNCTION(funcResultType = DAE.T_COMPLEX(complexClassType=ClassInf.RECORD(_),varLst=fieldVarList), path = fqPath),_) :=
544 Lookup.lookupType(cache, env, callPath, NONE());
545
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 true := AbsynUtil.pathEqual(fqPath,utPath2);
546
547 30 fieldTypeList := List.map(fieldVarList, Types.getVarType);
548 30 fieldNameList := List.map(fieldVarList, TypesDump.getVarName);
549
550 30 (funcArgs,namedArgList) := checkForAllWildCall(funcArgs,namedArgList,listLength(fieldNameList));
551
552 30 numPosArgs := listLength(funcArgs);
553 30 (_,fieldNamesNamed) := List.split(fieldNameList, numPosArgs);
554 30 checkMissingArgs(fqPath,numPosArgs,fieldNamesNamed,listLength(namedArgList),info);
555
556 30 (funcArgsNamedFixed,invalidArgs) := generatePositionalArgs(fieldNamesNamed,namedArgList,{});
557 30 funcArgs2 := listAppend(funcArgs,funcArgsNamedFixed);
558
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 Util.SUCCESS() := checkInvalidPatternNamedArgs(invalidArgs,fieldNameList,Util.SUCCESS(),info);
559 30 (cache,patterns) := elabPatternTuple(cache,env,funcArgs2,fieldTypeList,info,lhs);
560 30 namedPatterns := List.zip3(patterns, fieldNameList, List.map(fieldTypeList,Types.simplifyType));
561 30 namedPatterns := List.filterOnTrue(namedPatterns, filterEmptyPattern);
562 30 then (cache,DAE.PAT_CALL_NAMED(fqPath,namedPatterns));
563
564 case (cache, _, _)
565 algorithm
566
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 failure(Lookup.lookupType(cache, env, callPath, NONE()));
567 ✗ s := AbsynUtil.pathString(callPath);
568 ✗ Error.addSourceMessage(Error.META_CONSTRUCTOR_NOT_RECORD, {s}, info);
569 ✗ then fail();
570 end matchcontinue;
571 end elabPatternCall;
572
573 protected function checkMissingArgs
574 input Absyn.Path path;
575 input Integer numPosArgs;
576 input list<String> missingFieldNames;
577 input Integer numNamedArgs;
578 input SourceInfo info;
579 algorithm
580 () := match (missingFieldNames, numNamedArgs)
581 local
582 case ({}, 0) then ();
583 /* Language extension to not have to bind everything...
584 case (_,_,strs,0,_)
585 algorithm
586 str = stringDelimitList(strs,",");
587 str = AbsynUtil.pathString(path) + " missing pattern for fields: " + str;
588 Error.addSourceMessage(Error.META_INVALID_PATTERN,{str},info);
589 then fail();
590 */
591 /*
592 case (path,_,_,_,info)
593 algorithm
594 str = AbsynUtil.pathString(path) + " mixing positional and named patterns";
595 Error.addSourceMessage(Error.META_INVALID_PATTERN,{str},info);
596 then fail();
597 */
598 else ();
599 end match;
600 end checkMissingArgs;
601
602 protected function checkForAllWildCall "Converts a call REC(__) to REC(_,_,_,_)"
603 input list<Absyn.Exp> args;
604 input list<Absyn.NamedArg> named;
605 input Integer numFields;
606 output list<Absyn.Exp> outArgs;
607 output list<Absyn.NamedArg> outNamed;
608 algorithm
609 (outArgs,outNamed) := match (args, named)
610 case ({Absyn.CREF(Absyn.ALLWILD())}, {})
611 then ({},{});
612 else (args,named);
613 end match;
614 end checkForAllWildCall;
615
616 protected function validPatternType
617 input DAE.Type inTy1;
618 input DAE.Type inTy2;
619 input Absyn.Exp lhs;
620 input SourceInfo info;
621 output Option<DAE.Type> ty;
622 algorithm
623 ty := matchcontinue (inTy1, inTy2)
624 local
625 DAE.Type et;
626 String s,s1,s2;
627 DAE.ComponentRef cr;
628 DAE.Exp crefExp;
629 DAE.Type ty1, ty2;
630
631 case (DAE.T_METABOXED(ty = ty1), ty2)
632 algorithm
633 2207 cr := ComponentReferenceBasics.makeCrefIdent("#DUMMY#",DAE.T_UNKNOWN_DEFAULT,{});
634 2207 crefExp := Expression.crefExp(cr);
635 2207 (_,ty1) := Types.matchType(crefExp,ty1,ty2,true);
636 2207 et := Types.simplifyType(ty1);
637 then SOME(et);
638
639 case (ty1, ty2)
640 algorithm
641 22451 cr := ComponentReferenceBasics.makeCrefIdent("#DUMMY#",DAE.T_UNKNOWN_DEFAULT,{});
642 22451 crefExp := Expression.crefExp(cr);
643 22451 Types.matchType(crefExp,ty1,ty2,true);
644 then NONE();
645
646 case (ty1, ty2)
647 algorithm
648 10 s := Dump.printExpStr(lhs);
649 10 s1 := TypesDump.unparseType(ty1);
650 10 s2 := TypesDump.unparseType(ty2);
651 10 Error.addSourceMessage(Error.META_TYPE_MISMATCH_PATTERN, {s,s1,s2}, info);
652 10 then fail();
653 end matchcontinue;
654 end validPatternType;
655
656 protected function validUniontype
657 input Absyn.Path path1;
658 input Absyn.Path path2;
659 input SourceInfo info;
660 input Absyn.Exp lhs;
661 algorithm
662
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5268 times.
5268 if not AbsynUtil.pathEqual(path1,path2) then
663 ✗ Error.addSourceMessage(Error.META_CONSTRUCTOR_NOT_PART_OF_UNIONTYPE,
664 {Dump.printExpStr(lhs), AbsynUtil.pathString(path1), AbsynUtil.pathString(path2)}, info);
665 ✗ fail();
666 end if;
667 end validUniontype;
668
669 public function elabMatchExpression
670 input FCore.Cache inCache;
671 input FCore.Graph inEnv;
672 input Absyn.Exp matchExp;
673 input Boolean impl;
674 input Boolean performVectorization;
675 input DAE.Prefix inPrefix;
676 input SourceInfo info;
677 output FCore.Cache outCache;
678 output DAE.Exp outExp;
679 output DAE.Properties outProperties;
680 protected
681 Integer numError = Error.getNumErrorMessages();
682 algorithm
683 (outCache,outExp,outProperties) := matchcontinue (inCache, inEnv, matchExp, inPrefix)
684 local
685 Absyn.MatchType matchTy;
686 Absyn.Exp inExp;
687 list<Absyn.Exp> inExps;
688 list<Absyn.ElementItem> decls;
689 list<Absyn.Case> cases;
690 list<DAE.Element> matchDecls;
691 DAE.Prefix pre;
692 list<DAE.Exp> elabExps;
693 list<DAE.MatchCase> elabCases;
694 list<DAE.Type> tys;
695 DAE.Properties prop;
696 list<DAE.Properties> elabProps;
697 DAE.Type resType;
698 DAE.Type et;
699 String str;
700 DAE.Exp exp;
701 HashTableStringToPath.HashTable ht;
702 DAE.MatchType elabMatchTy;
703 FCore.Cache cache;
704 FCore.Graph env;
705 Integer hashSize;
706 list<list<String>> inputAliases,inputAliasesAndCrefs;
707 AvlSetString.Tree declsTree;
708
709 case (cache, env, Absyn.MATCHEXP(matchTy=matchTy,inputExp=inExp,localDecls=decls,cases=cases), pre)
710 algorithm
711 // First do inputs
712 1194 inExps := convertExpToPatterns(inExp);
713 1194 (inExps,inputAliases,inputAliasesAndCrefs) := List.map_3(inExps,getInputAsBinding);
714 1194 (cache,elabExps,elabProps) := Static.elabExpList(cache,env,inExps,impl,performVectorization,pre,info);
715 // Then add locals
716
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1190 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 1184 times.
1190 (cache,SOME((env,DAE.DAE(matchDecls),declsTree))) := addLocalDecls(cache,env,decls,FCore.matchScopeName,impl,info);
717 1184 tys := List.map(elabProps, Types.getPropType);
718 1184 env := addAliasesToEnv(env, tys, inputAliases, info);
719 1184 (cache,elabCases,resType) := elabMatchCases(cache,env,cases,tys,inputAliasesAndCrefs,declsTree,impl,performVectorization,pre,info);
720 1164 prop := DAE.PROP(resType,DAE.C_VAR());
721 1164 et := Types.simplifyType(resType);
722 1164 checkMatchSingleInfallibleCase(matchTy, elabCases, info);
723 1164 checkInfallibleNoBindingPatterns(elabCases, matchTy, info);
724 // If the whole match is a single infallible case (covered by
725 // MATCH_SINGLE_INFALLIBLE_CASE), don't also emit per-input "unused
726 // input" notifications for the same match — the agent would otherwise
727 // see two conflicting recommendations for the same code.
728 1164 (elabExps,inputAliases,elabCases) := filterUnusedPatterns(elabExps,inputAliases,elabCases,info,not isSingleInfallibleMatch(matchTy, elabCases)) "filterUnusedPatterns() First time to speed up the other optimizations.";
729 1164 elabCases := caseDeadCodeElimination(matchTy, elabCases, {}, {}, false);
730 // Do DCE before converting mc to m
731 1164 matchTy := optimizeContinueToMatch(matchTy,elabCases,info);
732 1164 elabCases := optimizeContinueJumps(matchTy, elabCases);
733 // hashSize = Util.nextPowerOf2(listLength(matchDecls)) + 1; // faster, but unstable in RML
734 1164 hashSize := Util.nextPrime(listLength(matchDecls));
735 1164 ht := getUsedLocalCrefs(Flags.isSet(Flags.PATTERNM_SKIP_FILTER_UNUSED_AS_BINDINGS),DAE.MATCHEXPRESSION(DAE.MATCHCONTINUE(),elabExps,inputAliases,matchDecls,elabCases,et),hashSize);
736 1164 (matchDecls,ht) := filterUnusedDecls(matchDecls,ht,{},HashTableStringToPath.emptyHashTableSized(hashSize));
737 1164 (elabExps,inputAliases,elabCases) := filterUnusedPatterns(elabExps,inputAliases,elabCases,info,false) "filterUnusedPatterns() again to filter out the last parts.";
738 1164 (elabMatchTy, elabCases) := optimizeMatchToSwitch(matchTy,elabCases,info);
739 1164 elabMatchTy := unboxSwitchType(elabMatchTy, elabExps);
740 1164 checkConstantMatchInputs(elabExps, info);
741 1164 exp := DAE.MATCHEXPRESSION(elabMatchTy,elabExps,inputAliases,matchDecls,elabCases,et);
742 then (cache,exp,prop);
743 else
744 algorithm
745
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 true := numError == Error.getNumErrorMessages();
746 ✗ str := Dump.printExpStr(matchExp);
747 ✗ Error.addSourceMessage(Error.META_MATCH_GENERAL_FAILURE, {str}, info);
748 ✗ then fail();
749 end matchcontinue;
750 end elabMatchExpression;
751
752 protected function checkConstantMatchInputs
753 input list<DAE.Exp> inputs;
754 input SourceInfo info;
755 algorithm
756
2/2
✓ Branch 0 taken 2035 times.
✓ Branch 1 taken 1164 times.
3199 for i in inputs loop
757
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2031 times.
2035 if Expression.isConstValue(i) then
758 8 Error.addSourceMessage(Error.META_MATCH_CONSTANT, {ExpressionBasics.printExpStr(i)}, info);
759 end if;
760 end for;
761 end checkConstantMatchInputs;
762
763 protected function optimizeMatchToSwitch
764 "match str case 'str1' ... case 'str2' case 'str3' => switch hash(str)...
765 match ut case UT1 ... case UT2 ... case UT3 => switch valueConstructor(ut)...
766 match int case 1 ... case 17 ... case 2 => switch(int)...
767 Works if all values are unique. Also works if there is one 'default' case at the end of the list (and there is only 1 pattern):
768 case (1,_) ... case (_,_) ... works
769 case (1,2) ... case (_,_) ... does not work
770 .
771 "
772 input Absyn.MatchType matchTy;
773 input list<DAE.MatchCase> cases;
774 input SourceInfo info;
775 output DAE.MatchType outType;
776 output list<DAE.MatchCase> outCases;
777 algorithm
778 (outType, outCases) := matchcontinue matchTy
779 local
780 tuple<Integer,DAE.Type,Integer> tpl;
781 list<list<DAE.Pattern>> patternMatrix;
782 list<Option<list<DAE.Pattern>>> optPatternMatrix;
783 Integer numNonEmptyColumns;
784 String str;
785 DAE.Type ty;
786 case Absyn.MATCHCONTINUE() then (DAE.MATCHCONTINUE(), cases);
787 case _
788 algorithm
789
2/2
✓ Branch 1 taken 406 times.
✓ Branch 2 taken 661 times.
1067 true := listLength(cases) > 2;
790
2/2
✓ Branch 0 taken 2899 times.
✓ Branch 1 taken 376 times.
3275 for c in cases loop
791
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2899 times.
✓ Branch 2 taken 2869 times.
✓ Branch 3 taken 30 times.
2899 DAE.CASE(patternGuard=NONE()) := c;
792 end for;
793 376 patternMatrix := List.transposeList(List.map(cases,getCasePatterns));
794 376 (optPatternMatrix,numNonEmptyColumns) := removeWildPatternColumnsFromMatrix(patternMatrix,{},0);
795 376 tpl := findPatternToConvertToSwitch(optPatternMatrix,1,numNonEmptyColumns,info);
796 212 (_,ty,_) := tpl;
797 212 str := TypesDump.unparseType(ty);
798 212 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.MATCH_TO_SWITCH_OPTIMIZATION, {str}, info);
799 212 outType := DAE.MATCH(SOME(tpl));
800 212 outCases := optimizeSwitchedMatchCases(outType, cases);
801 then
802 (outType, outCases);
803
804 else (DAE.MATCH(NONE()), cases);
805 end matchcontinue;
806 end optimizeMatchToSwitch;
807
808 protected function optimizeSwitchedMatchCases
809 "This function optimizes the cases of a match that has been optimized into a switch."
810 input DAE.MatchType inMatchType;
811 input list<DAE.MatchCase> inCases;
812 output list<DAE.MatchCase> outCases;
813 algorithm
814 outCases := match inMatchType
815 local
816 DAE.Pattern pat;
817 list<DAE.Pattern> patl;
818
819 // If we're switching on a uniontype, mark all cases that look like RECORD()
820 // as singleton, so we can skip doing pattern matching on them (we're
821 // already switching on their type, we don't need to check the type in the
822 // case also.
823 case DAE.MATCH(switch = SOME((_, DAE.T_METATYPE(), _)))
824
4/4
✓ Branch 0 taken 1423 times.
✓ Branch 1 taken 203 times.
✓ Branch 2 taken 1423 times.
✓ Branch 3 taken 203 times.
1626 then list(
825 match c
826 case DAE.CASE(patterns = {pat as DAE.PAT_CALL(patterns = patl)})
827 algorithm
828
2/2
✓ Branch 1 taken 544 times.
✓ Branch 2 taken 184 times.
728 if allPatternsWild(patl) then
829 544 pat.knownSingleton := true;
830 544 c.patterns := {pat};
831 end if;
832 then
833 c;
834
835 else c;
836 end match
837 for c in inCases);
838
839 else inCases;
840 end match;
841 end optimizeSwitchedMatchCases;
842
843 protected function removeWildPatternColumnsFromMatrix
844 input list<list<DAE.Pattern>> inPatternMatrix;
845 input list<Option<list<DAE.Pattern>>> inAcc;
846 input Integer inNumAcc;
847 output list<Option<list<DAE.Pattern>>> optPatternMatrix;
848 output Integer numNonEmptyColumns;
849 algorithm
850 (optPatternMatrix,numNonEmptyColumns) := match (inPatternMatrix,inAcc,inNumAcc)
851 local
852 Boolean alwaysMatch;
853 list<DAE.Pattern> pats;
854 Option<list<DAE.Pattern>> optPats;
855 list<list<DAE.Pattern>> patternMatrix;
856 list<Option<list<DAE.Pattern>>> acc;
857 Integer numAcc;
858
859 376 case ({},acc,numAcc) then (listReverse(acc),numAcc);
860
861 case (pats::patternMatrix,acc,numAcc)
862 algorithm
863 637 alwaysMatch := allPatternsAlwaysMatch(List.stripLast(pats));
864
2/2
✓ Branch 0 taken 451 times.
✓ Branch 1 taken 186 times.
637 optPats := if alwaysMatch then NONE() else SOME(pats);
865
2/2
✓ Branch 0 taken 451 times.
✓ Branch 1 taken 186 times.
637 numAcc := if alwaysMatch then numAcc else numAcc+1;
866 637 (acc,numAcc) := removeWildPatternColumnsFromMatrix(patternMatrix,optPats::acc,numAcc);
867 then (acc,numAcc);
868 end match;
869 end removeWildPatternColumnsFromMatrix;
870
871 protected function findPatternToConvertToSwitch
872 input list<Option<list<DAE.Pattern>>> inPatternMatrix;
873 input Integer index;
874 input Integer numPatternsInMatrix "If there is only 1 pattern, we can optimize the default case";
875 input SourceInfo info;
876 output tuple<Integer,DAE.Type,Integer> tpl;
877 algorithm
878 tpl := matchcontinue inPatternMatrix
879 local
880 list<DAE.Pattern> pats;
881 DAE.Type ty;
882 Integer extraarg;
883 list<Option<list<DAE.Pattern>>> patternMatrix;
884
885 case SOME(pats)::_
886 algorithm
887 449 (ty,extraarg) := findPatternToConvertToSwitch2(pats, {}, DAE.T_UNKNOWN_DEFAULT, true, numPatternsInMatrix);
888 212 then ((index,ty,extraarg));
889 case _::patternMatrix
890 394 then findPatternToConvertToSwitch(patternMatrix,index+1,numPatternsInMatrix,info);
891 end matchcontinue;
892 end findPatternToConvertToSwitch;
893
894 protected function findPatternToConvertToSwitch2
895 input list<DAE.Pattern> ipats;
896 input list<Integer> ixs;
897 input DAE.Type ity;
898 input Boolean allSubPatternsMatch;
899 input Integer numPatternsInMatrix;
900 output DAE.Type outTy;
901 output Integer extraarg;
902 algorithm
903 (outTy,extraarg) := match (ipats, ity, allSubPatternsMatch, numPatternsInMatrix)
904 local
905 Integer ix;
906 String str;
907 list<DAE.Pattern> pats,subpats;
908 DAE.Type ty;
909
910 case (DAE.PAT_CONSTANT(exp=DAE.SCONST(str))::pats, _, _, _)
911 algorithm
912 25 ix := stringHashDjb2Mod(str,65536);
913
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 23 times.
25 false := listMember(ix,ixs);
914 23 (ty,extraarg) := findPatternToConvertToSwitch2(pats,ix::ixs,DAE.T_STRING_DEFAULT,allSubPatternsMatch,numPatternsInMatrix);
915 then (ty,extraarg);
916
917 case (DAE.PAT_CALL(index=ix,patterns=subpats)::pats, _, _, _)
918 algorithm
919
2/2
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 1648 times.
1738 false := listMember(ix,ixs);
920
4/4
✓ Branch 0 taken 1606 times.
✓ Branch 1 taken 42 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 1522 times.
1732 (ty,extraarg) := findPatternToConvertToSwitch2(pats,ix::ixs,DAE.T_METATYPE_DEFAULT,allSubPatternsMatch and allPatternsAlwaysMatch(subpats),numPatternsInMatrix);
921 then (ty,extraarg);
922
923 case (DAE.PAT_CONSTANT(exp=DAE.ICONST(ix))::pats, _, _, _)
924 algorithm
925
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 35 times.
36 false := listMember(ix,ixs);
926 35 (ty,extraarg) := findPatternToConvertToSwitch2(pats,ix::ixs,DAE.T_INTEGER_DEFAULT,allSubPatternsMatch,numPatternsInMatrix);
927 then (ty,extraarg);
928
929 case (DAE.PAT_CONSTANT(exp=DAE.ENUM_LITERAL(index=ix))::pats, _, _, _)
930 guard not listMember(ix,ixs)
931 ✗ then findPatternToConvertToSwitch2(pats,ix::ixs,DAE.T_ENUMERATION_DEFAULT,allSubPatternsMatch,numPatternsInMatrix);
932
933 case ({}, DAE.T_STRING(), _, _)
934 algorithm
935
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 true := listLength(ixs)>11; // hashing has a considerable overhead, only convert to switch if it is worth it
936 ✗ ix := findMinMod(ixs,1);
937 then (DAE.T_STRING_DEFAULT,ix);
938
939 case ({_}, DAE.T_STRING(), _, 1)
940 algorithm
941
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 true := listLength(ixs)>11; // hashing has a considerable overhead, only convert to switch if it is worth it
942 1 ix := findMinMod(ixs,1);
943 then (DAE.T_STRING_DEFAULT,ix);
944
945 case ({}, _, _, _) then (ity,0);
946
947 // Sadly, we cannot switch a default uniontype as the previous case in not guaranteed
948 // to succeed matching if it matches for subpatterns.
949 case ({_}, _, true, 1) then (ity,0);
950 end match;
951 end findPatternToConvertToSwitch2;
952
953 protected function findMinMod
954 input list<Integer> inIxs;
955 input Integer inMod;
956 output Integer outMod;
957 algorithm
958 outMod := matchcontinue (inIxs,inMod)
959 local list<Integer> ixs; Integer mod;
960 case (ixs,mod)
961 algorithm
962 9 ixs := List.map1(ixs, intMod, mod);
963 9 ixs := List.sort(ixs, intLt);
964
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
9 {} := List.sortedDuplicates(ixs, intEq);
965 // This mod was high enough that all values were distinct
966 then mod;
967 else
968 algorithm
969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 true := inMod < 65536;
970 8 then findMinMod(inIxs,inMod*2);
971 end matchcontinue;
972 end findMinMod;
973
974 protected function filterUnusedPatterns
975 "case (1,_,_) then ...; case (2,_,_) then ...; =>"
976 input list<DAE.Exp> inputs "We can only remove inputs that are free from side-effects";
977 input list<list<String>> inAliases;
978 input list<DAE.MatchCase> inCases;
979 input SourceInfo info;
980 input Boolean emitNotifications "If true and PATTERNM_ALL_INFO is set, notifications are emitted for removable inputs and pattern-as-only cases.";
981 output list<DAE.Exp> outInputs;
982 output list<list<String>> outAliases;
983 output list<DAE.MatchCase> outCases;
984 algorithm
985 (outInputs,outAliases,outCases) := matchcontinue inCases
986 local
987 list<list<DAE.Pattern>> patternMatrix;
988 list<DAE.MatchCase> cases;
989
990 case cases
991 algorithm
992 2328 patternMatrix := List.transposeList(List.map(cases,getCasePatterns));
993
2/2
✓ Branch 1 taken 2314 times.
✓ Branch 2 taken 14 times.
2328 (true,outInputs,outAliases,patternMatrix) := filterUnusedPatterns2(inputs,inAliases,patternMatrix,false,info,emitNotifications,{},{},{});
994 14 patternMatrix := List.transposeList(patternMatrix);
995 14 cases := setCasePatternsCheckZero(cases,patternMatrix);
996 then (outInputs,outAliases,cases);
997 else (inputs,inAliases,inCases);
998 end matchcontinue;
999 end filterUnusedPatterns;
1000
1001 protected function setCasePatternsCheckZero
1002 "Handles the case when the pattern matrix becomes empty because no input is matched"
1003 input list<DAE.MatchCase> inCases;
1004 input list<list<DAE.Pattern>> patternMatrix;
1005 output list<DAE.MatchCase> outCases;
1006 algorithm
1007 outCases := match (inCases,patternMatrix)
1008 case ({},{}) then inCases;
1009 case (_,{})
1010 13 then List.map1(inCases,setCasePatterns,{});
1011 1 else List.threadMap(inCases,patternMatrix,setCasePatterns);
1012 end match;
1013 end setCasePatternsCheckZero;
1014
1015 protected function filterUnusedPatterns2
1016 "case (1,_,_) then ...; case (2,_,_) then ...; =>"
1017 input list<DAE.Exp> inInputs "We can only remove inputs that are free from side-effects";
1018 input list<list<String>> inAliases;
1019 input list<list<DAE.Pattern>> inPatternMatrix;
1020 input Boolean change "Only rebuild the cases if something changed";
1021 input SourceInfo info;
1022 input Boolean emitNotifications;
1023 input list<DAE.Exp> inputsAcc;
1024 input list<list<String>> aliasesAcc;
1025 input list<list<DAE.Pattern>> patternMatrixAcc;
1026 output Boolean outChange;
1027 output list<DAE.Exp> outInputs;
1028 output list<list<String>> outAliases;
1029 output list<list<DAE.Pattern>> outPatternMatrix;
1030 algorithm
1031 (outChange,outInputs,outAliases,outPatternMatrix) := matchcontinue (inInputs, inAliases, inPatternMatrix, change)
1032 local
1033 DAE.Exp e;
1034 list<DAE.Pattern> pats;
1035 list<DAE.Exp> inputs;
1036 list<list<DAE.Pattern>> patternMatrix;
1037 list<String> alias;
1038 list<list<String>> aliases;
1039
1040 case ({}, {}, {}, true)
1041 14 then (true,listReverse(inputsAcc),listReverse(aliasesAcc),listReverse(patternMatrixAcc));
1042 case (e::inputs, _::aliases, pats::patternMatrix, _)
1043 algorithm
1044
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 4065 times.
8135 (_,true) := Expression.traverseExpBottomUp(e,Expression.hasNoSideEffects,true);
1045
2/2
✓ Branch 1 taken 4048 times.
✓ Branch 2 taken 17 times.
4065 true := allPatternsWild(pats);
1046
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
17 if emitNotifications and Flags.isSet(Flags.PATTERNM_ALL_INFO) then
1047 ✗ Error.addSourceMessage(Error.META_MATCH_UNUSED_INPUT, {ExpressionBasics.printExpStr(e)}, info);
1048 end if;
1049 17 (outChange,outInputs,outAliases,outPatternMatrix) := filterUnusedPatterns2(inputs,aliases,patternMatrix,true,info,emitNotifications,inputsAcc,aliasesAcc,patternMatrixAcc);
1050 then (outChange,outInputs,outAliases,outPatternMatrix);
1051 case (e::inputs, alias::aliases, pats::patternMatrix, _)
1052 algorithm
1053
3/10
✓ Branch 0 taken 1832 times.
✓ Branch 1 taken 2238 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1832 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
4070 if emitNotifications and Flags.isSet(Flags.PATTERNM_ALL_INFO) and Expression.isCref(e) and allPatternsAlwaysMatch(pats) and not allPatternsWild(pats) then
1054 ✗ Error.addSourceMessage(Error.META_PATTERN_AS_ONLY, {ExpressionBasics.printExpStr(e), ExpressionBasics.printExpStr(e)}, info);
1055 end if;
1056 4070 (outChange,outInputs,outAliases,outPatternMatrix) := filterUnusedPatterns2(inputs,aliases,patternMatrix,change,info,emitNotifications,e::inputsAcc,alias::aliasesAcc,pats::patternMatrixAcc);
1057 then (outChange,outInputs,outAliases,outPatternMatrix);
1058 2314 else (false,{},{},{});
1059 end matchcontinue;
1060 end filterUnusedPatterns2;
1061
1062 protected function getUsedLocalCrefs
1063 input Boolean skipFilterUnusedAsBindings "if true, traverse the whole expression; else only the bodies and results";
1064 input DAE.Exp exp;
1065 input Integer hashSize;
1066 output HashTableStringToPath.HashTable ht;
1067 algorithm
1068 ht := match (skipFilterUnusedAsBindings, exp)
1069 local
1070 list<DAE.MatchCase> cases;
1071 case (true, _)
1072 algorithm
1073 ✗ (_,ht) := Expression.traverseExpBottomUp(exp, addLocalCref, HashTableStringToPath.emptyHashTableSized(hashSize));
1074 ✗ then ht;
1075 case (false, DAE.MATCHEXPRESSION(cases=cases))
1076 algorithm
1077 1164 (_,ht) := Expression.traverseCases(cases, addLocalCref, HashTableStringToPath.emptyHashTableSized(hashSize));
1078 1164 then ht;
1079 end match;
1080 end getUsedLocalCrefs;
1081
1082 protected function filterUnusedAsBindings
1083 input list<DAE.MatchCase> inCases;
1084 input HashTableStringToPath.HashTable ht;
1085 output list<DAE.MatchCase> outCases;
1086 algorithm
1087 outCases := match inCases
1088 local
1089 list<DAE.Pattern> patterns;
1090 list<DAE.Element> localDecls;
1091 list<DAE.Statement> body;
1092 Option<DAE.Exp> guardPattern, result;
1093 Integer jump;
1094 SourceInfo resultInfo, info;
1095 list<DAE.MatchCase> cases;
1096
1097 case {} then {};
1098 case DAE.CASE(patterns, guardPattern, localDecls, body, result, resultInfo, jump, info)::cases
1099 algorithm
1100 ✗ (patterns,_) := traversePatternList(patterns, removePatternAsBinding, (ht,info));
1101 ✗ cases := filterUnusedAsBindings(cases,ht);
1102 ✗ then DAE.CASE(patterns, guardPattern, localDecls, body, result, resultInfo, jump, info)::cases;
1103 end match;
1104 end filterUnusedAsBindings;
1105
1106 protected function removePatternAsBinding
1107 input DAE.Pattern inPat;
1108 input tuple<HashTableStringToPath.HashTable,SourceInfo> inTpl;
1109 output DAE.Pattern pat=inPat;
1110 output tuple<HashTableStringToPath.HashTable,SourceInfo> outTpl=inTpl;
1111 algorithm
1112 pat := matchcontinue (pat,inTpl)
1113 local
1114 HashTableStringToPath.HashTable ht;
1115 String id;
1116 SourceInfo info;
1117 case (DAE.PAT_AS(id=id,pat=pat),(ht,info))
1118 algorithm
1119 ✗ true := BaseHashTable.hasKey(id, ht);
1120 ✗ Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.META_UNUSED_AS_BINDING, {id}, info);
1121 then pat;
1122 case (DAE.PAT_AS_FUNC_PTR(id=id,pat=pat),(ht,_))
1123 algorithm
1124 ✗ true := BaseHashTable.hasKey(id, ht);
1125 then pat;
1126 else
1127 algorithm
1128 ✗ pat := simplifyPattern(inPat, 1);
1129 then pat;
1130 end matchcontinue;
1131 end removePatternAsBinding;
1132
1133 protected function addLocalCref
1134 "Use with Expression.traverseExpBottomUp to collect all CREF's that could be references to local
1135 variables."
1136 input DAE.Exp inExp;
1137 input HashTableStringToPath.HashTable inHt;
1138 output DAE.Exp outExp;
1139 output HashTableStringToPath.HashTable outHt;
1140 algorithm
1141 (outExp,outHt) := match (inExp,inHt)
1142 local
1143 DAE.Exp exp;
1144 HashTableStringToPath.HashTable ht;
1145 String name;
1146 list<DAE.MatchCase> cases;
1147 DAE.Pattern pat;
1148 DAE.ComponentRef cr;
1149 case (exp as DAE.CREF(componentRef=cr),ht)
1150 algorithm
1151 23073 ht := addLocalCrefHelper(cr,ht);
1152 then (exp,ht);
1153 case (exp as DAE.CALL(path=Absyn.IDENT(name), attr=DAE.CALL_ATTR(builtin=false)),ht)
1154 algorithm
1155 70 ht := BaseHashTable.add((name,Absyn.IDENT("")), ht);
1156 then (exp,ht);
1157 case (exp as DAE.PATTERN(pattern=pat),ht)
1158 algorithm
1159 442 (_,ht) := traversePattern(pat, addPatternAsBindings, ht);
1160 442 then (exp,ht);
1161 case (exp as DAE.MATCHEXPRESSION(cases=cases),ht)
1162 algorithm
1163 38 ht := addCasesLocalCref(cases,ht);
1164 then (exp,ht);
1165 else (inExp,inHt);
1166 end match;
1167 end addLocalCref;
1168
1169 protected function addLocalCrefHelper
1170 input DAE.ComponentRef cr;
1171 input HashTableStringToPath.HashTable iht;
1172 output HashTableStringToPath.HashTable ht;
1173 algorithm
1174 ht := match (cr,iht)
1175 local
1176 String name;
1177 list<DAE.Subscript> subs;
1178 DAE.ComponentRef cr2;
1179 case (DAE.CREF_IDENT(ident=name,subscriptLst=subs),ht)
1180 algorithm
1181 23070 ht := addLocalCrefSubs(subs,ht);
1182 23070 ht := BaseHashTable.add((name,Absyn.IDENT("")), ht);
1183 then ht;
1184 case (DAE.CREF_QUAL(ident=name,subscriptLst=subs,componentRef=cr2),ht)
1185 algorithm
1186 255 ht := addLocalCrefSubs(subs,ht);
1187 255 ht := BaseHashTable.add((name,Absyn.IDENT("")), ht);
1188 255 then addLocalCrefHelper(cr2,ht);
1189 else iht;
1190 end match;
1191 end addLocalCrefHelper;
1192
1193 protected function addLocalCrefSubs
1194 "Cref subscripts may also contain crefs"
1195 input list<DAE.Subscript> isubs;
1196 input HashTableStringToPath.HashTable iht;
1197 output HashTableStringToPath.HashTable outHt;
1198 algorithm
1199 outHt := match (isubs,iht)
1200 local
1201 DAE.Exp exp;
1202 list<DAE.Subscript> subs;
1203 HashTableStringToPath.HashTable ht;
1204
1205 case ({},ht) then ht;
1206 case (DAE.SLICE(exp)::subs,ht)
1207 algorithm
1208 ✗ (_,ht) := Expression.traverseExpBottomUp(exp, addLocalCref, ht);
1209 ✗ ht := addLocalCrefSubs(subs,ht);
1210 then ht;
1211 case (DAE.INDEX(exp)::subs,ht)
1212 algorithm
1213 ✗ (_,ht) := Expression.traverseExpBottomUp(exp, addLocalCref, ht);
1214 ✗ ht := addLocalCrefSubs(subs,ht);
1215 then ht;
1216 else iht;
1217 end match;
1218 end addLocalCrefSubs;
1219
1220 protected function checkDefUse
1221 "Use with Expression.traverseExpBottomUp to collect all CREF's that could be references to local
1222 variables."
1223 input DAE.Exp inExp;
1224 input tuple<AvlSetString.Tree,AvlSetString.Tree,SourceInfo> inTpl;
1225 output DAE.Exp outExp;
1226 output tuple<AvlSetString.Tree,AvlSetString.Tree,SourceInfo> outTpl;
1227 algorithm
1228 (outExp,outTpl) := matchcontinue (inExp,inTpl)
1229 local
1230 AvlSetString.Tree localsTree,useTree;
1231 String name;
1232 DAE.Pattern pat;
1233 DAE.ComponentRef cr;
1234 SourceInfo info;
1235 DAE.Type ty;
1236 tuple<AvlSetString.Tree,AvlSetString.Tree,SourceInfo> extra;
1237 case (DAE.CREF(componentRef=cr,ty=ty),extra as (localsTree,useTree,info))
1238 algorithm
1239 10322 name := ComponentReferenceBasics.crefFirstIdent(cr);
1240
4/4
✓ Branch 1 taken 9488 times.
✓ Branch 2 taken 828 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 9482 times.
10316 if AvlSetString.hasKey(localsTree,name) and not AvlSetString.hasKey(useTree,name) then
1241 6 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.META_UNUSED_ASSIGNMENT,{name},info);
1242 6 outExp := DAE.CREF(DAE.WILD(),ty);
1243 else
1244 outExp := inExp;
1245 end if;
1246 10316 then (outExp,extra);
1247 case (DAE.PATTERN(pattern=pat),extra)
1248 algorithm
1249 882 (pat,extra) := traversePattern(pat, checkDefUsePattern, extra);
1250 882 then (DAE.PATTERN(pat),extra);
1251 else (inExp,inTpl);
1252 end matchcontinue;
1253 end checkDefUse;
1254
1255 protected function checkDefUsePattern
1256 "Replace unused assignments with wildcards"
1257 input DAE.Pattern inPat;
1258 input tuple<AvlSetString.Tree,AvlSetString.Tree,SourceInfo> inTpl;
1259 output DAE.Pattern outPat;
1260 output tuple<AvlSetString.Tree,AvlSetString.Tree,SourceInfo> outTpl=inTpl;
1261 algorithm
1262 outPat := match (inPat,inTpl)
1263 local
1264 AvlSetString.Tree localsTree,useTree;
1265 String name;
1266 DAE.Pattern pat;
1267 SourceInfo info;
1268 case (DAE.PAT_AS(id=name,pat=pat),(localsTree,useTree,info))
1269 algorithm
1270
4/4
✓ Branch 1 taken 15211 times.
✓ Branch 2 taken 298 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 15200 times.
15509 if AvlSetString.hasKey(localsTree,name) and not AvlSetString.hasKey(useTree,name) then
1271 11 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.META_UNUSED_AS_BINDING,{name},info);
1272 else
1273 pat := inPat;
1274 end if;
1275 then pat;
1276 case (DAE.PAT_AS_FUNC_PTR(id=name,pat=pat),(localsTree,useTree,info))
1277 algorithm
1278
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
10 if AvlSetString.hasKey(localsTree,name) and not AvlSetString.hasKey(useTree,name) then
1279 ✗ Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.META_UNUSED_AS_BINDING,{name},info);
1280 else
1281 pat := inPat;
1282 end if;
1283 then pat;
1284 else
1285 algorithm
1286 44048 (pat,_) := simplifyPattern(inPat,1);
1287 then pat;
1288 end match;
1289 end checkDefUsePattern;
1290
1291 protected function useLocalCref
1292 "Use with Expression.traverseExpBottomUp to collect all CREF's that could be references to local
1293 variables."
1294 input DAE.Exp inExp;
1295 input AvlSetString.Tree inTree;
1296 output DAE.Exp outExp;
1297 output AvlSetString.Tree outTree;
1298 algorithm
1299 (outExp,outTree) := match (inExp,inTree)
1300 local
1301 DAE.Exp exp;
1302 AvlSetString.Tree tree;
1303 String name;
1304 list<DAE.MatchCase> cases;
1305 DAE.Pattern pat;
1306 DAE.ComponentRef cr;
1307 case (exp as DAE.CREF(componentRef=cr),tree)
1308 algorithm
1309 35902 tree := useLocalCrefHelper(cr,tree);
1310 then (exp,tree);
1311 case (exp as DAE.CALL(path=Absyn.IDENT(name), attr=DAE.CALL_ATTR(builtin=false)),tree)
1312 algorithm
1313 140 tree := AvlSetString.add(tree, name);
1314 then (exp,tree);
1315 case (exp as DAE.PATTERN(pattern=pat),tree)
1316 algorithm
1317 4 (_,tree) := traversePattern(pat, usePatternAsBindings, tree);
1318 4 then (exp,tree);
1319 case (exp as DAE.MATCHEXPRESSION(cases=cases),tree)
1320 algorithm
1321 76 tree := useCasesLocalCref(cases,tree);
1322 then (exp,tree);
1323 else (inExp,inTree);
1324 end match;
1325 end useLocalCref;
1326
1327 protected function useLocalCrefHelper
1328 input DAE.ComponentRef cr;
1329 input AvlSetString.Tree inTree;
1330 output AvlSetString.Tree tree;
1331 algorithm
1332 tree := match cr
1333 local
1334 String name;
1335 list<DAE.Subscript> subs;
1336 DAE.ComponentRef cr2;
1337 case DAE.CREF_IDENT(ident=name,subscriptLst=subs)
1338 algorithm
1339 35902 tree := useLocalCrefSubs(subs,inTree);
1340 35902 then AvlSetString.add(tree, name);
1341 case DAE.CREF_QUAL(ident=name,subscriptLst=subs,componentRef=cr2)
1342 algorithm
1343 476 tree := useLocalCrefSubs(subs,inTree);
1344 476 tree := AvlSetString.add(tree, name);
1345 476 then useLocalCrefHelper(cr2,tree);
1346 else inTree;
1347 end match;
1348 end useLocalCrefHelper;
1349
1350 protected function useLocalCrefSubs
1351 "Cref subscripts may also contain crefs"
1352 input list<DAE.Subscript> isubs;
1353 input AvlSetString.Tree inTree;
1354 output AvlSetString.Tree tree;
1355 algorithm
1356 tree := match isubs
1357 local
1358 DAE.Exp exp;
1359 list<DAE.Subscript> subs;
1360
1361 case {} then inTree;
1362 case DAE.SLICE(exp)::subs
1363 algorithm
1364 ✗ (_,tree) := Expression.traverseExpBottomUp(exp, useLocalCref, inTree);
1365 ✗ tree := useLocalCrefSubs(subs,tree);
1366 then tree;
1367 case DAE.INDEX(exp)::subs
1368 algorithm
1369 ✗ (_,tree) := Expression.traverseExpBottomUp(exp, useLocalCref, inTree);
1370 ✗ tree := useLocalCrefSubs(subs,tree);
1371 then tree;
1372 else inTree;
1373 end match;
1374 end useLocalCrefSubs;
1375
1376 protected function usePatternAsBindings
1377 "Traverse patterns and as-bindings as variable references in the hashtable"
1378 input DAE.Pattern inPat;
1379 input AvlSetString.Tree inTree;
1380 output DAE.Pattern outPat=inPat;
1381 output AvlSetString.Tree outTree;
1382 algorithm
1383 outTree := matchcontinue inPat
1384 case DAE.PAT_AS()
1385 72 then AvlSetString.add(inTree, inPat.id);
1386 case DAE.PAT_AS_FUNC_PTR()
1387 ✗ then AvlSetString.add(inTree, inPat.id);
1388 else inTree;
1389 end matchcontinue;
1390 end usePatternAsBindings;
1391
1392 protected function useCasesLocalCref
1393 input list<DAE.MatchCase> icases;
1394 input AvlSetString.Tree inTree;
1395 output AvlSetString.Tree tree;
1396 algorithm
1397 tree := match icases
1398 local
1399 list<DAE.Pattern> pats;
1400 list<DAE.MatchCase> cases;
1401
1402 case {} then inTree;
1403 case DAE.CASE(patterns=pats)::cases
1404 algorithm
1405 172 (_,tree) := traversePatternList(pats, usePatternAsBindings, inTree);
1406 172 tree := useCasesLocalCref(cases,tree);
1407 then tree;
1408 end match;
1409 end useCasesLocalCref;
1410
1411 protected function addCasesLocalCref
1412 input list<DAE.MatchCase> icases;
1413 input HashTableStringToPath.HashTable iht;
1414 output HashTableStringToPath.HashTable outHt;
1415 algorithm
1416 outHt := match (icases,iht)
1417 local
1418 list<DAE.Pattern> pats;
1419 list<DAE.MatchCase> cases;
1420 HashTableStringToPath.HashTable ht;
1421
1422 case ({},ht) then ht;
1423 case (DAE.CASE(patterns=pats)::cases,ht)
1424 algorithm
1425 86 (_,ht) := traversePatternList(pats, addPatternAsBindings, ht);
1426 86 ht := addCasesLocalCref(cases,ht);
1427 then ht;
1428 end match;
1429 end addCasesLocalCref;
1430
1431 protected function simplifyPattern
1432 "Simplifies a pattern, for example (_,_,_)=>_. For use with traversePattern"
1433 input DAE.Pattern inPat;
1434 input A extra;
1435 output DAE.Pattern outPat;
1436 output A outExtra=extra;
1437 replaceable type A subtypeof Any;
1438 algorithm
1439 outPat := match inPat
1440 local
1441 Absyn.Path name;
1442 list<tuple<DAE.Pattern, String, DAE.Type>> namedPatterns;
1443 list<DAE.Pattern> patterns;
1444 case DAE.PAT_CALL_NAMED(name, namedPatterns)
1445 algorithm
1446 55 namedPatterns := List.filterOnTrue(namedPatterns, filterEmptyPattern);
1447
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 5 times.
55 then if listEmpty(namedPatterns) then DAE.PAT_WILD() else DAE.PAT_CALL_NAMED(name, namedPatterns);
1448 case DAE.PAT_CALL_TUPLE(patterns)
1449
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 then if allPatternsWild(patterns) then DAE.PAT_WILD() else inPat;
1450 case DAE.PAT_META_TUPLE(patterns)
1451
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 148 times.
150 then if allPatternsWild(patterns) then DAE.PAT_WILD() else inPat;
1452 else inPat;
1453 end match;
1454 end simplifyPattern;
1455
1456 protected function addPatternAsBindings
1457 "Traverse patterns and as-bindings as variable references in the hashtable"
1458 input DAE.Pattern inPat;
1459 input HashTableStringToPath.HashTable inHt;
1460 output DAE.Pattern pat=inPat;
1461 output HashTableStringToPath.HashTable ht=inHt;
1462 algorithm
1463 ht := matchcontinue inPat
1464 local
1465 String id;
1466 case DAE.PAT_AS(id=id)
1467 222 then BaseHashTable.add((id,Absyn.IDENT("")), ht);
1468 case DAE.PAT_AS_FUNC_PTR(id=id)
1469 ✗ then BaseHashTable.add((id,Absyn.IDENT("")), ht);
1470 975 else ht;
1471 end matchcontinue;
1472 end addPatternAsBindings;
1473
1474 public function traversePatternList<TypeA>
1475 input list<DAE.Pattern> inPatterns;
1476 input Func func;
1477 input TypeA inExtra;
1478 output list<DAE.Pattern> outPatterns={};
1479 output TypeA extra=inExtra;
1480 partial function Func
1481 input DAE.Pattern inPattern;
1482 input TypeA inExtra;
1483 output DAE.Pattern outPattern;
1484 output TypeA outExtra;
1485 end Func;
1486 protected
1487 DAE.Pattern p;
1488 algorithm
1489
2/2
✓ Branch 0 taken 150909 times.
✓ Branch 1 taken 78896 times.
229805 for pat in inPatterns loop
1490 150909 (p, extra) := traversePattern(pat, func, extra);
1491 outPatterns := p :: outPatterns;
1492 end for;
1493 78896 outPatterns := Dangerous.listReverseInPlace(outPatterns);
1494 end traversePatternList;
1495
1496 public function traversePattern<TypeA>
1497 input DAE.Pattern inPattern;
1498 input Func func;
1499 input TypeA inExtra;
1500 output DAE.Pattern outPattern;
1501 output TypeA extra=inExtra;
1502 partial function Func
1503 input DAE.Pattern inPattern;
1504 input TypeA inExtra;
1505 output DAE.Pattern outPattern;
1506 output TypeA outExtra;
1507 end Func;
1508 algorithm
1509 (outPattern,extra) := match inPattern
1510 local
1511 DAE.Pattern pat,pat1,pat2;
1512 list<DAE.Pattern> pats;
1513 list<String> fields;
1514 list<DAE.Type> types, typeVars;
1515 String id,str;
1516 Option<DAE.Type> ty;
1517 Absyn.Path name;
1518 Integer index;
1519 list<tuple<DAE.Pattern,String,DAE.Type>> namedpats;
1520 Boolean knownSingleton;
1521 list<DAE.Var> fieldVars;
1522 DAE.Attributes attr;
1523 case DAE.PAT_AS(id,ty,attr,pat2)
1524 algorithm
1525 73899 (pat2,extra) := traversePattern(pat2,func,extra);
1526 73899 pat := DAE.PAT_AS(id,ty,attr,pat2);
1527
2/2
✓ Branch 0 taken 7567 times.
✓ Branch 1 taken 66332 times.
73899 (pat,extra) := func(pat,extra);
1528 then (pat,extra);
1529 case DAE.PAT_AS_FUNC_PTR(id,pat2)
1530 algorithm
1531 61 (pat2,extra) := traversePattern(pat2,func,extra);
1532 61 pat := DAE.PAT_AS_FUNC_PTR(id,pat2);
1533
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 56 times.
61 (pat,extra) := func(pat,extra);
1534 then (pat,extra);
1535 case DAE.PAT_CALL(name,index,pats,fieldVars,typeVars,knownSingleton)
1536 algorithm
1537 40743 (pats,extra) := traversePatternList(pats, func, extra);
1538
2/2
✓ Branch 0 taken 37170 times.
✓ Branch 1 taken 3573 times.
77913 pat := DAE.PAT_CALL(name,index,pats,fieldVars,typeVars,knownSingleton);
1539
2/2
✓ Branch 0 taken 5078 times.
✓ Branch 1 taken 35665 times.
40743 (pat,extra) := func(pat,extra);
1540 then (pat,extra);
1541 case DAE.PAT_CALL_NAMED(name,namedpats)
1542 algorithm
1543 190 (pats, fields, types) := List.unzip3(namedpats);
1544 190 (pats,extra) := traversePatternList(pats, func, extra);
1545 190 namedpats := List.zip3(pats, fields, types);
1546 190 pat := DAE.PAT_CALL_NAMED(name,namedpats);
1547
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 165 times.
190 (pat,extra) := func(pat,extra);
1548 then (pat,extra);
1549 case DAE.PAT_CALL_TUPLE(pats)
1550 algorithm
1551 117 (pats,extra) := traversePatternList(pats, func, extra);
1552 117 pat := DAE.PAT_CALL_TUPLE(pats);
1553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 (pat,extra) := func(pat,extra);
1554 then (pat,extra);
1555 case DAE.PAT_META_TUPLE(pats)
1556 algorithm
1557 785 (pats,extra) := traversePatternList(pats, func, extra);
1558 785 pat := DAE.PAT_META_TUPLE(pats);
1559
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 716 times.
785 (pat,extra) := func(pat,extra);
1560 then (pat,extra);
1561 case DAE.PAT_CONS(pat1,pat2)
1562 algorithm
1563 5511 (pat1,extra) := traversePattern(pat1,func,extra);
1564 5511 (pat2,extra) := traversePattern(pat2,func,extra);
1565 5511 pat := DAE.PAT_CONS(pat1,pat2);
1566
2/2
✓ Branch 0 taken 668 times.
✓ Branch 1 taken 4843 times.
5511 (pat,extra) := func(pat,extra);
1567 then (pat,extra);
1568 case pat as DAE.PAT_CONSTANT()
1569 algorithm
1570
2/2
✓ Branch 0 taken 1491 times.
✓ Branch 1 taken 12595 times.
14086 (pat,extra) := func(pat,extra);
1571 then (pat,extra);
1572 case DAE.PAT_SOME(pat1)
1573 algorithm
1574 1212 (pat1,extra) := traversePattern(pat1,func,extra);
1575 1212 pat := DAE.PAT_SOME(pat1);
1576
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 1060 times.
1212 (pat,extra) := func(pat,extra);
1577 then (pat,extra);
1578 case pat as DAE.PAT_WILD()
1579 algorithm
1580
2/2
✓ Branch 0 taken 13732 times.
✓ Branch 1 taken 100849 times.
114581 (pat,extra) := func(pat,extra);
1581 then (pat,extra);
1582 case pat
1583 algorithm
1584 ✗ str := "Patternm.traversePattern failed: " + ExpressionDump.patternStr(pat);
1585 ✗ Error.addMessage(Error.INTERNAL_ERROR, {str});
1586 ✗ then fail();
1587 end match;
1588 end traversePattern;
1589
1590 protected function filterUnusedDecls
1591 "Filters out unused local declarations"
1592 input list<DAE.Element> matchDecls;
1593 input HashTableStringToPath.HashTable ht;
1594 input list<DAE.Element> iacc;
1595 input HashTableStringToPath.HashTable iunusedHt;
1596 output list<DAE.Element> outDecls;
1597 output HashTableStringToPath.HashTable outUnusedHt;
1598 algorithm
1599 (outDecls,outUnusedHt) := matchcontinue (matchDecls, iacc, iunusedHt)
1600 local
1601 DAE.Element el;
1602 list<DAE.Element> rest;
1603 SourceInfo info;
1604 String name;
1605 list<DAE.Element> acc;
1606 HashTableStringToPath.HashTable unusedHt;
1607
1608 1164 case ({}, acc, unusedHt) then (listReverse(acc),unusedHt);
1609 case (DAE.VAR(componentRef=DAE.CREF_IDENT(ident=name), source=DAE.SOURCE(info=info))::rest, acc, unusedHt)
1610 algorithm
1611
2/2
✓ Branch 1 taken 4554 times.
✓ Branch 2 taken 132 times.
4686 false := BaseHashTable.hasKey(name, ht);
1612 132 unusedHt := BaseHashTable.add((name,Absyn.IDENT("")),unusedHt);
1613 132 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.META_UNUSED_DECL, {name}, info);
1614 132 (acc,unusedHt) := filterUnusedDecls(rest,ht,acc,unusedHt);
1615 then (acc,unusedHt);
1616 case (el::rest, acc, unusedHt)
1617 algorithm
1618 4554 (acc,unusedHt) := filterUnusedDecls(rest,ht,el::acc,unusedHt);
1619 then (acc,unusedHt);
1620 end matchcontinue;
1621 end filterUnusedDecls;
1622
1623 protected function caseDeadCodeElimination
1624 "matchcontinue: Removes empty, failing cases
1625 match: Removes empty cases that can't be matched by subsequent cases
1626 match: Removes cases that can't be reached because a previous case has a dominating pattern
1627 "
1628 input Absyn.MatchType matchType;
1629 input list<DAE.MatchCase> cases;
1630 input list<list<DAE.Pattern>> prevPatterns;
1631 input list<DAE.MatchCase> iacc;
1632 input Boolean iter "If we remove some code, it may cascade. We should we loop more.";
1633 output list<DAE.MatchCase> outCases;
1634 algorithm
1635 outCases := matchcontinue (matchType, cases, iacc, iter)
1636 local
1637 list<DAE.MatchCase> rest;
1638 list<DAE.Pattern> pats;
1639 DAE.MatchCase case_;
1640 SourceInfo info;
1641 list<DAE.MatchCase> acc;
1642
1643 1164 case (_, {}, acc, false) then listReverse(acc);
1644 1 case (_, {}, acc, true) then caseDeadCodeElimination(matchType,listReverse(acc),{},{},false);
1645 case (_, DAE.CASE(body={},result=NONE(),info=info)::{}, acc, _)
1646 algorithm
1647 1 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO), Error.META_DEAD_CODE, {"Last pattern is empty"}, info);
1648 1 then caseDeadCodeElimination(matchType,listReverse(acc),{},{},false);
1649 /* Tricky to get right; I'll try again later as it probably only gives marginal results anyway
1650 case (Absyn.MATCH(),DAE.CASE(patterns=pats,info=info)::rest,prevPatterns as _::_,acc,iter)
1651 algorithm
1652 oinfo = findOverlappingPattern(pats,acc);
1653 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO), Error.META_DEAD_CODE, {"Unreachable pattern"}, info);
1654 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO), Error.META_DEAD_CODE, {"Shadowing case"}, oinfo);
1655 then caseDeadCodeElimination(matchType,rest,pats::prevPatterns,acc,true);
1656 */
1657 case (Absyn.MATCHCONTINUE(), DAE.CASE(patterns=pats,body={},result=NONE(),info=info)::rest, acc, _)
1658 algorithm
1659
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 true := Flags.isSet(Flags.PATTERNM_DCE);
1660 2 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO), Error.META_DEAD_CODE, {"Empty matchcontinue case"}, info);
1661 2 acc := caseDeadCodeElimination(matchType,rest,pats::prevPatterns,acc,true);
1662 then acc;
1663 5159 case (_, (case_ as DAE.CASE(patterns=pats))::rest, acc, _) then caseDeadCodeElimination(matchType,rest,pats::prevPatterns,case_::acc,iter);
1664 end matchcontinue;
1665 end caseDeadCodeElimination;
1666
1667 /*
1668 protected function findOverlappingPattern
1669 input list<DAE.Pattern> patterns;
1670 input list<DAE.MatchCase> prevCases;
1671 output SourceInfo info;
1672 algorithm
1673 info := matchcontinue (patterns,prevCases)
1674 local
1675 list<DAE.Pattern> ps1,ps2;
1676 case (ps1,DAE.CASE(patterns=ps2,info=info)::_)
1677 algorithm
1678 true = patternListsDoOverlap(ps1,ps2); ???
1679 then info;
1680 case (ps1,_::prevCases) then findOverlappingPattern(ps1,prevCases);
1681 end matchcontinue;
1682 end findOverlappingPattern;
1683 */
1684
1685 protected function optimizeContinueJumps
1686 "If a case in a matchcontinue expression is followed by a (list of) cases that
1687 do not have overlapping patterns with the first one, an optimization can be made.
1688 If we match against the first pattern, we can jump a few positions in the loop!
1689
1690 For example:
1691 matchcontinue i,j
1692 case (1,_) then (); // (1) => skip (2),(3) if this pattern matches
1693 case (2,_) then (); // (2) => skip (3),(4) if this pattern matches
1694 case (3,_) then (); // (3) => skip (4),(5) if this pattern matches
1695 case (1,_) then (); // (4) => skip (5),(6) if this pattern matches
1696 case (2,_) then (); // (5) => skip (6) if this pattern matches
1697 case (3,_) then (); // (6)
1698 case (_,2) then (); // (7) => skip (8),(9) if this pattern matches
1699 case (1,1) then (); // (8) => skip (9) if this pattern matches
1700 case (2,1) then (); // (9) => skip (10) if this pattern matches
1701 case (1,_) then (); // (10)
1702 end matchcontinue;
1703 "
1704 input Absyn.MatchType matchType;
1705 input list<DAE.MatchCase> cases;
1706 output list<DAE.MatchCase> outCases;
1707 algorithm
1708 outCases := match matchType
1709 case Absyn.MATCH() then cases;
1710 97 else optimizeContinueJumps2(cases);
1711 end match;
1712 end optimizeContinueJumps;
1713
1714 protected function optimizeContinueJumps2
1715 input list<DAE.MatchCase> icases;
1716 output list<DAE.MatchCase> outCases;
1717 algorithm
1718 outCases := match icases
1719 local
1720 DAE.MatchCase case_;
1721 list<DAE.MatchCase> cases;
1722
1723 case {} then {};
1724 case case_::cases
1725 algorithm
1726 987 case_ := optimizeContinueJump(case_,cases,0);
1727 987 cases := optimizeContinueJumps2(cases);
1728 then case_::cases;
1729 end match;
1730 end optimizeContinueJumps2;
1731
1732 protected function optimizeContinueJump
1733 input DAE.MatchCase case_;
1734 input list<DAE.MatchCase> icases;
1735 input Integer jump;
1736 output DAE.MatchCase outCase;
1737 algorithm
1738 outCase := matchcontinue (case_, icases)
1739 local
1740 DAE.MatchCase case1;
1741 list<DAE.Pattern> ps1,ps2;
1742 list<DAE.MatchCase> cases;
1743
1744 214 case (case1, {}) then updateMatchCaseJump(case1,jump);
1745 case (case1 as DAE.CASE(patterns=ps1), DAE.CASE(patterns=ps2)::cases)
1746 algorithm
1747
2/2
✓ Branch 1 taken 773 times.
✓ Branch 2 taken 5635 times.
6408 true := patternListsDoNotOverlap(ps1,ps2);
1748 5635 then optimizeContinueJump(case1,cases,jump+1);
1749 773 case (case1, _) then updateMatchCaseJump(case1,jump);
1750 end matchcontinue;
1751 end optimizeContinueJump;
1752
1753 protected function updateMatchCaseJump
1754 "Updates the jump field of a DAE.MatchCase"
1755 input DAE.MatchCase case_;
1756 input Integer jump;
1757 output DAE.MatchCase outCase;
1758 algorithm
1759 outCase := match (case_,jump)
1760 local
1761 list<DAE.Pattern> patterns;
1762 list<DAE.Element> localDecls;
1763 list<DAE.Statement> body;
1764 Option<DAE.Exp> result,guardPattern;
1765 SourceInfo resultInfo, info;
1766 case (_,0) then case_;
1767 case (DAE.CASE(patterns, guardPattern, localDecls, body, result, resultInfo, _, info), _)
1768 560 then DAE.CASE(patterns, guardPattern, localDecls, body, result, resultInfo, jump, info);
1769 end match;
1770 end updateMatchCaseJump;
1771
1772 protected function optimizeContinueToMatch
1773 "If a matchcontinue expression has only one case, it is optimized to match instead.
1774 The same goes if for every case there is no overlapping pattern with a previous case.
1775 For example, the following example can be safely translated into a match-expression:
1776 matchcontinue i
1777 case 1 then ();
1778 case 2 then ();
1779 case 3 then ();
1780 end matchcontinue;
1781 "
1782 input Absyn.MatchType matchType;
1783 input list<DAE.MatchCase> cases;
1784 input SourceInfo info;
1785 output Absyn.MatchType outMatchType;
1786 algorithm
1787 outMatchType := match matchType
1788 case Absyn.MATCH() then Absyn.MATCH();
1789 104 else optimizeContinueToMatch2(cases,{},info);
1790 end match;
1791
1/2
✓ Branch 1 taken 1164 times.
✗ Branch 2 not taken.
1164 if Flags.isSet(Flags.PATTERNM_ALL_INFO) then
1792 ✗ checkMatchContinueSingleCaseToTry(outMatchType, cases, info);
1793 end if;
1794 end optimizeContinueToMatch;
1795
1796 protected function checkMatchContinueSingleCaseToTry
1797 "Emits a notification when a matchcontinue has exactly one real case and an
1798 else case, suggesting that it be rewritten as a try/else."
1799 input Absyn.MatchType matchType;
1800 input list<DAE.MatchCase> cases;
1801 input SourceInfo info;
1802 algorithm
1803 () := match (matchType, cases)
1804 local list<DAE.Pattern> firstPats, elsePats;
1805 case (Absyn.MATCHCONTINUE(),
1806 {DAE.CASE(patterns=firstPats), DAE.CASE(patterns=elsePats)})
1807 guard not allPatternsWild(firstPats) and allPatternsWild(elsePats)
1808 algorithm
1809 ✗ Error.addSourceMessage(Error.MATCHCONTINUE_TO_TRY_OPTIMIZATION, {}, info);
1810 then ();
1811 else ();
1812 end match;
1813 end checkMatchContinueSingleCaseToTry;
1814
1815 protected function optimizeContinueToMatch2
1816 "If a matchcontinue expression has only one case, it is optimized to match instead.
1817 The same goes if for every case there is no overlapping pattern with a previous case.
1818 For example, the following example can be safely translated into a match-expression:
1819 matchcontinue i
1820 case 1 then ();
1821 case 2 then ();
1822 case 3 then ();
1823 end matchcontinue;
1824 "
1825 input list<DAE.MatchCase> icases;
1826 input list<list<DAE.Pattern>> prevPatterns "All cases check its patterns against all previous patterns. If they overlap, we can't optimize away the continue";
1827 input SourceInfo info;
1828 output Absyn.MatchType outMatchType;
1829 algorithm
1830 outMatchType := matchcontinue icases
1831 local
1832 list<DAE.Pattern> patterns;
1833 list<DAE.MatchCase> cases;
1834
1835 case {}
1836 algorithm
1837 7 Error.assertionOrAddSourceMessage(not Flags.isSet(Flags.PATTERNM_ALL_INFO), Error.MATCHCONTINUE_TO_MATCH_OPTIMIZATION, {}, info);
1838 then Absyn.MATCH();
1839 case DAE.CASE(patterns=patterns)::cases
1840 algorithm
1841 454 assertAllPatternListsDoNotOverlap(prevPatterns,patterns);
1842 357 then optimizeContinueToMatch2(cases,patterns::prevPatterns,info);
1843 else Absyn.MATCHCONTINUE();
1844 end matchcontinue;
1845 end optimizeContinueToMatch2;
1846
1847 protected function assertAllPatternListsDoNotOverlap
1848 "If a matchcontinue expression has only one case, it is optimized to match instead.
1849 The same goes if for every case there is no overlapping pattern with a previous case.
1850 For example, the following example can be safely translated into a match-expression:
1851 matchcontinue i
1852 case 1 then ();
1853 case 2 then ();
1854 case 3 then ();
1855 end matchcontinue;
1856 "
1857 input list<list<DAE.Pattern>> ipss1;
1858 input list<DAE.Pattern> ps2;
1859 algorithm
1860 () := match ipss1
1861 local
1862 list<DAE.Pattern> ps1;
1863 list<list<DAE.Pattern>> pss1;
1864
1865 case {} then ();
1866 case ps1::pss1
1867 algorithm
1868
2/2
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 1702 times.
1799 true := patternListsDoNotOverlap(ps1,ps2);
1869 1702 assertAllPatternListsDoNotOverlap(pss1,ps2);
1870 then ();
1871 end match;
1872 end assertAllPatternListsDoNotOverlap;
1873
1874 protected function patternListsDoNotOverlap
1875 "Verifies that pats1 does not shadow pats2"
1876 input list<DAE.Pattern> ips1;
1877 input list<DAE.Pattern> ips2;
1878 output Boolean b;
1879 algorithm
1880 b := match (ips1,ips2)
1881 local
1882 Boolean res;
1883 DAE.Pattern p1,p2;
1884 list<DAE.Pattern> ps1,ps2;
1885
1886 case ({},{}) then false;
1887 case (p1::ps1,p2::ps2)
1888 algorithm
1889 13873 res := patternsDoNotOverlap(p1,p2);
1890
2/2
✓ Branch 0 taken 4230 times.
✓ Branch 1 taken 9643 times.
13873 res := if not res then patternListsDoNotOverlap(ps1,ps2) else res;
1891 then res;
1892 end match;
1893 end patternListsDoNotOverlap;
1894
1895 protected function patternsDoNotOverlap
1896 "Verifies that p1 do not shadow p2"
1897 input DAE.Pattern ip1;
1898 input DAE.Pattern ip2;
1899 output Boolean b;
1900 algorithm
1901 b := match (ip1,ip2)
1902 local
1903 DAE.Pattern head1,tail1,head2,tail2,p1,p2;
1904 list<DAE.Pattern> ps1,ps2;
1905 Boolean res;
1906 Absyn.Path name1,name2;
1907 Integer ix1,ix2;
1908 DAE.Exp e1,e2;
1909
1910
1911 case (DAE.PAT_WILD(),_) then false;
1912 case (_,DAE.PAT_WILD()) then false;
1913 case (DAE.PAT_AS_FUNC_PTR(),_) then false;
1914 case (DAE.PAT_AS(pat=p1),p2)
1915 1737 then patternsDoNotOverlap(p1,p2);
1916 case (p1,DAE.PAT_AS(pat=p2))
1917 1042 then patternsDoNotOverlap(p1,p2);
1918
1919 case (DAE.PAT_CONS(head1, tail1),DAE.PAT_CONS(head2, tail2))
1920
4/4
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 36 times.
✓ Branch 4 taken 45 times.
✓ Branch 5 taken 135 times.
216 then patternsDoNotOverlap(head1,head2) or patternsDoNotOverlap(tail1,tail2);
1921 case (DAE.PAT_SOME(p1),DAE.PAT_SOME(p2))
1922 ✗ then patternsDoNotOverlap(p1,p2);
1923 case (DAE.PAT_META_TUPLE(ps1),DAE.PAT_META_TUPLE(ps2))
1924 7 then patternListsDoNotOverlap(ps1,ps2);
1925 case (DAE.PAT_CALL_TUPLE(ps1),DAE.PAT_CALL_TUPLE(ps2))
1926 ✗ then patternListsDoNotOverlap(ps1,ps2);
1927
1928 case (DAE.PAT_CALL(name1,ix1,{},_,_),DAE.PAT_CALL(name2,ix2,{},_,_))
1929 algorithm
1930 10 res := ix1 == ix2;
1931
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 res := if res then AbsynUtil.pathEqual(name1, name2) else res;
1932 10 then not res;
1933
1934 case (DAE.PAT_CALL(name1,ix1,ps1,_,_),DAE.PAT_CALL(name2,ix2,ps2,_,_))
1935 algorithm
1936 8706 res := ix1 == ix2;
1937
2/2
✓ Branch 0 taken 3006 times.
✓ Branch 1 taken 5700 times.
8706 res := if res then AbsynUtil.pathEqual(name1, name2) else res;
1938
2/2
✓ Branch 0 taken 3006 times.
✓ Branch 1 taken 5700 times.
8706 res := if res then patternListsDoNotOverlap(ps1, ps2) else not res;
1939 then res;
1940
1941 // TODO: PAT_CALLED_NAMED?
1942
1943 // Constant patterns...
1944 case (DAE.PAT_CONSTANT(exp=e1),DAE.PAT_CONSTANT(exp=e2))
1945 1719 then not ExpressionBasics.expEqual(e1, e2);
1946 case (DAE.PAT_CONSTANT(),_) then true;
1947 case (_,DAE.PAT_CONSTANT()) then true;
1948
1949 else false;
1950 end match;
1951 end patternsDoNotOverlap;
1952
1953 protected function elabMatchCases
1954 input FCore.Cache cache;
1955 input FCore.Graph env;
1956 input list<Absyn.Case> cases;
1957 input list<DAE.Type> tys;
1958 input list<list<String>> inputAliases;
1959 input AvlSetString.Tree matchExpLocalTree;
1960 input Boolean impl;
1961 input Boolean performVectorization;
1962 input DAE.Prefix pre;
1963 input SourceInfo info;
1964 output FCore.Cache outCache;
1965 output list<DAE.MatchCase> elabCases;
1966 output DAE.Type resType;
1967 protected
1968 list<DAE.Exp> resExps;
1969 list<DAE.Type> resTypes,tysFixed;
1970 algorithm
1971 1184 tysFixed := List.map(tys, Types.getUniontypeIfMetarecordReplaceAllSubtypes);
1972 1184 (outCache,elabCases,resExps,resTypes) := elabMatchCases2(cache,env,cases,tysFixed,inputAliases,matchExpLocalTree,impl,performVectorization,pre,{},{},{});
1973 1164 (elabCases,resType) := fixCaseReturnTypes(elabCases,resExps,resTypes,info);
1974 end elabMatchCases;
1975
1976 protected function elabMatchCases2
1977 input FCore.Cache inCache;
1978 input FCore.Graph inEnv;
1979 input list<Absyn.Case> cases;
1980 input list<DAE.Type> tys;
1981 input list<list<String>> inputAliases;
1982 input AvlSetString.Tree matchExpLocalTree;
1983 input Boolean impl;
1984 input Boolean performVectorization;
1985 input DAE.Prefix pre;
1986 input list<DAE.MatchCase> inAccCases "Order does matter";
1987 input list<DAE.Exp> inAccExps "Order does matter";
1988 input list<DAE.Type> inAccTypes "Order does not matter";
1989 output FCore.Cache outCache;
1990 output list<DAE.MatchCase> elabCases;
1991 output list<DAE.Exp> resExps;
1992 output list<DAE.Type> resTypes;
1993 algorithm
1994 (outCache,elabCases,resExps,resTypes) :=
1995 match (inCache,inEnv,cases,inAccExps,inAccTypes)
1996 local
1997 Absyn.Case case_;
1998 list<Absyn.Case> rest;
1999 DAE.MatchCase elabCase;
2000 Option<DAE.Type> optType;
2001 Option<DAE.Exp> optExp;
2002 FCore.Cache cache;
2003 FCore.Graph env;
2004 list<DAE.Exp> accExps;
2005 list<DAE.Type> accTypes;
2006
2007 1164 case (cache,_,{},accExps,accTypes) then (cache,listReverse(inAccCases),listReverse(accExps),listReverse(accTypes));
2008 case (cache,env,case_::rest,accExps,accTypes)
2009 algorithm
2010 5176 (cache,elabCase,optExp,optType) := elabMatchCase(cache,env,case_,tys,inputAliases,matchExpLocalTree,impl,performVectorization,pre);
2011 5156 (cache,elabCases,accExps,accTypes) := elabMatchCases2(cache,env,rest,tys,inputAliases,matchExpLocalTree,impl,performVectorization,pre,elabCase::inAccCases,List.consOption(optExp,accExps),List.consOption(optType,accTypes));
2012 then (cache,elabCases,accExps,accTypes);
2013 end match;
2014 end elabMatchCases2;
2015
2016 protected function elabMatchCase
2017 input FCore.Cache inCache;
2018 input FCore.Graph inEnv;
2019 input Absyn.Case acase;
2020 input list<DAE.Type> tys;
2021 input list<list<String>> inputAliases;
2022 input AvlSetString.Tree matchExpLocalTree;
2023 input Boolean impl;
2024 input Boolean performVectorization;
2025 input DAE.Prefix pre;
2026 output FCore.Cache outCache;
2027 output DAE.MatchCase elabCase;
2028 output Option<DAE.Exp> resExp;
2029 output Option<DAE.Type> resType;
2030 algorithm
2031 (outCache,elabCase,resExp,resType) :=
2032 match (inCache,inEnv,acase)
2033 local
2034 Absyn.Exp result,pattern;
2035 list<Absyn.Exp> patterns;
2036 list<DAE.Pattern> elabPatterns, elabPatterns2;
2037 Option<Absyn.Exp> patternGuard;
2038 Option<DAE.Exp> elabResult,dPatternGuard;
2039 list<DAE.Element> caseDecls;
2040 Absyn.ClassPart cp;
2041 list<Absyn.AlgorithmItem> eqAlgs;
2042 list<SCode.Statement> algs;
2043 list<DAE.Statement> body;
2044 list<Absyn.ElementItem> decls;
2045 SourceInfo patternInfo,resultInfo,info;
2046 Integer len;
2047 FCore.Cache cache;
2048 FCore.Graph env;
2049 AvlSetString.Tree caseLocalTree,localsTree,useTree;
2050
2051 case (cache,env,Absyn.CASE(pattern=pattern,patternGuard=patternGuard,patternInfo=patternInfo,localDecls=decls,classPart=cp,result=result,resultInfo=resultInfo,info=info))
2052 algorithm
2053
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5176 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5176 times.
5176 (cache,SOME((env,DAE.DAE(caseDecls),caseLocalTree))) := addLocalDecls(cache,env,decls,FCore.caseScopeName,impl,info);
2054 5176 patterns := convertExpToPatterns(pattern);
2055
2/2
✓ Branch 1 taken 2570 times.
✓ Branch 2 taken 2606 times.
5176 patterns := if listLength(tys)==1 then {pattern} else patterns;
2056 5176 (cache,elabPatterns) := elabPatternTuple(cache, env, patterns, tys, patternInfo, pattern);
2057 5169 checkPatternsDuplicateAsBindings(elabPatterns, patternInfo);
2058 // open a pattern type scope
2059 5164 env := FGraph.openNewScope(env, SCode.NOT_ENCAPSULATED(), SOME(FCore.patternTypeScope), NONE());
2060 // and add the ID as pattern types to it
2061 5164 (elabPatterns2, cache) := addPatternAliasesList(elabPatterns, inputAliases, cache, inEnv);
2062 5164 (_, env) := traversePatternList(elabPatterns2, addEnvKnownAsBindings, env);
2063 5164 eqAlgs := Static.fromEquationsToAlgAssignments(cp);
2064 5164 algs := AbsynToSCode.translateClassdefAlgorithmitems(eqAlgs);
2065 5164 (cache,body) := InstSection.instStatements(cache, env, InnerOuter.emptyInstHierarchy, pre, ClassInf.FUNCTION(Absyn.IDENT("match"), false), algs, ElementSource.addElementSourceFileInfo(DAE.emptyElementSource,patternInfo), SCode.NON_INITIAL(), true, InstTypes.neverUnroll);
2066 5156 (cache,body,elabResult,resultInfo,resType) := elabResultExp(cache,env,body,result,impl,performVectorization,pre,resultInfo);
2067 5156 (cache,dPatternGuard) := elabPatternGuard(cache,env,patternGuard,impl,performVectorization,pre,patternInfo);
2068 5156 localsTree := AvlSetString.join(matchExpLocalTree, caseLocalTree);
2069 // Start building the def-use chain bottom-up
2070 5156 useTree := AvlSetString.new();
2071 5156 (_,useTree) := Expression.traverseExpBottomUp(DAE.META_OPTION(elabResult), useLocalCref, useTree);
2072 5156 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree,useTree);
2073 5156 (_,useTree) := Expression.traverseExpBottomUp(DAE.META_OPTION(dPatternGuard), useLocalCref, useTree);
2074 5156 (elabPatterns,_) := traversePatternList(elabPatterns, checkDefUsePattern, (localsTree,useTree,patternInfo));
2075 // Do the same thing again, for fun and glory
2076 5156 useTree := AvlSetString.new();
2077 5156 (_,useTree) := Expression.traverseExpBottomUp(DAE.META_OPTION(elabResult), useLocalCref, useTree);
2078 5156 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree,useTree);
2079 5156 (_,useTree) := Expression.traverseExpBottomUp(DAE.META_OPTION(dPatternGuard), useLocalCref, useTree);
2080 5156 (elabPatterns,_) := traversePatternList(elabPatterns, checkDefUsePattern, (localsTree,useTree,patternInfo));
2081 5156 elabCase := DAE.CASE(elabPatterns, dPatternGuard, caseDecls, body, elabResult, resultInfo, 0, info);
2082
1/2
✓ Branch 0 taken 5156 times.
✗ Branch 1 not taken.
5156 then (cache,elabCase,elabResult,resType);
2083
2084 // ELSE is the same as CASE, but without pattern
2085 case (cache,env,Absyn.ELSE(localDecls=decls,classPart=cp,result=result,resultInfo=resultInfo,info=info))
2086 algorithm
2087 // Needs to be same length as any other pattern for the simplification algorithms, etc to work properly
2088 310 len := listLength(tys);
2089 310 patterns := List.fill(Absyn.CREF(Absyn.WILD()),listLength(tys));
2090
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 231 times.
310 pattern := if len == 1 then Absyn.CREF(Absyn.WILD()) else Absyn.TUPLE(patterns);
2091 310 (cache,elabCase,elabResult,resType) := elabMatchCase(cache, env, Absyn.CASE(pattern,NONE(),info,decls,cp,result,resultInfo,NONE(),info), tys, inputAliases, matchExpLocalTree, impl, performVectorization, pre);
2092 then (cache,elabCase,elabResult,resType);
2093
2094 end match;
2095 end elabMatchCase;
2096
2097 protected function elabResultExp
2098 input FCore.Cache inCache;
2099 input FCore.Graph inEnv;
2100 input list<DAE.Statement> inBody "Is input in case we want to optimize for tail-recursion";
2101 input Absyn.Exp exp;
2102 input Boolean impl;
2103 input Boolean performVectorization;
2104 input DAE.Prefix pre;
2105 input SourceInfo inInfo;
2106 output FCore.Cache outCache;
2107 output list<DAE.Statement> outBody;
2108 output Option<DAE.Exp> resExp;
2109 output SourceInfo resultInfo;
2110 output Option<DAE.Type> resType;
2111 algorithm
2112 (outCache,outBody,resExp,resultInfo,resType) :=
2113 match (inCache,inEnv,inBody,AbsynUtil.stripCommentExpressions(exp))
2114 local
2115 DAE.Exp elabExp;
2116 DAE.Properties prop;
2117 DAE.Type ty;
2118 FCore.Cache cache;
2119 FCore.Graph env;
2120 list<DAE.Statement> body;
2121 SourceInfo info;
2122
2123 case (cache,_,body,Absyn.CALL(function_ = Absyn.CREF_IDENT("fail",{}), functionArgs = Absyn.FUNCTIONARGS({},{})))
2124 then (cache,body,NONE(),inInfo,NONE());
2125
2126 case (cache,env,body,_)
2127 algorithm
2128 5066 (cache,elabExp,prop) := Static.elabExp(cache,env,exp,impl,performVectorization,pre,inInfo);
2129 5066 ty := Types.getPropType(prop);
2130 5066 (elabExp,ty) := makeTupleFromMetaTuple(elabExp,ty);
2131 5066 (body,elabExp,info) := elabResultExp2(not Flags.isSet(Flags.PATTERNM_MOVE_LAST_EXP),body,elabExp,inInfo);
2132 5066 then (cache,body,SOME(elabExp),info,SOME(ty));
2133 end match;
2134 end elabResultExp;
2135
2136 protected function elabPatternGuard
2137 input FCore.Cache inCache;
2138 input FCore.Graph inEnv;
2139 input Option<Absyn.Exp> patternGuard;
2140 input Boolean impl;
2141 input Boolean performVectorization;
2142 input DAE.Prefix pre;
2143 input SourceInfo inInfo;
2144 output FCore.Cache outCache;
2145 output Option<DAE.Exp> outPatternGuard;
2146 algorithm
2147 (outCache,outPatternGuard) :=
2148 matchcontinue (inCache, inEnv, patternGuard, inInfo)
2149 local
2150 Absyn.Exp exp;
2151 DAE.Exp elabExp;
2152 DAE.Properties prop;
2153 FCore.Cache cache;
2154 FCore.Graph env;
2155 SourceInfo info;
2156 String str;
2157
2158 case (cache, _, NONE(), _)
2159 then (cache,NONE());
2160
2161 case (cache, env, SOME(exp), info)
2162 algorithm
2163 129 (cache,elabExp,prop) := Static.elabExp(cache,env,exp,impl,performVectorization,pre,info);
2164 129 (elabExp,_) := Types.matchType(elabExp,Types.getPropType(prop),DAE.T_BOOL_DEFAULT,true);
2165 then (cache,SOME(elabExp));
2166
2167 case (cache, env, SOME(exp), info)
2168 algorithm
2169 ✗ (_,_,prop) := Static.elabExp(cache,env,exp,impl,performVectorization,pre,info);
2170 ✗ str := TypesDump.unparseType(Types.getPropType(prop));
2171 ✗ Error.addSourceMessage(Error.GUARD_EXPRESSION_TYPE_MISMATCH, {str}, info);
2172 ✗ then fail();
2173
2174 end matchcontinue;
2175 end elabPatternGuard;
2176
2177 protected function elabResultExp2
2178 "(cr1,...,crn) = exp; then (cr1,...,crn); => then exp;
2179 cr = exp; then cr; => then exp;
2180
2181 Is recursive, and will remove all such assignments, i.e.:
2182 doStuff(); a = 1; b = a; c = b; then c;
2183 Becomes:
2184 doStuff(); then c;
2185
2186 This phase needs to be performed if we want to be able to discover places to
2187 optimize for tail recursion.
2188 "
2189 input Boolean skipPhase;
2190 input list<DAE.Statement> body;
2191 input DAE.Exp elabExp;
2192 input SourceInfo info;
2193 output list<DAE.Statement> outBody;
2194 output DAE.Exp outExp;
2195 output SourceInfo outInfo;
2196 algorithm
2197 (outBody,outExp,outInfo) := matchcontinue (skipPhase,body,elabExp,info)
2198 local
2199 DAE.Exp elabCr1,elabCr2;
2200 list<DAE.Exp> elabCrs1,elabCrs2;
2201 list<DAE.Statement> b;
2202 DAE.Exp e;
2203 SourceInfo i;
2204
2205 ✗ case (true,b,e,i) then (b,e,i);
2206 case (_,b,elabCr2 as DAE.CREF(),_)
2207 algorithm
2208
2/2
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 1539 times.
2293 (DAE.STMT_ASSIGN(exp1=elabCr1,exp=e,source=DAE.SOURCE(info=i)),b) := List.splitLast(b);
2209
2/2
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 1506 times.
1539 true := ExpressionBasics.expEqual(elabCr1,elabCr2);
2210 1506 (b,e,i) := elabResultExp2(false,b,e,i);
2211 then (b,e,i);
2212 case (_,b,DAE.TUPLE(elabCrs2),_)
2213 algorithm
2214
2/2
✓ Branch 1 taken 314 times.
✓ Branch 2 taken 153 times.
750 (DAE.STMT_TUPLE_ASSIGN(expExpLst=elabCrs1,exp=e,source=DAE.SOURCE(info=i)),b) := List.splitLast(b);
2215
2/2
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 94 times.
153 true := List.isEqualOnTrue(elabCrs1, elabCrs2, ExpressionBasics.expEqual);
2216 94 (b,e,i) := elabResultExp2(false,b,e,i);
2217 then (b,e,i);
2218 5066 else (body,elabExp,info);
2219 end matchcontinue;
2220 end elabResultExp2;
2221
2222 protected function fixCaseReturnTypes
2223 input list<DAE.MatchCase> icases;
2224 input list<DAE.Exp> iexps;
2225 input list<DAE.Type> itys;
2226 input SourceInfo info;
2227 output list<DAE.MatchCase> outCases;
2228 output DAE.Type ty;
2229 algorithm
2230 (outCases,ty) := matchcontinue (icases, iexps, itys)
2231 local
2232 String str;
2233 list<DAE.MatchCase> cases;
2234 list<DAE.Exp> exps;
2235 list<DAE.Type> tys;
2236
2237 case (cases, {}, {}) then (cases,DAE.T_NORETCALL_DEFAULT);
2238
2239 case (cases, exps, tys)
2240 algorithm
2241 1164 ty := List.reduce(List.map(tys, Types.boxIfUnboxedType), Types.superType);
2242 1164 ty := Types.superType(ty, ty);
2243 1164 ty := Types.unboxedType(ty);
2244 1164 ty := Types.makeRegularTupleFromMetaTupleOnTrue(Types.allTuple(tys),ty);
2245 1164 ty := Types.getUniontypeIfMetarecordReplaceAllSubtypes(ty);
2246 1164 (exps,_) := Types.matchTypes(exps, tys, ty, true);
2247 1164 cases := Types.fixCaseReturnTypes2(cases,exps,info);
2248 then (cases,ty);
2249
2250 // 2 different cases, one boxed and one unboxed to handle everything
2251 case (cases, exps, tys)
2252 algorithm
2253 ✗ ty := List.reduce(tys, Types.superType);
2254 ✗ ty := Types.superType(ty, ty);
2255 ✗ ty := Types.unboxedType(ty);
2256 ✗ ty := Types.makeRegularTupleFromMetaTupleOnTrue(Types.allTuple(tys),ty);
2257 ✗ ty := Types.getUniontypeIfMetarecordReplaceAllSubtypes(ty);
2258 ✗ (exps,_) := Types.matchTypes(exps, tys, ty, true);
2259 ✗ cases := Types.fixCaseReturnTypes2(cases,exps,info);
2260 then (cases,ty);
2261
2262 else
2263 algorithm
2264 ✗ tys := List.unionOnTrue(itys, {}, Types.equivtypes);
2265 ✗ str := stringAppendList(List.map1r(List.map(tys, TypesDump.unparseType), stringAppend, "\n "));
2266 ✗ Error.addSourceMessage(Error.META_MATCHEXP_RESULT_TYPES, {str}, info);
2267 ✗ then fail();
2268
2269 end matchcontinue;
2270 end fixCaseReturnTypes;
2271
2272 public function traverseConstantPatternsHelper<T>
2273 input DAE.Exp inExp;
2274 input T inT;
2275 input FuncExpType func;
2276 output DAE.Exp outExp;
2277 output T outT=inT;
2278 partial function FuncExpType
2279 input DAE.Exp inExp;
2280 input T inTypeT;
2281 output DAE.Exp outExp;
2282 output T outT;
2283 end FuncExpType;
2284 algorithm
2285 outExp := match inExp
2286 local
2287 list<DAE.MatchCase> cases, cases2;
2288 DAE.MatchCase case_;
2289 list<DAE.Pattern> patterns;
2290 case outExp as DAE.MATCHEXPRESSION(cases=cases)
2291 algorithm
2292 cases2 := {};
2293
2/2
✓ Branch 0 taken 5165 times.
✓ Branch 1 taken 1171 times.
6336 for c in cases loop
2294 case_ := c;
2295 case_ := match case_
2296 case DAE.CASE()
2297 algorithm
2298 5165 (patterns, outT) := traversePatternList(case_.patterns, function traverseConstantPatternsHelper2(func=func), outT);
2299
2/2
✓ Branch 1 taken 276 times.
✓ Branch 2 taken 4889 times.
5165 if not valueEq(case_.patterns, patterns) then
2300 276 case_.patterns := patterns;
2301 end if;
2302 then case_;
2303 end match;
2304 cases2 := case_::cases2;
2305 end for;
2306 1171 cases2 := Dangerous.listReverseInPlace(cases2);
2307
2/2
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 1107 times.
1171 if not valueEq(cases,cases2) then
2308 64 outExp.cases := cases2;
2309 end if;
2310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1171 times.
1171 (outExp,outT) := func(outExp,outT);
2311 then outExp;
2312 else
2313 algorithm
2314
2/2
✓ Branch 0 taken 1850776 times.
✓ Branch 1 taken 1522505 times.
3373281 (outExp,outT) := func(inExp,outT);
2315 then outExp;
2316 end match;
2317 end traverseConstantPatternsHelper;
2318
2319 function traverseConstantPatternsHelper2<T>
2320 input DAE.Pattern inPattern;
2321 input T inExtra;
2322 input FuncExpType func;
2323 output DAE.Pattern outPattern;
2324 output T extra=inExtra;
2325 partial function FuncExpType
2326 input DAE.Exp inExp;
2327 input T inTypeT;
2328 output DAE.Exp outExp;
2329 output T outT;
2330 end FuncExpType;
2331 algorithm
2332 outPattern := match inPattern
2333 local
2334 DAE.Exp exp;
2335 case outPattern as DAE.PAT_CONSTANT()
2336 algorithm
2337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1491 times.
1491 (exp, extra) := func(outPattern.exp, extra);
2338
2/2
✓ Branch 0 taken 302 times.
✓ Branch 1 taken 1189 times.
1491 if not referenceEq(outPattern.exp, exp) then
2339 302 outPattern.exp := exp;
2340 end if;
2341 then outPattern;
2342 else inPattern;
2343 end match;
2344 end traverseConstantPatternsHelper2;
2345
2346 protected function filterEmptyPattern
2347 input tuple<DAE.Pattern,String,DAE.Type> tpl;
2348 output Boolean outB;
2349 algorithm
2350 outB := match tpl
2351 case (DAE.PAT_WILD(),_,_) then false;
2352 else true;
2353 end match;
2354 end filterEmptyPattern;
2355
2356 protected function addLocalDecls
2357 "Adds local declarations to the environment and returns the DAE"
2358 input FCore.Cache inCache;
2359 input FCore.Graph inEnv;
2360 input list<Absyn.ElementItem> els;
2361 input String scopeName;
2362 input Boolean impl;
2363 input SourceInfo info;
2364 output FCore.Cache outCache;
2365 output Option<tuple<FCore.Graph,DAE.DAElist,AvlSetString.Tree>> res;
2366 algorithm
2367 (outCache,res) := matchcontinue (inCache, inEnv, els)
2368 local
2369 list<Absyn.ElementItem> ld;
2370 list<SCode.Element> ld2,ld3,ld4;
2371 list<tuple<SCode.Element, DAE.Mod>> ld_mod;
2372 DAE.DAElist dae1;
2373 FCore.Graph env2;
2374 ClassInf.State dummyFunc;
2375 String str;
2376 FCore.Cache cache;
2377 FCore.Graph env;
2378 Boolean b;
2379 AvlSetString.Tree declsTree;
2380 list<String> names;
2381
2382 case (cache, env, {})
2383 algorithm
2384 5403 declsTree := AvlSetString.new();
2385 5403 then (cache,SOME((env,DAE.emptyDae,declsTree)));
2386 case (cache, env, ld)
2387 algorithm
2388 963 env2 := FGraph.openScope(env, SCode.NOT_ENCAPSULATED(), scopeName,NONE());
2389
2390 // Tranform declarations such as Real x,y; to Real x; Real y;
2391 963 ld2 := AbsynToSCode.translateEitemlist(ld, SCode.PROTECTED());
2392
2393 // Filter out the components (just to be sure)
2394
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 961 times.
963 true := List.applyAndFold1(ld2, boolAnd, SCodeUtil.isComponentWithDirection, Absyn.BIDIR(), true);
2395 961 (cache,b) := List.fold1(ld2, checkLocalShadowing, env, (cache,false));
2396
2/2
✓ Branch 0 taken 957 times.
✓ Branch 1 taken 4 times.
961 ld2 := if b then {} else ld2;
2397
2398 // Transform the element list into a list of element,NOMOD
2399 961 ld_mod := InstUtil.addNomod(ld2);
2400
2401 dummyFunc := ClassInf.FUNCTION(Absyn.IDENT("dummieFunc"), false);
2402 961 (cache,env2,_) := InstUtil.addComponentsToEnv(cache, env2,
2403 InnerOuter.emptyInstHierarchy, DAE.NOMOD(), DAE.NOPRE(),
2404 dummyFunc, ld_mod, impl);
2405 961 (cache,env2,_,_,dae1,_,_,_,_,_) := Inst.instElementList(
2406 cache,env2, InnerOuter.emptyInstHierarchy, UnitAbsyn.noStore,
2407 DAE.NOMOD(), DAE.NOPRE(), dummyFunc, ld_mod, {},
2408 impl, InstTypes.INNER_CALL(), ConnectionGraph.EMPTY, Connect.emptySet, true);
2409
2410 961 names := List.map(ld2, SCodeUtil.elementName);
2411 961 declsTree := AvlSetString.addList(AvlSetString.new(), names);
2412
2413
2/2
✓ Branch 0 taken 957 times.
✓ Branch 1 taken 4 times.
961 res := if b then NONE() else SOME((env2,dae1,declsTree));
2414 then (cache,res);
2415
2416 case (cache, _, ld)
2417 algorithm
2418 2 ld2 := AbsynToSCode.translateEitemlist(ld, SCode.PROTECTED());
2419
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 ld2 as _::_ := List.filterOnTrue(ld2, SCodeUtil.isNotComponent);
2420 ✗ str := stringDelimitList(List.map1(ld2, SCodeDump.unparseElementStr, SCodeDump.defaultOptions),", ");
2421 ✗ Error.addSourceMessage(Error.META_INVALID_LOCAL_ELEMENT,{str},info);
2422 then (cache,NONE());
2423
2424 case (cache, _, ld)
2425 algorithm
2426 // Tranform declarations such as Real x,y; to Real x; Real y;
2427 2 ld2 := AbsynToSCode.translateEitemlist(ld, SCode.PROTECTED());
2428
2429 // Filter out the components (just to be sure)
2430 2 ld3 := List.select1(ld2, SCodeUtil.isComponentWithDirection, Absyn.INPUT());
2431 2 ld4 := List.select1(ld2, SCodeUtil.isComponentWithDirection, Absyn.OUTPUT());
2432
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 ld2 as _::_ := listAppend(ld3,ld4); // I don't care that this is slow; it's just for error message generation
2433 2 str := stringDelimitList(List.map1(ld2, SCodeDump.unparseElementStr, SCodeDump.defaultOptions),", ");
2434 2 Error.addSourceMessage(Error.META_INVALID_LOCAL_ELEMENT,{str},info);
2435 then (cache,NONE());
2436
2437 else
2438 algorithm
2439 ✗ Error.addSourceMessage(Error.INTERNAL_ERROR,{"Patternm.addLocalDecls failed"},info);
2440 then (inCache,NONE());
2441 end matchcontinue;
2442 end addLocalDecls;
2443
2444 protected function checkLocalShadowing
2445 input SCode.Element elt;
2446 input FCore.Graph env;
2447 input tuple<FCore.Cache,Boolean> inTpl;
2448 output tuple<FCore.Cache,Boolean> outTpl=inTpl;
2449 protected
2450 String name;
2451 FCore.Cache cache;
2452 Boolean b;
2453 SourceInfo info;
2454 SCode.Variability var;
2455 algorithm
2456
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4702 times.
4702 SCode.COMPONENT(name=name, info=info) := elt;
2457 4702 (cache,_) := inTpl;
2458 try
2459 4702 (cache,DAE.ATTR(variability=var),_,_,_,_,_,_,_) := Lookup.lookupVarInternalIdent(cache,env,name);
2460 b := match var
2461 // Allow shadowing constants. Should be safe since they become values pretty much straight away.
2462 case SCode.CONST() then true;
2463 else false;
2464 end match;
2465 else
2466 b := true;
2467 end try;
2468
2/2
✓ Branch 0 taken 4698 times.
✓ Branch 1 taken 4 times.
4702 if not b then
2469 4 Error.addSourceMessage(Error.MATCH_SHADOWING,{name},info);
2470 4 outTpl := (cache,true);
2471 end if;
2472 end checkLocalShadowing;
2473
2474 protected function allPatternsWild
2475 "Returns true if all patterns in the list are wildcards"
2476 input list<DAE.Pattern> ipats;
2477 output Boolean b;
2478 algorithm
2479 b := match ipats
2480 local list<DAE.Pattern> pats;
2481 case {} then true;
2482 1494 case DAE.PAT_WILD()::pats then allPatternsWild(pats);
2483 else false;
2484 end match;
2485 end allPatternsWild;
2486
2487 protected function allPatternsAlwaysMatch
2488 "Returns true if all patterns in the list are wildcards or as-bindings"
2489 input list<DAE.Pattern> ipats;
2490 output Boolean b;
2491 algorithm
2492 b := match ipats
2493 local DAE.Pattern pat; list<DAE.Pattern> pats;
2494 case {} then true;
2495 3468 case DAE.PAT_WILD()::pats then allPatternsAlwaysMatch(pats);
2496 2010 case DAE.PAT_AS(pat=pat)::pats then allPatternsAlwaysMatch(pat::pats);
2497 ✗ case DAE.PAT_AS_FUNC_PTR(pat=pat)::pats then allPatternsAlwaysMatch(pat::pats);
2498 else false;
2499 end match;
2500 end allPatternsAlwaysMatch;
2501
2502 protected function isInfallibleNoBinding
2503 "Returns true if the pattern is guaranteed to match without binding any
2504 variable, but is not just PAT_WILD itself (so it could be replaced with _)."
2505 input DAE.Pattern pat;
2506 output Boolean b;
2507 algorithm
2508 b := match pat
2509 local list<DAE.Pattern> pats; list<tuple<DAE.Pattern,String,DAE.Type>> namedPats;
2510 ✗ case DAE.PAT_META_TUPLE(patterns=pats) then List.all(pats, isInfallibleNoBindingOrWild);
2511 ✗ case DAE.PAT_CALL_TUPLE(patterns=pats) then List.all(pats, isInfallibleNoBindingOrWild);
2512 ✗ case DAE.PAT_CALL(knownSingleton=true, patterns=pats) then List.all(pats, isInfallibleNoBindingOrWild);
2513 case DAE.PAT_CALL_NAMED(name=_, patterns=namedPats)
2514 // PAT_CALL_NAMED has no knownSingleton flag, so only fire if there are no fields at all.
2515 ✗ then listEmpty(namedPats);
2516 else false;
2517 end match;
2518 end isInfallibleNoBinding;
2519
2520 protected function isInfallibleNoBindingOrWild
2521 input DAE.Pattern pat;
2522 output Boolean b;
2523 algorithm
2524 b := match pat
2525 case DAE.PAT_WILD() then true;
2526 ✗ else isInfallibleNoBinding(pat);
2527 end match;
2528 end isInfallibleNoBindingOrWild;
2529
2530 protected function isInfalliblePattern
2531 "Returns true if the pattern is guaranteed to match at runtime. Unlike
2532 isInfallibleNoBinding, the pattern is allowed to bind variables (PAT_AS /
2533 PAT_AS_FUNC_PTR), which is what makes it useful for the
2534 match-single-infallible-case rewrite to a destructuring assignment."
2535 input DAE.Pattern pat;
2536 output Boolean b;
2537 algorithm
2538 b := match pat
2539 local
2540 list<DAE.Pattern> pats;
2541 list<tuple<DAE.Pattern,String,DAE.Type>> namedPats;
2542 DAE.Pattern innerPat;
2543 case DAE.PAT_WILD() then true;
2544 293 case DAE.PAT_AS(pat=innerPat) then isInfalliblePattern(innerPat);
2545 ✗ case DAE.PAT_AS_FUNC_PTR(pat=innerPat) then isInfalliblePattern(innerPat);
2546 15 case DAE.PAT_META_TUPLE(patterns=pats) then List.all(pats, isInfalliblePattern);
2547 ✗ case DAE.PAT_CALL_TUPLE(patterns=pats) then List.all(pats, isInfalliblePattern);
2548 43 case DAE.PAT_CALL(knownSingleton=true, patterns=pats) then List.all(pats, isInfalliblePattern);
2549 ✗ case DAE.PAT_CALL_NAMED(patterns=namedPats) then listEmpty(namedPats);
2550 else false;
2551 end match;
2552 end isInfalliblePattern;
2553
2554 protected function isSingleInfallibleMatch
2555 "True when a match (not matchcontinue) has exactly one case with no else and
2556 every input's pattern in that case is infallible. Used both to emit the
2557 MATCH_SINGLE_INFALLIBLE_CASE notification and to suppress weaker notifications
2558 that the agent would otherwise see as duplicates."
2559 input Absyn.MatchType matchType;
2560 input list<DAE.MatchCase> cases;
2561 output Boolean b;
2562 algorithm
2563 b := match (matchType, cases)
2564 local list<DAE.Pattern> pats;
2565 case (Absyn.MATCH(), {DAE.CASE(patterns=pats)})
2566 208 then List.all(pats, isInfalliblePattern);
2567 else false;
2568 end match;
2569 end isSingleInfallibleMatch;
2570
2571 protected function checkMatchSingleInfallibleCase
2572 "Emits a notification when isSingleInfallibleMatch holds. Such a match never
2573 fails at runtime and is clearer as a destructuring assignment (or, if no
2574 bindings, as a plain statement)."
2575 input Absyn.MatchType matchType;
2576 input list<DAE.MatchCase> cases;
2577 input SourceInfo info;
2578 algorithm
2579
1/4
✓ Branch 1 taken 1164 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1164 if Flags.isSet(Flags.PATTERNM_ALL_INFO) and isSingleInfallibleMatch(matchType, cases) then
2580 ✗ Error.addSourceMessage(Error.MATCH_SINGLE_INFALLIBLE_CASE, {}, info);
2581 end if;
2582 end checkMatchSingleInfallibleCase;
2583
2584 protected function checkInfallibleNoBindingPatterns
2585 "Walks the patterns of each case looking for sub-patterns that are infallible
2586 and bind no variables. Such patterns can be replaced by a wildcard. When the
2587 whole match is a single infallible case (covered by the stronger
2588 MATCH_SINGLE_INFALLIBLE_CASE notification), we skip per-pattern reporting for
2589 that case so the user only sees the better recommendation."
2590 input list<DAE.MatchCase> cases;
2591 input Absyn.MatchType matchType;
2592 input SourceInfo info;
2593 algorithm
2594
1/2
✓ Branch 1 taken 1164 times.
✗ Branch 2 not taken.
1164 if not Flags.isSet(Flags.PATTERNM_ALL_INFO) then
2595 1164 return;
2596 end if;
2597 ✗ if isSingleInfallibleMatch(matchType, cases) then
2598 ✗ return;
2599 end if;
2600 ✗ for c in cases loop
2601 () := match c
2602 local list<DAE.Pattern> pats; SourceInfo cinfo;
2603 case DAE.CASE(patterns=pats, info=cinfo)
2604 algorithm
2605 ✗ for p in pats loop
2606 ✗ checkPatternInfallibleNoBinding(p, cinfo);
2607 end for;
2608 then ();
2609 end match;
2610 end for;
2611 end checkInfallibleNoBindingPatterns;
2612
2613 protected function checkPatternInfallibleNoBinding
2614 input DAE.Pattern pat;
2615 input SourceInfo info;
2616 algorithm
2617 () := match pat
2618 local
2619 list<DAE.Pattern> pats;
2620 list<tuple<DAE.Pattern,String,DAE.Type>> namedPats;
2621 DAE.Pattern innerPat;
2622 case DAE.PAT_WILD() then ();
2623 case _ guard isInfallibleNoBinding(pat)
2624 algorithm
2625 ✗ Error.addSourceMessage(Error.META_PATTERN_INFALLIBLE_NO_BINDING, {ExpressionDump.patternStr(pat)}, info);
2626 then ();
2627 case DAE.PAT_META_TUPLE(patterns=pats)
2628 algorithm
2629 ✗ for p in pats loop checkPatternInfallibleNoBinding(p, info); end for;
2630 then ();
2631 case DAE.PAT_CALL_TUPLE(patterns=pats)
2632 algorithm
2633 ✗ for p in pats loop checkPatternInfallibleNoBinding(p, info); end for;
2634 then ();
2635 case DAE.PAT_CALL(patterns=pats)
2636 algorithm
2637 ✗ for p in pats loop checkPatternInfallibleNoBinding(p, info); end for;
2638 then ();
2639 case DAE.PAT_CALL_NAMED(patterns=namedPats)
2640 algorithm
2641 ✗ for tpl in namedPats loop
2642 ✗ checkPatternInfallibleNoBinding(Util.tuple31(tpl), info);
2643 end for;
2644 then ();
2645 case DAE.PAT_CONS(head=innerPat)
2646 algorithm
2647 ✗ checkPatternInfallibleNoBinding(innerPat, info);
2648 ✗ checkPatternInfallibleNoBinding(pat.tail, info);
2649 then ();
2650 case DAE.PAT_SOME(pat=innerPat)
2651 algorithm
2652 ✗ checkPatternInfallibleNoBinding(innerPat, info);
2653 then ();
2654 case DAE.PAT_AS(pat=innerPat)
2655 algorithm
2656 ✗ checkPatternInfallibleNoBinding(innerPat, info);
2657 then ();
2658 case DAE.PAT_AS_FUNC_PTR(pat=innerPat)
2659 algorithm
2660 ✗ checkPatternInfallibleNoBinding(innerPat, info);
2661 then ();
2662 else ();
2663 end match;
2664 end checkPatternInfallibleNoBinding;
2665
2666 protected function getCasePatterns
2667 "Accessor function for DAE.Case"
2668 input DAE.MatchCase case_;
2669 output list<DAE.Pattern> pats;
2670 algorithm
2671 13111 DAE.CASE(patterns=pats) := case_;
2672 end getCasePatterns;
2673
2674 protected function setCasePatterns
2675 "Sets the patterns field in a DAE.Case"
2676 input DAE.MatchCase case1;
2677 input list<DAE.Pattern> pats;
2678 output DAE.MatchCase case2;
2679 algorithm
2680 case2 := match case1
2681 local
2682 list<DAE.Element> localDecls;
2683 list<DAE.Statement> body;
2684 Option<DAE.Exp> patternGuard,result;
2685 Integer jump;
2686 SourceInfo resultInfo,info;
2687 case DAE.CASE(_,patternGuard,localDecls,body,result,resultInfo,jump,info)
2688 26 then DAE.CASE(pats,patternGuard,localDecls,body,result,resultInfo,jump,info);
2689 end match;
2690 end setCasePatterns;
2691
2692 public function getValueCtor
2693 "Get the constructor index of a uniontype record based on its index in the uniontype"
2694 input Integer ix;
2695 output Integer ctor;
2696 algorithm
2697 4495 ctor := ix+3;
2698 end getValueCtor;
2699
2700 public function sortPatternsByComplexity
2701 input list<DAE.Pattern> inPatterns;
2702 output list<tuple<DAE.Pattern,Integer>> outPatterns;
2703 algorithm
2704 5161 outPatterns := List.toListWithPositions(inPatterns);
2705 5161 outPatterns := List.sort(outPatterns, sortPatternsByComplexityWork);
2706 end sortPatternsByComplexity;
2707
2708 protected function sortPatternsByComplexityWork
2709 input tuple<DAE.Pattern,Integer> tpl1;
2710 input tuple<DAE.Pattern,Integer> tpl2;
2711 output Boolean greater;
2712 protected
2713 DAE.Pattern pat1,pat2;
2714 Integer i1,i2,c1,c2;
2715 algorithm
2716 5715 (pat1,i1) := tpl1;
2717 5715 (pat2,i2) := tpl2;
2718 5715 (_,c1) := traversePattern(pat1,patternComplexity,0);
2719 5715 (_,c2) := traversePattern(pat2,patternComplexity,0);
2720 // If both complexities are equal, keep the original ordering
2721 // If c1 is 0, and c2 is not 0 we move the left pattern to the end.
2722 // Else we move the cheaper pattern to the beginning
2723
6/6
✓ Branch 0 taken 2651 times.
✓ Branch 1 taken 3064 times.
✓ Branch 2 taken 1596 times.
✓ Branch 3 taken 1468 times.
✓ Branch 4 taken 275 times.
✓ Branch 5 taken 1321 times.
5715 greater := if c1 == c2 then i1 > i2 else (if c2 == 0 then false else (if c1 == 0 then true else c1 > c2));
2724 end sortPatternsByComplexityWork;
2725
2726 protected function patternComplexity
2727 input DAE.Pattern inPat;
2728 input Integer inComplexity;
2729 output DAE.Pattern outPat=inPat;
2730 output Integer i=inComplexity;
2731 algorithm
2732 i := match inPat
2733 local
2734 DAE.Exp exp;
2735 case DAE.PAT_CONSTANT(exp=exp)
2736 algorithm
2737 1457 (_,i) := Expression.traverseExpBottomUp(exp,constantComplexity,i);
2738 then i;
2739 case DAE.PAT_CONS()
2740 496 then i+5;
2741 case DAE.PAT_CALL(knownSingleton=false)
2742 4034 then i+5;
2743 case DAE.PAT_SOME()
2744 115 then i+5;
2745 else i;
2746 end match;
2747 end patternComplexity;
2748
2749 protected function constantComplexity
2750 input DAE.Exp inExp;
2751 input Integer ii;
2752 output DAE.Exp outExp;
2753 output Integer oi;
2754 algorithm
2755 (outExp,oi) := match (inExp,ii)
2756 local
2757 DAE.Exp e;
2758 String str;
2759 Integer i;
2760 ✗ case (e as DAE.SCONST(str),i) then (e,i+5+stringLength(str));
2761 78 case (e as DAE.ICONST(_),i) then (e,i+1);
2762 700 case (e as DAE.BCONST(_),i) then (e,i+1);
2763 14 case (e as DAE.RCONST(_),i) then (e,i+2);
2764 665 case (e,i) then (e,i+5); // lists and such; add a little something in addition to its members....
2765 end match;
2766 end constantComplexity;
2767
2768 protected function addEnvKnownAsBindings
2769 input DAE.Pattern inPat;
2770 input FCore.Graph inEnv;
2771 output DAE.Pattern pat=inPat;
2772 output FCore.Graph env=inEnv;
2773 algorithm
2774 env := match pat
2775 case DAE.PAT_AS()
2776 17102 then addEnvKnownAsBindings2(pat,env,findFirstNonAsPattern(pat.pat));
2777 else env;
2778 end match;
2779 end addEnvKnownAsBindings;
2780
2781 protected function addEnvKnownAsBindings2
2782 input DAE.Pattern inPat;
2783 input FCore.Graph inEnv;
2784 input DAE.Pattern firstPattern;
2785 output FCore.Graph env=inEnv;
2786 algorithm
2787 env := match (inPat,firstPattern)
2788 local
2789 Absyn.Path name,path;
2790 String id;
2791 DAE.Type ty;
2792 list<DAE.Var> fields;
2793 Integer index;
2794 Boolean knownSingleton;
2795 DAE.Attributes attr;
2796 list<DAE.Type> typeVars;
2797 case (DAE.PAT_AS(id=id,attr=attr),DAE.PAT_CALL(index=index,typeVars=typeVars,fields=fields,knownSingleton=knownSingleton,name=name))
2798 algorithm
2799 4271 path := AbsynUtil.stripLast(name);
2800
2/2
✓ Branch 0 taken 4144 times.
✓ Branch 1 taken 127 times.
8415 ty := DAE.T_METARECORD(name,path,typeVars,index,fields,knownSingleton);
2801 4271 env := FGraph.mkComponentNode(env, DAE.TYPES_VAR(id,attr,ty,DAE.UNBOUND(),false,NONE()), SCode.COMPONENT(id,SCode.defaultPrefixes,SCode.defaultVarAttr,Absyn.TPATH(name,NONE()),SCode.NOMOD(),SCode.noComment,NONE(),Absyn.dummyInfo), DAE.NOMOD(), FCore.VAR_DAE(), FGraph.empty());
2802 then env;
2803 else env;
2804 end match;
2805 end addEnvKnownAsBindings2;
2806
2807 protected function findFirstNonAsPattern
2808 input DAE.Pattern inPattern;
2809 output DAE.Pattern outPattern;
2810 algorithm
2811 outPattern := match inPattern
2812 2976 case DAE.PAT_AS(pat=outPattern) then findFirstNonAsPattern(outPattern);
2813 else inPattern;
2814 end match;
2815 end findFirstNonAsPattern;
2816
2817 protected function getInputAsBinding
2818 input Absyn.Exp inExp;
2819 output Absyn.Exp exp;
2820 output list<String> aliases;
2821 output list<String> aliasesAndCrefs;
2822 algorithm
2823 (exp,aliases,aliasesAndCrefs) := match inExp
2824 local
2825 String id;
2826 case Absyn.CREF(componentRef=Absyn.CREF_IDENT(id,{})) then (inExp,{},{id});
2827 case Absyn.AS(id,exp)
2828 algorithm
2829 3 (exp,aliases,aliasesAndCrefs) := getInputAsBinding(exp);
2830 3 then (exp,id::aliases,id::aliasesAndCrefs);
2831 else (inExp,{},{});
2832 end match;
2833 annotation(Documentation(info="<html>
2834 <p>Checks an input expression to the match-expression for alias candidates.</p>
2835 <p>If the input is a cref, it is a candidate for a metarecord to bind with dot-notation.</p>
2836 <p>If the input is an as-binding (cref as exp), cref is used as an alias, and we keep recursing to find aliases.
2837 The as-binding is then removed, using only the exp-part as the actual input to the match-expression</p>
2838 <p>Note: An as-binding is again overridden by an as-binding in the case pattern.</p>
2839 </html>"));
2840 end getInputAsBinding;
2841
2842 protected function addPatternAliasesList
2843 input list<DAE.Pattern> inPatterns;
2844 input list<list<String>> inAliases;
2845 input FCore.Cache inCache;
2846 input FCore.Graph inEnv;
2847 output list<DAE.Pattern> outPatterns = {};
2848 output FCore.Cache outCache = inCache;
2849 protected
2850 list<String> aliases;
2851 list<list<String>> rest_aliases = inAliases;
2852 algorithm
2853
2/2
✓ Branch 0 taken 9577 times.
✓ Branch 1 taken 5164 times.
14741 for pat in inPatterns loop
2854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9577 times.
9577 aliases :: rest_aliases := rest_aliases;
2855 9577 (pat, outCache) := addPatternAliases(pat, aliases, outCache, inEnv);
2856 outPatterns := pat :: outPatterns;
2857 end for;
2858
2859 5164 outPatterns := listReverse(outPatterns);
2860 end addPatternAliasesList;
2861
2862 protected function addPatternAliases
2863 input DAE.Pattern inPattern;
2864 input list<String> inAliases;
2865 input FCore.Cache inCache;
2866 input FCore.Graph inEnv;
2867 output DAE.Pattern pat = inPattern;
2868 output FCore.Cache outCache = inCache;
2869 protected
2870 DAE.Attributes attr;
2871 algorithm
2872
2/2
✓ Branch 0 taken 9526 times.
✓ Branch 1 taken 9577 times.
19103 for alias in inAliases loop
2873 9526 (outCache, DAE.TYPES_VAR(attributes = attr), _, _, _, _) :=
2874 Lookup.lookupIdent(outCache, inEnv, alias);
2875 9526 pat := DAE.PAT_AS(alias, NONE(), attr, pat);
2876 end for;
2877 end addPatternAliases;
2878
2879 protected function addAliasesToEnv
2880 input FCore.Graph inEnv;
2881 input list<DAE.Type> inTypes;
2882 input list<list<String>> inAliases;
2883 input SourceInfo info;
2884 output FCore.Graph outEnv;
2885 algorithm
2886 outEnv := match (inEnv, inTypes, inAliases)
2887 local
2888 list<DAE.Type> tys;
2889 list<list<String>> aliases;
2890 list<String> rest;
2891 String id;
2892 FCore.Graph env;
2893 DAE.Type ty;
2894 DAE.Attributes attr;
2895 case (_, {}, {}) then inEnv;
2896 2077 case (_, _::tys, {}::aliases) then addAliasesToEnv(inEnv,tys,aliases,info);
2897 case (env, ty::_, (id::rest)::aliases)
2898 algorithm
2899 attr := DAE.dummyAttrInput;
2900 3 env := FGraph.mkComponentNode(env, DAE.TYPES_VAR(id,attr,ty,DAE.UNBOUND(),false,NONE()), SCode.COMPONENT(id,SCode.defaultPrefixes,SCode.defaultVarAttr,Absyn.TPATH(Absyn.IDENT("$dummy"),NONE()),SCode.NOMOD(),SCode.noComment,NONE(),info), DAE.NOMOD(), FCore.VAR_DAE(), FGraph.empty());
2901 3 then addAliasesToEnv(env,inTypes,rest::aliases,info);
2902 end match;
2903 end addAliasesToEnv;
2904
2905 protected function statementListFindDeadStoreRemoveEmptyStatements
2906 input list<DAE.Statement> inBody;
2907 input AvlSetString.Tree localsTree;
2908 input AvlSetString.Tree inUseTree;
2909 output list<DAE.Statement> body;
2910 output AvlSetString.Tree useTree;
2911 algorithm
2912 10670 (body,useTree) := List.map1Fold(listReverse(inBody),statementFindDeadStore,localsTree,inUseTree);
2913 10670 body := List.select(body,isNotDummyStatement);
2914 10670 body := listReverse(body);
2915 end statementListFindDeadStoreRemoveEmptyStatements;
2916
2917 protected function statementFindDeadStore
2918 input DAE.Statement inStatement;
2919 input AvlSetString.Tree localsTree;
2920 input AvlSetString.Tree inUseTree;
2921 output DAE.Statement outStatement;
2922 output AvlSetString.Tree useTree;
2923 algorithm
2924 (outStatement,useTree) := match inStatement
2925 local
2926 AvlSetString.Tree elseTree;
2927 list<DAE.Statement> body;
2928 DAE.Exp exp,lhs,cond,msg,level;
2929 list<DAE.Exp> exps;
2930 DAE.Else else_;
2931 DAE.Type ty;
2932 SourceInfo info;
2933 Boolean b;
2934 String id;
2935 DAE.ElementSource source;
2936 list<tuple<DAE.ComponentRef, array<DAE.Exp>>> sub_iters;
2937
2938 case DAE.STMT_ASSIGN(type_=ty,exp1=lhs,exp=exp,source=source as DAE.SOURCE(info=info))
2939 algorithm
2940 9834 (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, inUseTree);
2941 9834 lhs := Expression.traverseExpBottomUp(lhs, checkDefUse, (localsTree,useTree,info));
2942 9834 outStatement := Algorithm.makeAssignmentNoTypeCheck(ty,lhs,exp,source);
2943 9834 then (outStatement,useTree);
2944
2945 case DAE.STMT_TUPLE_ASSIGN(type_=ty,expExpLst=exps,exp=exp,source=source as DAE.SOURCE(info=info))
2946 algorithm
2947 654 (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, inUseTree);
2948
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 654 times.
654 (DAE.TUPLE(exps),_) := Expression.traverseExpBottomUp(DAE.TUPLE(exps), checkDefUse, (localsTree,useTree,info));
2949 654 outStatement := Algorithm.makeTupleAssignmentNoTypeCheck(ty,exps,exp,source);
2950 654 then (outStatement,useTree);
2951
2952 case DAE.STMT_ASSIGN_ARR(type_=ty,lhs=lhs,exp=exp,source=source as DAE.SOURCE(info=info))
2953 algorithm
2954 ✗ (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, inUseTree);
2955 ✗ lhs := Expression.traverseExpBottomUp(lhs, checkDefUse, (localsTree,useTree,info));
2956 ✗ outStatement := Algorithm.makeArrayAssignmentNoTypeCheck(ty,lhs,exp,source);
2957 ✗ then (outStatement,useTree);
2958
2959 case DAE.STMT_IF(exp=exp,statementLst=body,else_=else_,source=source)
2960 algorithm
2961 212 (else_,elseTree) := elseFindDeadStore(else_, localsTree, inUseTree);
2962 212 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree,inUseTree);
2963 212 (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, useTree);
2964 212 useTree := AvlSetString.join(useTree,elseTree);
2965 212 then (DAE.STMT_IF(exp,body,else_,source),useTree);
2966
2967 case DAE.STMT_FOR(ty,b,id,exp,body,source,sub_iters)
2968 algorithm
2969 // Loops repeat, so check for usage in the whole loop before removing any dead stores.
2970 16 ErrorExt.setCheckpoint(getInstanceName());
2971 16 (_, useTree) := List.map1Fold(body, statementFindDeadStore, localsTree, inUseTree);
2972 16 ErrorExt.rollBack(getInstanceName());
2973 16 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree, useTree);
2974 16 (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, useTree);
2975 // TODO: We should remove ident from the use-tree in case of shadowing... But our avlTree cannot delete
2976 16 useTree := AvlSetString.join(useTree,inUseTree);
2977
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
32 then (DAE.STMT_FOR(ty,b,id,exp,body,source,sub_iters),useTree);
2978
2979 case DAE.STMT_WHILE(exp=exp,statementLst=body,source=source)
2980 algorithm
2981 // Loops repeat, so check for usage in the whole loop before removing any dead stores.
2982 ✗ ErrorExt.setCheckpoint(getInstanceName());
2983 ✗ (_, useTree) := List.map1Fold(body, statementFindDeadStore, localsTree, inUseTree);
2984 ✗ ErrorExt.rollBack(getInstanceName());
2985 ✗ (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body, localsTree, useTree);
2986 ✗ (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, useTree);
2987 // The loop might not be entered just like if. The following should not remove all previous uses:
2988 // while false loop
2989 // return;
2990 // end while;
2991 ✗ useTree := AvlSetString.join(useTree,inUseTree);
2992 ✗ then (DAE.STMT_WHILE(exp,body,source),useTree);
2993
2994 // No PARFOR in MetaModelica
2995 ✗ case DAE.STMT_PARFOR() then fail();
2996
2997 case DAE.STMT_ASSERT(cond=cond,msg=msg,level=level)
2998 algorithm
2999 ✗ (_,useTree) := Expression.traverseExpBottomUp(cond, useLocalCref, inUseTree);
3000 ✗ (_,useTree) := Expression.traverseExpBottomUp(msg, useLocalCref, useTree);
3001 ✗ (_,useTree) := Expression.traverseExpBottomUp(level, useLocalCref, useTree);
3002 ✗ then (inStatement,useTree);
3003
3004 // Reset the tree; we do not execute anything after this
3005 case DAE.STMT_TERMINATE(msg=exp)
3006 algorithm
3007 ✗ (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, AvlSetString.new());
3008 ✗ then (inStatement,useTree);
3009
3010 // No when or reinit in functions
3011 ✗ case DAE.STMT_WHEN() then fail();
3012 ✗ case DAE.STMT_REINIT() then fail();
3013
3014 // There is no use after this one, so we can reset the tree
3015 case DAE.STMT_NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("fail")))
3016 42 then (inStatement,AvlSetString.new());
3017
3018 40 case DAE.STMT_RETURN() then (inStatement,AvlSetString.new());
3019
3020 case DAE.STMT_NORETCALL(exp=exp)
3021 algorithm
3022 908 (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, inUseTree);
3023 908 then (inStatement,useTree);
3024
3025 case DAE.STMT_BREAK() then (inStatement,inUseTree);
3026 case DAE.STMT_CONTINUE() then (inStatement,inUseTree);
3027 case DAE.STMT_ARRAY_INIT() then (inStatement,inUseTree);
3028 case DAE.STMT_FAILURE(body=body,source=source)
3029 algorithm
3030 8 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree,inUseTree);
3031 8 then (DAE.STMT_FAILURE(body,source),useTree);
3032 end match;
3033 end statementFindDeadStore;
3034
3035 protected function elseFindDeadStore
3036 input DAE.Else inElse;
3037 input AvlSetString.Tree localsTree;
3038 input AvlSetString.Tree inUseTree;
3039 output DAE.Else outElse;
3040 output AvlSetString.Tree useTree;
3041 algorithm
3042 (outElse,useTree) := match inElse
3043 local
3044 DAE.Exp exp;
3045 list<DAE.Statement> body;
3046 DAE.Else else_;
3047 AvlSetString.Tree elseTree;
3048 case DAE.NOELSE() then (inElse,inUseTree);
3049 case DAE.ELSEIF(exp,body,else_)
3050 algorithm
3051 8 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree,inUseTree);
3052 8 (_,useTree) := Expression.traverseExpBottomUp(exp, useLocalCref, useTree);
3053 8 (else_,elseTree) := elseFindDeadStore(else_, localsTree, inUseTree);
3054 8 useTree := AvlSetString.join(useTree,elseTree);
3055 8 else_ := DAE.ELSEIF(exp,body,else_);
3056 8 then (else_,useTree);
3057 case DAE.ELSE(body)
3058 algorithm
3059 114 (body,useTree) := statementListFindDeadStoreRemoveEmptyStatements(body,localsTree,inUseTree);
3060 114 else_ := DAE.ELSE(body);
3061 114 then (else_,useTree);
3062 end match;
3063 end elseFindDeadStore;
3064
3065 protected function isNotDummyStatement
3066 input DAE.Statement statement;
3067 output Boolean b;
3068 algorithm
3069 11688 b := Algorithm.isNotDummyStatement(statement);
3070
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 11688 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
11688 Error.assertionOrAddSourceMessage(b or not Flags.isSet(Flags.PATTERNM_ALL_INFO),Error.META_DEAD_CODE,{"Statement optimised away"},ElementSource.getElementSourceFileInfo(Algorithm.getStatementSource(statement)));
3071 end isNotDummyStatement;
3072
3073 protected function makeTupleFromMetaTuple
3074 input DAE.Exp inExp;
3075 input DAE.Type inType;
3076 output DAE.Exp exp;
3077 output DAE.Type ty;
3078 algorithm
3079 (exp,ty) := match (inExp,inType)
3080 local
3081 list<DAE.Exp> exps;
3082 list<DAE.Type> tys,tys2;
3083 case (DAE.META_TUPLE(exps),DAE.T_METATUPLE(types=tys))
3084 algorithm
3085 691 tys2 := List.map(tys, Types.unboxedType);
3086 691 (exps,tys2) := Types.matchTypeTuple(exps, tys, tys2, false);
3087 691 then (DAE.TUPLE(exps),DAE.T_TUPLE(tys2,NONE()));
3088 else (inExp,inType);
3089 end match;
3090 end makeTupleFromMetaTuple;
3091
3092 protected function convertExpToPatterns
3093 "Converts an expression to a list of patterns. If the expression is a tuple
3094 then the contents of the tuple are returned, otherwise the expression itself
3095 is returned as a list."
3096 input Absyn.Exp inExp;
3097 output list<Absyn.Exp> outInputs;
3098 algorithm
3099 outInputs := match inExp
3100 local
3101 Absyn.Exp exp;
3102 585 case Absyn.EXPRESSIONCOMMENT(exp=exp) then convertExpToPatterns(exp);
3103 41 case Absyn.TUPLE({exp}) then convertExpToPatterns(exp);
3104 3215 case Absyn.TUPLE() then inExp.expressions;
3105 else {inExp};
3106 end match;
3107 end convertExpToPatterns;
3108
3109 protected function unboxSwitchType
3110 input output DAE.MatchType elabMatchTy;
3111 input list<DAE.Exp> elabExps;
3112 protected
3113 Integer idx, hash_mod;
3114 DAE.Type ty;
3115 algorithm
3116 elabMatchTy := match elabMatchTy
3117 case DAE.MatchType.MATCH(switch = SOME((idx, ty as DAE.T_ENUMERATION(), hash_mod)))
3118 guard Types.isBoxedType(Expression.typeof(listHead(elabExps)))
3119 ✗ then DAE.MatchType.MATCH(SOME((idx, DAE.T_METABOXED(ty), hash_mod)));
3120
3121 else elabMatchTy;
3122 end match;
3123 end unboxSwitchType;
3124
3125 annotation(__OpenModelica_Interface="frontend");
3126 end Patternm;
3127