diff --git a/.CI/compliance-newinst.failures b/.CI/compliance-newinst.failures index 8a21a6ea4af..28f1b25d797 100644 --- a/.CI/compliance-newinst.failures +++ b/.CI/compliance-newinst.failures @@ -110,9 +110,6 @@ ModelicaCompliance.Functions.HigherOrder.PartialApplication2 ModelicaCompliance.Functions.HigherOrder.PartialApplication3 ModelicaCompliance.Functions.HigherOrder.Quadrature1 ModelicaCompliance.Functions.HigherOrder.Quadrature2 -ModelicaCompliance.Functions.Records.RecordConstructorConstantModifiable -ModelicaCompliance.Functions.Records.RecordConstructorDefaultValue -ModelicaCompliance.Functions.Records.RecordConstructorDefaultValueDependent ModelicaCompliance.Functions.Restrictions.FunctionAssignInput ModelicaCompliance.Inheritance.Flattening.DuplicateInheritedNeqClasses ModelicaCompliance.Inheritance.Restrictions.ArrayClassWithComp diff --git a/OMCompiler/Compiler/NFFrontEnd/NFCall.mo b/OMCompiler/Compiler/NFFrontEnd/NFCall.mo index 5dd7f6afed6..6a861f24d24 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFCall.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFCall.mo @@ -38,6 +38,7 @@ import Expression = NFExpression; import NFInstNode.InstNode; import NFPrefixes.Variability; import Type = NFType; +import Record = NFRecord; protected import BuiltinCall = NFBuiltinCall; @@ -582,8 +583,37 @@ uniontype Call output Expression exp; algorithm exp := match call - case TYPED_CALL() - then Expression.RECORD(Function.name(call.fn), ty, call.arguments); + local + Expression arg; + list call_args, local_args, args; + list fields; + + case TYPED_CALL(arguments = call_args) + algorithm + local_args := Function.getLocalArguments(call.fn); + fields := Type.recordFields(ty); + args := {}; + + for field in fields loop + if Record.Field.isInput(field) then + arg :: call_args := call_args; + else + arg :: local_args := local_args; + end if; + + args := arg :: args; + end for; + + args := listReverseInPlace(args); + then + Expression.RECORD(Function.name(call.fn), ty, args); + + else + algorithm + Error.assertion(false, getInstanceName() + " got unknown call", sourceInfo()); + then + fail(); + end match; end toRecordExpression; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFCeval.mo b/OMCompiler/Compiler/NFFrontEnd/NFCeval.mo index 11f676077c4..dc6a0f624c2 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFCeval.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFCeval.mo @@ -51,6 +51,7 @@ import ComplexType = NFComplexType; import Subscript = NFSubscript; import NFTyping.TypingError; import DAE; +import Record = NFRecord; protected import NFFunction.Function; @@ -701,34 +702,33 @@ function makeRecordBindingExp protected ClassTree tree; array comps; - list fields; - list field_names; + list args; + list fields; Type ty; InstNode c; ComponentRef cr; - Expression field_exp; + Expression arg; algorithm tree := Class.classTree(InstNode.getClass(typeNode)); comps := ClassTree.getComponents(tree); - fields := {}; - field_names := {}; + args := {}; for i in arrayLength(comps):-1:1 loop c := comps[i]; ty := InstNode.getType(c); cr := ComponentRef.CREF(c, {}, ty, NFComponentRef.Origin.CREF, cref); - field_exp := Expression.CREF(ty, cr); + arg := Expression.CREF(ty, cr); if Component.variability(InstNode.component(c)) <= Variability.PARAMETER then - field_exp := evalExp_impl(field_exp, EvalTarget.IGNORE_ERRORS()); + arg := evalExp_impl(arg, EvalTarget.IGNORE_ERRORS()); end if; - fields := field_exp :: fields; - field_names := InstNode.name(c) :: field_names; + args := arg :: args; end for; - ty := Type.setRecordFields(field_names, recordType); - exp := Expression.RECORD(InstNode.scopePath(recordNode), ty, fields); + fields := Record.collectRecordFields(typeNode); + ty := Type.setRecordFields(fields, recordType); + exp := Expression.RECORD(InstNode.scopePath(recordNode), ty, args); end makeRecordBindingExp; function splitRecordArrayExp diff --git a/OMCompiler/Compiler/NFFrontEnd/NFComplexType.mo b/OMCompiler/Compiler/NFFrontEnd/NFComplexType.mo index 78971037427..5ea5ed698fc 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFComplexType.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFComplexType.mo @@ -31,6 +31,7 @@ encapsulated uniontype NFComplexType import NFInstNode.InstNode; + import Record = NFRecord; protected import ComplexType = NFComplexType; @@ -59,7 +60,7 @@ public record RECORD InstNode constructor; - list fieldNames; + list fields; end RECORD; record EXTERNAL_OBJECT diff --git a/OMCompiler/Compiler/NFFrontEnd/NFExpression.mo b/OMCompiler/Compiler/NFFrontEnd/NFExpression.mo index bad90680b41..58e8d71fab0 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFExpression.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFExpression.mo @@ -69,6 +69,7 @@ public import NFComponentRef.Origin; import NFTyping.ExpOrigin; import Values; + import Record = NFRecord; uniontype ClockKind record INFERRED_CLOCK @@ -1725,8 +1726,7 @@ public then DAE.ARRAY(Type.toDAE(exp.ty), Type.isScalarArray(exp.ty), list(toDAE(e) for e in exp.elements)); - case RECORD(ty = Type.COMPLEX(complexTy = ComplexType.RECORD(fieldNames = names))) - then DAE.RECORD(exp.path, list(toDAE(e) for e in exp.elements), names, Type.toDAE(exp.ty)); + case RECORD() then toDAERecord(exp.ty, exp.path, exp.elements); case RANGE() then DAE.RANGE( @@ -1807,6 +1807,37 @@ public end match; end toDAE; + function toDAERecord + input Type ty; + input Absyn.Path path; + input list args; + output DAE.Exp exp; + protected + list field_names = {}; + Expression arg; + list rest_args = args; + list dargs = {}; + algorithm + for field in Type.recordFields(ty) loop + arg :: rest_args := rest_args; + + () := match field + case Record.Field.INPUT() + algorithm + field_names := field.name :: field_names; + dargs := toDAE(arg) :: dargs; + then + (); + + else (); + end match; + end for; + + field_names := listReverseInPlace(field_names); + dargs := listReverseInPlace(dargs); + exp := DAE.RECORD(path, dargs, field_names, Type.toDAE(ty)); + end toDAERecord; + function toDAEValueOpt input Option exp; output Option value = Util.applyOption(exp, toDAEValue); @@ -1820,7 +1851,8 @@ public local Type ty; list vals; - list fields; + list fields; + list field_names; case INTEGER() then Values.INTEGER(exp.value); case REAL() then Values.REAL(exp.value); @@ -1835,8 +1867,7 @@ public then ValuesUtil.makeArray(vals); - case RECORD(ty = Type.COMPLEX(complexTy = ComplexType.RECORD(fieldNames = fields))) - then Values.RECORD(exp.path, list(toDAEValue(e) for e in exp.elements), fields, -1); + case RECORD() then toDAEValueRecord(exp.ty, exp.path, exp.elements); else algorithm @@ -1846,6 +1877,37 @@ public end match; end toDAEValue; + function toDAEValueRecord + input Type ty; + input Absyn.Path path; + input list args; + output Values.Value value; + protected + list field_names = {}; + Expression arg; + list rest_args = args; + list values = {}; + algorithm + for field in Type.recordFields(ty) loop + arg :: rest_args := rest_args; + + () := match field + case Record.Field.INPUT() + algorithm + field_names := field.name :: field_names; + values := toDAEValue(arg) :: values; + then + (); + + else (); + end match; + end for; + + field_names := listReverseInPlace(field_names); + values := listReverseInPlace(values); + value := Values.RECORD(path, values, field_names, -1); + end toDAEValueRecord; + function dimensionCount input Expression exp; output Integer dimCount; @@ -5079,7 +5141,6 @@ public end match; end nthRecordElement; - function splitRecordCref input Expression exp; output Expression outExp; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo index b97ef32bff3..d99552510fc 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo @@ -193,7 +193,7 @@ algorithm if Binding.isBound(b) then b := flattenBinding(b, ComponentRef.rest(prefix)); - bindings := getRecordBindings(b); + bindings := getRecordBindings(b, comps); Error.assertion(listLength(bindings) == arrayLength(comps), getInstanceName() + " got record binding with wrong number of elements for " + @@ -475,18 +475,19 @@ end isTypeAttributeNamed; function getRecordBindings input Binding binding; - output list recordBindings; + input array comps; + output list recordBindings = {}; protected Expression binding_exp; - list expl; Variability var; algorithm binding_exp := Binding.getTypedExp(binding); var := Binding.variability(binding); + // Convert the expressions in the record expression into bindings. recordBindings := match binding_exp - case Expression.RECORD() then - list(if Expression.isEmpty(e) then + case Expression.RECORD() + then list(if Expression.isEmpty(e) then // The binding for a record field might be Expression.EMPTY if it comes // from an evaluated function call where it wasn't assigned a value. NFBinding.EMPTY_BINDING diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo b/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo index 816f89f5a3e..8c813d7d6f1 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo @@ -1771,6 +1771,24 @@ uniontype Function output Boolean isPartial = InstNode.isPartial(fn.node); end isPartial; + function getLocalArguments + input Function fn; + output list localArgs = {}; + protected + Binding binding; + algorithm + for l in fn.locals loop + if InstNode.isComponent(l) then + binding := Component.getBinding(InstNode.component(l)); + Error.assertion(Binding.hasExp(binding), + getInstanceName() + " got local component without binding", sourceInfo()); + localArgs := Binding.getExp(binding) :: localArgs; + end if; + end for; + + localArgs := listReverseInPlace(localArgs); + end getLocalArguments; + protected function collectParams "Sorts all the function parameters as inputs, outputs and locals." diff --git a/OMCompiler/Compiler/NFFrontEnd/NFInst.mo b/OMCompiler/Compiler/NFFrontEnd/NFInst.mo index b747aa738c6..3f76b81f62f 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFInst.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFInst.mo @@ -2212,12 +2212,11 @@ function makeRecordComplexType output ComplexType ty; protected InstNode cls_node; - list inputs; - list fields; + list fields; algorithm cls_node := if SCodeUtil.isOperatorRecord(InstNode.definition(node)) then InstNode.classScope(node) else InstNode.classScope(InstNode.getDerivedNode(node)); - fields := list(InstNode.name(c) for c in Record.collectRecordParams(cls_node)); + fields := Record.collectRecordFields(cls_node); ty := ComplexType.RECORD(cls_node, fields); end makeRecordComplexType; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo b/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo index 9ecd441bddb..0fad54358fc 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo @@ -61,9 +61,30 @@ import NFClassTree.ClassTree; import ComplexType = NFComplexType; import ComponentRef = NFComponentRef; import NFFunction.FunctionStatus; +import MetaModelica.Dangerous.listReverseInPlace; public +encapsulated uniontype Field + record INPUT + String name; + end INPUT; + + record LOCAL + String name; + end LOCAL; + + function isInput + input Field field; + output Boolean isInput; + algorithm + isInput := match field + case INPUT() then true; + else false; + end match; + end isInput; +end Field; + function instDefaultConstructor input Absyn.Path path; input output InstNode node; @@ -175,5 +196,76 @@ algorithm end if; end collectRecordParam; +function collectRecordFields + input InstNode recNode; + output list fields; +protected + ClassTree tree; +algorithm + tree := Class.classTree(InstNode.getClass(recNode)); + fields := ClassTree.foldComponents(tree, collectRecordField, {}); + fields := listReverseInPlace(fields); +end collectRecordFields; + +function collectRecordField + input InstNode component; + input output list fields; +protected + InstNode comp_node = InstNode.resolveInner(component); + Component comp; +algorithm + if InstNode.isProtected(comp_node) then + fields := Field.LOCAL(InstNode.name(comp_node)) :: fields; + else + comp := InstNode.component(comp_node); + + if Component.isConst(comp) and Component.hasBinding(comp) then + fields := Field.LOCAL(InstNode.name(comp_node)) :: fields; + else + fields := Field.INPUT(InstNode.name(comp_node)) :: fields; + end if; + end if; +end collectRecordField; + +function fieldsToDAE + input list fields; + output list fieldNames = {}; +algorithm + for field in fields loop + () := match field + case Field.INPUT() + algorithm + fieldNames := field.name :: fieldNames; + then + (); + + else (); + end match; + end for; +end fieldsToDAE; + +function foldInputFields + input list fields; + input list args; + input FuncT func; + input output ArgT foldArg; + + partial function FuncT + input T arg; + input output ArgT foldArg; + end FuncT; +protected + T arg; + list rest_args = args; +algorithm + for field in fields loop + arg :: rest_args := rest_args; + + if Field.isInput(field) then + foldArg := func(arg, foldArg); + end if; + end for; +end foldInputFields; + annotation(__OpenModelica_Interface="frontend"); end NFRecord; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFType.mo b/OMCompiler/Compiler/NFFrontEnd/NFType.mo index b873169f920..2d95e26ec66 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFType.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFType.mo @@ -44,6 +44,7 @@ public import ConvertDAE = NFConvertDAE; import ComponentRef = NFComponentRef; import NFFunction.Function; + import Record = NFRecord; type FunctionType = enumeration( FUNCTIONAL_PARAMETER "Function parameter of function type.", @@ -880,8 +881,18 @@ public end match; end lookupRecordFieldType; + function recordFields + input Type recordType; + output list fields; + algorithm + fields := match recordType + case COMPLEX(complexTy = ComplexType.RECORD(fields = fields)) then fields; + else {}; + end match; + end recordFields; + function setRecordFields - input list fields; + input list fields; input output Type recordType; algorithm recordType := match recordType diff --git a/testsuite/flattening/modelica/scodeinst/Makefile b/testsuite/flattening/modelica/scodeinst/Makefile index a92fbbf00bc..94549b799bd 100644 --- a/testsuite/flattening/modelica/scodeinst/Makefile +++ b/testsuite/flattening/modelica/scodeinst/Makefile @@ -708,6 +708,7 @@ RecordBinding2.mo \ RecordBinding3.mo \ RecordBinding4.mo \ RecordBinding5.mo \ +RecordBinding6.mo \ RecordConstructor1.mo \ RecordConstructor2.mo \ RecordExtends1.mo \ diff --git a/testsuite/flattening/modelica/scodeinst/RecordBinding6.mo b/testsuite/flattening/modelica/scodeinst/RecordBinding6.mo new file mode 100644 index 00000000000..abfe4ded93e --- /dev/null +++ b/testsuite/flattening/modelica/scodeinst/RecordBinding6.mo @@ -0,0 +1,29 @@ +// name: RecordBinding6 +// keywords: +// status: correct +// cflags: -d=newInst +// + +record R + Real x; + constant Real y = 2.0; + Real z; +end R; + +model RecordBinding6 + constant R r = R(1.0, 3.0); + constant Real x = r.x; + constant Real y = r.y; + constant Real z = r.z; +end RecordBinding6; + +// Result: +// class RecordBinding6 +// constant Real r.x = 1.0; +// constant Real r.y = 2.0; +// constant Real r.z = 3.0; +// constant Real x = 1.0; +// constant Real y = 2.0; +// constant Real z = 3.0; +// end RecordBinding6; +// endResult