Skip to content

Commit

Permalink
Fix for bug #1104
Browse files Browse the repository at this point in the history
- Report error on recursive definitions.


git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@9735 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
perost committed Sep 2, 2011
1 parent bbf897a commit e223f61
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 67 deletions.
66 changes: 0 additions & 66 deletions Compiler/FrontEnd/Inst.mo
Expand Up @@ -6565,8 +6565,6 @@ algorithm

(cache, cls, cenv) = Lookup.lookupClass(cache, env, t, true);

checkRecursiveDefinition(env, cenv, ci_state, cls);

// If the element is protected, and an external modification
// is applied, it is an error.
checkProt(vis, mm, vn);
Expand Down Expand Up @@ -6833,51 +6831,6 @@ algorithm
end matchcontinue;
end removeSelfModReferenceExp;

protected function checkRecursiveDefinition
"Checks that a class does not have a recursive definition,
i.e. an instance of itself. This is not allowed in Modelica."
input Env.Env env;
input Env.Env cenv;
input ClassInf.State ci_state;
input SCode.Element cl;
algorithm
_ := matchcontinue(env,cenv,ci_state,cl)
local
Absyn.Path envPath,cenvPath;
String name,s;
// No envpath, nothing to check.
case(env,cenv,ci_state,cl)
equation
NONE() = Env.getEnvPath(env);
then ();
// No recursive definition, succeed.
case(env,cenv,ci_state,SCode.CLASS(name=name))
equation
envPath = Env.getEnvName(env);
cenvPath = Env.getEnvName(Env.openScope(cenv,SCode.NOT_ENCAPSULATED(),SOME(name),NONE()));
false = Absyn.pathEqual(envPath,cenvPath);
then ();
// No recursive definition, succeed.
case(env,cenv,ci_state,cl)
equation
false = checkRecursiveDefinitionRecConst(ci_state,cl);
then ();
// report error: recursive definition
case(env,cenv,ci_state,SCode.CLASS(name=name))
equation
cenvPath = Env.getEnvName(Env.openScope(cenv,SCode.NOT_ENCAPSULATED(),SOME(name),NONE()));
s = Absyn.pathString(cenvPath);
Error.addMessage(Error.RECURSIVE_DEFINITION,{s});
then fail();
// failure
case(env,_,ci_state,cl)
equation
true = RTOpts.debugFlag("failtrace");
Debug.fprint("failtrace","-Inst.checkRecursiveDefinition failed, envpath="+&Env.printEnvPathStr(env)+&"\n");
then fail();
end matchcontinue;
end checkRecursiveDefinition;

protected function checkMultiplyDeclared
"Check if variable is multiply declared and
that all declarations are identical if so."
Expand Down Expand Up @@ -15333,25 +15286,6 @@ algorithm
end matchcontinue;
end instConditionalDeclaration;

protected function checkRecursiveDefinitionRecConst
"help function to checkRecursiveDefinition
Makes exception for record constructor
functions which have the output record
name being the same as the function name.

This function returns false if class
restriction is record and ci_state
is function"
input ClassInf.State ci_state;
input SCode.Element cl;
output Boolean res;
algorithm
res := matchcontinue(ci_state,cl)
case(ClassInf.FUNCTION(_),SCode.CLASS(restriction=SCode.R_RECORD())) then false;
case(_,_) then true;
end matchcontinue;
end checkRecursiveDefinitionRecConst;

protected function propagateClassPrefix
"Propagate ClassPrefix, i.e. variability to a component.
This is needed to make sure that e.g. a parameter does
Expand Down
54 changes: 54 additions & 0 deletions Compiler/FrontEnd/SCodeCheck.mo
Expand Up @@ -505,4 +505,58 @@ algorithm
end matchcontinue;
end checkDuplicateRedeclarations2;

public function checkRecursiveComponentDeclaration
"Checks if a component is declared with a type that is one of the enclosing
classes, e.g:
class A
class B
A a;
end B;
end A;
"
input String inComponentName;
input Absyn.Info inComponentInfo;
input SCodeEnv.Env inTypeEnv;
input SCodeEnv.Item inTypeItem;
input SCodeEnv.Env inComponentEnv;
algorithm
_ := matchcontinue(inComponentName, inComponentInfo, inTypeEnv, inTypeItem,
inComponentEnv)
local
String cls_name, ty_name;
SCodeEnv.AvlTree tree;
SCodeEnv.Item item;
SCode.Element el;

