From 66094846e67c4a835d103667fa5491a4f3598bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=96stlund?= Date: Wed, 30 May 2018 19:20:58 +0200 Subject: [PATCH] [NF] Function improvements/cleanup. - Refactored handling of builtin functions with special rules into a new package NFBuiltinCall. - Cleaned up NFCall a bit. - Removed default variability argument from BuiltinCall.makeCall and fixed all calls to it to give the actual variability instead of just setting it to constant. - Implemented some basic handling of functional formal parameters. - Fixed handling of String function so that it doesn't fail without error for a non-basic argument without a 'String' overload. Belonging to [master]: - OpenModelica/OMCompiler#2481 - OpenModelica/OpenModelica-testsuite#966 --- Compiler/NFFrontEnd/NFBuiltinCall.mo | 1516 +++++++++++ Compiler/NFFrontEnd/NFCall.mo | 3001 +++++---------------- Compiler/NFFrontEnd/NFConnectEquations.mo | 11 +- Compiler/NFFrontEnd/NFExpression.mo | 6 +- Compiler/NFFrontEnd/NFFunction.mo | 43 +- Compiler/NFFrontEnd/NFInst.mo | 154 +- Compiler/NFFrontEnd/NFLookupState.mo | 33 +- Compiler/NFFrontEnd/NFModelicaBuiltin.mo | 2 +- Compiler/NFFrontEnd/NFType.mo | 7 +- Compiler/NFFrontEnd/NFTypeCheck.mo | 23 +- Compiler/NFFrontEnd/NFTyping.mo | 8 +- Compiler/boot/LoadCompilerSources.mos | 1 + 12 files changed, 2450 insertions(+), 2355 deletions(-) create mode 100644 Compiler/NFFrontEnd/NFBuiltinCall.mo diff --git a/Compiler/NFFrontEnd/NFBuiltinCall.mo b/Compiler/NFFrontEnd/NFBuiltinCall.mo new file mode 100644 index 0000000000..2433674e30 --- /dev/null +++ b/Compiler/NFFrontEnd/NFBuiltinCall.mo @@ -0,0 +1,1516 @@ +/* + * This file is part of OpenModelica. + * + * Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC), + * c/o Linköpings universitet, Department of Computer and Information Science, + * SE-58183 Linköping, Sweden. + * + * All rights reserved. + * + * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR + * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. + * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES + * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, + * ACCORDING TO RECIPIENTS CHOICE. + * + * The OpenModelica software and the Open Source Modelica + * Consortium (OSMC) Public License (OSMC-PL) are obtained + * from OSMC, either from the above address, + * from the URLs: http://www.ida.liu.se/projects/OpenModelica or + * http://www.openmodelica.org, and in the OpenModelica distribution. + * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html. + * + * This program is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH + * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. + * + * See the full OSMC Public License conditions for more details. + * + */ + +encapsulated package NFBuiltinCall + import Absyn; + import NFCall.Call; + import NFCall.CallAttributes; + import DAE; + import Expression = NFExpression; + import NFInstNode.InstNode; + import NFPrefixes.Variability; + import Type = NFType; + +protected + import Ceval = NFCeval; + import ComponentRef = NFComponentRef; + import Dimension = NFDimension; + import List; + import MetaModelica.Dangerous.listReverseInPlace; + import NFClass.Class; + import NFFunction.Function; + import NFFunction.FunctionMatchKind; + import NFFunction.MatchedFunction; + import NFFunction.NamedArg; + import NFFunction.TypedArg; + import NFFunction.TypedNamedArg; + import NFInstNode.CachedData; + import NFTyping.ExpOrigin; + import Prefixes = NFPrefixes; + import TypeCheck = NFTypeCheck; + import Typing = NFTyping; + import Util; + +public + function needSpecialHandling + input Call call; + output Boolean special; + algorithm + () := match call + case Call.UNTYPED_CALL() + algorithm + CachedData.FUNCTION(specialBuiltin = special) := + InstNode.getFuncCache(InstNode.classScope(ComponentRef.node(call.ref))); + then + (); + + else + algorithm + Error.assertion(false, getInstanceName() + " got unknown call: " + + Call.toString(call), sourceInfo()); + then + fail(); + end match; + end needSpecialHandling; + + function typeSpecial + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef cref; + InstNode fn_node; + Expression first; + list rest; + String name; + algorithm + Call.UNTYPED_CALL(ref = cref) := call; + + (callExp, ty, variability) := match ComponentRef.firstName(cref) + case "String" then typeStringCall(call, origin, info); + case "branch" then typeBranchCall(call, origin, info); + case "cardinality" then typeCardinalityCall(call, origin, info); + case "cat" then typeCatCall(call, origin, info); + case "change" then typeChangeCall(call, origin, info); + case "der" then typeDerCall(call, origin, info); + case "diagonal" then typeDiagonalCall(call, origin, info); + case "edge" then typeEdgeCall(call, origin, info); + case "fill" then typeFillCall(call, origin, info); + case "getInstanceName" then typeGetInstanceName(call); + case "initial" then typeDiscreteCall(call, origin, info); + case "isRoot" then typeIsRootCall(call, origin, info); + case "matrix" then typeMatrixCall(call, origin, info); + case "max" then typeMinMaxCall(call, origin, info); + case "min" then typeMinMaxCall(call, origin, info); + case "ndims" then typeNdimsCall(call, origin, info); + case "noEvent" then typeNoEventCall(call, origin, info); + case "ones" then typeZerosOnesCall("ones", call, origin, info); + case "potentialRoot" then typePotentialRootCall(call, origin, info); + case "pre" then typePreCall(call, origin, info); + case "product" then typeSumProductCall(call, origin, info); + case "root" then typeRootCall(call, origin, info); + case "rooted" then typeRootedCall(call, origin, info); + case "scalar" then typeScalarCall(call, origin, info); + case "smooth" then typeSmoothCall(call, origin, info); + case "sum" then typeSumProductCall(call, origin, info); + case "symmetric" then typeSymmetricCall(call, origin, info); + case "terminal" then typeDiscreteCall(call, origin, info); + case "transpose" then typeTransposeCall(call, origin, info); + case "vector" then typeVectorCall(call, origin, info); + case "zeros" then typeZerosOnesCall("zeros", call, origin, info); + else + algorithm + Error.assertion(false, getInstanceName() + " got unhandled builtin function: " + Call.toString(call), sourceInfo()); + then + fail(); + end match; + end typeSpecial; + + function makeSizeExp + input list posArgs; + input list namedArgs; + input SourceInfo info; + output Expression callExp; + protected + Integer argc = listLength(posArgs); + Expression arg1, arg2; + algorithm + assertNoNamedParams("size", namedArgs, info); + + callExp := match posArgs + case {arg1} then Expression.SIZE(arg1, NONE()); + case {arg1, arg2} then Expression.SIZE(arg1, SOME(arg2)); + else + algorithm + Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {"size" + List.toString(posArgs, Expression.toString, "", "(", ", ", ")", true), + "size(Any[:, ...]) => Integer[:]\n size(Any[:, ...], Integer) => Integer"}, info); + then + fail(); + end match; + end makeSizeExp; + + function makeArrayExp + input list posArgs; + input list namedArgs; + input SourceInfo info; + output Expression arrayExp; + protected + ComponentRef fn_ref; + list args; + list named_args; + Type ty; + algorithm + assertNoNamedParams("array", namedArgs, info); + + // array can take any number of arguments, but needs at least one. + if listEmpty(posArgs) then + Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {"array" + List.toString(posArgs, Expression.toString, "", "(", ", ", ")", true), + "array(Any, Any, ...) => Any[:]"}, info); + fail(); + end if; + + arrayExp := Expression.ARRAY(Type.UNKNOWN(), posArgs); + end makeArrayExp; + + function makeCatExp + input Integer n; + input list args; + input list tys; + input Variability variability; + input SourceInfo info; + output Expression callExp; + output Type ty; + protected + Expression arg2; + list args2 = {}, res = {}; + list tys2 = tys, tys3; + list> dimsLst = {}; + list dims; + Type resTy = Type.UNKNOWN(), ty1, ty2, resTyToMatch; + TypeCheck.MatchKind mk; + Integer maxn, pos; + Dimension sumDim; + algorithm + Error.assertion(listLength(args)==listLength(tys) and listLength(args)>=1, getInstanceName() + " got wrong input sizes", sourceInfo()); + + // First: Get the number of dimensions and the element type + + for arg in args loop + ty::tys2 := tys2; + dimsLst := Type.arrayDims(ty) :: dimsLst; + if Type.isEqual(resTy, Type.UNKNOWN()) then + resTy := Type.arrayElementType(ty); + else + (,, ty1, mk) := TypeCheck.matchExpressions(Expression.INTEGER(0), Type.arrayElementType(ty), Expression.INTEGER(0), resTy); + if TypeCheck.isCompatibleMatch(mk) then + resTy := ty1; + end if; + end if; + end for; + + maxn := max(listLength(d) for d in dimsLst); + if maxn <> min(listLength(d) for d in dimsLst) then + Error.addSourceMessageAndFail(Error.NF_DIFFERENT_NUM_DIM_IN_ARGUMENTS, {stringDelimitList(list(String(listLength(d)) for d in dimsLst), ", "), "cat"}, info); + end if; + if n < 1 or n > maxn then + Error.addSourceMessageAndFail(Error.NF_CAT_WRONG_DIMENSION, {String(maxn), String(n)}, info); + end if; + + tys2 := tys; + tys3 := {}; + args2 := {}; + pos := listLength(args)+2; + + // Second: Try to match the element type of all the arguments + + for arg in args loop + ty::tys2 := tys2; + pos := pos-1; + ty2 := Type.setArrayElementType(ty, resTy); + (arg2, ty1, mk) := TypeCheck.matchTypes(ty, ty2, arg, allowUnknown = true); + if TypeCheck.isIncompatibleMatch(mk) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, {String(pos), "cat", "arg", Expression.toString(arg), Type.toString(ty), Type.toString(ty2)}, info); + end if; + args2 := arg2 :: args2; + tys3 := ty1 :: tys3; + end for; + + // Third: We now have matched the element types of all arguments + // Try to match the dimensions as well + + resTy := Type.UNKNOWN(); + tys2 := tys3; + + for arg in args2 loop + ty::tys2 := tys2; + + if Type.isEqual(resTy, Type.UNKNOWN()) then + resTy := ty; + else + (,, ty1, mk) := TypeCheck.matchExpressions(Expression.INTEGER(0), ty, Expression.INTEGER(0), resTy); + if TypeCheck.isCompatibleMatch(mk) then + resTy := ty1; + end if; + end if; + end for; + + // Got the supertype of the dimensions; trying to match all arguments + // with the concatenated dimension set to unknown. + + dims := Type.arrayDims(resTy); + resTyToMatch := Type.ARRAY(Type.arrayElementType(resTy), List.set(dims, n, Dimension.UNKNOWN())); + dims := list(listGet(lst, n) for lst in dimsLst); + sumDim := Dimension.fromInteger(0); + for d in dims loop + // Create the concatenated dimension + sumDim := Dimension.add(sumDim, d); + end for; + resTy := Type.ARRAY(Type.arrayElementType(resTy), List.set(Type.arrayDims(resTy), n, sumDim)); + tys2 := tys3; + tys3 := {}; + res := {}; + pos := listLength(args)+2; + + for arg in args2 loop + ty::tys2 := tys2; + pos := pos-1; + (arg2, ty1, mk) := TypeCheck.matchTypes(ty, resTyToMatch, arg, allowUnknown=true); + if TypeCheck.isIncompatibleMatch(mk) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, {String(pos), "cat", "arg", Expression.toString(arg), Type.toString(ty), Type.toString(resTyToMatch)}, info); + end if; + res := arg2 :: res; + tys3 := ty1 :: tys3; + end for; + + // We have all except dimension n having equal sizes; with matching types + + ty := resTy; + callExp := Expression.CALL(makeCall2(NFBuiltinFuncs.CAT, Expression.INTEGER(n)::res, resTy, variability)); + end makeCatExp; + + function makeCall + "Creates a call to a builtin function, given a Function and a list of + argument expressions." + input Function func; + input list args; + input Variability var; + output Call call; + algorithm + call := Call.TYPED_CALL(func, func.returnType, var, args, + CallAttributes.CALL_ATTR(func.returnType, false, true, false, false, + DAE.NO_INLINE(), DAE.NO_TAIL())); + end makeCall; + + function makeCall2 + "Creates a call to a builtin function, given a Function, list of argument + expressions and a return type. Used for builtin functions defined with no + return type." + input Function func; + input list args; + input Type returnType; + input Variability var; + output Call call; + algorithm + call := Call.TYPED_CALL(func, returnType, var, args, + CallAttributes.CALL_ATTR(returnType, false, true, false, false, + DAE.NO_INLINE(), DAE.NO_TAIL())); + end makeCall2; + +protected + function assertNoNamedParams + input String fnName; + input list namedArgs; + input SourceInfo info; + algorithm + if not listEmpty(namedArgs) then + Error.addSourceMessage(Error.NO_SUCH_PARAMETER, + {fnName, Util.tuple21(listHead(namedArgs))}, info); + fail(); + end if; + end assertNoNamedParams; + + function typeStringCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type outType; + output Variability var; + protected + Type arg_ty; + list args; + list named_args; + Call ty_call; + algorithm + ty_call as Call.ARG_TYPED_CALL(_, args, named_args) := Call.typeNormalCall(call, origin, info); + (_, arg_ty, _) :: _ := args; + arg_ty := Type.arrayElementType(arg_ty); + + if Type.isComplex(arg_ty) then + (callExp, outType, var) := typeOverloadedStringCall(arg_ty, args, named_args, ty_call, origin, info); + else + (callExp, outType, var) := typeBuiltinStringCall(ty_call, origin, info); + end if; + end typeStringCall; + + function typeBuiltinStringCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var; + protected + Call ty_call; + algorithm + ty_call := Call.matchTypedNormalCall(call, origin, info); + ty := Call.typeOf(ty_call); + var := Call.variability(ty_call); + callExp := Expression.CALL(ty_call); + end typeBuiltinStringCall; + + function typeOverloadedStringCall + input Type overloadedType; + input list args; + input list namedArgs; + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type outType; + output Variability var = Variability.CONSTANT; + protected + ComponentRef fn_ref; + list candidates; + InstNode recopnode; + MatchedFunction matchedFunc; + list matchedFunctions, exactMatches; + algorithm + Type.COMPLEX(cls=recopnode) := overloadedType; + + try + fn_ref := Function.lookupFunctionSimple("'String'", recopnode); + else + // If there's no 'String' overload, let the normal String handler print the error. + typeBuiltinStringCall(call, origin, info); + fail(); + end try; + + fn_ref := Function.instFuncRef(fn_ref, InstNode.info(recopnode)); + candidates := Function.typeRefCache(fn_ref); + for fn in candidates loop + TypeCheck.checkValidOperatorOverload("'String'", fn, recopnode); + end for; + + matchedFunctions := Function.matchFunctionsSilent(candidates, args, namedArgs, info); + exactMatches := MatchedFunction.getExactMatches(matchedFunctions); + if listEmpty(exactMatches) then + Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.typedString(call), Function.candidateFuncListString(candidates)}, info); + fail(); + end if; + + if listLength(exactMatches) == 1 then + matchedFunc ::_ := exactMatches; + outType := Function.returnType(matchedFunc.func); + + for arg in matchedFunc.args loop + var := Prefixes.variabilityMax(var, Util.tuple33(arg)); + end for; + + callExp := Expression.CALL( + Call.TYPED_CALL( + matchedFunc.func, + outType, + var, + list(Util.tuple31(a) for a in matchedFunc.args), + CallAttributes.CALL_ATTR(outType, false, false, false, false, DAE.NO_INLINE(),DAE.NO_TAIL())) + ); + return; + else + Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_FUNCTIONS_NFINST, + {Call.typedString(call), Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); + fail(); + end if; + end typeOverloadedStringCall; + + function typeDiscreteCall + "Types a function call that can be typed normally, but which always has + discrete variability regardless of the variability of the arguments." + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.DISCRETE; + protected + Call argtycall; + Function fn; + list args; + TypedArg start,interval; + algorithm + argtycall := Call.typeMatchNormalCall(call, origin, info); + ty := Call.typeOf(argtycall); + callExp := Expression.CALL(Call.unboxArgs(argtycall)); + end typeDiscreteCall; + + function typeNdimsCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty = Type.INTEGER(); + output Variability variability = Variability.PARAMETER; + protected + list args; + list named_args; + Type arg_ty; + algorithm + Call.UNTYPED_CALL(arguments = args, named_args = named_args) := call; + + assertNoNamedParams("ndims", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "ndims(Any) => Integer"}, info); + fail(); + end if; + + // The number of dimensions an expression has is always known, + // so we might as well evaluate the ndims call here. + (_, arg_ty, _) := Typing.typeExp(listHead(args), origin, info); + callExp := Expression.INTEGER(Type.dimensionCount(arg_ty)); + end typeNdimsCall; + + function typePreCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + algorithm + (callExp, ty, variability) := typePreChangeCall("pre", call, origin, info); + end typePreCall; + + function typeChangeCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + algorithm + (callExp, ty, variability) := typePreChangeCall("change", call, origin, info); + ty := Type.setArrayElementType(ty, Type.BOOLEAN()); + end typeChangeCall; + + function typePreChangeCall + input String name; + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability = Variability.DISCRETE; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Variability var; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + + assertNoNamedParams(name, named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Any) => Any"}, info); + end if; + + // pre/change may not be used in a function context. + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + (arg, ty, var) := Typing.typeExp(listHead(args), origin, info); + + if not Expression.isCref(arg) then + Error.addSourceMessage(Error.ARGUMENT_MUST_BE_VARIABLE, + {"First", ComponentRef.toString(fn_ref), ""}, info); + fail(); + end if; + + if var == Variability.CONTINUOUS then + Error.addSourceMessageAndFail(Error.INVALID_ARGUMENT_VARIABILITY, + {"1", ComponentRef.toString(fn_ref), Prefixes.variabilityString(Variability.DISCRETE), + Expression.toString(arg), Prefixes.variabilityString(var)}, info); + end if; + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, var)); + end typePreChangeCall; + + function typeDerCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + Type ety; + algorithm + // der may not be used in a function context. + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"der"}, info); + fail(); + end if; + + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("der", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "der(Real) => Real"}, info); + end if; + + {arg} := args; + (arg, ty, variability) := Typing.typeExp(arg, origin, info); + + ety := Type.arrayElementType(ty); + + if Type.isInteger(ety) then + ty := Type.setArrayElementType(ty, Type.REAL()); + arg := Expression.typeCastElements(arg, Type.REAL()); + elseif not Type.isReal(ety) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), + Type.toString(ty), "Real"}, info); + end if; + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeDerCall; + + function typeDiagonalCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Dimension dim; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("diagonal", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "diagonal(Any[n]) => Any[n, n]"}, info); + end if; + + (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + + ty := match ty + case Type.ARRAY(dimensions = {dim}) + then Type.ARRAY(ty.elementType, {dim, dim}); + + else + algorithm + Error.addSourceMessage(Error.ARG_TYPE_MISMATCH, + {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), + Type.toString(ty), "Any[:]"}, info); + then + fail(); + end match; + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeDiagonalCall; + + function typeEdgeCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability = Variability.DISCRETE; + protected + Call argtycall; + Function fn; + list args; + TypedArg arg; + InstNode fn_node; + CallAttributes ca; + algorithm + // edge may not be used in a function context. + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"edge"}, info); + fail(); + end if; + + argtycall as Call.ARG_TYPED_CALL(ComponentRef.CREF(node = fn_node), args, _) := Call.typeNormalCall(call, origin, info); + argtycall := Call.matchTypedNormalCall(argtycall, origin, info); + ty := Call.typeOf(argtycall); + callExp := Expression.CALL(Call.unboxArgs(argtycall)); + + {arg} := args; + if not Expression.isCref(Util.tuple31(arg)) then + Error.addSourceMessage(Error.ARGUMENT_MUST_BE_VARIABLE, + {"First", "edge", ""}, info); + fail(); + end if; + end typeEdgeCall; + + function typeMinMaxCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var; + protected + Call argtycall; + algorithm + argtycall := Call.typeMatchNormalCall(call, origin, info); + argtycall := Call.unboxArgs(argtycall); + ty := Call.typeOf(argtycall); + var := Call.variability(argtycall); + callExp := Expression.CALL(argtycall); + // TODO: check basic type in two argument overload. + // check arrays of simple types in one argument overload. + // fix return type. + end typeMinMaxCall; + + function typeSumProductCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var; + protected + Call argtycall; + algorithm + // TODO: Rewrite this whole thing. + argtycall := Call.typeMatchNormalCall(call, origin, info); + argtycall := Call.unboxArgs(argtycall); + ty := Call.typeOf(argtycall); + var := Call.variability(argtycall); + callExp := Expression.CALL(argtycall); + end typeSumProductCall; + + function typeSmoothCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg1, arg2; + Type ty1, ty2; + Variability var; + Function fn; + TypeCheck.MatchKind mk; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("smooth", named_args, info); + + if listLength(args) <> 2 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "smooth(Integer, Any) => Any"}, info); + end if; + + {arg1, arg2} := args; + (arg1, ty1, var) := Typing.typeExp(arg1, origin, info); + (arg2, ty2, variability) := Typing.typeExp(arg2, origin, info); + + // First argument must be Integer. + if not Type.isInteger(ty1) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg1), + Type.toString(ty1), "Integer"}, info); + end if; + + // First argument must be a parameter expression. + if var > Variability.PARAMETER then + Error.addSourceMessageAndFail(Error.INVALID_ARGUMENT_VARIABILITY, + {"1", ComponentRef.toString(fn_ref), Prefixes.variabilityString(Variability.PARAMETER), + Expression.toString(arg1), Prefixes.variabilityString(variability)}, info); + end if; + + // Second argument must be Real, array of allowed expressions or record + // containing only components of allowed expressions. + // TODO: Also handle records here. + (arg2, ty, mk) := TypeCheck.matchTypes(ty2, Type.setArrayElementType(ty2, Type.REAL()), arg2, true); + + if not TypeCheck.isValidArgumentMatch(mk) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {"2", ComponentRef.toString(fn_ref), "", Expression.toString(arg2), + Type.toString(ty2), "Real\n Real[:, ...]\n Real record\n Real record[:, ...]"}, info); + end if; + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg1, arg2}, ty, var)); + end typeSmoothCall; + + function typeFillCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression fill_arg; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("fill", named_args, info); + + // fill can take any number of arguments, but needs at least two. + if listLength(args) < 2 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "fill(Any, Integer, ...) => Any[:, ...]"}, info); + end if; + + fill_arg :: args := args; + + // Type the first argument, which is the fill value. + (fill_arg, ty, _) := Typing.typeExp(fill_arg, origin, info); + (callExp, ty, variability) := typeFillCall2(fn_ref, ty, fill_arg, args, origin, info); + end typeFillCall; + + function typeFillCall2 + input ComponentRef fnRef; + input Type fillType; + input Expression fillArg; + input list dimensionArgs; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability = Variability.CONSTANT; + protected + Expression fill_arg; + list ty_args; + Variability arg_var; + Type arg_ty; + Function fn; + list dims; + algorithm + ty_args := {fillArg}; + dims := {}; + + // Type the dimension arguments. + for arg in dimensionArgs loop + (arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info); + + if arg_var <= Variability.STRUCTURAL_PARAMETER then + arg := Ceval.evalExp(arg); + arg_ty := Expression.typeOf(arg); + end if; + + // Each dimension argument must be an Integer expression. + if not Type.isInteger(arg_ty) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {intString(listLength(ty_args) + 1), ComponentRef.toString(fnRef), "", + Expression.toString(arg), Type.toString(arg_ty), "Integer"}, info); + end if; + + variability := Prefixes.variabilityMax(variability, arg_var); + ty_args := arg :: ty_args; + dims := Dimension.fromExp(arg, arg_var) :: dims; + end for; + + ty_args := listReverseInPlace(ty_args); + dims := listReverseInPlace(dims); + + {fn} := Function.typeRefCache(fnRef); + ty := Type.liftArrayLeftList(fillType, dims); + + if variability <= Variability.STRUCTURAL_PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) == 0 then + callExp := Ceval.evalBuiltinFill(ty_args); + else + callExp := Expression.CALL(makeCall2(NFBuiltinFuncs.FILL_FUNC, ty_args, ty, variability)); + end if; + end typeFillCall2; + + function typeZerosOnesCall + input String name; + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression fill_arg; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams(name, named_args, info); + + // zeros/ones can take any number of arguments, but needs at least one. + if listEmpty(args) then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Integer, ...) => Integer[:, ...]"}, info); + end if; + + fill_arg := Expression.INTEGER(if name == "ones" then 1 else 0); + (callExp, ty, variability) := typeFillCall2(fn_ref, Type.INTEGER(), fill_arg, args, origin, info); + end typeZerosOnesCall; + + function typeScalarCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Variability var; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("scalar", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "scalar(Any[1, ...]) => Any"}, info); + end if; + + (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + + // scalar requires all dimensions of the array to be 1. + for dim in Type.arrayDims(ty) loop + if Dimension.isKnown(dim) and not Dimension.size(dim) == 1 then + Error.addSourceMessageAndFail(Error.INVALID_ARRAY_DIM_IN_SCALAR_OP, + {Type.toString(ty)}, info); + end if; + end for; + + ty := Type.arrayElementType(ty); + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeScalarCall; + + function typeVectorCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Variability var; + Function fn; + Integer dim_size = -1, i = 1; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("vector", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "vector(Any) => Any[:]\n vector(Any[:, ...]) => Any[:]"}, info); + end if; + + (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + + // vector requires that at most one dimension is > 1, and that dimension + // determines the type of the vector call. + for dim in Type.arrayDims(ty) loop + if Dimension.isKnown(dim) then + if Dimension.size(dim) > 1 then + if dim_size == -1 then + dim_size := Dimension.size(dim); + else + Error.addSourceMessageAndFail(Error.NF_VECTOR_INVALID_DIMENSIONS, + {Type.toString(ty), Call.toString(call)}, info); + end if; + end if; + end if; + + i := i + 1; + end for; + + // If the argument was scalar or an array where all dimensions where 1, set + // the dimension size to 1. + if dim_size == -1 then + dim_size := 1; + end if; + + ty := Type.ARRAY(Type.arrayElementType(ty), {Dimension.fromInteger(dim_size)}); + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeVectorCall; + + function typeMatrixCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Variability var; + Function fn; + list dims; + Dimension dim1, dim2; + Integer i; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("matrix", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "vector(Any) => Any[:]\n vector(Any[:, ...]) => Any[:]"}, info); + end if; + + (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + dims := Type.arrayDims(ty); + + dims := match listLength(dims) + case 0 then {Dimension.fromInteger(1), Dimension.fromInteger(1)}; + case 1 then {listHead(dims), Dimension.fromInteger(1)}; + case 2 then dims; + else + algorithm + // matrix requires all but the first two dimensions to have size 1. + dim1 :: dim2 :: dims := dims; + i := 3; + + for dim in dims loop + if Dimension.isKnown(dim) and Dimension.size(dim) > 1 then + Error.addSourceMessageAndFail(Error.INVALID_ARRAY_DIM_IN_CONVERSION_OP, + {String(i), "matrix", "1", Dimension.toString(dim)}, info); + end if; + + i := i + 1; + end for; + then + {dim1, dim2}; + end match; + + ty := Type.ARRAY(Type.arrayElementType(ty), dims); + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeMatrixCall; + + function typeCatCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args, res; + list named_args; + list tys; + Expression arg; + Variability var; + TypeCheck.MatchKind mk; + Function fn; + Integer n; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("cat", named_args, info); + + if listLength(args) < 2 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "cat(Integer, Any[:,:], ...) => Any[:]"}, info); + end if; + + arg::args := args; + + (arg, ty, variability) := Typing.typeExp(arg, origin, info); + (arg, ty, mk) := TypeCheck.matchTypes(ty, Type.INTEGER(), arg); + + if variability > Variability.PARAMETER then + Error.addSourceMessageAndFail(Error.NF_CAT_FIRST_ARG_EVAL, {Expression.toString(arg), Prefixes.variabilityString(variability)}, info); + end if; + Expression.INTEGER(n) := Ceval.evalExp(arg, Ceval.EvalTarget.GENERIC(info)); + + res := {}; + tys := {}; + + for a in args loop + (arg, ty, var) := Typing.typeExp(a, origin, info); + variability := Prefixes.variabilityMax(var, variability); + res := arg :: res; + tys := ty :: tys; + end for; + + (callExp, ty) := makeCatExp(n, listReverse(res), listReverse(tys), variability, info); + end typeCatCall; + + function typeSymmetricCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("symmetric", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "symmetric(Any[n, n]) => Any[n, n]"}, info); + end if; + + (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + + if not Type.isSquareMatrix(ty) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), + Type.toString(ty), "Any[n, n]"}, info); + end if; + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeSymmetricCall; + + function typeTransposeCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Dimension dim1, dim2; + list rest_dims; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("transpose", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "transpose(Any[n, m, ...]) => Any[m, n, ...]"}, info); + end if; + + (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + + ty := match ty + case Type.ARRAY(dimensions = dim1 :: dim2 :: rest_dims) + then Type.ARRAY(ty.elementType, dim2 :: dim1 :: rest_dims); + + else + algorithm + Error.addSourceMessage(Error.ARG_TYPE_MISMATCH, + {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), + Type.toString(ty), "Any[:, :, ...]"}, info); + then + fail(); + end match; + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeTransposeCall; + + function typeCardinalityCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.PARAMETER; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("cardinality", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Connector) => Integer"}, info); + end if; + + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + (arg, ty) := Typing.typeExp(listHead(args), origin, info); + + if not Expression.isCref(arg) then + Error.addSourceMessageAndFail(Error.ARGUMENT_MUST_BE_VARIABLE, + {"First", ComponentRef.toString(fn_ref), ""}, info); + end if; + + if not Type.isConnector(ty) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {"1", ComponentRef.toString(fn_ref), "", + Expression.toString(arg), Type.toString(ty), "connector"}, info); + end if; + + {fn} := Function.typeRefCache(fn_ref); + ty := Type.INTEGER(); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, var)); + // TODO: Check cardinality restrictions, 3.7.2.3. + end typeCardinalityCall; + + function typeBranchCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.PARAMETER; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg1, arg2; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("Connections.branch", named_args, info); + + if listLength(args) <> 2 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Connector, Connector)"}, info); + end if; + + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + {arg1, arg2} := args; + + (arg1, ty) := Typing.typeExp(arg1, origin, info); + checkConnectionsArgument(arg1, ty, fn_ref, 1, info); + (arg2, ty) := Typing.typeExp(arg2, origin, info); + checkConnectionsArgument(arg2, ty, fn_ref, 2, info); + + {fn} := Function.typeRefCache(fn_ref); + ty := Type.NORETCALL(); + callExp := Expression.CALL(makeCall2(fn, {arg1, arg2}, ty, var)); + end typeBranchCall; + + function typeIsRootCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.PARAMETER; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("Connections.isRoot", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Connector)"}, info); + end if; + + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + (arg, ty) := Typing.typeExp(listHead(args), origin, info); + checkConnectionsArgument(arg, ty, fn_ref, 1, info); + + {fn} := Function.typeRefCache(fn_ref); + ty := Type.BOOLEAN(); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, var)); + end typeIsRootCall; + + function typePotentialRootCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.PARAMETER; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg1, arg2; + Function fn; + Integer args_len; + String name; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + + for narg in named_args loop + (name, arg2) := narg; + + if name == "priority" then + args := List.appendElt(arg2, args); + else + Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, + {ComponentRef.toString(fn_ref), name}, info); + end if; + end for; + + args_len := listLength(args); + if args_len < 1 or args_len > 2 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Connector, Integer = 0)"}, info); + end if; + + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + arg1 :: args := args; + + (arg1, ty) := Typing.typeExp(arg1, origin, info); + checkConnectionsArgument(arg1, ty, fn_ref, 1, info); + + if args_len == 2 then + arg2 := listHead(args); + (arg2, ty) := Typing.typeExp(arg2, origin, info); + + if not Type.isInteger(ty) then + Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, + {"2", ComponentRef.toString(fn_ref), "", Expression.toString(arg2), + Type.toString(ty), "Integer"}, info); + end if; + else + arg2 := Expression.INTEGER(0); + end if; + + {fn} := Function.typeRefCache(fn_ref); + ty := Type.NORETCALL(); + callExp := Expression.CALL(makeCall2(fn, {arg1, arg2}, ty, var)); + end typePotentialRootCall; + + function typeRootCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.PARAMETER; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("Connections.root", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Connector)"}, info); + end if; + + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + (arg, ty) := Typing.typeExp(listHead(args), origin, info); + checkConnectionsArgument(arg, ty, fn_ref, 1, info); + + {fn} := Function.typeRefCache(fn_ref); + ty := Type.NORETCALL(); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, var)); + end typeRootCall; + + function typeRootedCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability var = Variability.PARAMETER; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("Connections.rooted", named_args, info); + + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), ComponentRef.toString(fn_ref) + "(Connector)"}, info); + end if; + + if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then + Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, + {ComponentRef.toString(fn_ref)}, info); + end if; + + (arg, ty) := Typing.typeExp(listHead(args), origin, info); + checkConnectionsArgument(arg, ty, fn_ref, 1, info); + + {fn} := Function.typeRefCache(fn_ref); + ty := Type.BOOLEAN(); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, var)); + end typeRootedCall; + + function checkConnectionsArgument + input Expression arg; + input Type ty; + input ComponentRef fnRef; + input Integer argIndex; + input SourceInfo info; + algorithm + () := match arg + local + Type ty2; + InstNode node; + Boolean valid_cref; + ComponentRef rest_cref; + + case Expression.CREF() + algorithm + valid_cref := match arg.cref + case ComponentRef.CREF(node = node, origin = NFComponentRef.Origin.CREF, + restCref = ComponentRef.CREF(ty = ty2, origin = NFComponentRef.Origin.CREF, + restCref = rest_cref)) + then Class.isOverdetermined(InstNode.getClass(node)) and + Type.isConnector(ty2) and + not ComponentRef.isFromCref(rest_cref); + + else false; + end match; + + if not valid_cref then + Error.addSourceMessageAndFail( + if argIndex == 1 then Error.INVALID_ARGUMENT_TYPE_BRANCH_FIRST else + Error.INVALID_ARGUMENT_TYPE_BRANCH_SECOND, + {ComponentRef.toString(fnRef)}, info); + end if; + then + (); + + else + algorithm + Error.addSourceMessage(Error.ARG_TYPE_MISMATCH, + {String(argIndex), ComponentRef.toString(fnRef), "", + Expression.toString(arg), Type.toString(ty), "overconstrained type/record"}, info); + then + fail(); + end match; + end checkConnectionsArgument; + + function typeNoEventCall + input Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + output Expression callExp; + output Type ty; + output Variability variability; + protected + ComponentRef fn_ref; + list args; + list named_args; + Expression arg; + Function fn; + algorithm + Call.UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + assertNoNamedParams("noEvent", named_args, info); + + // noEvent takes exactly one argument. + if listLength(args) <> 1 then + Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {Call.toString(call), "noEvent(Any) => Any"}, info); + end if; + + {arg} := args; + (arg, ty, variability) := Typing.typeExp(arg, intBitOr(origin, ExpOrigin.NOEVENT), info); + + {fn} := Function.typeRefCache(fn_ref); + callExp := Expression.CALL(makeCall2(fn, {arg}, ty, variability)); + end typeNoEventCall; + + function typeGetInstanceName + input Call call; + output Expression result; + output Type ty = Type.STRING(); + output Variability var = Variability.CONSTANT; + protected + InstNode scope; + algorithm + Call.UNTYPED_CALL(call_scope = scope) := call; + result := Expression.STRING(Absyn.pathString(InstNode.scopePath(scope, includeRoot = true))); + end typeGetInstanceName; + +annotation(__OpenModelica_Interface="frontend"); +end NFBuiltinCall; diff --git a/Compiler/NFFrontEnd/NFCall.mo b/Compiler/NFFrontEnd/NFCall.mo index 4688d75478..f0a03512a7 100644 --- a/Compiler/NFFrontEnd/NFCall.mo +++ b/Compiler/NFFrontEnd/NFCall.mo @@ -33,70 +33,58 @@ encapsulated package NFCall import Absyn; import DAE; -import NFInstNode.InstNode; import Expression = NFExpression; -import Type = NFType; +import NFInstNode.InstNode; import NFPrefixes.Variability; +import Type = NFType; protected -import NFBinding.Binding; -import NFComponent.Component; -import NFInstNode.CachedData; +import BuiltinCall = NFBuiltinCall; +import Ceval = NFCeval; import ComponentRef = NFComponentRef; import Dimension = NFDimension; -import NFFunction.Function; +import ErrorExt; +import Inline = NFInline; import Inst = NFInst; -import NFInstNode.InstNodeType; -import Lookup = NFLookup; -import Typing = NFTyping; -import TypeCheck = NFTypeCheck; -import Types; import List; -import NFClass.Class; -import ErrorExt; -import Util; -import Prefixes = NFPrefixes; +import Lookup = NFLookup; import MetaModelica.Dangerous.listReverseInPlace; -import NFTyping.ExpOrigin; +import NFBinding.Binding; +import NFClass.Class; +import NFComponent.Component; +import NFFunction.Function; +import NFFunction.FunctionMatchKind; +import NFFunction.MatchedFunction; import NFFunction.NamedArg; import NFFunction.TypedArg; import NFFunction.TypedNamedArg; -import NFFunction.FunctionMatchKind; -import NFFunction.MatchedFunction; -import Ceval = NFCeval; -import SimplifyExp = NFSimplifyExp; -import Subscript = NFSubscript; -import Inline = NFInline; +import NFInstNode.CachedData; +import NFTyping.ExpOrigin; +import Prefixes = NFPrefixes; +import TypeCheck = NFTypeCheck; +import Typing = NFTyping; +import Util; public -uniontype CallAttributes - record CALL_ATTR - Type ty "The type of the return value, if several return values this is undefined"; - Boolean tuple_ "tuple" ; - Boolean builtin "builtin Function call" ; - Boolean isImpure "if the function has prefix *impure* is true, else false"; - Boolean isFunctionPointerCall; - DAE.InlineType inlineType; - DAE.TailCall tailCall "Input variables of the function if the call is tail-recursive"; - end CALL_ATTR; - - function toDAE - input CallAttributes attr; - output DAE.CallAttributes fattr; - algorithm - fattr := DAE.CALL_ATTR(Type.toDAE(attr.ty), attr.tuple_, attr.builtin, - attr.isImpure, attr.isFunctionPointerCall, attr.inlineType, attr.tailCall); - end toDAE; -end CallAttributes; - -public constant CallAttributes callAttrBuiltinBool = CALL_ATTR(Type.BOOLEAN(),false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinInteger = CALL_ATTR(Type.INTEGER(),false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinReal = CALL_ATTR(Type.REAL(),false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinString = CALL_ATTR(Type.STRING(),false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinOther = CALL_ATTR(Type.UNKNOWN(),false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinImpureBool = CALL_ATTR(Type.BOOLEAN(),false,true,true,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinImpureInteger = CALL_ATTR(Type.INTEGER(),false,true,true,false,DAE.NO_INLINE(),DAE.NO_TAIL()); -public constant CallAttributes callAttrBuiltinImpureReal = CALL_ATTR(Type.REAL(),false,true,true,false,DAE.NO_INLINE(),DAE.NO_TAIL()); + uniontype CallAttributes + record CALL_ATTR + Type ty "The type of the return value, if several return values this is undefined"; + Boolean tuple_ "tuple" ; + Boolean builtin "builtin Function call" ; + Boolean isImpure "if the function has prefix *impure* is true, else false"; + Boolean isFunctionPointerCall; + DAE.InlineType inlineType; + DAE.TailCall tailCall "Input variables of the function if the call is tail-recursive"; + end CALL_ATTR; + + function toDAE + input CallAttributes attr; + output DAE.CallAttributes fattr; + algorithm + fattr := DAE.CALL_ATTR(Type.toDAE(attr.ty), attr.tuple_, attr.builtin, + attr.isImpure, attr.isFunctionPointerCall, attr.inlineType, attr.tailCall); + end toDAE; + end CallAttributes; protected type ParameterTree = ParameterTreeImpl.Tree; @@ -195,236 +183,6 @@ uniontype Call end match; end instantiate; - protected - function instNormalCall - input Absyn.ComponentRef functionName; - input Absyn.FunctionArgs functionArgs; - input InstNode scope; - input SourceInfo info; - output Expression callExp; - protected - ComponentRef fn_ref; - list args; - list named_args; - algorithm - (args, named_args) := instArgs(functionArgs, scope, info); - - callExp := match Absyn.crefFirstIdent(functionName) - // size creates Expression.SIZE instead of Expression.CALL. - case "size" then makeSizeExp(args, named_args, info); - // array() call with no iterators creates Expression.ARRAY instead of Expression.CALL. - // If it had iterators then it will not reach here. The args would have been parsed to - // Absyn.FOR_ITER_FARG and that is handled in instIteratorCall. - case "array" then makeArrayExp(args, named_args, info); - else algorithm - (fn_ref, _, _) := Function.instFunc(functionName,scope,info); - then - Expression.CALL(UNTYPED_CALL(fn_ref, args, named_args, scope)); - end match; - end instNormalCall; - - function instArgs - input Absyn.FunctionArgs args; - input InstNode scope; - input SourceInfo info; - output list posArgs; - output list namedArgs; - algorithm - (posArgs, namedArgs) := match args - case Absyn.FUNCTIONARGS() - algorithm - posArgs := list(Inst.instExp(a, scope, info) for a in args.args); - namedArgs := list(instNamedArg(a, scope, info) for a in args.argNames); - then - (posArgs, namedArgs); - - else - algorithm - Error.assertion(false, getInstanceName() + " got unknown function args", sourceInfo()); - then - fail(); - end match; - end instArgs; - - function instNamedArg - input Absyn.NamedArg absynArg; - input InstNode scope; - input SourceInfo info; - output NamedArg arg; - protected - String name; - Absyn.Exp exp; - algorithm - Absyn.NAMEDARG(argName = name, argValue = exp) := absynArg; - arg := (name, Inst.instExp(exp, scope, info)); - end instNamedArg; - - function instIteratorCall - input Absyn.ComponentRef functionName; - input Absyn.FunctionArgs functionArgs; - input InstNode scope; - input SourceInfo info; - output Expression callExp; - protected - ComponentRef fn_ref, arr_fn_ref; - Expression exp; - list> iters; - Call call; - Boolean is_builtin_reduction, is_array; - algorithm - (is_builtin_reduction, is_array) := match Absyn.crefFirstIdent(functionName) - case "$array" then (false, true); - case "array" then (false, true); - case "min" then (true, false); - case "max" then (true, false); - case "sum" then (true, false); - case "product" then (true, false); - else (false, false); - end match; - - (exp, iters) := instIteratorCallArgs(functionArgs, scope, info); - - // If it is one of the builtin functions above the call operates as a "reduction" - // (think of it like just a call to the overload of the function that takes array as argument.) - // We handle it by making a call to the builtin function with an array as argument. - // Which is valid since all these builtin functions accept array arguments anyway. - if is_builtin_reduction then - // start by making an array map call. - call := UNTYPED_MAP_CALL(exp, iters); - - // wrap the array call in the given function - // e.g. sum(array(i for i in ...)). - fn_ref := Function.instFunc(functionName, scope, info); - call := UNTYPED_CALL(fn_ref, {Expression.CALL(call)}, {}, scope); - else - // Otherwise, make an array call with the original function call as an argument. - // But only if the original function is not array() itself. - // e.g. Change myfunc(i for i in ...) TO array(myfunc(i) for i in ...). - if not is_array then - fn_ref := Function.instFunc(functionName, scope, info); - call := UNTYPED_CALL(fn_ref, {exp}, {}, scope); - exp := Expression.CALL(call); - end if; - - call := UNTYPED_MAP_CALL(exp, iters); - end if; - - callExp := Expression.CALL(call); - end instIteratorCall; - - function instIteratorCallArgs - input Absyn.FunctionArgs args; - input InstNode scope; - input SourceInfo info; - output Expression exp; - output list> iters; - algorithm - _ := match args - local - InstNode for_scope; - - case Absyn.FOR_ITER_FARG() - algorithm - (for_scope, iters) := instIterators(args.iterators, scope, info); - exp := Inst.instExp(args.exp, for_scope, info); - then - (); - end match; - end instIteratorCallArgs; - - function instIterators - input list inIters; - input InstNode scope; - input SourceInfo info; - output InstNode outScope = scope; - output list> outIters = {}; - protected - Expression range; - InstNode iter; - algorithm - for i in inIters loop - range := Inst.instExp(Util.getOption(i.range), outScope, info); - (outScope, iter) := Inst.addIteratorToScope(i.name, outScope, info); - outIters := (iter, range) :: outIters; - end for; - - outIters := listReverse(outIters); - end instIterators; - - function builtinSpecialHandling - input Call call; - output Boolean special; - algorithm - () := match call - local - InstNode fn_node; - - case UNTYPED_CALL(ComponentRef.CREF(node = fn_node)) algorithm - CachedData.FUNCTION(_, _, special) := InstNode.getFuncCache(fn_node); - then (); - case UNTYPED_MAP_CALL() algorithm - Error.assertion(false, getInstanceName() + " got a map call: " + Call.toString(call), sourceInfo()); - then (); - end match; - end builtinSpecialHandling; - - function typeSpecialBuiltinFunction - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; - protected - ComponentRef cref; - InstNode fn_node; - Expression first; - list rest; - String name; - algorithm - UNTYPED_CALL(ref = cref) := call; - - (callExp, ty, variability) := match ComponentRef.firstName(cref) - case "String" then typeStringCall(call, origin, info); - case "branch" then typeBranchCall(call, origin, info); - case "cardinality" then typeCardinalityCall(call, origin, info); - case "cat" then typeCatCall(call, origin, info); - case "change" then typeChangeCall(call, origin, info); - case "der" then typeDerCall(call, origin, info); - case "diagonal" then typeDiagonalCall(call, origin, info); - case "edge" then typeEdgeCall(call, origin, info); - case "fill" then typeFillCall(call, origin, info); - case "getInstanceName" then typeGetInstanceName(call); - case "initial" then typeDiscreteCall(call, origin, info); - case "isRoot" then typeIsRootCall(call, origin, info); - case "matrix" then typeMatrixCall(call, origin, info); - case "max" then typeMinMaxCall(call, origin, info); - case "min" then typeMinMaxCall(call, origin, info); - case "ndims" then typeNdimsCall(call, origin, info); - case "noEvent" then typeNoEventCall(call, origin, info); - case "ones" then typeZerosOnesCall(call, origin, info); - case "potentialRoot" then typePotentialRootCall(call, origin, info); - case "pre" then typePreCall(call, origin, info); - case "product" then typeSumProductCall(call, origin, info); - case "root" then typeRootCall(call, origin, info); - case "rooted" then typeRootedCall(call, origin, info); - case "scalar" then typeScalarCall(call, origin, info); - case "smooth" then typeSmoothCall(call, origin, info); - case "sum" then typeSumProductCall(call, origin, info); - case "symmetric" then typeSymmetricCall(call, origin, info); - case "terminal" then typeDiscreteCall(call, origin, info); - case "transpose" then typeTransposeCall(call, origin, info); - case "vector" then typeVectorCall(call, origin, info); - case "zeros" then typeZerosOnesCall(call, origin, info); - else - algorithm - Error.assertion(false, getInstanceName() + " got unhandled builtin function: " + Call.toString(call), sourceInfo()); - then - fail(); - end match; - end typeSpecialBuiltinFunction; - - public function typeCall input Expression callExp; input ExpOrigin.Type origin; @@ -440,11 +198,11 @@ uniontype Call outExp := match callExp case Expression.CALL(UNTYPED_CALL(ref = cref)) algorithm - if(builtinSpecialHandling(callExp.call)) then - (outExp, ty, var) := typeSpecialBuiltinFunction(callExp.call, origin, info); + if(BuiltinCall.needSpecialHandling(callExp.call)) then + (outExp, ty, var) := BuiltinCall.typeSpecial(callExp.call, origin, info); else call := typeMatchNormalCall(callExp.call, origin, info); - ty := getType(call); + ty := typeOf(call); var := variability(call); if isRecordConstructor(call) then @@ -460,7 +218,7 @@ uniontype Call case Expression.CALL(UNTYPED_MAP_CALL()) algorithm call := typeMapIteratorCall(callExp.call, origin, info); - ty := getType(call); + ty := typeOf(call); var := variability(call); then Expression.CALL(call); @@ -486,74 +244,19 @@ uniontype Call end match; end typeCall; - function typeMapIteratorCall + function typeNormalCall input output Call call; input ExpOrigin.Type origin; input SourceInfo info; - output Type ty; - output Variability variability; - protected - Expression arg, range; - Type iter_ty; - Binding binding; - Variability iter_var; - InstNode iter; - list dims = {}; - list> iters = {}; algorithm - (call, ty, variability) := match call - // This is always a call to the function array()/$array(). See instIteratorCall. - // Other mapping function calls are already wrapped by array() at this point. - case UNTYPED_MAP_CALL() - algorithm - variability := Variability.CONSTANT; - - for i in call.iters loop - (iter, range) := i; - (range, iter_ty, iter_var) := Typing.typeIterator(iter, range, origin, structural = false); - dims := listAppend(Type.arrayDims(iter_ty), dims); - variability := Variability.variabilityMax(variability, iter_var); - iters := (iter, range) :: iters; - end for; - iters := listReverseInPlace(iters); - - (arg, ty) := Typing.typeExp(call.exp, origin, info); - ty := Type.liftArrayLeftList(ty, dims); - then - (TYPED_MAP_CALL(ty, variability, arg, iters), ty, variability); + call := match call + local + list fnl; + Boolean is_external; - else + case UNTYPED_CALL() algorithm - Error.assertion(false, getInstanceName() + " got invalid function call expression", sourceInfo()); - then - fail(); - end match; - end typeMapIteratorCall; - - function typeMatchNormalCall - input output Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - protected - Call argtycall; - algorithm - argtycall := typeNormalCall(call, origin, info); - call := matchTypedNormalCall(argtycall, origin, info); - end typeMatchNormalCall; - - function typeNormalCall - input output Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - algorithm - call := match call - local - list fnl; - Boolean is_external; - - case UNTYPED_CALL() - algorithm - fnl := typeCachedFunctions(call.ref); + fnl := Function.typeRefCache(call.ref); // Don't evaluate constants or structural parameters for external functions, // the code generation can't handle it in some cases (see bug #4904). // TODO: Remove this when #4904 is fixed. @@ -569,38 +272,50 @@ uniontype Call end match; end typeNormalCall; - function typeCachedFunctions - "Returns the function(s) referenced by the given cref, and types them if - they are not already typed." - input ComponentRef functionRef; - output list functions; + function makeTypedCall + input Function fn; + input list args; + input Type returnType; + input Variability variability; + output Call call; protected - InstNode fn_node; - Boolean typed, special; - String name; + CallAttributes ca; algorithm - functions := match functionRef - case ComponentRef.CREF(node = fn_node) - algorithm - CachedData.FUNCTION(functions, typed, special) := InstNode.getFuncCache(fn_node); - - // Type the function(s) if not already done. - if not typed then - functions := list(Function.typeFunctionSignature(f) for f in functions); - InstNode.setFuncCache(fn_node, CachedData.FUNCTION(functions, true, special)); - functions := list(Function.typeFunctionBody(f) for f in functions); - InstNode.setFuncCache(fn_node, CachedData.FUNCTION(functions, true, special)); - end if; - then - functions; + ca := CallAttributes.CALL_ATTR( + returnType, + Type.isTuple(returnType), + Function.isBuiltin(fn), + Function.isImpure(fn), + Function.isFunctionPointer(fn), + Function.inlineBuiltin(fn), + DAE.NO_TAIL() + ); - else + call := TYPED_CALL(fn, returnType, variability, args, ca); + end makeTypedCall; + + function unboxArgs + input output Call call; + algorithm + () := match call + case TYPED_CALL() algorithm - Error.assertion(false, getInstanceName() + " got invalid function call reference", sourceInfo()); + call.arguments := list(Expression.unbox(arg) for arg in call.arguments); then - fail(); + (); end match; - end typeCachedFunctions; + end unboxArgs; + + function typeMatchNormalCall + input output Call call; + input ExpOrigin.Type origin; + input SourceInfo info; + protected + Call argtycall; + algorithm + argtycall := typeNormalCall(call, origin, info); + call := matchTypedNormalCall(argtycall, origin, info); + end typeMatchNormalCall; function matchTypedNormalCall input output Call call; @@ -650,2081 +365,835 @@ uniontype Call if MatchedFunction.isVectorized(matchedFunc) then call := vectorizeCall(call, matchedFunc.mk, scope, info); end if; - end matchTypedNormalCall; - function makeTypedCall - input Function fn; - input list args; - input Type returnType; - input Variability variability; - output Call call; - protected - CallAttributes ca; + function typeOf + input Call call; + output Type ty; algorithm - ca := CallAttributes.CALL_ATTR( - returnType, - Type.isTuple(returnType), - Function.isBuiltin(fn), - Function.isImpure(fn), - Function.isFunctionPointer(fn), - Function.inlineBuiltin(fn), - DAE.NO_TAIL() - ); - - call := TYPED_CALL(fn, returnType, variability, args, ca); - end makeTypedCall; + ty := match call + case TYPED_CALL() then call.ty; + case TYPED_MAP_CALL() then call.ty; + else Type.UNKNOWN(); + end match; + end typeOf; - function vectorizeCall - input Call base_call; - input FunctionMatchKind mk; - input InstNode scope; - input SourceInfo info; - output Call vectorized_call; - protected - Type ty, vect_ty; - Expression exp; - list> iters; - InstNode iter; - Integer i; - list vect_dims; - list arg_is_vected, b_list; - Boolean b; - list vect_args; + function setType + input output Call call; + input Type ty; algorithm - vectorized_call := match base_call - case TYPED_CALL() - algorithm - FunctionMatchKind.VECTORIZED(vect_dims, arg_is_vected) := mk; - iters := {}; - i := 1; + call := match call + case TYPED_CALL() algorithm call.ty := ty; then call; + case TYPED_MAP_CALL() algorithm call.ty := ty; then call; + end match; + end setType; - for dim in vect_dims loop - Error.assertion(Dimension.isKnown(dim, allowExp = true), getInstanceName() + - " got unknown dimension for vectorized call", info); + function variability + input Call call; + output Variability var; + algorithm + var := match call + local + Boolean var_set; - // Create the range on which we will iterate to vectorize. - ty := Type.ARRAY(Type.INTEGER(), {dim}); - exp := Expression.RANGE(ty, Expression.INTEGER(1), NONE(), Dimension.sizeExp(dim)); + case UNTYPED_CALL() + algorithm + var_set := true; - // Create the iterator. - iter := InstNode.fromComponent("$i" + intString(i), - Component.ITERATOR(Type.INTEGER(), Variability.CONSTANT, info), scope); + if ComponentRef.isSimple(call.ref) then + var := match ComponentRef.firstName(call.ref) + case "change" then Variability.DISCRETE; + case "edge" then Variability.DISCRETE; + case "pre" then Variability.DISCRETE; + case "ndims" then Variability.PARAMETER; + case "cardinality" then Variability.PARAMETER; + else algorithm var_set := false; then Variability.CONTINUOUS; + end match; + end if; - iters := (iter, exp) :: iters; + if not var_set then + var := Expression.variabilityList(call.arguments); - // Now that iterator is ready apply it, as a subscript, to each argument that is supposed to be vectorized - // Make a cref expression from the iterator - exp := Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER())); - vect_args := {}; - b_list := arg_is_vected; - for arg in base_call.arguments loop - // If the argument is supposed to be vectorized - b :: b_list := b_list; - vect_args := (if b then Expression.applyIndexSubscript(exp, arg) else arg) :: vect_args; + for narg in call.named_args loop + var := Prefixes.variabilityMax(var, Expression.variability(Util.tuple22(narg))); end for; - - base_call.arguments := listReverse(vect_args); - i := i + 1; - end for; - - vect_ty := Type.liftArrayLeftList(base_call.ty, vect_dims); + end if; then - TYPED_MAP_CALL(vect_ty, base_call.var, Expression.CALL(base_call), iters); + var; - end match; - end vectorizeCall; + case UNTYPED_MAP_CALL() then Expression.variability(call.exp); + case TYPED_CALL() then call.var; + case TYPED_MAP_CALL() then call.var; + else algorithm + Error.assertion(false, getInstanceName() + " got untyped call", sourceInfo()); + then fail(); + end match; + end variability; - function evaluateCallType - input output Type ty; - input Function fn; - input list args; - input output ParameterTree ptree = ParameterTree.EMPTY(); + function compare + input Call call1; + input Call call2; + output Integer comp; algorithm - ty := match ty - local - list dims; - list tys; + comp := match (call1, call2) + case (UNTYPED_CALL(), UNTYPED_CALL()) + then ComponentRef.compare(call1.ref, call2.ref); - case Type.ARRAY() - algorithm - (dims, ptree) := List.map1Fold(ty.dimensions, evaluateCallTypeDim, (fn, args), ptree); - ty.dimensions := dims; - then - ty; + case (TYPED_CALL(), TYPED_CALL()) + then Absyn.pathCompare(Function.name(call1.fn), Function.name(call2.fn)); - case Type.TUPLE() - algorithm - (tys, ptree) := List.map2Fold(ty.types, evaluateCallType, fn, args, ptree); - ty.types := tys; - then - ty; + case (UNTYPED_CALL(), TYPED_CALL()) + then Absyn.pathCompare(ComponentRef.toPath(call1.ref), Function.name(call2.fn)); - else ty; + case (TYPED_CALL(), UNTYPED_CALL()) + then Absyn.pathCompare(Function.name(call1.fn), ComponentRef.toPath(call2.ref)); end match; - end evaluateCallType; - function evaluateCallTypeDim - input output Dimension dim; - input tuple> fnArgs; - input output ParameterTree ptree; + if comp == 0 then + comp := Expression.compareList(arguments(call1), arguments(call2)); + end if; + end compare; + + function isExternal + input Call call; + output Boolean isExternal; algorithm - dim := match dim - local - Expression exp; + isExternal := match call + case UNTYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref))); + case ARG_TYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref))); + case TYPED_CALL() then Function.isExternal(call.fn); + else false; + end match; + end isExternal; - case Dimension.EXP() - algorithm - ptree := buildParameterTree(fnArgs, ptree); - exp := Expression.map(dim.exp, function evaluateCallTypeDimExp(ptree = ptree)); - exp := Ceval.evalExp(exp, Ceval.EvalTarget.IGNORE_ERRORS()); - then - Dimension.fromExp(exp, dim.var); - - else dim; - end match; - end evaluateCallTypeDim; - - function buildParameterTree - input tuple> fnArgs; - input output ParameterTree ptree; - protected - Function fn; - list args; - Expression arg; - algorithm - if not ParameterTree.isEmpty(ptree) then - return; - end if; - - (fn, args) := fnArgs; - - for i in fn.inputs loop - arg :: args := args; - ptree := ParameterTree.add(ptree, InstNode.name(i), arg); - end for; - - // TODO: Add local variable bindings. - end buildParameterTree; - - function evaluateCallTypeDimExp - input Expression exp; - input ParameterTree ptree; - output Expression outExp; - algorithm - outExp := match exp - local - InstNode node; - Option oexp; - Expression e; - - case Expression.CREF(cref = ComponentRef.CREF(node = node, restCref = ComponentRef.EMPTY())) - algorithm - oexp := ParameterTree.getOpt(ptree, InstNode.name(node)); - - if isSome(oexp) then - SOME(outExp) := oexp; - // TODO: Apply subscripts. - end if; - then - outExp; - - else exp; - end match; - end evaluateCallTypeDimExp; - - function getSpecialReturnType - input Function fn; - input list args; - output Type ty; - algorithm - ty := match fn.path - case Absyn.IDENT("min") - then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); - case Absyn.IDENT("max") - then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); - case Absyn.IDENT("sum") - then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); - case Absyn.IDENT("product") - then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); - else - algorithm - Error.assertion(false, getInstanceName() + ": unhandled case for " + - Absyn.pathString(fn.path), sourceInfo()); - then - fail(); - end match; - end getSpecialReturnType; - - function typeArgs - input output Call call; - input Boolean replaceConstants; - input ExpOrigin.Type origin; - input SourceInfo info; - algorithm - call := match call - local - Expression arg; - Type arg_ty; - Variability arg_var; - list typedArgs; - list typedNamedArgs; - String name; - - case UNTYPED_CALL() - algorithm - typedArgs := {}; - for arg in call.arguments loop - (arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = replaceConstants); - typedArgs := (arg, arg_ty, arg_var) :: typedArgs; - end for; - - typedArgs := listReverse(typedArgs); - - typedNamedArgs := {}; - for narg in call.named_args loop - (name,arg) := narg; - (arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = replaceConstants); - typedNamedArgs := (name, arg, arg_ty, arg_var) :: typedNamedArgs; - end for; - - typedNamedArgs := listReverse(typedNamedArgs); - then - ARG_TYPED_CALL(call.ref, typedArgs, typedNamedArgs, call.call_scope); - end match; - end typeArgs; - - function checkMatchingFunctions - input Call call; - input SourceInfo info; - output MatchedFunction matchedFunc; - protected - list matchedFunctions, exactMatches; - Function func; - list allfuncs; - InstNode fn_node; - Integer numerr = Error.getNumErrorMessages(); - list errors; - algorithm - ErrorExt.setCheckpoint("NFCall:checkMatchingFunctions"); - matchedFunctions := {}; - - _ := match call - case ARG_TYPED_CALL(ref = ComponentRef.CREF(node = fn_node)) algorithm - allfuncs := Function.getCachedFuncs(fn_node); - matchedFunctions := Function.matchFunctions(allfuncs, call.arguments, call.named_args, info); - then - (); - end match; - - if listEmpty(matchedFunctions) then - // Don't show error messages for overloaded functions, it leaks - // implementation details and usually doesn't provide any more info than - // what the "no match found" error gives anyway. - if listLength(allfuncs) > 1 then - ErrorExt.rollBack("NFCall:checkMatchingFunctions"); - Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {typedString(call), candidateFuncListString(allfuncs)}, info); - - // Only show the error message for no matching functions if no other error - // was shown. - // functions that for some reason failed to match without giving any error. - elseif numerr == Error.getNumErrorMessages() then - ErrorExt.rollBack("NFCall:checkMatchingFunctions"); - Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {typedString(call), candidateFuncListString(allfuncs)}, info); - else - ErrorExt.delCheckpoint("NFCall:checkMatchingFunctions"); - end if; - - fail(); - end if; - - // If we have at least one matching function then we discard all error messages - // about matching. We have one matching func if we reach here. - ErrorExt.rollBack("NFCall:checkMatchingFunctions"); - - if listLength(matchedFunctions) == 1 then - matchedFunc ::_ := matchedFunctions; - - // Overwrite the actuall function name with the overload name - // for builtin functions. - if Function.isBuiltin(matchedFunc.func) then - func := matchedFunc.func; - func.path := Function.nameConsiderBuiltin(func); - matchedFunc.func := func; - end if; - return; - end if; - - if listLength(matchedFunctions) > 1 then - exactMatches := MatchedFunction.getExactMatches(matchedFunctions); - if listLength(exactMatches) == 1 then - matchedFunc ::_ := exactMatches; - - // Overwrite the actuall function name with the overload name - // for builtin functions. - if Function.isBuiltin(matchedFunc.func) then - func := matchedFunc.func; - func.path := Function.nameConsiderBuiltin(func); - matchedFunc.func := func; - end if; - return; - else - matchedFunctions := resolveOverloadedVsDefaultConstructorAmbigutiy(matchedFunctions); - if listLength(matchedFunctions) == 1 then - matchedFunc ::_ := matchedFunctions; - return; - else - Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_FUNCTIONS_NFINST, - {typedString(call), candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); - fail(); - end if; - end if; - end if; - - end checkMatchingFunctions; - - function resolveOverloadedVsDefaultConstructorAmbigutiy - input list matchedFunctions; - output list outMatches; - algorithm - // We have at least two exact matches. find the default constructor (if there is one) and remove it from the list - // so that it - // - doesn't cause ambiguities if there is only one other match left OR - // - it doesn't appear in the error messages in the case of more than one overloaded constructor matches. - outMatches := list(m for m guard not Function.isDefaultRecordConstructor(m.func) in matchedFunctions); - end resolveOverloadedVsDefaultConstructorAmbigutiy; - - function typeOf - input Call call; - output Type ty; - algorithm - ty := match call - case TYPED_CALL() then call.ty; - case TYPED_MAP_CALL() then call.ty; - else Type.UNKNOWN(); - end match; - end typeOf; - - function getType = typeOf; - - function setType - input output Call call; - input Type ty; - algorithm - call := match call - case TYPED_CALL() algorithm call.ty := ty; then call; - case TYPED_MAP_CALL() algorithm call.ty := ty; then call; - end match; - end setType; - - function variability - input Call call; - output Variability var; - algorithm - var := match call - local - Boolean var_set; - - case UNTYPED_CALL() - algorithm - var_set := true; - - if ComponentRef.isSimple(call.ref) then - var := match ComponentRef.firstName(call.ref) - case "change" then Variability.DISCRETE; - case "edge" then Variability.DISCRETE; - case "pre" then Variability.DISCRETE; - case "ndims" then Variability.PARAMETER; - case "cardinality" then Variability.PARAMETER; - else algorithm var_set := false; then Variability.CONTINUOUS; - end match; - end if; - - if not var_set then - var := Expression.variabilityList(call.arguments); - - for narg in call.named_args loop - var := Prefixes.variabilityMax(var, Expression.variability(Util.tuple22(narg))); - end for; - end if; - then - var; - - case UNTYPED_MAP_CALL() then Expression.variability(call.exp); - case TYPED_CALL() then call.var; - case TYPED_MAP_CALL() then call.var; - else algorithm - Error.assertion(false, getInstanceName() + " got untyped call", sourceInfo()); - then fail(); - end match; - end variability; - - function makeBuiltinCat - input Integer n; - input list args; - input list tys; - input SourceInfo info; - output Expression callExp; - output Type ty; - protected - Expression arg2; - list args2 = {}, res = {}; - list tys2 = tys, tys3; - list> dimsLst = {}; - list dims; - Type resTy = Type.UNKNOWN(), ty1, ty2, resTyToMatch; - TypeCheck.MatchKind mk; - Integer maxn, pos; - Dimension sumDim; - algorithm - Error.assertion(listLength(args)==listLength(tys) and listLength(args)>=1, getInstanceName() + " got wrong input sizes", sourceInfo()); - - // First: Get the number of dimensions and the element type - - for arg in args loop - ty::tys2 := tys2; - dimsLst := Type.arrayDims(ty) :: dimsLst; - if Type.isEqual(resTy, Type.UNKNOWN()) then - resTy := Type.arrayElementType(ty); - else - (,, ty1, mk) := TypeCheck.matchExpressions(Expression.INTEGER(0), Type.arrayElementType(ty), Expression.INTEGER(0), resTy); - if TypeCheck.isCompatibleMatch(mk) then - resTy := ty1; - end if; - end if; - end for; - - maxn := max(listLength(d) for d in dimsLst); - if maxn <> min(listLength(d) for d in dimsLst) then - Error.addSourceMessageAndFail(Error.NF_DIFFERENT_NUM_DIM_IN_ARGUMENTS, {stringDelimitList(list(String(listLength(d)) for d in dimsLst), ", "), "cat"}, info); - end if; - if n < 1 or n > maxn then - Error.addSourceMessageAndFail(Error.NF_CAT_WRONG_DIMENSION, {String(maxn), String(n)}, info); - end if; - - tys2 := tys; - tys3 := {}; - args2 := {}; - pos := listLength(args)+2; - - // Second: Try to match the element type of all the arguments - - for arg in args loop - ty::tys2 := tys2; - pos := pos-1; - ty2 := Type.setArrayElementType(ty, resTy); - (arg2, ty1, mk) := TypeCheck.matchTypes(ty, ty2, arg, allowUnknown = true); - if TypeCheck.isIncompatibleMatch(mk) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, {String(pos), "cat", "arg", Expression.toString(arg), Type.toString(ty), Type.toString(ty2)}, info); - end if; - args2 := arg2 :: args2; - tys3 := ty1 :: tys3; - end for; - - // Third: We now have matched the element types of all arguments - // Try to match the dimensions as well - - resTy := Type.UNKNOWN(); - tys2 := tys3; - - for arg in args2 loop - ty::tys2 := tys2; - - if Type.isEqual(resTy, Type.UNKNOWN()) then - resTy := ty; - else - (,, ty1, mk) := TypeCheck.matchExpressions(Expression.INTEGER(0), ty, Expression.INTEGER(0), resTy); - if TypeCheck.isCompatibleMatch(mk) then - resTy := ty1; - end if; - end if; - end for; - - // Got the supertype of the dimensions; trying to match all arguments - // with the concatenated dimension set to unknown. - - dims := Type.arrayDims(resTy); - resTyToMatch := Type.ARRAY(Type.arrayElementType(resTy), List.set(dims, n, Dimension.UNKNOWN())); - dims := list(listGet(lst, n) for lst in dimsLst); - sumDim := Dimension.fromInteger(0); - for d in dims loop - // Create the concatenated dimension - sumDim := Dimension.add(sumDim, d); - end for; - resTy := Type.ARRAY(Type.arrayElementType(resTy), List.set(Type.arrayDims(resTy), n, sumDim)); - tys2 := tys3; - tys3 := {}; - res := {}; - pos := listLength(args)+2; - - for arg in args2 loop - ty::tys2 := tys2; - pos := pos-1; - (arg2, ty1, mk) := TypeCheck.matchTypes(ty, resTyToMatch, arg, allowUnknown=true); - if TypeCheck.isIncompatibleMatch(mk) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, {String(pos), "cat", "arg", Expression.toString(arg), Type.toString(ty), Type.toString(resTyToMatch)}, info); - end if; - res := arg2 :: res; - tys3 := ty1 :: tys3; - end for; - - // We have all except dimension n having equal sizes; with matching types - - ty := resTy; - callExp := Expression.CALL(makeBuiltinCall2(NFBuiltinFuncs.CAT, Expression.INTEGER(n)::res, resTy)); - end makeBuiltinCat; - -protected - function matchFunction - input Function func; - input list args; - input list named_args; - input SourceInfo info; - output list out_args; - output Boolean matched; - output FunctionMatchKind matchKind; - algorithm - (out_args, matched) := Function.fillArgs(args, named_args, func, info); - if matched then - (out_args, matched, matchKind) := Function.matchArgs(func, out_args, info); - end if; - end matchFunction; - - public - function arguments - input Call call; - output list arguments; - algorithm - arguments := match call - case UNTYPED_CALL() then call.arguments; - case TYPED_CALL() then call.arguments; - end match; - end arguments; - - function compare - input Call call1; - input Call call2; - output Integer comp; - algorithm - comp := match (call1, call2) - case (UNTYPED_CALL(), UNTYPED_CALL()) - then ComponentRef.compare(call1.ref, call2.ref); - - case (TYPED_CALL(), TYPED_CALL()) - then Absyn.pathCompare(Function.name(call1.fn), Function.name(call2.fn)); - - case (UNTYPED_CALL(), TYPED_CALL()) - then Absyn.pathCompare(ComponentRef.toPath(call1.ref), Function.name(call2.fn)); - - case (TYPED_CALL(), UNTYPED_CALL()) - then Absyn.pathCompare(Function.name(call1.fn), ComponentRef.toPath(call2.ref)); - end match; - - if comp == 0 then - comp := Expression.compareList(arguments(call1), arguments(call2)); - end if; - end compare; - - function toDAE - input Call call; - output DAE.Exp daeCall; - algorithm - daeCall := match call - - case TYPED_CALL() - then DAE.CALL(Function.nameConsiderBuiltin(call.fn), - list(Expression.toDAE(e) for e in call.arguments), - CallAttributes.toDAE(call.attributes)); - - case TYPED_MAP_CALL() - then DAE.REDUCTION( - DAE.REDUCTIONINFO(Function.name(NFBuiltinFuncs.ARRAY_FUNC), Absyn.COMBINE(), Type.toDAE(call.ty), NONE(), String(Util.getTempVariableIndex()), String(Util.getTempVariableIndex()), NONE()), - Expression.toDAE(call.exp), - list(iteratorToDAE(iter) for iter in call.iters)); - - else - algorithm - Error.assertion(false, getInstanceName() + " got untyped call", sourceInfo()); - then - fail(); - end match; - end toDAE; - - function iteratorToDAE - input tuple iter; - output DAE.ReductionIterator diter; - protected - InstNode iter_node; - Expression iter_range; - Component c; - Binding b; - algorithm - (iter_node, iter_range) := iter; - diter := DAE.REDUCTIONITER(InstNode.name(iter_node), Expression.toDAE(iter_range), NONE(), - Type.toDAE(Expression.typeOf(iter_range))); - end iteratorToDAE; - - function toString - input Call call; - output String str; - protected - String name, arg_str,c; - Expression argexp; - list iters; - algorithm - str := match call - case UNTYPED_CALL() - algorithm - name := ComponentRef.toString(call.ref); - arg_str := stringDelimitList(list(Expression.toString(arg) for arg in call.arguments), ", "); - then - name + "(" + arg_str + ")"; - - case ARG_TYPED_CALL() - algorithm - name := ComponentRef.toString(call.ref); - arg_str := stringDelimitList(list(Expression.toString(Util.tuple31(arg)) for arg in call.arguments), ", "); - for arg in call.named_args loop - c := if arg_str == "" then "" else ", "; - arg_str := arg_str + c + Util.tuple41(arg) + " = " + Expression.toString(Util.tuple42(arg)); - end for; - then - name + "(" + arg_str + ")"; - - case UNTYPED_MAP_CALL() - algorithm - name := Absyn.pathString(Function.name(NFBuiltinFuncs.ARRAY_FUNC)); - arg_str := Expression.toString(call.exp); - then - name + "(" + arg_str + ")"; - - case TYPED_CALL() - algorithm - name := Absyn.pathString(Function.name(call.fn)); - arg_str := stringDelimitList(list(Expression.toString(arg) for arg in call.arguments), ", "); - then - name + "(" + arg_str + ")"; - - case TYPED_MAP_CALL() - algorithm - name := Absyn.pathString(Function.name(NFBuiltinFuncs.ARRAY_FUNC)); - arg_str := Expression.toString(call.exp); - c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " + - Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", "); - then - name + "(" + arg_str + " for " + c + ")"; - - end match; - end toString; - - function typedString - "Like toString, but prefixes each argument with its type as a comment." - input Call call; - output String str; - protected - String name, arg_str,c; - Expression argexp; - algorithm - str := match call - case ARG_TYPED_CALL() - algorithm - name := ComponentRef.toString(call.ref); - arg_str := stringDelimitList(list("/*" + Type.toString(Util.tuple32(arg)) + "*/ " + - Expression.toString(Util.tuple31(arg)) for arg in call.arguments), ", "); - - for arg in call.named_args loop - c := if arg_str == "" then "" else ", "; - arg_str := arg_str + c + Util.tuple41(arg) + " = /*" + - Type.toString(Util.tuple43(arg)) + "*/ " + Expression.toString(Util.tuple42(arg)); - end for; - then - name + "(" + arg_str + ")"; - - case TYPED_CALL() - algorithm - name := Absyn.pathString(Function.name(call.fn)); - arg_str := stringDelimitList(list(Expression.toStringTyped(arg) for arg in call.arguments), ", "); - then - name + "(" + arg_str + ")"; - - else toString(call); - end match; - end typedString; - - function typedFunction - input Call call; - output Function fn; - algorithm - fn := match call - case TYPED_CALL() then call.fn; - case TYPED_MAP_CALL() then NFBuiltinFuncs.ARRAY_FUNC; - else - algorithm - Error.assertion(false, getInstanceName() + " got untyped function", sourceInfo()); - then - fail(); - end match; - end typedFunction; - - function makeSizeExp - input list posArgs; - input list namedArgs; - input SourceInfo info; - output Expression callExp; - protected - Integer argc = listLength(posArgs); - Expression arg1, arg2; - algorithm - if not listEmpty(namedArgs) then - for arg in namedArgs loop - Error.addSourceMessage(Error.NO_SUCH_PARAMETER, - {"size", Util.tuple21(arg)}, info); - end for; - fail(); - end if; - - callExp := match posArgs - case {arg1} then Expression.SIZE(arg1, NONE()); - case {arg1, arg2} then Expression.SIZE(arg1, SOME(arg2)); - else - algorithm - Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {"size" + List.toString(posArgs, Expression.toString, "", "(", ", ", ")", true), - "size(Any[:, ...]) => Integer[:]\n size(Any[:, ...], Integer) => Integer"}, info); - then - fail(); - end match; - end makeSizeExp; - - function makeArrayExp - input list posArgs; - input list namedArgs; - input SourceInfo info; - output Expression arrayExp; - protected - ComponentRef fn_ref; - list args; - list named_args; - Type ty; - algorithm - // array doesn't have any named parameters. - if not listEmpty(namedArgs) then - for arg in namedArgs loop - Error.addSourceMessage(Error.NO_SUCH_PARAMETER, - {"array", Util.tuple21(arg)}, info); - end for; - fail(); - end if; - - // array can take any number of arguments, but needs at least one. - if listEmpty(posArgs) then - Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {"array" + List.toString(posArgs, Expression.toString, "", "(", ", ", ")", true), - "array(Any, Any, ...) => Any[:]"}, info); - fail(); - end if; - - arrayExp := Expression.ARRAY(Type.UNKNOWN(), posArgs); - end makeArrayExp; - - function makeBuiltinCall - "Creates a call to a builtin function, given a Function and a list of - argument expressions." - input Function func; - input list args; - input Variability var = Variability.CONSTANT; - output Call call; - algorithm - call := TYPED_CALL(func, func.returnType, var, args, - CallAttributes.CALL_ATTR(func.returnType, false, true, false, false, - DAE.NO_INLINE(), DAE.NO_TAIL())); - end makeBuiltinCall; - - function makeBuiltinCall2 - "Creates a call to a builtin function, given a Function, list of - argument expressions and a return type. Used for builtin functions defined with no return type." - input Function func; - input list args; - input Type returnType; // you can use func.returnType if the buiting function is defined with the corrrect type. - input Variability var = Variability.CONSTANT; // :( We don't have variability info in the arg expressions. - output Call call; - algorithm - call := TYPED_CALL(func, returnType, var, args, - CallAttributes.CALL_ATTR(returnType, false, true, false, false, - DAE.NO_INLINE(), DAE.NO_TAIL())); - end makeBuiltinCall2; - - function typeStringCall - input Call inCall; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type outType; - output Variability var; - protected - Call call; - Function operfn; - list args; - list named_args; - Type argty; - Expression exp; - ComponentRef fn_ref; - list candidates; - Boolean matched; - InstNode recopnode; - FunctionMatchKind matchKind; - MatchedFunction matchedFunc; - list matchedFunctions, exactMatches; - algorithm - call as ARG_TYPED_CALL(_, args, named_args) := typeNormalCall(inCall, origin, info); - (exp, argty, _)::_ := args; - - if Type.isComplex(Type.arrayElementType(argty)) then - Type.COMPLEX(cls=recopnode) := argty; - - // This will fail if it can't find the function. - fn_ref := Function.lookupFunctionSimple("'String'", recopnode); - fn_ref := Function.instFuncRef(fn_ref, InstNode.info(recopnode)); - candidates := Call.typeCachedFunctions(fn_ref); - for fn in candidates loop - TypeCheck.checkValidOperatorOverload("'String'", fn, recopnode); - end for; - - matchedFunctions := Function.matchFunctionsSilent(candidates, args, named_args, info); - exactMatches := MatchedFunction.getExactMatches(matchedFunctions); - if listEmpty(exactMatches) then - Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {typedString(call), candidateFuncListString(candidates)}, info); - fail(); - end if; - - if listLength(exactMatches) == 1 then - matchedFunc ::_ := exactMatches; - outType := Function.returnType(matchedFunc.func); - callExp := Expression.CALL(Call.TYPED_CALL(matchedFunc.func, outType, Variability.CONSTANT, list(Util.tuple31(a) for a in matchedFunc.args) - , CallAttributes.CALL_ATTR( - outType, false, false, false, false, DAE.NO_INLINE(),DAE.NO_TAIL()) - ) - ); - - return; - else - Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_FUNCTIONS_NFINST, - {typedString(call), candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); - fail(); - end if; - - end if; - - call := matchTypedNormalCall(call, origin, info); - outType := getType(call); - var := variability(call); - callExp := Expression.CALL(call); - end typeStringCall; - - function isExternal + function isRecordConstructor input Call call; - output Boolean isExternal; + output Boolean isConstructor; algorithm - isExternal := match call - case UNTYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref))); - case ARG_TYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref))); - case TYPED_CALL() then Function.isExternal(call.fn); + isConstructor := match call + case UNTYPED_CALL() + then SCode.isRecord(InstNode.definition(ComponentRef.node(call.ref))); + case TYPED_CALL() + then SCode.isRecord(InstNode.definition(call.fn.node)); else false; end match; - end isExternal; - -protected - function typeDiscreteCall - "Types a function call that can be typed normally, but which always has - discrete variability regardless of the variability of the arguments." - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.DISCRETE; - protected - Call argtycall; - Function fn; - list args; - TypedArg start,interval; - algorithm - argtycall := typeMatchNormalCall(call, origin, info); - ty := getType(argtycall); - callExp := Expression.CALL(unboxArgs(argtycall)); - end typeDiscreteCall; - - function typeNdimsCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty = Type.INTEGER(); - output Variability variability = Variability.PARAMETER; - protected - list args; - list named_args; - Type arg_ty; - algorithm - UNTYPED_CALL(arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"ndims", Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "ndims(Any) => Integer"}, info); - fail(); - end if; - - // The number of dimensions an expression has is always known, - // so we might as well evaluate the ndims call here. - (_, arg_ty, _) := Typing.typeExp(listHead(args), origin, info); - callExp := Expression.INTEGER(Type.dimensionCount(arg_ty)); - end typeNdimsCall; - - function typePreCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability = Variability.DISCRETE; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Variability var; - Function fn; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Any) => Any"}, info); - end if; - - // pre/change may not be used in a function context. - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); - end if; - - (arg, ty, var) := Typing.typeExp(listHead(args), origin, info); - - if not Expression.isCref(arg) then - Error.addSourceMessage(Error.ARGUMENT_MUST_BE_VARIABLE, - {"First", ComponentRef.toString(fn_ref), ""}, info); - fail(); - end if; - - if var == Variability.CONTINUOUS then - Error.addSourceMessageAndFail(Error.INVALID_ARGUMENT_VARIABILITY, - {"1", ComponentRef.toString(fn_ref), Prefixes.variabilityString(Variability.DISCRETE), - Expression.toString(arg), Prefixes.variabilityString(var)}, info); - end if; - - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, var)); - end typePreCall; - - function typeChangeCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability = Variability.DISCRETE; - algorithm - (callExp, ty, variability) := typePreCall(call, origin, info); - ty := Type.setArrayElementType(ty, Type.BOOLEAN()); - end typeChangeCall; + end isRecordConstructor; - function typeDerCall + function inlineType input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Function fn; - Type ety; + output DAE.InlineType inlineTy; algorithm - // der may not be used in a function context. - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"der"}, info); - fail(); - end if; - - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"der", Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "der(Real) => Real"}, info); - end if; - - {arg} := args; - (arg, ty, variability) := Typing.typeExp(arg, origin, info); - - ety := Type.arrayElementType(ty); - - if Type.isInteger(ety) then - ty := Type.setArrayElementType(ty, Type.REAL()); - arg := Expression.typeCastElements(arg, Type.REAL()); - elseif not Type.isReal(ety) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), - Type.toString(ty), "Real"}, info); - end if; - - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeDerCall; + inlineTy := match call + case TYPED_CALL(attributes = CallAttributes.CALL_ATTR(inlineType = inlineTy)) + then inlineTy; + else DAE.InlineType.NO_INLINE(); + end match; + end inlineType; - function typeDiagonalCall + function typedFunction input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Dimension dim; - Function fn; + output Function fn; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"diagonal", Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "diagonal(Any[n]) => Any[n, n]"}, info); - end if; - - (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); - - ty := match ty - case Type.ARRAY(dimensions = {dim}) - then Type.ARRAY(ty.elementType, {dim, dim}); - + fn := match call + case TYPED_CALL() then call.fn; + case TYPED_MAP_CALL() then NFBuiltinFuncs.ARRAY_FUNC; else algorithm - Error.addSourceMessage(Error.ARG_TYPE_MISMATCH, - {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), - Type.toString(ty), "Any[:]"}, info); + Error.assertion(false, getInstanceName() + " got untyped function", sourceInfo()); then fail(); end match; + end typedFunction; - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeDiagonalCall; - - function typeEdgeCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability = Variability.DISCRETE; - protected - Call argtycall; - Function fn; - list args; - TypedArg arg; - InstNode fn_node; - CallAttributes ca; - algorithm - // edge may not be used in a function context. - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessage(Error.EXP_INVALID_IN_FUNCTION, {"edge"}, info); - fail(); - end if; - - argtycall as ARG_TYPED_CALL(ComponentRef.CREF(node = fn_node), args, _) := typeNormalCall(call, origin, info); - argtycall := matchTypedNormalCall(argtycall, origin, info); - ty := getType(argtycall); - callExp := Expression.CALL(unboxArgs(argtycall)); - - {arg} := args; - if not Expression.isCref(Util.tuple31(arg)) then - Error.addSourceMessage(Error.ARGUMENT_MUST_BE_VARIABLE, - {"First", "edge", ""}, info); - fail(); - end if; - end typeEdgeCall; - - function typeMinMaxCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var; - protected - Call argtycall; - algorithm - argtycall := typeMatchNormalCall(call, origin, info); - argtycall := unboxArgs(argtycall); - ty := getType(argtycall); - var := variability(argtycall); - callExp := Expression.CALL(argtycall); - // TODO: check basic type in two argument overload. - // check arrays of simple types in one argument overload. - // fix return type. - end typeMinMaxCall; - - function typeSumProductCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var; - protected - Call argtycall; - algorithm - // TODO: Rewrite this whole thing. - argtycall := typeMatchNormalCall(call, origin, info); - argtycall := unboxArgs(argtycall); - ty := getType(argtycall); - var := variability(argtycall); - callExp := Expression.CALL(argtycall); - end typeSumProductCall; - - function typeSmoothCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg1, arg2; - Type ty1, ty2; - Variability var; - Function fn; - TypeCheck.MatchKind mk; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - // smooth doesn't have any named parameters. - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"smooth", Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 2 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "smooth(Integer, Any) => Any"}, info); - end if; - - {arg1, arg2} := args; - (arg1, ty1, var) := Typing.typeExp(arg1, origin, info); - (arg2, ty2, variability) := Typing.typeExp(arg2, origin, info); - - // First argument must be Integer. - if not Type.isInteger(ty1) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg1), - Type.toString(ty1), "Integer"}, info); - end if; - - // First argument must be a parameter expression. - if var > Variability.PARAMETER then - Error.addSourceMessageAndFail(Error.INVALID_ARGUMENT_VARIABILITY, - {"1", ComponentRef.toString(fn_ref), Prefixes.variabilityString(Variability.PARAMETER), - Expression.toString(arg1), Prefixes.variabilityString(variability)}, info); - end if; - - // Second argument must be Real, array of allowed expressions or record - // containing only components of allowed expressions. - // TODO: Also handle records here. - (arg2, ty, mk) := TypeCheck.matchTypes(ty2, Type.setArrayElementType(ty2, Type.REAL()), arg2, true); - - if not TypeCheck.isValidArgumentMatch(mk) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {"2", ComponentRef.toString(fn_ref), "", Expression.toString(arg2), - Type.toString(ty2), "Real\n Real[:, ...]\n Real record\n Real record[:, ...]"}, info); - end if; - - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg1, arg2}, ty, var)); - end typeSmoothCall; - - function typeFillCall + function arguments input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression fill_arg; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - // fill doesn't have any named parameters. - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"fill", Util.tuple21(listHead(named_args))}, info); - end if; - - // fill can take any number of arguments, but needs at least two. - if listLength(args) < 2 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "fill(Any, Integer, ...) => Any[:, ...]"}, info); - end if; - - fill_arg :: args := args; - - // Type the first argument, which is the fill value. - (fill_arg, ty, _) := Typing.typeExp(fill_arg, origin, info); - (callExp, ty, variability) := typeFillCall2(fn_ref, ty, fill_arg, args, origin, info); - end typeFillCall; - - function typeFillCall2 - input ComponentRef fnRef; - input Type fillType; - input Expression fillArg; - input list dimensionArgs; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability = Variability.CONSTANT; - protected - Expression fill_arg; - list ty_args; - Variability arg_var; - Type arg_ty; - Function fn; - list dims; + output list arguments; algorithm - ty_args := {fillArg}; - dims := {}; - - // Type the dimension arguments. - for arg in dimensionArgs loop - (arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info); - - if arg_var <= Variability.STRUCTURAL_PARAMETER then - arg := Ceval.evalExp(arg); - arg_ty := Expression.typeOf(arg); - end if; - - // Each dimension argument must be an Integer expression. - if not Type.isInteger(arg_ty) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {intString(listLength(ty_args) + 1), ComponentRef.toString(fnRef), "", - Expression.toString(arg), Type.toString(arg_ty), "Integer"}, info); - end if; - - variability := Prefixes.variabilityMax(variability, arg_var); - ty_args := arg :: ty_args; - dims := Dimension.fromExp(arg, arg_var) :: dims; - end for; - - ty_args := listReverseInPlace(ty_args); - dims := listReverseInPlace(dims); - - {fn} := typeCachedFunctions(fnRef); - ty := Type.liftArrayLeftList(fillType, dims); - - if variability <= Variability.STRUCTURAL_PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) == 0 then - callExp := Ceval.evalBuiltinFill(ty_args); - else - callExp := Expression.CALL(makeBuiltinCall2(NFBuiltinFuncs.FILL_FUNC, ty_args, ty, variability)); - end if; - end typeFillCall2; + arguments := match call + case UNTYPED_CALL() then call.arguments; + case TYPED_CALL() then call.arguments; + end match; + end arguments; - function typeZerosOnesCall + function toRecordExpression input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression fill_arg; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - // zeros/ones doesn't have any named parameters. - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; - - // zeros/ones can take any number of arguments, but needs at least one. - if listEmpty(args) then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Integer, ...) => Integer[:, ...]"}, info); - end if; - - if ComponentRef.firstName(fn_ref) == "ones" then - fill_arg := Expression.INTEGER(1); - else - fill_arg := Expression.INTEGER(0); - end if; - - (callExp, ty, variability) := typeFillCall2(fn_ref, Type.INTEGER(), fill_arg, args, origin, info); - end typeZerosOnesCall; + input Type ty; + output Expression exp; + algorithm + exp := match call + case TYPED_CALL() + then Expression.RECORD(Function.name(call.fn), ty, call.arguments); + end match; + end toRecordExpression; - function typeScalarCall + function toString input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; + output String str; protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Variability var; - Function fn; + String name, arg_str,c; + Expression argexp; + list iters; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + str := match call + case UNTYPED_CALL() + algorithm + name := ComponentRef.toString(call.ref); + arg_str := stringDelimitList(list(Expression.toString(arg) for arg in call.arguments), ", "); + then + name + "(" + arg_str + ")"; - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + case ARG_TYPED_CALL() + algorithm + name := ComponentRef.toString(call.ref); + arg_str := stringDelimitList(list(Expression.toString(Util.tuple31(arg)) for arg in call.arguments), ", "); + for arg in call.named_args loop + c := if arg_str == "" then "" else ", "; + arg_str := arg_str + c + Util.tuple41(arg) + " = " + Expression.toString(Util.tuple42(arg)); + end for; + then + name + "(" + arg_str + ")"; - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "scalar(Any[1, ...]) => Any"}, info); - end if; + case UNTYPED_MAP_CALL() + algorithm + name := Absyn.pathString(Function.name(NFBuiltinFuncs.ARRAY_FUNC)); + arg_str := Expression.toString(call.exp); + then + name + "(" + arg_str + ")"; - (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + case TYPED_CALL() + algorithm + name := Absyn.pathString(Function.name(call.fn)); + arg_str := stringDelimitList(list(Expression.toString(arg) for arg in call.arguments), ", "); + then + name + "(" + arg_str + ")"; - // scalar requires all dimensions of the array to be 1. - for dim in Type.arrayDims(ty) loop - if Dimension.isKnown(dim) and not Dimension.size(dim) == 1 then - Error.addSourceMessageAndFail(Error.INVALID_ARRAY_DIM_IN_SCALAR_OP, - {Type.toString(ty)}, info); - end if; - end for; + case TYPED_MAP_CALL() + algorithm + name := Absyn.pathString(Function.name(NFBuiltinFuncs.ARRAY_FUNC)); + arg_str := Expression.toString(call.exp); + c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " + + Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", "); + then + name + "(" + arg_str + " for " + c + ")"; - ty := Type.arrayElementType(ty); - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeScalarCall; + end match; + end toString; - function typeVectorCall + function typedString + "Like toString, but prefixes each argument with its type as a comment." input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; + output String str; protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Variability var; - Function fn; - Integer dim_size = -1, i = 1; + String name, arg_str,c; + Expression argexp; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + str := match call + case ARG_TYPED_CALL() + algorithm + name := ComponentRef.toString(call.ref); + arg_str := stringDelimitList(list("/*" + Type.toString(Util.tuple32(arg)) + "*/ " + + Expression.toString(Util.tuple31(arg)) for arg in call.arguments), ", "); - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "vector(Any) => Any[:]\n vector(Any[:, ...]) => Any[:]"}, info); - end if; + for arg in call.named_args loop + c := if arg_str == "" then "" else ", "; + arg_str := arg_str + c + Util.tuple41(arg) + " = /*" + + Type.toString(Util.tuple43(arg)) + "*/ " + Expression.toString(Util.tuple42(arg)); + end for; + then + name + "(" + arg_str + ")"; - (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + case TYPED_CALL() + algorithm + name := Absyn.pathString(Function.name(call.fn)); + arg_str := stringDelimitList(list(Expression.toStringTyped(arg) for arg in call.arguments), ", "); + then + name + "(" + arg_str + ")"; - // vector requires that at most one dimension is > 1, and that dimension - // determines the type of the vector call. - for dim in Type.arrayDims(ty) loop - if Dimension.isKnown(dim) then - if Dimension.size(dim) > 1 then - if dim_size == -1 then - dim_size := Dimension.size(dim); - else - Error.addSourceMessageAndFail(Error.NF_VECTOR_INVALID_DIMENSIONS, - {Type.toString(ty), toString(call)}, info); - end if; - end if; - end if; + else toString(call); + end match; + end typedString; - i := i + 1; - end for; + function toDAE + input Call call; + output DAE.Exp daeCall; + algorithm + daeCall := match call + case TYPED_CALL() + then DAE.CALL( + Function.nameConsiderBuiltin(call.fn), + list(Expression.toDAE(e) for e in call.arguments), + CallAttributes.toDAE(call.attributes)); - // If the argument was scalar or an array where all dimensions where 1, set - // the dimension size to 1. - if dim_size == -1 then - dim_size := 1; - end if; + case TYPED_MAP_CALL() + then DAE.REDUCTION( + DAE.REDUCTIONINFO( + Function.name(NFBuiltinFuncs.ARRAY_FUNC), + Absyn.COMBINE(), + Type.toDAE(call.ty), + NONE(), + String(Util.getTempVariableIndex()), + String(Util.getTempVariableIndex()), + NONE()), + Expression.toDAE(call.exp), + list(iteratorToDAE(iter) for iter in call.iters)); - ty := Type.ARRAY(Type.arrayElementType(ty), {Dimension.fromInteger(dim_size)}); - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeVectorCall; + else + algorithm + Error.assertion(false, getInstanceName() + " got untyped call", sourceInfo()); + then + fail(); + end match; + end toDAE; - function typeMatrixCall - input Call call; - input ExpOrigin.Type origin; +protected + function instNormalCall + input Absyn.ComponentRef functionName; + input Absyn.FunctionArgs functionArgs; + input InstNode scope; input SourceInfo info; output Expression callExp; - output Type ty; - output Variability variability; protected ComponentRef fn_ref; list args; list named_args; - Expression arg; - Variability var; - Function fn; - list dims; - Dimension dim1, dim2; - Integer i; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + (args, named_args) := instArgs(functionArgs, scope, info); - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "vector(Any) => Any[:]\n vector(Any[:, ...]) => Any[:]"}, info); - end if; + callExp := match Absyn.crefFirstIdent(functionName) + // size creates Expression.SIZE instead of Expression.CALL. + case "size" then BuiltinCall.makeSizeExp(args, named_args, info); + // array() call with no iterators creates Expression.ARRAY instead of Expression.CALL. + // If it had iterators then it will not reach here. The args would have been parsed to + // Absyn.FOR_ITER_FARG and that is handled in instIteratorCall. + case "array" then BuiltinCall.makeArrayExp(args, named_args, info); + else algorithm + (fn_ref, _, _) := Function.instFunc(functionName,scope,info); + then + Expression.CALL(UNTYPED_CALL(fn_ref, args, named_args, scope)); + end match; + end instNormalCall; - (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); - dims := Type.arrayDims(ty); + function instArgs + input Absyn.FunctionArgs args; + input InstNode scope; + input SourceInfo info; + output list posArgs; + output list namedArgs; + algorithm + (posArgs, namedArgs) := match args + case Absyn.FUNCTIONARGS() + algorithm + posArgs := list(Inst.instExp(a, scope, info) for a in args.args); + namedArgs := list(instNamedArg(a, scope, info) for a in args.argNames); + then + (posArgs, namedArgs); - dims := match listLength(dims) - case 0 then {Dimension.fromInteger(1), Dimension.fromInteger(1)}; - case 1 then {listHead(dims), Dimension.fromInteger(1)}; - case 2 then dims; else algorithm - // matrix requires all but the first two dimensions to have size 1. - dim1 :: dim2 :: dims := dims; - i := 3; - - for dim in dims loop - if Dimension.isKnown(dim) and Dimension.size(dim) > 1 then - Error.addSourceMessageAndFail(Error.INVALID_ARRAY_DIM_IN_CONVERSION_OP, - {String(i), "matrix", "1", Dimension.toString(dim)}, info); - end if; - - i := i + 1; - end for; + Error.assertion(false, getInstanceName() + " got unknown function args", sourceInfo()); then - {dim1, dim2}; + fail(); end match; + end instArgs; - ty := Type.ARRAY(Type.arrayElementType(ty), dims); - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeMatrixCall; + function instNamedArg + input Absyn.NamedArg absynArg; + input InstNode scope; + input SourceInfo info; + output NamedArg arg; + protected + String name; + Absyn.Exp exp; + algorithm + Absyn.NAMEDARG(argName = name, argValue = exp) := absynArg; + arg := (name, Inst.instExp(exp, scope, info)); + end instNamedArg; - function typeCatCall - input Call call; - input ExpOrigin.Type origin; + function instIteratorCall + input Absyn.ComponentRef functionName; + input Absyn.FunctionArgs functionArgs; + input InstNode scope; input SourceInfo info; output Expression callExp; - output Type ty; - output Variability variability; protected - ComponentRef fn_ref; - list args, res; - list named_args; - list tys; - Expression arg; - Variability var; - TypeCheck.MatchKind mk; - Function fn; - Integer n; + ComponentRef fn_ref, arr_fn_ref; + Expression exp; + list> iters; + Call call; + Boolean is_builtin_reduction, is_array; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + (is_builtin_reduction, is_array) := match Absyn.crefFirstIdent(functionName) + case "$array" then (false, true); + case "array" then (false, true); + case "min" then (true, false); + case "max" then (true, false); + case "sum" then (true, false); + case "product" then (true, false); + else (false, false); + end match; - if listLength(args) < 2 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "cat(Integer, Any[:,:], ...) => Any[:]"}, info); - end if; + (exp, iters) := instIteratorCallArgs(functionArgs, scope, info); - arg::args := args; + // If it is one of the builtin functions above the call operates as a "reduction" + // (think of it like just a call to the overload of the function that takes array as argument.) + // We handle it by making a call to the builtin function with an array as argument. + // Which is valid since all these builtin functions accept array arguments anyway. + if is_builtin_reduction then + // start by making an array map call. + call := UNTYPED_MAP_CALL(exp, iters); - (arg, ty, variability) := Typing.typeExp(arg, origin, info); - (arg, ty, mk) := TypeCheck.matchTypes(ty, Type.INTEGER(), arg); + // wrap the array call in the given function + // e.g. sum(array(i for i in ...)). + fn_ref := Function.instFunc(functionName, scope, info); + call := UNTYPED_CALL(fn_ref, {Expression.CALL(call)}, {}, scope); + else + // Otherwise, make an array call with the original function call as an argument. + // But only if the original function is not array() itself. + // e.g. Change myfunc(i for i in ...) TO array(myfunc(i) for i in ...). + if not is_array then + fn_ref := Function.instFunc(functionName, scope, info); + call := UNTYPED_CALL(fn_ref, {exp}, {}, scope); + exp := Expression.CALL(call); + end if; - if variability > Variability.PARAMETER then - Error.addSourceMessageAndFail(Error.NF_CAT_FIRST_ARG_EVAL, {Expression.toString(arg), Prefixes.variabilityString(variability)}, info); + call := UNTYPED_MAP_CALL(exp, iters); end if; - Expression.INTEGER(n) := Ceval.evalExp(arg, Ceval.EvalTarget.GENERIC(info)); - res := {}; - tys := {}; - - for a in args loop - (arg, ty, var) := Typing.typeExp(a, origin, info); - variability := Prefixes.variabilityMax(var, variability); - res := arg :: res; - tys := ty :: tys; - end for; + callExp := Expression.CALL(call); + end instIteratorCall; - (callExp, ty) := makeBuiltinCat(n, listReverse(res), listReverse(tys), info); + function instIteratorCallArgs + input Absyn.FunctionArgs args; + input InstNode scope; + input SourceInfo info; + output Expression exp; + output list> iters; + algorithm + _ := match args + local + InstNode for_scope; - end typeCatCall; + case Absyn.FOR_ITER_FARG() + algorithm + (for_scope, iters) := instIterators(args.iterators, scope, info); + exp := Inst.instExp(args.exp, for_scope, info); + then + (); + end match; + end instIteratorCallArgs; - function typeSymmetricCall - input Call call; - input ExpOrigin.Type origin; + function instIterators + input list inIters; + input InstNode scope; input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; + output InstNode outScope = scope; + output list> outIters = {}; protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Function fn; + Expression range; + InstNode iter; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"symmetric", Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "symmetric(Any[n, n]) => Any[n, n]"}, info); - end if; - - (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); - - if not Type.isSquareMatrix(ty) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), - Type.toString(ty), "Any[n, n]"}, info); - end if; + for i in inIters loop + range := Inst.instExp(Util.getOption(i.range), outScope, info); + (outScope, iter) := Inst.addIteratorToScope(i.name, outScope, info); + outIters := (iter, range) :: outIters; + end for; - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeSymmetricCall; + outIters := listReverse(outIters); + end instIterators; - function typeTransposeCall - input Call call; + function typeMapIteratorCall + input output Call call; input ExpOrigin.Type origin; input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; + output Type ty; + output Variability variability; protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Dimension dim1, dim2; - list rest_dims; - Function fn; + Expression arg, range; + Type iter_ty; + Binding binding; + Variability iter_var; + InstNode iter; + list dims = {}; + list> iters = {}; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"transpose", Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "transpose(Any[n, m, ...]) => Any[m, n, ...]"}, info); - end if; + (call, ty, variability) := match call + // This is always a call to the function array()/$array(). See instIteratorCall. + // Other mapping function calls are already wrapped by array() at this point. + case UNTYPED_MAP_CALL() + algorithm + variability := Variability.CONSTANT; - (arg, ty, variability) := Typing.typeExp(listHead(args), origin, info); + for i in call.iters loop + (iter, range) := i; + (range, iter_ty, iter_var) := Typing.typeIterator(iter, range, origin, structural = false); + dims := listAppend(Type.arrayDims(iter_ty), dims); + variability := Variability.variabilityMax(variability, iter_var); + iters := (iter, range) :: iters; + end for; + iters := listReverseInPlace(iters); - ty := match ty - case Type.ARRAY(dimensions = dim1 :: dim2 :: rest_dims) - then Type.ARRAY(ty.elementType, dim2 :: dim1 :: rest_dims); + (arg, ty) := Typing.typeExp(call.exp, origin, info); + ty := Type.liftArrayLeftList(ty, dims); + then + (TYPED_MAP_CALL(ty, variability, arg, iters), ty, variability); else algorithm - Error.addSourceMessage(Error.ARG_TYPE_MISMATCH, - {"1", ComponentRef.toString(fn_ref), "", Expression.toString(arg), - Type.toString(ty), "Any[:, :, ...]"}, info); + Error.assertion(false, getInstanceName() + " got invalid function call expression", sourceInfo()); then fail(); end match; + end typeMapIteratorCall; - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeTransposeCall; - - function typeCardinalityCall - input Call call; + function typeArgs + input output Call call; + input Boolean replaceConstants; input ExpOrigin.Type origin; input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.PARAMETER; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Function fn; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Connector) => Integer"}, info); - end if; - - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); - end if; + call := match call + local + Expression arg; + Type arg_ty; + Variability arg_var; + list typedArgs; + list typedNamedArgs; + String name; - (arg, ty) := Typing.typeExp(listHead(args), origin, info); + case UNTYPED_CALL() + algorithm + typedArgs := {}; + for arg in call.arguments loop + (arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = replaceConstants); + typedArgs := (arg, arg_ty, arg_var) :: typedArgs; + end for; - if not Expression.isCref(arg) then - Error.addSourceMessageAndFail(Error.ARGUMENT_MUST_BE_VARIABLE, - {"First", ComponentRef.toString(fn_ref), ""}, info); - end if; + typedArgs := listReverse(typedArgs); - if not Type.isConnector(ty) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {"1", ComponentRef.toString(fn_ref), "", - Expression.toString(arg), Type.toString(ty), "connector"}, info); - end if; + typedNamedArgs := {}; + for narg in call.named_args loop + (name,arg) := narg; + (arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = replaceConstants); + typedNamedArgs := (name, arg, arg_ty, arg_var) :: typedNamedArgs; + end for; - {fn} := typeCachedFunctions(fn_ref); - ty := Type.INTEGER(); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, var)); - // TODO: Check cardinality restrictions, 3.7.2.3. - end typeCardinalityCall; + typedNamedArgs := listReverse(typedNamedArgs); + then + ARG_TYPED_CALL(call.ref, typedArgs, typedNamedArgs, call.call_scope); + end match; + end typeArgs; - function typeBranchCall + function checkMatchingFunctions input Call call; - input ExpOrigin.Type origin; input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.PARAMETER; + output MatchedFunction matchedFunc; protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg1, arg2; - Function fn; + list matchedFunctions, exactMatches; + Function func; + list allfuncs; + InstNode fn_node; + Integer numerr = Error.getNumErrorMessages(); + list errors; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; - - if listLength(args) <> 2 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Connector, Connector)"}, info); - end if; - - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); - end if; - - {arg1, arg2} := args; - - (arg1, ty) := Typing.typeExp(arg1, origin, info); - checkConnectionsArgument(arg1, ty, fn_ref, 1, info); - (arg2, ty) := Typing.typeExp(arg2, origin, info); - checkConnectionsArgument(arg2, ty, fn_ref, 2, info); - - {fn} := typeCachedFunctions(fn_ref); - ty := Type.NORETCALL(); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg1, arg2}, ty, var)); - end typeBranchCall; + ErrorExt.setCheckpoint("NFCall:checkMatchingFunctions"); + matchedFunctions := {}; - function typeIsRootCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.PARAMETER; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Function fn; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + _ := match call + case ARG_TYPED_CALL(ref = ComponentRef.CREF(node = fn_node)) algorithm + allfuncs := Function.getCachedFuncs(fn_node); + matchedFunctions := Function.matchFunctions(allfuncs, call.arguments, call.named_args, info); + then + (); + end match; - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + if listEmpty(matchedFunctions) then + // Don't show error messages for overloaded functions, it leaks + // implementation details and usually doesn't provide any more info than + // what the "no match found" error gives anyway. + if listLength(allfuncs) > 1 then + ErrorExt.rollBack("NFCall:checkMatchingFunctions"); + Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {typedString(call), Function.candidateFuncListString(allfuncs)}, info); - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Connector)"}, info); - end if; + // Only show the error message for no matching functions if no other error + // was shown. + // functions that for some reason failed to match without giving any error. + elseif numerr == Error.getNumErrorMessages() then + ErrorExt.rollBack("NFCall:checkMatchingFunctions"); + Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, + {typedString(call), Function.candidateFuncListString(allfuncs)}, info); + else + ErrorExt.delCheckpoint("NFCall:checkMatchingFunctions"); + end if; - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); + fail(); end if; - (arg, ty) := Typing.typeExp(listHead(args), origin, info); - checkConnectionsArgument(arg, ty, fn_ref, 1, info); + // If we have at least one matching function then we discard all error messages + // about matching. We have one matching func if we reach here. + ErrorExt.rollBack("NFCall:checkMatchingFunctions"); - {fn} := typeCachedFunctions(fn_ref); - ty := Type.BOOLEAN(); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, var)); - end typeIsRootCall; + if listLength(matchedFunctions) == 1 then + matchedFunc ::_ := matchedFunctions; - function typePotentialRootCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.PARAMETER; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg1, arg2; - Function fn; - Integer args_len; - String name; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + // Overwrite the actuall function name with the overload name + // for builtin functions. + if Function.isBuiltin(matchedFunc.func) then + func := matchedFunc.func; + func.path := Function.nameConsiderBuiltin(func); + matchedFunc.func := func; + end if; + return; + end if; - for narg in named_args loop - (name, arg2) := narg; + if listLength(matchedFunctions) > 1 then + exactMatches := MatchedFunction.getExactMatches(matchedFunctions); + if listLength(exactMatches) == 1 then + matchedFunc ::_ := exactMatches; - if name == "priority" then - args := listAppend(args, {arg2}); + // Overwrite the actuall function name with the overload name + // for builtin functions. + if Function.isBuiltin(matchedFunc.func) then + func := matchedFunc.func; + func.path := Function.nameConsiderBuiltin(func); + matchedFunc.func := func; + end if; + return; else - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), name}, info); + matchedFunctions := resolveOverloadedVsDefaultConstructorAmbigutiy(matchedFunctions); + if listLength(matchedFunctions) == 1 then + matchedFunc ::_ := matchedFunctions; + return; + else + Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_FUNCTIONS_NFINST, + {typedString(call), Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); + fail(); + end if; end if; - end for; - - args_len := listLength(args); - if args_len < 1 or args_len > 2 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Connector, Integer = 0)"}, info); - end if; - - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); end if; - arg1 :: args := args; + end checkMatchingFunctions; - (arg1, ty) := Typing.typeExp(arg1, origin, info); - checkConnectionsArgument(arg1, ty, fn_ref, 1, info); + function resolveOverloadedVsDefaultConstructorAmbigutiy + input list matchedFunctions; + output list outMatches; + algorithm + // We have at least two exact matches. find the default constructor (if there is one) and remove it from the list + // so that it + // - doesn't cause ambiguities if there is only one other match left OR + // - it doesn't appear in the error messages in the case of more than one overloaded constructor matches. + outMatches := list(m for m guard not Function.isDefaultRecordConstructor(m.func) in matchedFunctions); + end resolveOverloadedVsDefaultConstructorAmbigutiy; - if args_len == 2 then - arg2 := listHead(args); - (arg2, ty) := Typing.typeExp(arg2, origin, info); + function iteratorToDAE + input tuple iter; + output DAE.ReductionIterator diter; + protected + InstNode iter_node; + Expression iter_range; + Component c; + Binding b; + algorithm + (iter_node, iter_range) := iter; + diter := DAE.REDUCTIONITER(InstNode.name(iter_node), Expression.toDAE(iter_range), NONE(), + Type.toDAE(Expression.typeOf(iter_range))); + end iteratorToDAE; - if not Type.isInteger(ty) then - Error.addSourceMessageAndFail(Error.ARG_TYPE_MISMATCH, - {"2", ComponentRef.toString(fn_ref), "", Expression.toString(arg2), - Type.toString(ty), "Integer"}, info); - end if; - else - arg2 := Expression.INTEGER(0); + function matchFunction + input Function func; + input list args; + input list named_args; + input SourceInfo info; + output list out_args; + output Boolean matched; + output FunctionMatchKind matchKind; + algorithm + (out_args, matched) := Function.fillArgs(args, named_args, func, info); + if matched then + (out_args, matched, matchKind) := Function.matchArgs(func, out_args, info); end if; + end matchFunction; - {fn} := typeCachedFunctions(fn_ref); - ty := Type.NORETCALL(); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg1, arg2}, ty, var)); - end typePotentialRootCall; - - function typeRootCall - input Call call; - input ExpOrigin.Type origin; + function vectorizeCall + input Call base_call; + input FunctionMatchKind mk; + input InstNode scope; input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.PARAMETER; + output Call vectorized_call; protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Function fn; + Type ty, vect_ty; + Expression exp; + list> iters; + InstNode iter; + Integer i; + list vect_dims; + list arg_is_vected, b_list; + Boolean b; + list vect_args; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + vectorized_call := match base_call + case TYPED_CALL() + algorithm + FunctionMatchKind.VECTORIZED(vect_dims, arg_is_vected) := mk; + iters := {}; + i := 1; - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + for dim in vect_dims loop + Error.assertion(Dimension.isKnown(dim, allowExp = true), getInstanceName() + + " got unknown dimension for vectorized call", info); - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Connector)"}, info); - end if; + // Create the range on which we will iterate to vectorize. + ty := Type.ARRAY(Type.INTEGER(), {dim}); + exp := Expression.RANGE(ty, Expression.INTEGER(1), NONE(), Dimension.sizeExp(dim)); - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); - end if; + // Create the iterator. + iter := InstNode.fromComponent("$i" + intString(i), + Component.ITERATOR(Type.INTEGER(), Variability.CONSTANT, info), scope); - (arg, ty) := Typing.typeExp(listHead(args), origin, info); - checkConnectionsArgument(arg, ty, fn_ref, 1, info); + iters := (iter, exp) :: iters; - {fn} := typeCachedFunctions(fn_ref); - ty := Type.NORETCALL(); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, var)); - end typeRootCall; + // Now that iterator is ready apply it, as a subscript, to each argument that is supposed to be vectorized + // Make a cref expression from the iterator + exp := Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER())); + vect_args := {}; + b_list := arg_is_vected; + for arg in base_call.arguments loop + // If the argument is supposed to be vectorized + b :: b_list := b_list; + vect_args := (if b then Expression.applyIndexSubscript(exp, arg) else arg) :: vect_args; + end for; - function typeRootedCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability var = Variability.PARAMETER; - protected - ComponentRef fn_ref; - list args; - list named_args; - Expression arg; - Function fn; - algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; + base_call.arguments := listReverse(vect_args); + i := i + 1; + end for; - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {ComponentRef.toString(fn_ref), Util.tuple21(listHead(named_args))}, info); - end if; + vect_ty := Type.liftArrayLeftList(base_call.ty, vect_dims); + then + TYPED_MAP_CALL(vect_ty, base_call.var, Expression.CALL(base_call), iters); - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), ComponentRef.toString(fn_ref) + "(Connector)"}, info); - end if; + end match; + end vectorizeCall; - if intBitAnd(origin, ExpOrigin.FUNCTION) > 0 then - Error.addSourceMessageAndFail(Error.EXP_INVALID_IN_FUNCTION, - {ComponentRef.toString(fn_ref)}, info); - end if; + function evaluateCallType + input output Type ty; + input Function fn; + input list args; + input output ParameterTree ptree = ParameterTree.EMPTY(); + algorithm + ty := match ty + local + list dims; + list tys; - (arg, ty) := Typing.typeExp(listHead(args), origin, info); - checkConnectionsArgument(arg, ty, fn_ref, 1, info); + case Type.ARRAY() + algorithm + (dims, ptree) := List.map1Fold(ty.dimensions, evaluateCallTypeDim, (fn, args), ptree); + ty.dimensions := dims; + then + ty; - {fn} := typeCachedFunctions(fn_ref); - ty := Type.BOOLEAN(); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, var)); - end typeRootedCall; + case Type.TUPLE() + algorithm + (tys, ptree) := List.map2Fold(ty.types, evaluateCallType, fn, args, ptree); + ty.types := tys; + then + ty; - function checkConnectionsArgument - input Expression arg; - input Type ty; - input ComponentRef fnRef; - input Integer argIndex; - input SourceInfo info; + else ty; + end match; + end evaluateCallType; + + function evaluateCallTypeDim + input output Dimension dim; + input tuple> fnArgs; + input output ParameterTree ptree; algorithm - () := match arg + dim := match dim local - Type ty2; - InstNode node; - Boolean valid_cref; - ComponentRef rest_cref; + Expression exp; - case Expression.CREF() + case Dimension.EXP() algorithm - valid_cref := match arg.cref - case ComponentRef.CREF(node = node, origin = NFComponentRef.Origin.CREF, - restCref = ComponentRef.CREF(ty = ty2, origin = NFComponentRef.Origin.CREF, - restCref = rest_cref)) - then Class.isOverdetermined(InstNode.getClass(node)) and - Type.isConnector(ty2) and - not ComponentRef.isFromCref(rest_cref); - - else false; - end match; - - if not valid_cref then - Error.addSourceMessageAndFail( - if argIndex == 1 then Error.INVALID_ARGUMENT_TYPE_BRANCH_FIRST else - Error.INVALID_ARGUMENT_TYPE_BRANCH_SECOND, - {ComponentRef.toString(fnRef)}, info); - end if; + ptree := buildParameterTree(fnArgs, ptree); + exp := Expression.map(dim.exp, function evaluateCallTypeDimExp(ptree = ptree)); + exp := Ceval.evalExp(exp, Ceval.EvalTarget.IGNORE_ERRORS()); then - (); + Dimension.fromExp(exp, dim.var); - else - algorithm - Error.addSourceMessage(Error.ARG_TYPE_MISMATCH, - {String(argIndex), ComponentRef.toString(fnRef), "", - Expression.toString(arg), Type.toString(ty), "overconstrained type/record"}, info); - then - fail(); + else dim; end match; - end checkConnectionsArgument; + end evaluateCallTypeDim; - function typeNoEventCall - input Call call; - input ExpOrigin.Type origin; - input SourceInfo info; - output Expression callExp; - output Type ty; - output Variability variability; + function buildParameterTree + input tuple> fnArgs; + input output ParameterTree ptree; protected - ComponentRef fn_ref; + Function fn; list args; - list named_args; Expression arg; - Function fn; algorithm - UNTYPED_CALL(ref = fn_ref, arguments = args, named_args = named_args) := call; - - // noEvent doesn't have any named parameters. - if not listEmpty(named_args) then - Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER, - {"noEvent", Util.tuple21(listHead(named_args))}, info); + if not ParameterTree.isEmpty(ptree) then + return; end if; - // noEvent takes exactly one argument. - if listLength(args) <> 1 then - Error.addSourceMessageAndFail(Error.NO_MATCHING_FUNCTION_FOUND_NFINST, - {toString(call), "noEvent(Any) => Any"}, info); - end if; + (fn, args) := fnArgs; - {arg} := args; - (arg, ty, variability) := Typing.typeExp(arg, intBitOr(origin, ExpOrigin.NOEVENT), info); + for i in fn.inputs loop + arg :: args := args; + ptree := ParameterTree.add(ptree, InstNode.name(i), arg); + end for; - {fn} := typeCachedFunctions(fn_ref); - callExp := Expression.CALL(makeBuiltinCall2(fn, {arg}, ty, variability)); - end typeNoEventCall; + // TODO: Add local variable bindings. + end buildParameterTree; - function typeGetInstanceName - input Call call; - output Expression result; - output Type ty = Type.STRING(); - output Variability var = Variability.CONSTANT; - protected - InstNode scope; + function evaluateCallTypeDimExp + input Expression exp; + input ParameterTree ptree; + output Expression outExp; algorithm - Call.UNTYPED_CALL(call_scope = scope) := call; - result := Expression.STRING(Absyn.pathString(InstNode.scopePath(scope, includeRoot = true))); - end typeGetInstanceName; + outExp := match exp + local + InstNode node; + Option oexp; + Expression e; - function unboxArgs - input output Call call; - algorithm - () := match call - case TYPED_CALL() + case Expression.CREF(cref = ComponentRef.CREF(node = node, restCref = ComponentRef.EMPTY())) algorithm - call.arguments := list(Expression.unbox(arg) for arg in call.arguments); - then - (); - end match; - end unboxArgs; - - public - function candidateFuncListString - input list fns; - output String s = stringDelimitList(list(Function.signatureString(fn, true) for fn in fns), "\n "); - end candidateFuncListString; + oexp := ParameterTree.getOpt(ptree, InstNode.name(node)); - function isRecordConstructor - input Call call; - output Boolean isConstructor; - algorithm - isConstructor := match call - case UNTYPED_CALL() - then SCode.isRecord(InstNode.definition(ComponentRef.node(call.ref))); - case TYPED_CALL() - then SCode.isRecord(InstNode.definition(call.fn.node)); - else false; - end match; - end isRecordConstructor; + if isSome(oexp) then + SOME(outExp) := oexp; + // TODO: Apply subscripts. + end if; + then + outExp; - function toRecordExpression - input Call call; - input Type ty; - output Expression exp; - algorithm - exp := match call - case TYPED_CALL() - then Expression.RECORD(Function.name(call.fn), ty, call.arguments); + else exp; end match; - end toRecordExpression; + end evaluateCallTypeDimExp; - function inlineType - input Call call; - output DAE.InlineType inlineTy; + function getSpecialReturnType + input Function fn; + input list args; + output Type ty; algorithm - inlineTy := match call - case TYPED_CALL(attributes = CallAttributes.CALL_ATTR(inlineType = inlineTy)) - then inlineTy; - else DAE.InlineType.NO_INLINE(); + ty := match fn.path + case Absyn.IDENT("min") + then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); + case Absyn.IDENT("max") + then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); + case Absyn.IDENT("sum") + then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); + case Absyn.IDENT("product") + then Type.arrayElementType(Expression.typeOf(Expression.unbox(listHead(args)))); + else + algorithm + Error.assertion(false, getInstanceName() + ": unhandled case for " + + Absyn.pathString(fn.path), sourceInfo()); + then + fail(); end match; - end inlineType; + end getSpecialReturnType; end Call; annotation(__OpenModelica_Interface="frontend"); diff --git a/Compiler/NFFrontEnd/NFConnectEquations.mo b/Compiler/NFFrontEnd/NFConnectEquations.mo index 32f4f805bc..4362074d37 100644 --- a/Compiler/NFFrontEnd/NFConnectEquations.mo +++ b/Compiler/NFFrontEnd/NFConnectEquations.mo @@ -61,6 +61,7 @@ import NFClass.Class; import NFBinding.Binding; import NFFunction.Function; import Global; +import BuiltinCall = NFBuiltinCall; constant Expression EQ_ASSERT_STR = Expression.STRING("Connected constants/parameters must be equal"); @@ -209,7 +210,7 @@ algorithm // Modelica doesn't allow == for Reals, so to keep the flat Modelica // somewhat valid we use 'abs(lhs - rhs) <= 0' instead. exp := Expression.BINARY(lhs_exp, Operator.makeSub(ty), rhs_exp); - exp := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.ABS_REAL, {exp})); + exp := Expression.CALL(BuiltinCall.makeCall(NFBuiltinFuncs.ABS_REAL, {exp}, Expression.variability(exp))); exp := Expression.RELATION(exp, Operator.makeLessEq(ty), Expression.REAL(0.0)); else // For any other type, generate assertion for 'lhs == rhs'. @@ -295,6 +296,7 @@ algorithm DAE.ElementSource src, src1, src2; Expression cref1, cref2, e1, e2; list inside, outside; + Variability var1, var2; // Unconnected stream connector, do nothing. case ({Connector.CONNECTOR(face = Face.INSIDE)}) then {}; @@ -508,7 +510,8 @@ function makeInStreamCall output Expression inStreamCall; annotation(__OpenModelica_EarlyInline = true); algorithm - inStreamCall := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.IN_STREAM, {streamExp})); + inStreamCall := Expression.CALL(BuiltinCall.makeCall( + NFBuiltinFuncs.IN_STREAM, {streamExp}, Expression.variability(streamExp))); end makeInStreamCall; function makePositiveMaxCall @@ -532,8 +535,8 @@ algorithm flow_threshold := flowThreshold; end if; - positiveMaxCall := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.POSITIVE_MAX_REAL, - {flowExp, flow_threshold})); + positiveMaxCall := Expression.CALL(BuiltinCall.makeCall(NFBuiltinFuncs.POSITIVE_MAX_REAL, + {flowExp, flow_threshold}, Connector.variability(element))); setGlobalRoot(Global.isInStream, SOME(true)); end makePositiveMaxCall; diff --git a/Compiler/NFFrontEnd/NFExpression.mo b/Compiler/NFFrontEnd/NFExpression.mo index 09c60d6e37..430c86fe74 100644 --- a/Compiler/NFFrontEnd/NFExpression.mo +++ b/Compiler/NFFrontEnd/NFExpression.mo @@ -36,6 +36,7 @@ protected import List; import Builtin = NFBuiltin; + import BuiltinCall = NFBuiltinCall; import Expression = NFExpression; import Function = NFFunction; import RangeIterator = NFRangeIterator; @@ -3104,7 +3105,8 @@ public // An expression with array type, but which is not an array expression. // Such an expression can't be promoted here, so we create a promote call instead. case (_, _) guard isArray - then CALL(Call.makeBuiltinCall2(NFBuiltinFuncs.PROMOTE, {exp, INTEGER(dims)}, listHead(types))); + then CALL(BuiltinCall.makeCall2( + NFBuiltinFuncs.PROMOTE, {exp, INTEGER(dims)}, listHead(types), variability(exp))); // A scalar expression, promote it as many times as the number of types given. else @@ -3262,7 +3264,7 @@ public algorithm indexExp := match enumExp case ENUM_LITERAL() then INTEGER(enumExp.index); - else CALL(Call.makeBuiltinCall( + else CALL(BuiltinCall.makeCall( NFBuiltinFuncs.INTEGER_ENUM, {enumExp}, variability(enumExp))); end match; end enumIndexExp; diff --git a/Compiler/NFFrontEnd/NFFunction.mo b/Compiler/NFFrontEnd/NFFunction.mo index b3304aebd9..43bddee8ce 100644 --- a/Compiler/NFFrontEnd/NFFunction.mo +++ b/Compiler/NFFrontEnd/NFFunction.mo @@ -295,7 +295,7 @@ uniontype Function CachedData cache; algorithm // Look up the function. - fn_node := ComponentRef.node(fn_ref); + fn_node := InstNode.classScope(ComponentRef.node(fn_ref)); cache := InstNode.getFuncCache(fn_node); // Check if a cached instantiation of this function already exists. @@ -408,7 +408,7 @@ uniontype Function protected CachedData cache; algorithm - cache := InstNode.getFuncCache(inNode); + cache := InstNode.getFuncCache(InstNode.classScope(inNode)); outFuncs := match cache case CachedData.FUNCTION() then cache.funcs; else fail(); @@ -509,6 +509,11 @@ uniontype Function str := Absyn.pathString(fn_name) + "(" + input_str + ")" + output_str; end signatureString; + function candidateFuncListString + input list fns; + output String s = stringDelimitList(list(Function.signatureString(fn, true) for fn in fns), "\n "); + end candidateFuncListString; + function callString "Constructs a string representing a call, for use in error messages." input Function fn; @@ -942,6 +947,40 @@ uniontype Function end match; end isTyped; + function typeRefCache + "Returns the function(s) referenced by the given cref, and types them if + they are not already typed." + input ComponentRef functionRef; + output list functions; + protected + InstNode fn_node; + Boolean typed, special; + String name; + algorithm + functions := match functionRef + case ComponentRef.CREF(node = fn_node) + algorithm + fn_node := InstNode.classScope(fn_node); + CachedData.FUNCTION(functions, typed, special) := InstNode.getFuncCache(fn_node); + + // Type the function(s) if not already done. + if not typed then + functions := list(typeFunctionSignature(f) for f in functions); + InstNode.setFuncCache(fn_node, CachedData.FUNCTION(functions, true, special)); + functions := list(typeFunctionBody(f) for f in functions); + InstNode.setFuncCache(fn_node, CachedData.FUNCTION(functions, true, special)); + end if; + then + functions; + + else + algorithm + Error.assertion(false, getInstanceName() + " got invalid function call reference", sourceInfo()); + then + fail(); + end match; + end typeRefCache; + function typeFunction input output Function fn; algorithm diff --git a/Compiler/NFFrontEnd/NFInst.mo b/Compiler/NFFrontEnd/NFInst.mo index 66a7f28325..f651812a37 100644 --- a/Compiler/NFFrontEnd/NFInst.mo +++ b/Compiler/NFFrontEnd/NFInst.mo @@ -1318,7 +1318,7 @@ algorithm Component inst_comp; InstNode ty_node; Class ty; - Boolean use_binding; + Boolean use_binding, in_function; case SCode.COMPONENT(info = info) algorithm @@ -1340,7 +1340,8 @@ algorithm // Instantiate the component's attributes, and merge them with the // attributes of the component's parent (e.g. constant SomeComplexClass c). attr := instComponentAttributes(component.attributes, component.prefixes); - attr := mergeComponentAttributes(attributes, attr, node); + attr := mergeComponentAttributes(attributes, attr, node, + Class.isFunction(InstNode.getClass(parent))); // Create the untyped component and update the node with it. We need the // untyped component in instClass to make sure everything is scoped @@ -1495,6 +1496,7 @@ function mergeComponentAttributes input Component.Attributes outerAttr; input Component.Attributes innerAttr; input InstNode node; + input Boolean inFunction; output Component.Attributes attr; protected ConnectorType cty; @@ -1513,7 +1515,13 @@ algorithm cty := Prefixes.mergeConnectorType(outerAttr.connectorType, innerAttr.connectorType, node); par := Prefixes.mergeParallelism(outerAttr.parallelism, innerAttr.parallelism, node); var := Prefixes.variabilityMin(outerAttr.variability, innerAttr.variability); - dir := Prefixes.mergeDirection(outerAttr.direction, innerAttr.direction, node); + + if inFunction then + dir := innerAttr.direction; + else + dir := Prefixes.mergeDirection(outerAttr.direction, innerAttr.direction, node); + end if; + fin := outerAttr.isFinal or innerAttr.isFinal; redecl := innerAttr.isRedeclare; repl := innerAttr.isReplaceable; @@ -2140,72 +2148,112 @@ algorithm crefExp := match cref case ComponentRef.CREF() + then + match cref.node + case InstNode.COMPONENT_NODE() + then instCrefComponent(cref, cref.node, found_scope, info); + case InstNode.CLASS_NODE() + then if Class.isFunction(InstNode.getClass(cref.node)) then + instCrefFunction(cref, info) + else + instCrefTypename(cref, cref.node, info); + else + algorithm + Error.assertion(false, getInstanceName() + " got invalid instance node", sourceInfo()); + then + fail(); + end match; + + else Expression.CREF(Type.UNKNOWN(), cref); + end match; +end instCref; + +function instCrefComponent + input ComponentRef cref; + input InstNode node; + input InstNode scope; + input SourceInfo info; + output Expression crefExp; +protected + Component comp; + ComponentRef prefixed_cref; +algorithm + comp := InstNode.component(node); + + crefExp := match comp + case Component.ITERATOR() algorithm - if InstNode.isComponent(cref.node) then - comp := InstNode.component(cref.node); + checkUnsubscriptableCref(cref, info); + then + Expression.CREF(Type.UNKNOWN(), ComponentRef.makeIterator(node, comp.ty)); - crefExp := match comp - case Component.ITERATOR() - algorithm - checkUnsubscriptableCref(cref, cref.subscripts, info); - then - Expression.CREF(Type.UNKNOWN(), ComponentRef.makeIterator(cref.node, comp.ty)); + case Component.ENUM_LITERAL() + algorithm + checkUnsubscriptableCref(cref, info); + then + comp.literal; - case Component.ENUM_LITERAL() - algorithm - checkUnsubscriptableCref(cref, cref.subscripts, info); - then - comp.literal; + case Component.TYPE_ATTRIBUTE() + algorithm + Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR, + {InstNode.name(node), InstNode.name(InstNode.parent(node))}, info); + then + fail(); - case Component.TYPE_ATTRIBUTE() - algorithm - Error.addSourceMessage(Error.LOOKUP_VARIABLE_ERROR, - {Dump.printComponentRefStr(absynCref), InstNode.name(scope)}, info); - then - fail(); + else + algorithm + prefixed_cref := ComponentRef.fromNodeList(InstNode.scopeList(scope)); + prefixed_cref := if ComponentRef.isEmpty(prefixed_cref) then + cref else ComponentRef.append(cref, prefixed_cref); + then + Expression.CREF(Type.UNKNOWN(), prefixed_cref); - else - algorithm - prefixed_cref := ComponentRef.fromNodeList(InstNode.scopeList(found_scope)); - prefixed_cref := if ComponentRef.isEmpty(prefixed_cref) then - cref else ComponentRef.append(cref, prefixed_cref); - then - Expression.CREF(Type.UNKNOWN(), prefixed_cref); + end match; +end instCrefComponent; - end match; - else - checkUnsubscriptableCref(cref, cref.subscripts, info); - ty := InstNode.getType(cref.node); +function instCrefFunction + input ComponentRef cref; + input SourceInfo info; + output Expression crefExp; +protected + ComponentRef fn_ref; +algorithm + fn_ref := Function.instFuncRef(cref, info); + crefExp := Expression.CREF(Type.UNKNOWN(), fn_ref); +end instCrefFunction; - ty := match ty - case Type.BOOLEAN() then Type.ARRAY(ty, {Dimension.BOOLEAN()}); - case Type.ENUMERATION() then Type.ARRAY(ty, {Dimension.ENUM(ty)}); - else - algorithm - // This should be caught by lookupComponent, only type name classes - // are allowed to be used where a component is expected. - Error.assertion(false, getInstanceName() + " got unknown class node", sourceInfo()); - then - fail(); - end match; +function instCrefTypename + input ComponentRef cref; + input InstNode node; + input SourceInfo info; + output Expression crefExp; +protected + Type ty; +algorithm + checkUnsubscriptableCref(cref, info); + ty := InstNode.getType(node); - crefExp := Expression.TYPENAME(ty); - end if; + ty := match ty + case Type.BOOLEAN() then Type.ARRAY(ty, {Dimension.BOOLEAN()}); + case Type.ENUMERATION() then Type.ARRAY(ty, {Dimension.ENUM(ty)}); + else + algorithm + Error.assertion(false, getInstanceName() + " got unknown class node " + + InstNode.name(node), sourceInfo()); then - crefExp; - - else Expression.CREF(Type.UNKNOWN(), cref); + fail(); end match; -end instCref; + + crefExp := Expression.TYPENAME(ty); +end instCrefTypename; function checkUnsubscriptableCref input ComponentRef cref; - input list subscripts; input SourceInfo info; algorithm - if not listEmpty(subscripts) then + if ComponentRef.hasSubscripts(cref) then Error.addSourceMessage(Error.WRONG_NUMBER_OF_SUBSCRIPTS, - {ComponentRef.toString(cref), String(listLength(subscripts)), "0"}, info); + {ComponentRef.toString(cref), String(listLength(ComponentRef.getSubscripts(cref))), "0"}, info); fail(); end if; end checkUnsubscriptableCref; diff --git a/Compiler/NFFrontEnd/NFLookupState.mo b/Compiler/NFFrontEnd/NFLookupState.mo index fc814763ce..63760fcd40 100644 --- a/Compiler/NFFrontEnd/NFLookupState.mo +++ b/Compiler/NFFrontEnd/NFLookupState.mo @@ -40,6 +40,7 @@ protected import Dump; import Error; import System; +import NFClass.Class; public uniontype LookupStateName @@ -130,14 +131,21 @@ uniontype LookupState LookupStateName.CREF(name), info); end assertComponent; - function isCallable + function isCallableType input InstNode node; output Boolean callable; protected SCode.Element def = InstNode.definition(node); algorithm callable := SCode.isRecord(def) or SCode.isOperator(def); - end isCallable; + end isCallableType; + + function isCallableComponent + input InstNode node; + output Boolean callable; + algorithm + callable := Class.isFunction(InstNode.getClass(node)); + end isCallableComponent; function isFunction input LookupState state; @@ -147,7 +155,9 @@ uniontype LookupState isFunction := match state case FUNC() then true; case COMP_FUNC() then true; - case CLASS() then isCallable(node); + case CLASS() then isCallableType(node); + case COMP() then isCallableComponent(node); + case COMP_COMP() then isCallableComponent(node); else false; end match; end isFunction; @@ -177,18 +187,21 @@ uniontype LookupState SourceInfo info2; // Found the expected kind of element. - case (COMP(), COMP()) then (); - case (COMP_COMP(), COMP()) then (); - case (PREDEF_COMP(), COMP()) then (); + case (COMP(), COMP()) then (); + case (COMP_COMP(), COMP()) then (); + case (PREDEF_COMP(), COMP()) then (); + case (FUNC(), COMP()) then (); + case (COMP_FUNC(), COMP()) then (); case (PACKAGE(), CLASS()) then (); case (CLASS(), CLASS()) then (); case (PREDEF_CLASS(), CLASS()) then (); case (FUNC(), CLASS()) then (); - case (FUNC(), FUNC()) then (); - case (COMP_FUNC(), FUNC()) then (); - + case (FUNC(), FUNC()) then (); + case (COMP_FUNC(), FUNC()) then (); - case (CLASS(), FUNC()) guard isCallable(node) then (); + case (CLASS(), FUNC()) guard isCallableType(node) then (); + case (COMP(), FUNC()) guard isCallableComponent(node) then (); + case (COMP_COMP(), FUNC()) guard isCallableComponent(node) then (); // Found a class via a component, but expected a function. case (COMP_CLASS(), FUNC()) diff --git a/Compiler/NFFrontEnd/NFModelicaBuiltin.mo b/Compiler/NFFrontEnd/NFModelicaBuiltin.mo index 09d310c23f..161cda2b3f 100644 --- a/Compiler/NFFrontEnd/NFModelicaBuiltin.mo +++ b/Compiler/NFFrontEnd/NFModelicaBuiltin.mo @@ -852,7 +852,7 @@ record SimulationResult String simulationOptions; String messages; end SimulationResult; */ -encapsulated package OpenModelica "OpenModelica internal defintions and scripting functions" +encapsulated package OpenModelica "OpenModelica internal definitions and scripting functions" package $Code "Code quoting is not a uniontype yet because that would require enabling MetaModelica diff --git a/Compiler/NFFrontEnd/NFType.mo b/Compiler/NFFrontEnd/NFType.mo index 38fbe296cf..c0eb71dfa5 100644 --- a/Compiler/NFFrontEnd/NFType.mo +++ b/Compiler/NFFrontEnd/NFType.mo @@ -42,6 +42,7 @@ public import Subscript = NFSubscript; import ComplexType = NFComplexType; import ConvertDAE = NFConvertDAE; + import ComponentRef = NFComponentRef; record INTEGER end INTEGER; @@ -88,8 +89,8 @@ public end COMPLEX; record FUNCTION + //ComponentRef fnRef; Type resultType; - DAE.FunctionAttributes attributes; end FUNCTION; record METABOXED "Used for MetaModelica generic types" @@ -643,8 +644,8 @@ public list(Dimension.toDAE(d) for d in ty.dimensions)); case Type.TUPLE() then DAE.T_TUPLE(list(toDAE(t) for t in ty.types), ty.names); - case Type.FUNCTION() - then DAE.T_FUNCTION({} /*TODO:FIXME*/, toDAE(ty.resultType, makeTypeVars), ty.attributes, Absyn.IDENT("TODO:FIXME")); + //case Type.FUNCTION() + // then DAE.T_FUNCTION({} /*TODO:FIXME*/, toDAE(ty.resultType, makeTypeVars), ty.attributes, Absyn.IDENT("TODO:FIXME")); case Type.NORETCALL() then DAE.T_NORETCALL_DEFAULT; case Type.UNKNOWN() then DAE.T_UNKNOWN_DEFAULT; case Type.COMPLEX() diff --git a/Compiler/NFFrontEnd/NFTypeCheck.mo b/Compiler/NFFrontEnd/NFTypeCheck.mo index 51829e767e..43e3c73daa 100644 --- a/Compiler/NFFrontEnd/NFTypeCheck.mo +++ b/Compiler/NFFrontEnd/NFTypeCheck.mo @@ -68,6 +68,7 @@ import NFFunction.TypedArg; import NFFunction.FunctionMatchKind; import NFFunction.MatchedFunction; import NFCall.Call; +import BuiltinCall = NFBuiltinCall; import NFCall.CallAttributes; import ComponentRef = NFComponentRef; import ErrorExt; @@ -199,7 +200,7 @@ algorithm if oper_defined then fn_ref := Function.instFuncRef(fn_ref, InstNode.info(node1)); - for fn in Call.typeCachedFunctions(fn_ref) loop + for fn in Function.typeRefCache(fn_ref) loop checkValidOperatorOverload(opstr, fn, node1); candidates := fn::candidates; end for; @@ -221,7 +222,7 @@ algorithm if oper_defined then fn_ref := Function.instFuncRef(fn_ref, InstNode.info(node2)); - for fn in Call.typeCachedFunctions(fn_ref) loop + for fn in Function.typeRefCache(fn_ref) loop checkValidOperatorOverload(opstr, fn, node2); candidates := fn::candidates; end for; @@ -268,7 +269,7 @@ algorithm else Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_OPERATOR_FUNCTIONS_NFINST, {Expression.toString(Expression.BINARY(inExp1, inOp, inExp2)) - , Call.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); + , Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); fail(); end if; @@ -331,7 +332,7 @@ algorithm else // TODO: FIX ME: Add proper error message. print("Ambiguous operator: " + "\nCandidates:\n "); - print(Call.candidateFuncListString(list(Util.tuple31(fn) for fn in matchedfuncs))); + print(Function.candidateFuncListString(list(Util.tuple31(fn) for fn in matchedfuncs))); print("\n"); fail(); end if; @@ -859,7 +860,7 @@ algorithm fn_ref := Function.lookupFunctionSimple(opstr, node1); fn_ref := Function.instFuncRef(fn_ref, InstNode.info(node1)); - candidates := Call.typeCachedFunctions(fn_ref); + candidates := Function.typeRefCache(fn_ref); for fn in candidates loop checkValidOperatorOverload(opstr, fn, node1); end for; @@ -884,8 +885,8 @@ algorithm ); else Error.addSourceMessage(Error.AMBIGUOUS_MATCHING_OPERATOR_FUNCTIONS_NFINST, - {Expression.toString(Expression.UNARY(inOp, inExp1)) - , Call.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); + {Expression.toString(Expression.UNARY(inOp, inExp1)), + Function.candidateFuncListString(list(mfn.func for mfn in matchedFunctions))}, info); fail(); end if; @@ -2008,11 +2009,11 @@ algorithm if isSome(stepExp) then SOME(step_exp) := stepExp; var := Prefixes.variabilityMax(var, Expression.variability(step_exp)); - dim_exp := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.DIV_INT, {dim_exp, step_exp}, var)); + dim_exp := Expression.CALL(BuiltinCall.makeCall(NFBuiltinFuncs.DIV_INT, {dim_exp, step_exp}, var)); end if; dim_exp := Expression.BINARY(dim_exp, Operator.makeSub(Type.INTEGER()), Expression.INTEGER(1)); - dim_exp := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.MAX_INT, {dim_exp}, var)); + dim_exp := Expression.CALL(BuiltinCall.makeCall(NFBuiltinFuncs.MAX_INT, {dim_exp}, var)); then Dimension.fromExp(dim_exp, var); @@ -2062,8 +2063,8 @@ algorithm dim_exp := Expression.BINARY(dim_exp, Operator.makeAdd(Type.REAL()), Expression.REAL(5e-15)); end if; - dim_exp := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.FLOOR, {dim_exp}, var)); - dim_exp := Expression.CALL(Call.makeBuiltinCall(NFBuiltinFuncs.INTEGER_REAL, {dim_exp}, var)); + dim_exp := Expression.CALL(BuiltinCall.makeCall(NFBuiltinFuncs.FLOOR, {dim_exp}, var)); + dim_exp := Expression.CALL(BuiltinCall.makeCall(NFBuiltinFuncs.INTEGER_REAL, {dim_exp}, var)); dim_exp := Expression.BINARY(dim_exp, Operator.makeAdd(Type.INTEGER()), Expression.INTEGER(1)); then Dimension.fromExp(dim_exp, var); diff --git a/Compiler/NFFrontEnd/NFTyping.mo b/Compiler/NFFrontEnd/NFTyping.mo index 861055ba81..a1f5fd5e20 100644 --- a/Compiler/NFFrontEnd/NFTyping.mo +++ b/Compiler/NFFrontEnd/NFTyping.mo @@ -58,6 +58,7 @@ import Algorithm = NFAlgorithm; protected import Builtin = NFBuiltin; +import BuiltinCall = NFBuiltinCall; import Ceval = NFCeval; import ClassInf; import ComponentRef = NFComponentRef; @@ -1487,7 +1488,7 @@ algorithm resTys := ty::resTys; res := e::res; end for; - (arrayExp, arrayType) := Call.makeBuiltinCat(1, res, resTys, info); + (arrayExp, arrayType) := BuiltinCall.makeCatExp(1, res, resTys, variability, info); else (arrayExp, arrayType, variability) := typeMatrixComma(listHead(elements), origin, info); if Type.dimensionCount(arrayType) < 2 then @@ -1515,7 +1516,7 @@ algorithm Error.assertion(not listEmpty(elements), getInstanceName() + " expected non-empty arguments", sourceInfo()); if listLength(elements) > 1 then for e in elements loop - (exp, ty1, ) := typeExp(e, origin, info); + (exp, ty1, var) := typeExp(e, origin, info); expl := exp :: expl; if Type.isEqual(ty, Type.UNKNOWN()) then ty := ty1; @@ -1526,6 +1527,7 @@ algorithm end if; end if; tys := ty1 :: tys; + variability := Prefixes.variabilityMax(variability, var); n := max(n, Type.dimensionCount(ty)); end for; tys2 := {}; @@ -1545,7 +1547,7 @@ algorithm res := e :: res; tys2 := ty3 :: tys2; end for; - (arrayExp, arrayType) := Call.makeBuiltinCat(2, res, tys2, info); + (arrayExp, arrayType) := BuiltinCall.makeCatExp(2, res, tys2, variability, info); else (arrayExp, arrayType, variability) := typeExp(listHead(elements), origin, info); end if; diff --git a/Compiler/boot/LoadCompilerSources.mos b/Compiler/boot/LoadCompilerSources.mos index 78724ca5c3..7ea92447b6 100644 --- a/Compiler/boot/LoadCompilerSources.mos +++ b/Compiler/boot/LoadCompilerSources.mos @@ -291,6 +291,7 @@ if true then /* Suppress output */ "../NFFrontEnd/NFAlgorithm.mo", "../NFFrontEnd/NFBinding.mo", "../NFFrontEnd/NFBuiltin.mo", + "../NFFrontEnd/NFBuiltinCall.mo", "../NFFrontEnd/NFBuiltinFuncs.mo", "../NFFrontEnd/NFCall.mo", "../NFFrontEnd/NFCeval.mo",