From dc81059a37959321f3097467b0ebbecd2ca6ac77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=96stlund?= Date: Thu, 14 Jun 2018 16:02:41 +0200 Subject: [PATCH] [NF] Operator overloading improvements. - Only generate default constructors for operator records that has no overloaded constructor defined. - Avoid generating duplicate operator functions that causes the matching to fail. - Some other minor fixes. Belonging to [master]: - OpenModelica/OMCompiler#2504 - OpenModelica/OpenModelica-testsuite#974 --- Compiler/NFFrontEnd/NFBuiltinCall.mo | 6 +- Compiler/NFFrontEnd/NFCeval.mo | 8 +- Compiler/NFFrontEnd/NFClass.mo | 12 + Compiler/NFFrontEnd/NFEvalFunction.mo | 7 +- Compiler/NFFrontEnd/NFExpression.mo | 2 + Compiler/NFFrontEnd/NFFlatten.mo | 8 +- Compiler/NFFrontEnd/NFFunction.mo | 16 +- Compiler/NFFrontEnd/NFFunctionDerivative.mo | 2 +- Compiler/NFFrontEnd/NFInst.mo | 32 ++- Compiler/NFFrontEnd/NFOperatorOverloading.mo | 156 ++++++++++++ Compiler/NFFrontEnd/NFRecord.mo | 85 ------- Compiler/NFFrontEnd/NFRestriction.mo | 8 +- Compiler/NFFrontEnd/NFSections.mo | 18 +- Compiler/NFFrontEnd/NFTypeCheck.mo | 254 +++++++++---------- Compiler/Util/Error.mo | 10 +- Compiler/boot/LoadCompilerSources.mos | 1 + 16 files changed, 377 insertions(+), 248 deletions(-) create mode 100644 Compiler/NFFrontEnd/NFOperatorOverloading.mo diff --git a/Compiler/NFFrontEnd/NFBuiltinCall.mo b/Compiler/NFFrontEnd/NFBuiltinCall.mo index 788fb377bd..3672b3069e 100644 --- a/Compiler/NFFrontEnd/NFBuiltinCall.mo +++ b/Compiler/NFFrontEnd/NFBuiltinCall.mo @@ -383,9 +383,9 @@ protected fn_ref := Function.instFunctionRef(fn_ref, InstNode.info(recopnode)); candidates := Function.typeRefCache(fn_ref); - for fn in candidates loop - TypeCheck.checkValidOperatorOverload("'String'", fn, recopnode); - end for; + //for fn in candidates loop + // TypeCheck.checkValidOperatorOverload("'String'", fn, recopnode); + //end for; matchedFunctions := Function.matchFunctionsSilent(candidates, args, namedArgs, info); exactMatches := MatchedFunction.getExactMatches(matchedFunctions); diff --git a/Compiler/NFFrontEnd/NFCeval.mo b/Compiler/NFFrontEnd/NFCeval.mo index f9d1aa89b0..9f8659ed7f 100644 --- a/Compiler/NFFrontEnd/NFCeval.mo +++ b/Compiler/NFFrontEnd/NFCeval.mo @@ -343,11 +343,11 @@ algorithm binding; // A record field without an explicit binding, evaluate the parent's binding - // if it as one and fetch the binding from it instead. + // if it has one and fetch the binding from it instead. case (_, _, InstNode.COMPONENT_NODE(parent = rec_node as InstNode.COMPONENT_NODE())) guard Type.isRecord(InstNode.getType(rec_node)) algorithm - exp := evalComponentBinding(rec_node, Expression.EMPTY(), target); + exp := evalComponentBinding(rec_node, Expression.EMPTY(Type.UNKNOWN()), target); exp := Expression.lookupRecordField(InstNode.name(node), exp); binding := Binding.CEVAL_BINDING(exp); InstNode.updateComponent(Component.setBinding(binding, component), node); @@ -1766,7 +1766,7 @@ algorithm case {e1, e2} then evalBuiltinMax2(e1, e2); case {e1 as Expression.ARRAY(ty = ty)} algorithm - result := Expression.fold(e1, evalBuiltinMax2, Expression.EMPTY()); + result := Expression.fold(e1, evalBuiltinMax2, Expression.EMPTY(ty)); if Expression.isEmpty(result) then result := Expression.CALL(Call.makeTypedCall(fn, @@ -1812,7 +1812,7 @@ algorithm case {e1, e2} then evalBuiltinMin2(e1, e2); case {e1 as Expression.ARRAY(ty = ty)} algorithm - result := Expression.fold(e1, evalBuiltinMin2, Expression.EMPTY()); + result := Expression.fold(e1, evalBuiltinMin2, Expression.EMPTY(ty)); if Expression.isEmpty(result) then result := Expression.CALL(Call.makeTypedCall(fn, diff --git a/Compiler/NFFrontEnd/NFClass.mo b/Compiler/NFFrontEnd/NFClass.mo index 3c5e282c9e..8839880207 100644 --- a/Compiler/NFFrontEnd/NFClass.mo +++ b/Compiler/NFFrontEnd/NFClass.mo @@ -536,6 +536,18 @@ uniontype Class end match; end setPrefixes; + function isEncapsulated + input Class cls; + output Boolean isEncapsulated; + algorithm + isEncapsulated := match cls + case PARTIAL_CLASS() then SCode.encapsulatedBool(cls.prefixes.encapsulatedPrefix); + case EXPANDED_CLASS() then SCode.encapsulatedBool(cls.prefixes.encapsulatedPrefix); + case EXPANDED_DERIVED() then SCode.encapsulatedBool(cls.prefixes.encapsulatedPrefix); + else false; + end match; + end isEncapsulated; + function lastBaseClass input output InstNode node; protected diff --git a/Compiler/NFFrontEnd/NFEvalFunction.mo b/Compiler/NFFrontEnd/NFEvalFunction.mo index f52145d982..64f3bea934 100644 --- a/Compiler/NFFrontEnd/NFEvalFunction.mo +++ b/Compiler/NFFrontEnd/NFEvalFunction.mo @@ -125,7 +125,7 @@ algorithm fn_body := Function.getBody(fn); repl := createReplacements(fn, args); // TODO: Also apply replacements to the replacements themselves, i.e. the - // bindings of the function parameters. But the probably need to be + // bindings of the function parameters. But they probably need to be // sorted by dependencies first. fn_body := applyReplacements(repl, fn_body); ctrl := evaluateStatements(fn_body); @@ -225,9 +225,10 @@ algorithm ty := InstNode.getType(node); result := match ty - case Type.ARRAY() guard Type.hasKnownSize(ty) then Expression.fillType(ty, Expression.EMPTY()); + case Type.ARRAY() guard Type.hasKnownSize(ty) + then Expression.fillType(ty, Expression.EMPTY(Type.arrayElementType(ty))); case Type.COMPLEX() then buildRecordBinding(ty.cls); - else Expression.EMPTY(); + else Expression.EMPTY(ty); end match; end buildBinding; diff --git a/Compiler/NFFrontEnd/NFExpression.mo b/Compiler/NFFrontEnd/NFExpression.mo index 0c355f52ea..998b22ef26 100644 --- a/Compiler/NFFrontEnd/NFExpression.mo +++ b/Compiler/NFFrontEnd/NFExpression.mo @@ -199,6 +199,7 @@ public end MUTABLE; record EMPTY + Type ty; end EMPTY; function isCref @@ -568,6 +569,7 @@ public case TUPLE_ELEMENT() then exp.ty; case BOX() then Type.METABOXED(typeOf(exp.exp)); case MUTABLE() then typeOf(Mutable.access(exp.exp)); + case EMPTY() then exp.ty; else Type.UNKNOWN(); end match; end typeOf; diff --git a/Compiler/NFFrontEnd/NFFlatten.mo b/Compiler/NFFrontEnd/NFFlatten.mo index f188076b4e..f8a9fd66b5 100644 --- a/Compiler/NFFrontEnd/NFFlatten.mo +++ b/Compiler/NFFrontEnd/NFFlatten.mo @@ -82,6 +82,7 @@ import Variable = NFVariable; import ElementSource; import Ceval = NFCeval; import NFTyping.ExpOrigin; +import SimplifyExp = NFSimplifyExp; public type FunctionTree = FunctionTreeImpl.Tree; @@ -309,7 +310,6 @@ algorithm binding := flattenBinding(binding, prefix); end if; - // If the component is an array component with a binding and at least discrete variability, // move the binding into an equation. This avoids having to scalarize the binding. if Type.isArray(ty) and Binding.isBound(binding) and @@ -384,6 +384,7 @@ protected Expression binding_exp; Equation eq; list bindings; + Variability comp_var; algorithm dims := Type.arrayDims(ty); binding := Component.getBinding(comp); @@ -393,8 +394,11 @@ algorithm binding := flattenBinding(binding, prefix); binding_exp := Binding.getTypedExp(binding); - if Component.variability(comp) <= Variability.PARAMETER then + comp_var := Component.variability(comp); + if comp_var <= Variability.PARAMETER then binding_exp := Ceval.evalExp(binding_exp); + else + binding_exp := SimplifyExp.simplify(binding_exp); end if; if not Expression.isRecord(binding_exp) then diff --git a/Compiler/NFFrontEnd/NFFunction.mo b/Compiler/NFFrontEnd/NFFunction.mo index 9c7b49dd66..de45192718 100644 --- a/Compiler/NFFrontEnd/NFFunction.mo +++ b/Compiler/NFFrontEnd/NFFunction.mo @@ -70,6 +70,7 @@ import Dimension = NFDimension; import Statement = NFStatement; import Sections = NFSections; import Algorithm = NFAlgorithm; +import OperatorOverloading = NFOperatorOverloading; public @@ -340,17 +341,24 @@ uniontype Function list funcs; list fn_ders; + case SCode.CLASS() guard SCode.isOperatorRecord(def) + algorithm + fnNode := instFunction3(fnNode); + fnNode := OperatorOverloading.instConstructor(fnPath, fnNode, info); + then + (fnNode, false); + case SCode.CLASS() guard SCode.isRecord(def) algorithm fnNode := instFunction3(fnNode); - fnNode := Record.instConstructors(fnPath, fnNode, info); + fnNode := Record.instDefaultConstructor(fnPath, fnNode, info); then (fnNode, false); case SCode.CLASS(restriction = SCode.R_OPERATOR(), classDef = cdef as SCode.PARTS()) algorithm fnNode := instFunction3(fnNode); - fnNode := Record.instOperatorFunctions(fnNode, info); + fnNode := OperatorOverloading.instOperatorFunctions(fnNode, info); then (fnNode, false); @@ -368,6 +376,10 @@ uniontype Function case SCode.CLASS() algorithm + if SCode.isOperator(def) then + OperatorOverloading.checkOperatorRestrictions(fnNode); + end if; + fnNode := InstNode.setNodeType(NFInstNode.InstNodeType.ROOT_CLASS(), fnNode); fnNode := instFunction3(fnNode); fn := new(fnPath, fnNode); diff --git a/Compiler/NFFrontEnd/NFFunctionDerivative.mo b/Compiler/NFFrontEnd/NFFunctionDerivative.mo index f71c6b36c3..a0c4bf03f7 100644 --- a/Compiler/NFFrontEnd/NFFunctionDerivative.mo +++ b/Compiler/NFFrontEnd/NFFunctionDerivative.mo @@ -213,7 +213,7 @@ protected input Function fn; input InstNode scope; input SourceInfo info; - output Expression order = Expression.EMPTY(); + output Expression order = Expression.EMPTY(Type.UNKNOWN()); output list> conditions = {}; protected String id; diff --git a/Compiler/NFFrontEnd/NFInst.mo b/Compiler/NFFrontEnd/NFInst.mo index 16a32796f0..892aeb4a87 100644 --- a/Compiler/NFFrontEnd/NFInst.mo +++ b/Compiler/NFFrontEnd/NFInst.mo @@ -97,6 +97,7 @@ import FlatModel = NFFlatModel; import ElementSource; import SimplifyModel = NFSimplifyModel; import Record = NFRecord; +import OperatorOverloading = NFOperatorOverloading; public function instClassInProgram @@ -1808,7 +1809,7 @@ algorithm inst_cls := Class.INSTANCED_CLASS(ty, cls.elements, sections, cls.restriction); InstNode.updateClass(inst_cls, node); - instComplexType(ty); + instRecordConstructor(cls.restriction, node); then (); @@ -1822,6 +1823,8 @@ algorithm for i in 1:arrayLength(dims) loop dims[i] := instDimension(dims[i], dim_scope, info); end for; + + instRecordConstructor(cls.restriction, node); then (); @@ -1875,15 +1878,15 @@ algorithm ty := ComplexType.RECORD(cls_node, fields); end makeRecordComplexType; -function instComplexType - input Type ty; +function instRecordConstructor + input Restriction restriction; + input InstNode node; +protected + CachedData cache; + Absyn.Path path; algorithm - () := match ty - local - InstNode node; - CachedData cache; - - case Type.COMPLEX(complexTy = ComplexType.RECORD(node)) + () := match restriction + case Restriction.RECORD() algorithm cache := InstNode.getFuncCache(node); @@ -1892,8 +1895,13 @@ algorithm else algorithm InstNode.cacheInitFunc(node); - Record.instConstructors( - InstNode.scopePath(node, includeRoot = true), node, InstNode.info(node)); + path := InstNode.scopePath(node, includeRoot = true); + + if SCode.isOperatorRecord(InstNode.definition(node)) then + OperatorOverloading.instConstructor(path, node, InstNode.info(node)); + else + Record.instDefaultConstructor(path, node, InstNode.info(node)); + end if; then (); @@ -1903,7 +1911,7 @@ algorithm else (); end match; -end instComplexType; +end instRecordConstructor; function instBuiltinAttribute input output Modifier attribute; diff --git a/Compiler/NFFrontEnd/NFOperatorOverloading.mo b/Compiler/NFFrontEnd/NFOperatorOverloading.mo new file mode 100644 index 0000000000..e50ec6196f --- /dev/null +++ b/Compiler/NFFrontEnd/NFOperatorOverloading.mo @@ -0,0 +1,156 @@ +/* + * 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 NFOperatorOverloading + import Absyn; + import NFInstNode.InstNode; + +protected + import NFFunction.Function; + import Record = NFRecord; + import ComponentRef = NFComponentRef; + import NFClassTree.ClassTree; + import NFClass.Class; + +public + function instConstructor + input Absyn.Path path; + input output InstNode recordNode; + input SourceInfo info; + protected + ComponentRef ctor_ref; + Absyn.Path ctor_path; + Boolean ctor_overloaded; + InstNode ctor_node; + algorithm + // Check if the operator record has an overloaded constructor declared. + try + ctor_ref := Function.lookupFunctionSimple("'constructor'", recordNode); + ctor_overloaded := true; + else + ctor_overloaded := false; + end try; + + if ctor_overloaded then + // If it has an overloaded constructor, instantiate it and add the + // function(s) to the record node. + //ctor_node := ComponentRef.node(ctor_ref); + (_, ctor_node) := Function.instFunctionRef(ctor_ref, info); + ctor_path := InstNode.scopePath(ctor_node, includeRoot = true); + //ctor_node := Function.instFunction2(ctor_path, ctor_node, info); + + for f in Function.getCachedFuncs(ctor_node) loop + checkOperatorConstructorOutput(f, Class.lastBaseClass(recordNode), ctor_path, info); + recordNode := InstNode.cacheAddFunc(recordNode, f, false); + end for; + else + // If it doesn't have an an overloaded constructor, construct a default + // record constructor and use that instead. + recordNode := Record.instDefaultConstructor(path, recordNode, info); + end if; + end instConstructor; + + function instOperatorFunctions + input output InstNode node; + input SourceInfo info; + protected + ClassTree tree; + array mclss; + Absyn.Path path; + list allfuncs = {}, funcs; + algorithm + checkOperatorRestrictions(node); + tree := Class.classTree(InstNode.getClass(node)); + + () := match tree + case ClassTree.FLAT_TREE(classes = mclss) + algorithm + for op in mclss loop + //path := InstNode.scopePath(op, includeRoot = true); + //Function.instFunction2(path, op, info); + Function.instFunctionNode(op); + funcs := Function.getCachedFuncs(op); + allfuncs := listAppend(funcs, allfuncs); + end for; + + for f in allfuncs loop + node := InstNode.cacheAddFunc(node, f, false); + end for; + then + (); + + else + algorithm + Error.assertion(false, getInstanceName() + " got non-instantiated function", sourceInfo()); + then + fail(); + + end match; + end instOperatorFunctions; + + function checkOperatorRestrictions + input InstNode operatorNode; + algorithm + if not SCode.isElementEncapsulated(InstNode.definition(operatorNode)) then + Error.addSourceMessage(Error.OPERATOR_NOT_ENCAPSULATED, + {Absyn.pathString(InstNode.scopePath(operatorNode, includeRoot = true))}, + InstNode.info(operatorNode)); + fail(); + end if; + end checkOperatorRestrictions; + +protected + function checkOperatorConstructorOutput + input Function fn; + input InstNode recordNode; + input Absyn.Path path; + input SourceInfo info; + protected + InstNode output_node, output_ty; + algorithm + if listLength(fn.outputs) <> 1 then + Error.addSourceMessage(Error.OPERATOR_OVERLOADING_ONE_OUTPUT_ERROR, + {Absyn.pathString(path)}, info); + fail(); + end if; + + output_node := listHead(fn.outputs); + output_ty := InstNode.classScope(output_node); + if not InstNode.isSame(output_ty, recordNode) then + Error.addSourceMessage(Error.OPERATOR_OVERLOADING_INVALID_OUTPUT_TYPE, + {InstNode.name(output_node), Absyn.pathString(path), + InstNode.name(recordNode), InstNode.name(output_ty)}, info); + fail(); + end if; + end checkOperatorConstructorOutput; + + annotation(__OpenModelica_Interface="frontend"); +end NFOperatorOverloading; diff --git a/Compiler/NFFrontEnd/NFRecord.mo b/Compiler/NFFrontEnd/NFRecord.mo index 102c4dd668..85567a28ab 100644 --- a/Compiler/NFFrontEnd/NFRecord.mo +++ b/Compiler/NFFrontEnd/NFRecord.mo @@ -67,53 +67,6 @@ import ErrorExt; public -function instConstructors - input Absyn.Path path; - input output InstNode node; - input SourceInfo info; -protected - InstNode ctor_over; - DAE.FunctionAttributes attr; - ComponentRef con_ref; - Boolean ctor_defined; -algorithm - - // See if we have overloaded constructors. - try - con_ref := Function.lookupFunctionSimple("'constructor'", node); - ctor_defined := true; - else - ctor_defined := false; - end try; - - if ctor_defined then - ctor_over := ComponentRef.node(con_ref); - ctor_over := Function.instFunction2(InstNode.scopePath(ctor_over, includeRoot = true), ctor_over, InstNode.info(ctor_over)); - for f in Function.getCachedFuncs(ctor_over) loop - node := InstNode.cacheAddFunc(node, f, false); - end for; - end if; - - // See if we have '0' constructor. - try - con_ref := Function.lookupFunctionSimple("'0'", node); - ctor_defined := true; - else - ctor_defined := false; - end try; - - if ctor_defined then - ctor_over := ComponentRef.node(con_ref); - - ctor_over := Function.instFunction2(InstNode.scopePath(ctor_over, includeRoot = true), ctor_over, InstNode.info(ctor_over)); - for f in Function.getCachedFuncs(ctor_over) loop - node := InstNode.cacheAddFunc(node, f, false); - end for; - end if; - - node := instDefaultConstructor(path, node, info); -end instConstructors; - function instDefaultConstructor input Absyn.Path path; input output InstNode node; @@ -212,43 +165,5 @@ algorithm end match; end collectRecordParams; -function instOperatorFunctions - input output InstNode node; - input SourceInfo info; -protected - ClassTree tree; - array mclss; - InstNode op; - Absyn.Path path; - list allfuncs = {}, funcs; -algorithm - tree := Class.classTree(InstNode.getClass(node)); - - () := match tree - case ClassTree.FLAT_TREE(classes = mclss) - algorithm - for i in arrayLength(mclss):-1:1 loop - op := mclss[i]; - path := InstNode.scopePath(op); - Function.instFunction2(path, op, info); - funcs := Function.getCachedFuncs(op); - allfuncs := listAppend(allfuncs,funcs); - end for; - - for f in allfuncs loop - node := InstNode.cacheAddFunc(node, f, false); - end for; - then - (); - - else - algorithm - Error.assertion(false, getInstanceName() + " got non-instantiated function", sourceInfo()); - then - fail(); - - end match; -end instOperatorFunctions; - annotation(__OpenModelica_Interface="frontend"); end NFRecord; diff --git a/Compiler/NFFrontEnd/NFRestriction.mo b/Compiler/NFFrontEnd/NFRestriction.mo index e257ad673d..5ce0b0e607 100644 --- a/Compiler/NFFrontEnd/NFRestriction.mo +++ b/Compiler/NFFrontEnd/NFRestriction.mo @@ -48,7 +48,11 @@ public record FUNCTION end FUNCTION; record MODEL end MODEL; record OPERATOR end OPERATOR; - record RECORD end RECORD; + + record RECORD + Boolean isOperator; + end RECORD; + record RECORD_CONSTRUCTOR end RECORD_CONSTRUCTOR; record TYPE end TYPE; record UNKNOWN end UNKNOWN; @@ -64,7 +68,7 @@ public case SCode.Restriction.R_FUNCTION() then FUNCTION(); case SCode.Restriction.R_MODEL() then MODEL(); case SCode.Restriction.R_OPERATOR() then OPERATOR(); - case SCode.Restriction.R_RECORD() then RECORD(); + case SCode.Restriction.R_RECORD() then RECORD(sres.isOperator); case SCode.Restriction.R_TYPE() then TYPE(); else MODEL(); end match; diff --git a/Compiler/NFFrontEnd/NFSections.mo b/Compiler/NFFrontEnd/NFSections.mo index eb290e3cd8..ec659d1af0 100644 --- a/Compiler/NFFrontEnd/NFSections.mo +++ b/Compiler/NFFrontEnd/NFSections.mo @@ -96,15 +96,29 @@ public function prependEquation input Equation eq; input output Sections sections; + input Boolean isInitial = false; algorithm sections := match sections case SECTIONS() algorithm - sections.equations := eq :: sections.equations; + if isInitial then + sections.initialEquations := eq :: sections.initialEquations; + else + sections.equations := eq :: sections.equations; + end if; then sections; - else SECTIONS({eq}, {}, {}, {}); + case EMPTY() + then if isInitial then SECTIONS({}, {eq}, {}, {}) else SECTIONS({eq}, {}, {}, {}); + + else + algorithm + Error.assertion(false, getInstanceName() + + " got invalid Sections to prepend equation to", sourceInfo()); + then + fail(); + end match; end prependEquation; diff --git a/Compiler/NFFrontEnd/NFTypeCheck.mo b/Compiler/NFFrontEnd/NFTypeCheck.mo index 7c8c9b87e8..35b2e3360a 100644 --- a/Compiler/NFFrontEnd/NFTypeCheck.mo +++ b/Compiler/NFFrontEnd/NFTypeCheck.mo @@ -204,7 +204,7 @@ algorithm if oper_defined then fn_ref := Function.instFunctionRef(fn_ref, InstNode.info(node1)); for fn in Function.typeRefCache(fn_ref) loop - checkValidOperatorOverload(opstr, fn, node1); + // checkValidOperatorOverload(opstr, fn, node1); candidates := fn::candidates; end for; end if; @@ -226,7 +226,7 @@ algorithm if oper_defined then fn_ref := Function.instFunctionRef(fn_ref, InstNode.info(node2)); for fn in Function.typeRefCache(fn_ref) loop - checkValidOperatorOverload(opstr, fn, node2); + //checkValidOperatorOverload(opstr, fn, node2); candidates := fn::candidates; end for; end if; @@ -237,7 +237,7 @@ algorithm args := {(inExp1,inType1,var1),(inExp2,inType2,var2)}; matchedFunctions := Function.matchFunctionsSilent(candidates, args, {}, info); - // We only allow exact matches for operator overlaoding. e.g. no casting or generic matches. + // We only allow exact matches for operator overloading. e.g. no casting or generic matches. exactMatches := MatchedFunction.getExactMatches(matchedFunctions); if listEmpty(exactMatches) then @@ -297,10 +297,9 @@ protected Type ty; Variability var; algorithm - exp1 := inExp1; exp2 := inExp2; for fn in candidates loop - {in1,in2} := fn.inputs; + in1 :: in2 :: _ := fn.inputs; (_, _, mk1) := matchTypes(InstNode.getType(in1),inType1,inExp1,false); (_, _, mk2) := matchTypes(InstNode.getType(in2),inType2,inExp2,false); @@ -323,7 +322,6 @@ algorithm end if; end for; - if listLength(matchedfuncs) == 1 then (operfn, {exp1,exp2}, var)::_ := matchedfuncs; outType := Function.returnType(operfn); @@ -337,125 +335,125 @@ algorithm end if; end implicitConstructAndMatch; -function checkValidBinaryOperatorOverload - input String oper_name; - input Function oper_func; - input InstNode rec_node; -protected - SourceInfo info; -algorithm - info := InstNode.info(oper_func.node); - checkOneOutput(oper_name, oper_func.outputs, rec_node, info); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, info); - checkTwoInputs(oper_name, oper_func.inputs, rec_node, info); -end checkValidBinaryOperatorOverload; - -function checkValidOperatorOverload - input String oper_name; - input Function oper_func; - input InstNode rec_node; -protected - Type ty1, ty2; - InstNode out_class; -algorithm - () := match oper_name - case "'constructor'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'0'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'+'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'-'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'*'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'/'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'^'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); - then (); - case "'and'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.BOOLEAN_NODE, InstNode.info(oper_func.node)); - then (); - case "'or'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.BOOLEAN_NODE, InstNode.info(oper_func.node)); - then (); - case "'not'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.BOOLEAN_NODE, InstNode.info(oper_func.node)); - then (); - case "'String'" algorithm - checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); - checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.STRING_NODE, InstNode.info(oper_func.node)); - then (); - - else (); - - end match; -end checkValidOperatorOverload; - -public -function checkOneOutput - input String oper_name; - input list outputs; - input InstNode rec_node; - input SourceInfo info; -protected - InstNode out_class; -algorithm - if listLength(outputs) <> 1 then - Error.addSourceMessage(Error.OPERATOR_OVERLOADING_WARNING, - {"Overloaded " + oper_name + " operator functions are required to have exactly one output. Found " - + intString(listLength(outputs))}, info); - end if; -end checkOneOutput; - -public -function checkTwoInputs - input String oper_name; - input list inputs; - input InstNode rec_node; - input SourceInfo info; -protected - InstNode out_class; -algorithm - if listLength(inputs) < 2 then - Error.addSourceMessage(Error.OPERATOR_OVERLOADING_WARNING, - {"Binary overloaded " + oper_name + " operator functions are required to have at least two inputs. Found " - + intString(listLength(inputs))}, info); - end if; -end checkTwoInputs; - -function checkOutputType - input String oper_name; - input InstNode outc; - input InstNode expected; - input SourceInfo info; -protected - InstNode out_class; -algorithm - out_class := InstNode.classScope(outc); - if not InstNode.isSame(out_class, expected) then - Error.addSourceMessage(Error.OPERATOR_OVERLOADING_WARNING, - {"Wrong type for output of overloaded operator function '"+ oper_name + - "'. Expected '" + InstNode.scopeName(expected) + "' Found '" + InstNode.scopeName(outc) + "'"}, info); - end if; -end checkOutputType; +//function checkValidBinaryOperatorOverload +// input String oper_name; +// input Function oper_func; +// input InstNode rec_node; +//protected +// SourceInfo info; +//algorithm +// info := InstNode.info(oper_func.node); +// checkOneOutput(oper_name, oper_func.outputs, rec_node, info); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, info); +// checkTwoInputs(oper_name, oper_func.inputs, rec_node, info); +//end checkValidBinaryOperatorOverload; + +//function checkValidOperatorOverload +// input String oper_name; +// input Function oper_func; +// input InstNode rec_node; +//protected +// Type ty1, ty2; +// InstNode out_class; +//algorithm +// () := match oper_name +// case "'constructor'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'0'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'+'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'-'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'*'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'/'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'^'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), rec_node, InstNode.info(oper_func.node)); +// then (); +// case "'and'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.BOOLEAN_NODE, InstNode.info(oper_func.node)); +// then (); +// case "'or'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.BOOLEAN_NODE, InstNode.info(oper_func.node)); +// then (); +// case "'not'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.BOOLEAN_NODE, InstNode.info(oper_func.node)); +// then (); +// case "'String'" algorithm +// checkOneOutput(oper_name, oper_func.outputs, rec_node, InstNode.info(oper_func.node)); +// checkOutputType(oper_name, List.first(oper_func.outputs), NFBuiltin.STRING_NODE, InstNode.info(oper_func.node)); +// then (); +// +// else (); +// +// end match; +//end checkValidOperatorOverload; + +//public +//function checkOneOutput +// input String oper_name; +// input list outputs; +// input InstNode rec_node; +// input SourceInfo info; +//protected +// InstNode out_class; +//algorithm +// if listLength(outputs) <> 1 then +// Error.addSourceMessage(Error.OPERATOR_OVERLOADING_WARNING, +// {"Overloaded " + oper_name + " operator functions are required to have exactly one output. Found " +// + intString(listLength(outputs))}, info); +// end if; +//end checkOneOutput; +// +//public +//function checkTwoInputs +// input String oper_name; +// input list inputs; +// input InstNode rec_node; +// input SourceInfo info; +//protected +// InstNode out_class; +//algorithm +// if listLength(inputs) < 2 then +// Error.addSourceMessage(Error.OPERATOR_OVERLOADING_WARNING, +// {"Binary overloaded " + oper_name + " operator functions are required to have at least two inputs. Found " +// + intString(listLength(inputs))}, info); +// end if; +//end checkTwoInputs; +// +//function checkOutputType +// input String oper_name; +// input InstNode outc; +// input InstNode expected; +// input SourceInfo info; +//protected +// InstNode out_class; +//algorithm +// out_class := InstNode.classScope(outc); +// if not InstNode.isSame(out_class, expected) then +// Error.addSourceMessage(Error.OPERATOR_OVERLOADING_WARNING, +// {"Wrong type for output of overloaded operator function '"+ oper_name + +// "'. Expected '" + InstNode.scopeName(expected) + "' Found '" + InstNode.scopeName(outc) + "'"}, info); +// end if; +//end checkOutputType; function checkBinaryOperationAdd input Expression exp1; @@ -861,9 +859,9 @@ algorithm fn_ref := Function.lookupFunctionSimple(opstr, node1); fn_ref := Function.instFunctionRef(fn_ref, InstNode.info(node1)); candidates := Function.typeRefCache(fn_ref); - for fn in candidates loop - checkValidOperatorOverload(opstr, fn, node1); - end for; + //for fn in candidates loop + // checkValidOperatorOverload(opstr, fn, node1); + //end for; args := {(inExp1,inType1,var)}; matchedFunctions := Function.matchFunctionsSilent(candidates, args, {}, info); diff --git a/Compiler/Util/Error.mo b/Compiler/Util/Error.mo index 1720a36ca4..0b4bba8a0c 100644 --- a/Compiler/Util/Error.mo +++ b/Compiler/Util/Error.mo @@ -805,6 +805,12 @@ public constant Message INVALID_FUNCTION_DERIVATIVE_ATTR = MESSAGE(338, TRANSLAT Util.gettext("‘%s‘ is not a valid function derivative attribute.")); public constant Message INVALID_FUNCTION_DERIVATIVE_INPUT = MESSAGE(339, TRANSLATION(), ERROR(), Util.gettext("‘%s‘ is not an input of function ‘%s‘.")); +public constant Message OPERATOR_OVERLOADING_ONE_OUTPUT_ERROR = MESSAGE(340, TRANSLATION(), ERROR(), + Util.gettext("Operator %s must have exactly one output.")); +public constant Message OPERATOR_OVERLOADING_INVALID_OUTPUT_TYPE = MESSAGE(341, TRANSLATION(), ERROR(), + Util.gettext("Output ‘%s‘ in operator %s must be of type %s, got type %s.")); +public constant Message OPERATOR_NOT_ENCAPSULATED = MESSAGE(342, TRANSLATION(), ERROR(), + Util.gettext("Operator %s is not encapsulated.")); public constant Message INITIALIZATION_NOT_FULLY_SPECIFIED = MESSAGE(496, TRANSLATION(), WARNING(), Util.gettext("The initial conditions are not fully specified. %s.")); public constant Message INITIALIZATION_OVER_SPECIFIED = MESSAGE(497, TRANSLATION(), WARNING(), @@ -1090,10 +1096,6 @@ public constant Message SUSAN_ERROR = MESSAGE(7000, TRANSLATION(), ERROR(), Util.notrans("%s")); public constant Message TEMPLATE_ERROR = MESSAGE(7001, TRANSLATION(), ERROR(), Util.gettext("Template error: %s.")); -public constant Message OPERATOR_OVERLOADING_WARNING = MESSAGE(7002, TRANSLATION(), WARNING(), - Util.gettext("Operator Overloading: %s.")); -public constant Message OPERATOR_OVERLOADING_ERROR = MESSAGE(7003, TRANSLATION(), ERROR(), - Util.gettext("Operator Overloading: %s.")); public constant Message PARMODELICA_WARNING = MESSAGE(7004, TRANSLATION(), WARNING(), Util.notrans("ParModelica: %s.")); public constant Message PARMODELICA_ERROR = MESSAGE(7005, TRANSLATION(), ERROR(), diff --git a/Compiler/boot/LoadCompilerSources.mos b/Compiler/boot/LoadCompilerSources.mos index 767ed5128a..5fafa2e355 100644 --- a/Compiler/boot/LoadCompilerSources.mos +++ b/Compiler/boot/LoadCompilerSources.mos @@ -324,6 +324,7 @@ if true then /* Suppress output */ "../NFFrontEnd/NFLookupState.mo", "../NFFrontEnd/NFModifier.mo", "../NFFrontEnd/NFOperator.mo", + "../NFFrontEnd/NFOperatorOverloading.mo", "../NFFrontEnd/NFPrefixes.mo", "../NFFrontEnd/NFRangeIterator.mo", "../NFFrontEnd/NFRecord.mo",