Skip to content

Commit

Permalink
Fix for bug #1334:
Browse files Browse the repository at this point in the history
- Added cycle detection to instElementList for constants and parameters.
- Also sort parameters in instElementList.
- Updated test cases due to different sorting of parameters.
- Updated mofiles/CyclicBindingParam and mofiles/CyclicBindingConst and moved
  them from failing tests to working tests.


git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@8063 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
perost committed Mar 2, 2011
1 parent fca7b30 commit dd89f9d
Show file tree
Hide file tree
Showing 4 changed files with 337 additions and 11 deletions.
94 changes: 84 additions & 10 deletions Compiler/FrontEnd/Inst.mo
Expand Up @@ -4947,6 +4947,7 @@ algorithm
end addNomod;

public function instElementList
"Instantiates a list of elements."
input Env.Cache inCache;
input Env.Env inEnv;
input InstanceHierarchy inIH;
Expand All @@ -4972,46 +4973,71 @@ public function instElementList
protected
list<tuple<SCode.Element, DAE.Mod>> el;
algorithm
el := sortElementList(inElements);
el := sortElementList(inElements, inEnv);
(outCache, outEnv, outIH, outStore, outDae, outSets, outState, outTypesVarLst, outGraph) :=
instElementList2(inCache, inEnv, inIH, store, inMod, inPrefix, inSets,
inState, el, inInstDims, inImplInst, inCallingScope, inGraph);
end instElementList;

