From e947c52a3a45cd39ad2c3c36c51375706956323e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=96stlund?= Date: Tue, 29 Aug 2023 17:15:28 +0200 Subject: [PATCH] Improving typing of dimensions in relaxed contexts (#11098) Fixes #11088 --- OMCompiler/Compiler/NFFrontEnd/NFTyping.mo | 86 ++++++++++++------- .../instance-API/GetModelInstanceDim1.mos | 76 ++++++++++++++++ testsuite/openmodelica/instance-API/Makefile | 1 + 3 files changed, 134 insertions(+), 29 deletions(-) create mode 100644 testsuite/openmodelica/instance-API/GetModelInstanceDim1.mos diff --git a/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo b/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo index bd163c7e3ff..e2667498532 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo @@ -679,41 +679,17 @@ algorithm then fail(); - // An untyped binding, type the expression only as much as is needed - // to get the dimension we're looking for. case Binding.UNTYPED_BINDING() - algorithm - dim_index := index + parent_dims; - (dim, oexp, ty_err) := typeExpDim(b.bindingExp, dim_index, InstContext.set(context, NFInstContext.DIMENSION), info); - - // If the deduced dimension is unknown, evaluate the binding and try again. - if Dimension.isUnknown(dim) and not TypingError.isError(ty_err) then - exp := if isSome(oexp) then Util.getOption(oexp) else b.bindingExp; - exp := Ceval.evalExp(exp, Ceval.EvalTarget.DIMENSION(component, index, exp, info)); - (dim, ty_err) := nthDimensionBoundsChecked(Expression.typeOf(exp), dim_index); - end if; - then - (dim, ty_err); + then deduceDimensionFromExp(b.bindingExp, NONE(), index, parent_dims, component, context, info); - // A typed binding, get the dimension from the binding's type. case Binding.TYPED_BINDING() - algorithm - dim_index := index + parent_dims; - (dim, ty_err) := nthDimensionBoundsChecked(b.bindingType, dim_index); - - // If the deduced dimension is unknown, evaluate the binding and try again. - if Dimension.isUnknown(dim) and not TypingError.isError(ty_err) then - exp := Ceval.evalExp(b.bindingExp, Ceval.EvalTarget.DIMENSION(component, index, b.bindingExp, info)); - (dim, ty_err) := nthDimensionBoundsChecked(Expression.typeOf(exp), dim_index); - end if; - then - (dim, ty_err); - + then deduceDimensionFromExp(b.bindingExp, SOME(b.bindingType), index, parent_dims, component, context, info); else (dimension, TypingError.NO_ERROR()); end match; () := match ty_err case TypingError.OUT_OF_BOUNDS() + guard not InstContext.inRelaxed(context) algorithm Error.addSourceMessage(Error.DIMENSION_DEDUCTION_FROM_BINDING_FAILURE, {String(index), InstNode.name(component), Binding.toString(b)}, info); @@ -723,12 +699,18 @@ algorithm else (); end match; - // Make sure the dimension is constant evaluted, and also mark it as structural. + // Make sure the dimension is constant evaluated, and also mark it as structural. dim := match dim case Dimension.EXP(exp = exp) algorithm Structural.markExp(exp); - exp := Ceval.evalExp(exp, Ceval.EvalTarget.DIMENSION(component, index, exp, info)); + + if InstContext.inRelaxed(context) then + exp := Ceval.tryEvalExp(exp); + else + exp := Ceval.evalExp(exp, Ceval.EvalTarget.DIMENSION(component, index, exp, info)); + end if; + exp := subscriptDimExp(exp, component); then Dimension.fromExp(exp, dim.var); @@ -752,6 +734,52 @@ algorithm end match; end typeDimension; +function deduceDimensionFromExp + input Expression exp; + input Option ty; + input Integer index; + input Integer parentDims; + input InstNode component; + input InstContext.Type context; + input SourceInfo info; + output Dimension dim; + output TypingError error; +protected + Option oe; + Expression e; + Integer dim_index; +algorithm + // If the binding expression comes from a parent of the component rather than + // the component iself the dimension index needs to be offset by the number of + // dimensions of the parent(s). + dim_index := index + parentDims; + + if isSome(ty) then + // If the type is known, take the dimension directly from it. + (dim, error) := nthDimensionBoundsChecked(Util.getOption(ty), dim_index); + oe := NONE(); + else + // If the type is unknown, try to type the expression only as much as is + // needed to get the dimension we're looking for. + (dim, oe, error) := typeExpDim(exp, dim_index, + InstContext.set(context, NFInstContext.DIMENSION), info); + end if; + + // If the deduced dimension is unknown, evaluate the binding and try again. + if Dimension.isUnknown(dim) and not TypingError.isError(error) then + // Use the typed expression from typeExpDim if it was returned. + e := if isSome(oe) then Util.getOption(oe) else exp; + + if InstContext.inRelaxed(context) then + e := Ceval.tryEvalExp(e); + else + e := Ceval.evalExp(e, Ceval.EvalTarget.DIMENSION(component, index, e, info)); + end if; + + (dim, error) := nthDimensionBoundsChecked(Expression.typeOf(e), dim_index); + end if; +end deduceDimensionFromExp; + function subscriptDimExp "Tries to fix dimension expressions that are lacking subscripts after having been evaluated." diff --git a/testsuite/openmodelica/instance-API/GetModelInstanceDim1.mos b/testsuite/openmodelica/instance-API/GetModelInstanceDim1.mos new file mode 100644 index 00000000000..8b172ea4fe2 --- /dev/null +++ b/testsuite/openmodelica/instance-API/GetModelInstanceDim1.mos @@ -0,0 +1,76 @@ +// name: GetModelInstanceDim1 +// keywords: +// status: correct +// cflags: -d=newInst +// +// + +loadString(" + model M + parameter Integer n; + parameter Real x[:] = ones(n); + end M; +"); + +getModelInstance(M, prettyPrint = true); +getErrorString(); + +// Result: +// true +// "{ +// \"name\": \"M\", +// \"restriction\": \"model\", +// \"elements\": [ +// { +// \"$kind\": \"component\", +// \"name\": \"n\", +// \"type\": \"Integer\", +// \"prefixes\": { +// \"variability\": \"parameter\" +// } +// }, +// { +// \"$kind\": \"component\", +// \"name\": \"x\", +// \"type\": \"Real\", +// \"dims\": { +// \"absyn\": [ +// \":\" +// ], +// \"typed\": [ +// \"n\" +// ] +// }, +// \"modifiers\": \"ones(n)\", +// \"value\": { +// \"binding\": { +// \"$kind\": \"call\", +// \"name\": \"fill\", +// \"arguments\": [ +// 1, +// { +// \"$kind\": \"cref\", +// \"parts\": [ +// { +// \"name\": \"n\" +// } +// ] +// } +// ] +// } +// }, +// \"prefixes\": { +// \"variability\": \"parameter\" +// } +// } +// ], +// \"source\": { +// \"filename\": \"\", +// \"lineStart\": 2, +// \"columnStart\": 3, +// \"lineEnd\": 5, +// \"columnEnd\": 8 +// } +// }" +// "" +// endResult diff --git a/testsuite/openmodelica/instance-API/Makefile b/testsuite/openmodelica/instance-API/Makefile index c4ff36ed860..5aeb89a9f7d 100644 --- a/testsuite/openmodelica/instance-API/Makefile +++ b/testsuite/openmodelica/instance-API/Makefile @@ -30,6 +30,7 @@ GetModelInstanceConnection3.mos \ GetModelInstanceDerived1.mos \ GetModelInstanceDerived2.mos \ GetModelInstanceDerived3.mos \ +GetModelInstanceDim1.mos \ GetModelInstanceDuplicate1.mos \ GetModelInstanceEnum1.mos \ GetModelInstanceEnum2.mos \