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 |