diff --git a/Compiler/NFFrontEnd/NFBinding.mo b/Compiler/NFFrontEnd/NFBinding.mo index 7b49dc058c6..6b4cfaf9db2 100644 --- a/Compiler/NFFrontEnd/NFBinding.mo +++ b/Compiler/NFFrontEnd/NFBinding.mo @@ -605,6 +605,24 @@ public end match; end mapExp; + function containsExp + input Binding binding; + input PredFunc predFn; + output Boolean res; + + partial function PredFunc + input Expression exp; + output Boolean res; + end PredFunc; + algorithm + res := match binding + case UNTYPED_BINDING() then Expression.contains(binding.bindingExp, predFn); + case TYPED_BINDING() then Expression.contains(binding.bindingExp, predFn); + case FLAT_BINDING() then Expression.contains(binding.bindingExp, predFn); + case CEVAL_BINDING() then Expression.contains(binding.bindingExp, predFn); + else false; + end match; + end containsExp; end Binding; annotation(__OpenModelica_Interface="frontend"); diff --git a/Compiler/NFFrontEnd/NFComponent.mo b/Compiler/NFFrontEnd/NFComponent.mo index 4a1574d0793..895fe7cdcc7 100644 --- a/Compiler/NFFrontEnd/NFComponent.mo +++ b/Compiler/NFFrontEnd/NFComponent.mo @@ -826,7 +826,7 @@ uniontype Component return; end if; - fixed := fixed and Expression.isTrue(Binding.getTypedExp(binding)); + fixed := fixed and Expression.isTrue(Binding.getExp(binding)); end getFixedAttribute; diff --git a/Compiler/NFFrontEnd/NFExpression.mo b/Compiler/NFFrontEnd/NFExpression.mo index 5a1ac37cd30..87403dd7a6f 100644 --- a/Compiler/NFFrontEnd/NFExpression.mo +++ b/Compiler/NFFrontEnd/NFExpression.mo @@ -3814,34 +3814,13 @@ public algorithm res := match cref case ComponentRef.CREF() - then subscriptsContains(cref.subscripts, func) or + then Subscript.listContainsExp(cref.subscripts, func) or crefContains(cref.restCref, func); else false; end match; end crefContains; - function subscriptsContains - input list subs; - input ContainsPred func; - output Boolean res; - algorithm - for s in subs loop - res := match s - case Subscript.UNTYPED() then contains(s.exp, func); - case Subscript.INDEX() then contains(s.index, func); - case Subscript.SLICE() then contains(s.slice, func); - else false; - end match; - - if res then - return; - end if; - end for; - - res := false; - end subscriptsContains; - function listContains input list expl; input ContainsPred func; @@ -3911,6 +3890,146 @@ public end match; end callContains; + function containsShallow + input Expression exp; + input ContainsPred func; + output Boolean res; + algorithm + res := match exp + case CREF() then crefContainsShallow(exp.cref, func); + case ARRAY() then listContainsShallow(exp.elements, func); + + case MATRIX() + algorithm + res := false; + + for row in exp.elements loop + if listContainsShallow(row, func) then + res := true; + break; + end if; + end for; + then + res; + + case RANGE() + then func(exp.start) or + Util.applyOptionOrDefault(exp.step, func, false) or + func(exp.stop); + + case TUPLE() then listContainsShallow(exp.elements, func); + case RECORD() then listContainsShallow(exp.elements, func); + case CALL() then callContainsShallow(exp.call, func); + + case SIZE() + then Util.applyOptionOrDefault(exp.dimIndex, func, false) or + func(exp.exp); + + case BINARY() then func(exp.exp1) or func(exp.exp2); + case UNARY() then func(exp.exp); + case LBINARY() then func(exp.exp1) or func(exp.exp2); + case LUNARY() then func(exp.exp); + case RELATION() then func(exp.exp1) or func(exp.exp2); + case IF() then func(exp.condition) or func(exp.trueBranch) or func(exp.falseBranch); + case CAST() then func(exp.exp); + case UNBOX() then func(exp.exp); + + case SUBSCRIPTED_EXP() + then func(exp.exp) or Subscript.listContainsExpShallow(exp.subscripts, func); + + case TUPLE_ELEMENT() then func(exp.tupleExp); + case RECORD_ELEMENT() then func(exp.recordExp); + case PARTIAL_FUNCTION_APPLICATION() then listContains(exp.args, func); + case BOX() then func(exp.exp); + else false; + end match; + end containsShallow; + + function crefContainsShallow + input ComponentRef cref; + input ContainsPred func; + output Boolean res; + algorithm + res := match cref + case ComponentRef.CREF() + then Subscript.listContainsExpShallow(cref.subscripts, func) or + crefContainsShallow(cref.restCref, func); + + else false; + end match; + end crefContainsShallow; + + function listContainsShallow + input list expl; + input ContainsPred func; + output Boolean res; + algorithm + for e in expl loop + if func(e) then + res := true; + return; + end if; + end for; + + res := false; + end listContainsShallow; + + function callContainsShallow + input Call call; + input ContainsPred func; + output Boolean res; + algorithm + res := match call + local + Expression e; + + case Call.UNTYPED_CALL() + algorithm + res := listContainsShallow(call.arguments, func); + + if not res then + for arg in call.named_args loop + (_, e) := arg; + + if func(e) then + res := true; + break; + end if; + end for; + end if; + then + res; + + case Call.ARG_TYPED_CALL() + algorithm + for arg in call.arguments loop + (e, _, _) := arg; + + if func(e) then + res := true; + return; + end if; + end for; + + for arg in call.named_args loop + (_, e, _, _) := arg; + + if func(e) then + res := true; + return; + end if; + end for; + then + false; + + case Call.TYPED_CALL() then listContainsShallow(call.arguments, func); + case Call.UNTYPED_ARRAY_CONSTRUCTOR() then func(call.exp); + case Call.TYPED_ARRAY_CONSTRUCTOR() then func(call.exp); + case Call.UNTYPED_REDUCTION() then func(call.exp); + case Call.TYPED_REDUCTION() then func(call.exp); + end match; + end callContainsShallow; + function arrayFirstScalar "Returns the first scalar element of an array. Fails if the array is empty." input Expression arrayExp; diff --git a/Compiler/NFFrontEnd/NFInst.mo b/Compiler/NFFrontEnd/NFInst.mo index 624569500b9..73dd15ebbd7 100644 --- a/Compiler/NFFrontEnd/NFInst.mo +++ b/Compiler/NFFrontEnd/NFInst.mo @@ -1407,6 +1407,10 @@ algorithm attr := mergeRedeclaredComponentAttributes(Util.getOption(originalAttr), attr, node); end if; + if not attr.isFinal and Modifier.isFinal(mod) then + attr.isFinal := true; + end if; + // Create the untyped component and update the node with it. We need the // untyped component in instClass to make sure everything is scoped // correctly during lookup, but the class node the component should have @@ -3185,21 +3189,21 @@ algorithm case Component.UNTYPED_COMPONENT(binding = binding, condition = condition) algorithm - // @adrpo: if Evaluate=true make the parameter a structural parameter - // only make it a structural parameter if is not constant, duh!, 1071 regressions :) - if c.attributes.variability == Variability.PARAMETER and - (Component.getEvaluateAnnotation(c) or evalAllParams) then + if isStructuralComponent(c, c.attributes, binding, node, evalAllParams) then markStructuralParamsComp(c, node); end if; + // Parameters used in array dimensions are structural. for dim in c.dimensions loop markStructuralParamsDim(dim); end for; + // Parameters that determine the size of a component binding are structural. if Binding.isBound(binding) then markStructuralParamsExpSize(Binding.getUntypedExp(binding)); end if; + // Parameters used in a component condition are structural. if Binding.isBound(condition) then markStructuralParamsExp(Binding.getUntypedExp(condition)); end if; @@ -3223,6 +3227,128 @@ algorithm end match; end updateImplicitVariabilityComp; +function isStructuralComponent + input Component component; + input Component.Attributes compAttrs; + input Binding compBinding; + input InstNode compNode; + input Boolean evalAllParams; + output Boolean isStructural; +protected + Boolean is_fixed; +algorithm + if compAttrs.variability <> Variability.PARAMETER then + // Only parameters can be structural. + isStructural := false; + elseif evalAllParams or Component.getEvaluateAnnotation(component) then + // If -d=evaluateAllParameters is set or the parameter has an Evaluate=true + // annotation we should probably evaluate the parameter, which we do by + // marking it as structural. + if not Component.getFixedAttribute(component) then + // Except non-fixed parameters. + isStructural := false; + elseif Binding.isUnbound(compBinding) then + // Except parameters with no bindings. + if not evalAllParams then + // Print a warning if a parameter has an Evaluate=true annotation but no binding. + Error.addSourceMessage(Error.UNBOUND_PARAMETER_EVALUATE_TRUE, + {InstNode.name(compNode)}, InstNode.info(compNode)); + end if; + + isStructural := false; + elseif isBindingNotFixed(compBinding, requireFinal = false) then + // Except parameters that depend on non-fixed parameters. + isStructural := false; + else + // All other parameters are considered structural in this case. + isStructural := true; + end if; + elseif Component.isFinal(component) and Component.getFixedAttribute(component) then + // If a parameter is fixed and final we might also want to evaluate it, + // since its binding can't be modified. But only if all parameters it + // depends on are also fixed and final. + if Binding.isUnbound(compBinding) or isBindingNotFixed(compBinding, requireFinal = true) then + isStructural := false; + else + isStructural := true; + end if; + else + isStructural := false; + end if; +end isStructuralComponent; + +function isBindingNotFixed + input Binding binding; + input Boolean requireFinal; + input Integer depth = 1; + output Boolean isNotFixed; +algorithm + if depth > 4 then + isNotFixed := true; + return; + end if; + + isNotFixed := match binding + case Binding.UNTYPED_BINDING() + then isExpressionNotFixed(binding.bindingExp, requireFinal, depth); + + else false; + end match; +end isBindingNotFixed; + +function isExpressionNotFixed + input Expression exp; + input Boolean requireFinal; + input Integer depth; + output Boolean isNotFixed; +algorithm + isNotFixed := match exp + local + InstNode node; + Component c; + Variability var; + Expression e; + + case Expression.CREF() + algorithm + node := ComponentRef.node(exp.cref); + + if InstNode.isComponent(node) then + c := InstNode.component(node); + var := Component.variability(c); + + if var <= Variability.STRUCTURAL_PARAMETER then + isNotFixed := false; + elseif var == Variability.PARAMETER and + (not requireFinal or Component.isFinal(c)) and + Component.getFixedAttribute(c) then + isNotFixed := isBindingNotFixed(Component.getBinding(c), requireFinal, depth + 1); + else + isNotFixed := true; + end if; + else + isNotFixed := true; + end if; + then + isNotFixed or + Expression.containsShallow(exp, + function isExpressionNotFixed(requireFinal = requireFinal, depth = depth)); + + case Expression.SIZE() + algorithm + if isSome(exp.dimIndex) then + isNotFixed := isExpressionNotFixed(Util.getOption(exp.dimIndex), requireFinal, depth); + else + isNotFixed := false; + end if; + then + isNotFixed; + + else Expression.containsShallow(exp, + function isExpressionNotFixed(requireFinal = requireFinal, depth = depth)); + end match; +end isExpressionNotFixed; + function markStructuralParamsDim input Dimension dimension; algorithm diff --git a/Compiler/NFFrontEnd/NFModifier.mo b/Compiler/NFFrontEnd/NFModifier.mo index c9286bc9713..6669a760076 100644 --- a/Compiler/NFFrontEnd/NFModifier.mo +++ b/Compiler/NFFrontEnd/NFModifier.mo @@ -479,6 +479,16 @@ public end match; end isEach; + function isFinal + input Modifier mod; + output Boolean isFinal; + algorithm + isFinal := match mod + case MODIFIER(finalPrefix = SCode.FINAL()) then true; + else false; + end match; + end isFinal; + function map input output Modifier mod; input FuncT func; diff --git a/Compiler/NFFrontEnd/NFSubscript.mo b/Compiler/NFFrontEnd/NFSubscript.mo index 4a67508b0b6..b1033ae016f 100644 --- a/Compiler/NFFrontEnd/NFSubscript.mo +++ b/Compiler/NFFrontEnd/NFSubscript.mo @@ -316,6 +316,34 @@ public res := false; end listContainsExp; + function containsExpShallow + input Subscript subscript; + input Expression.ContainsPred func; + output Boolean res; + algorithm + res := match subscript + case UNTYPED() then func(subscript.exp); + case INDEX() then func(subscript.index); + case SLICE() then func(subscript.slice); + else false; + end match; + end containsExpShallow; + + function listContainsExpShallow + input list subscripts; + input Expression.ContainsPred func; + output Boolean res; + algorithm + for s in subscripts loop + if containsExpShallow(s, func) then + res := true; + return; + end if; + end for; + + res := false; + end listContainsExpShallow; + function applyExp input Subscript subscript; input ApplyFunc func;