protected function sortElementList
input list<tuple<SCode.Element, DAE.Mod>> inElements;
output list<tuple<SCode.Element, DAE.Mod>> outElements;
"Sorts constants and parameters by dependencies, so that they are instantiated
before they are used."
input list<Element> inElements;
input Env.Env inEnv;
output list<Element> outElements;
type Element = tuple<SCode.Element, DAE.Mod>;
protected
list<tuple<Element, list<Element>>> cycles;
algorithm
(outElements, _) := Graph.topologicalSort(
(outElements, cycles) := Graph.topologicalSort(
Graph.buildGraph(inElements, getElementDependencies, inElements),
isElementEqual);
checkCyclicalComponents(cycles, inEnv);
end sortElementList;

protected function getElementDependencies
"Returns the dependencies given an element."
input tuple<SCode.Element, DAE.Mod> inElement;
input list<tuple<SCode.Element, DAE.Mod>> inAllElements;
output list<tuple<SCode.Element, DAE.Mod>> outDependencies;
algorithm
outDependencies := match(inElement, inAllElements)
outDependencies := matchcontinue(inElement, inAllElements)
local
Absyn.Exp bind_exp;
SCode.Variability var;
Absyn.Exp bind_exp, cond_exp;
list<tuple<SCode.Element, DAE.Mod>> deps;

case ((SCode.COMPONENT(attributes = SCode.ATTR(variability = SCode.CONST()),
// For constants and parameters we check the binding modification.
case ((SCode.COMPONENT(attributes = SCode.ATTR(variability = var),
modifications = SCode.MOD(binding = SOME((bind_exp, _)))), _), _)
equation
true = SCode.isParameterOrConst(var);
(_, (_, _, (_, deps))) = Absyn.traverseExpBidir(bind_exp,
(getElementDependenciesTraverserEnter,
getElementDependenciesTraverserExit,
(inAllElements, {})));
then
deps;

// For other variables we check the condition, since they might be
// conditional on a constant or parameter.
case ((SCode.COMPONENT(condition = SOME(cond_exp)), _), _)
equation
(_, (_, _, (_, deps))) = Absyn.traverseExpBidir(cond_exp,
(getElementDependenciesTraverserEnter,
getElementDependenciesTraverserExit,
(inAllElements, {})));
then
deps;

else then {};
end match;
end matchcontinue;
end getElementDependencies;

protected function getElementDependenciesTraverserEnter
"Traverse function used by getElementDependencies to collect all dependencies
for an element. The first ElementList in the input argument is a list of all
elements, and the second is a list of accumulated dependencies."
input tuple<Absyn.Exp, tuple<ElementList, ElementList>> inTuple;
output tuple<Absyn.Exp, tuple<ElementList, ElementList>> outTuple;
type ElementList = list<tuple<SCode.Element, DAE.Mod>>;
Expand All @@ -5026,6 +5052,9 @@ algorithm
case ((exp as Absyn.CREF(componentRef = Absyn.CREF_IDENT(name = id)),
(all_el, accum_el)))
equation
// Try and delete the element with the given name from the list of all
// elements. If this succeeds, add it to the list of elements. This
// ensures that we don't add any dependency more than once.
(all_el, SOME(e)) = Util.listDeleteMemberOnTrue(id, all_el,
isElementNamed);
then
Expand All @@ -5036,6 +5065,7 @@ algorithm
end getElementDependenciesTraverserEnter;

protected function getElementDependenciesTraverserExit
"Dummy traversal function used by getElementDependencies."
input tuple<Absyn.Exp, tuple<ElementList, ElementList>> inTuple;
output tuple<Absyn.Exp, tuple<ElementList, ElementList>> outTuple;
type ElementList = list<tuple<SCode.Element, DAE.Mod>>;
Expand All @@ -5044,6 +5074,8 @@ algorithm
end getElementDependenciesTraverserExit;

protected function isElementNamed
"Returns true if the given element has the same name as the given string,
otherwise false."
input String inName;
input tuple<SCode.Element, DAE.Mod> inElement;
output Boolean isNamed;
Expand All @@ -5063,6 +5095,7 @@ algorithm
end isElementNamed;

protected function isElementEqual
"Checks that two elements are equal, i.e. has the same name."
input tuple<SCode.Element, DAE.Mod> inElement1;
input tuple<SCode.Element, DAE.Mod> inElement2;
output Boolean isEqual;
Expand All @@ -5072,14 +5105,55 @@ algorithm
String id1, id2;

case ((SCode.COMPONENT(component = id1), _),

(SCode.COMPONENT(component = id2), _))
(SCode.COMPONENT(component = id2), _))
then stringEqual(id1, id2);

else then false;
end matchcontinue;
end isElementEqual;

protected function checkCyclicalComponents
"Checks the return value from Graph.topologicalSort. If the list of cycles is
not empty, print an error message and fail, since it's not allowed for
constants or parameters to have cyclic dependencies."
input list<tuple<Element, list<Element>>> inCycles;
input Env.Env inEnv;
type Element = tuple<SCode.Element, DAE.Mod>;
algorithm
_ := match(inCycles, inEnv)
local
list<list<Element>> cycles;
list<list<String>> names;
list<String> cycles_strs;
String cycles_str, scope_str;

case ({}, _) then ();

else
equation
cycles = Graph.findCycles(inCycles, isElementEqual);
names = Util.listListMap(cycles, elementName);
cycles_strs = Util.listMap1(names, Util.stringDelimitList, ",");
cycles_str = Util.stringDelimitList(cycles_strs, "}, {");
cycles_str = "{" +& cycles_str +& "}";
scope_str = Env.printEnvPathStr(inEnv);
Error.addMessage(Error.CIRCULAR_COMPONENTS, {scope_str, cycles_str});
then
fail();
end match;
end checkCyclicalComponents;

protected function elementName
"Returns the name of the given element."
input tuple<SCode.Element, DAE.Mod> inElement;
output String outName;
protected
SCode.Element elem;
algorithm
(elem, _) := inElement;
outName := SCode.elementName(elem);
end elementName;

public function instElementList2
"function: instElementList
Moved to instClassdef, FIXME: Move commments later
Expand Down
2 changes: 1 addition & 1 deletion Compiler/FrontEnd/SCode.mo
Expand Up @@ -2148,7 +2148,7 @@ algorithm
end matchcontinue;
end accessibilityEqual;

protected function variabilityEqual
public function variabilityEqual
"function variabilityEqual
Returns true if two Variablity prefixes are equal"
input Variability var1;
Expand Down
3 changes: 3 additions & 0 deletions Compiler/Util/Error.mo
Expand Up @@ -254,6 +254,7 @@ public constant ErrorID ELAB_CODE_EXP_FAILED=166;
public constant ErrorID EQUATION_TRANSITION_FAILURE=167;
public constant ErrorID METARECORD_CONTAINS_METARECORD_MEMBER=168;
public constant ErrorID INVALID_EXTERNAL_OBJECT=169;
public constant ErrorID CIRCULAR_COMPONENTS=170;

public constant ErrorID UNBOUND_PARAMETER_WITH_START_VALUE_WARNING=499;
public constant ErrorID UNBOUND_PARAMETER_WARNING=500;
Expand Down Expand Up @@ -709,6 +710,8 @@ protected constant list<tuple<Integer, MessageType, Severity, String>> errorTabl
"Function %s not found in scope %s."),
(INVALID_EXTERNAL_OBJECT,TRANSLATION(),ERROR(),
"Invalid external object %s, %s."),
(CIRCULAR_COMPONENTS,TRANSLATION(),ERROR(),
"Cyclically dependent constants or parameters found in scope %s: %s"),
(MATCHCONTINUE_TO_MATCH_OPTIMIZATION,TRANSLATION(),NOTIFICATION(),"This matchcontinue expression has no overlapping patterns and should be using match instead of matchcontinue."),
(META_DEAD_CODE,TRANSLATION(),NOTIFICATION(),"Dead code elimination: %s."),
(META_UNUSED_DECL,TRANSLATION(),NOTIFICATION(),"Unused local variable: %s."),
Expand Down

0 comments on commit dd89f9d

Please sign in to comment.