// No environment means one of the basic types.
case (_, _, {}, _, _) then ();

// Check that the environment of the components type is not an enclosing
// scope of the component itself.
case (_, _, _, _, _)
equation
false = SCodeEnv.envPrefixOf(inTypeEnv, inComponentEnv);
then
();

// Make an exception for components in functions.
case (_, _, _, _, SCodeEnv.FRAME(name = SOME(cls_name)) ::
SCodeEnv.FRAME(clsAndVars = tree) :: _)
equation
SCodeEnv.CLASS(cls = el) = SCodeEnv.avlTreeGet(tree, cls_name);
true = SCode.isFunction(el);
then
();

else
equation
ty_name = SCodeEnv.getItemName(inTypeItem);
Error.addSourceMessage(Error.RECURSIVE_DEFINITION,
{inComponentName, ty_name}, inComponentInfo);
then
fail();

end matchcontinue;
end checkRecursiveComponentDeclaration;

end SCodeCheck;
2 changes: 2 additions & 0 deletions Compiler/FrontEnd/SCodeDependency.mo
Expand Up @@ -716,6 +716,8 @@ algorithm
analyseTypeSpec(ty, inEnv, info);
(ty_item, ty_env) = SCodeLookup.lookupTypeSpec(ty, inEnv, info);
ty_env = SCodeEnv.mergeItemEnv(ty_item, ty_env);
SCodeCheck.checkRecursiveComponentDeclaration(name, info, ty_env,
ty_item, inEnv);
analyseModifier(mods, inEnv, ty_env, info);
analyseOptExp(cond_exp, inEnv, info);
analyseConstrainClass(SCode.replaceableOptConstraint(SCode.prefixesReplaceable(prefixes)), inEnv, info);
Expand Down
34 changes: 34 additions & 0 deletions Compiler/FrontEnd/SCodeEnv.mo
Expand Up @@ -1255,6 +1255,40 @@ algorithm
end match;
end getEnvPath;

public function envPrefixOf
input Env inPrefixEnv;
input Env inEnv;
output Boolean outIsPrefix;
algorithm
outIsPrefix := envPrefixOf2(listReverse(inPrefixEnv), listReverse(inEnv));
end envPrefixOf;

public function envPrefixOf2
"Checks if one environment is a prefix of another."
input Env inPrefixEnv;
input Env inEnv;
output Boolean outIsPrefix;
algorithm
outIsPrefix := matchcontinue(inPrefixEnv, inEnv)
local
String n1, n2;
Env rest1, rest2;

case ({}, _) then true;

case (FRAME(name = NONE()) :: rest1, FRAME(name = NONE()) :: rest2)
then envPrefixOf2(rest1, rest2);

case (FRAME(name = SOME(n1)) :: rest1, FRAME(name = SOME(n2)) :: rest2)
equation
true = stringEqual(n1, n2);
then
envPrefixOf2(rest1, rest2);

else false;
end matchcontinue;
end envPrefixOf2;

public function getItemInfo
"Returns the Absyn.Info of an environment item."
input Item inItem;
Expand Down
2 changes: 1 addition & 1 deletion Compiler/Util/Error.mo
Expand Up @@ -623,7 +623,7 @@ protected constant list<tuple<Integer, MessageType, Severity, String>> errorTabl
(DUPLICATE_CLASSES_NOT_EQUIVALENT,TRANSLATION(),ERROR(),
"Duplicate class definitions (due to inheritance) not equivalent, first definiton is: %s, second definition is: %s"),
(PACKAGE_VARIABLE_NOT_CONSTANT, TRANSLATION(),ERROR(),"Variable %s in package %s is not constant"),
(RECURSIVE_DEFINITION,TRANSLATION(),ERROR(),"Class %s has a recursive definition, i.e. contains an instance of itself"),
(RECURSIVE_DEFINITION,TRANSLATION(),ERROR(),"Declaration of element %s causes recursive definition of class %s."),
(NON_STREAM_OPERAND_IN_STREAM_OPERATOR, TRANSLATION(), ERROR(),
"Operand %s to operator %s is not a stream variable."),
(UNBALANCED_CONNECTOR, TRANSLATION(), WARNING(),
Expand Down

0 comments on commit e223f61

Please sign in to comment.