Skip to content

Commit

Permalink
Perform type-checking on when conditions
Browse files Browse the repository at this point in the history
Previously, any expression was allowed in when-conditions. Now only
Boolean expressions, and also checks the usage of initial() in the
condition.
  • Loading branch information
sjoelund authored and OpenModelica-Hudson committed Dec 5, 2016
1 parent 4a4bd52 commit de28a22
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 7 deletions.
24 changes: 24 additions & 0 deletions Compiler/FrontEnd/Expression.mo
Expand Up @@ -6230,6 +6230,30 @@ algorithm
end match;
end extractCrefsStatment;

public function expHasInitial "
returns true if the expression contains any initial() call"
input DAE.Exp exp;
output Boolean found;
algorithm
(_,found) := traverseExpTopDown(exp, traversingexpHasInitial, false);
end expHasInitial;

public function traversingexpHasInitial
input output DAE.Exp exp;
output Boolean cont;
input output Boolean found;
algorithm
if found then
cont := false;
return;
end if;
(cont,found) := match exp
case DAE.CALL(path= Absyn.IDENT("initial"))
then (false,true);
else (true,found);
end match;
end traversingexpHasInitial;

public function expHasCrefs "
@author: adrpo 2011-04-29
returns true if the expression contains crefs"
Expand Down
62 changes: 57 additions & 5 deletions Compiler/FrontEnd/InstSection.mo
Expand Up @@ -2875,7 +2875,7 @@ protected function instWhenEqBranch
input Boolean inImpl;
input Boolean inUnrollLoops;
input ConnectionGraph.ConnectionGraph inGraph;
input SourceInfo inInfo;
input SourceInfo info;
output FCore.Cache outCache;
output FCore.Graph outEnv;
output InnerOuter.InstHierarchy outIH;
Expand All @@ -2886,14 +2886,39 @@ protected
Absyn.Exp cond;
list<SCode.EEquation> body;
DAE.Properties prop;
list<Absyn.Exp> aexps;
list<DAE.Exp> dexps;
DAE.Exp dexp;
DAE.Type ty;
Boolean isClock;
algorithm
(cond, body) := inBranch;

// Instantiate the when condition.
(outCache, outCondition) :=
instExp(inCache, inEnv, inIH, inPrefix, cond, inImpl, inInfo);
isClock := false;
outCondition := match cond
case Absyn.ARRAY(arrayExp=aexps)
algorithm
dexps := {};
for aexp in aexps loop
(outCache, dexp, prop) := instExp(inCache, inEnv, inIH, inPrefix, aexp, inImpl, info);
ty := Types.getPropType(prop);
dexp := checkWhenCondition(dexp, ty, aexp, info);
dexps := dexp::dexps;
end for;
then Expression.makeArray(listReverse(dexps), DAE.T_BOOL_DEFAULT, true);
else
algorithm
(outCache, dexp, prop) := instExp(inCache, inEnv, inIH, inPrefix, cond, inImpl, info);
ty := Types.getPropType(prop);
if Types.isClockOrSubTypeClock(ty) then
isClock := true;
else
dexp := checkWhenCondition(dexp, ty, cond, info);
end if;
then dexp;
end match;

if not Types.isClockOrSubTypeClock(Expression.typeof(outCondition)) then
if not isClock then
List.map_0(body, checkForNestedWhenInEq);
end if;

Expand All @@ -2903,6 +2928,33 @@ algorithm
instEEquation, body, inImpl, alwaysUnroll, inGraph);
end instWhenEqBranch;

protected function checkWhenCondition
input output DAE.Exp exp;
input DAE.Type ty;
input Absyn.Exp aexp;
input SourceInfo info;
algorithm
try
exp := Types.matchType(exp, ty, DAE.T_BOOL_DEFAULT);
else
Error.addSourceMessage(Error.IF_CONDITION_TYPE_ERROR,{Dump.printExpStr(aexp),Types.unparseType(ty)},info);
fail();
end try;
if Config.languageStandardAtLeast(Config.LanguageStandard.'3.2') then
_ := match exp
case DAE.CALL(path=Absyn.IDENT("initial")) then ();
case DAE.CALL(path=Absyn.FULLYQUALIFIED(Absyn.IDENT("initial"))) then ();
else
algorithm
if Expression.expHasInitial(exp) then
Error.addSourceMessage(Error.INITIAL_CALL_WARNING,{Dump.printExpStr(aexp)},info);
fail();
end if;
then ();
end match;
end if;
end checkWhenCondition;

protected function instConnect "
Generates connectionsets for connections.
Parameters and constants in connectors should generate appropriate assert statements.
Expand Down
3 changes: 2 additions & 1 deletion Compiler/FrontEnd/Static.mo
Expand Up @@ -7877,7 +7877,8 @@ algorithm
functionParallelism=funcParal)),
vect_dims,
slots) := elabTypes(cache, inEnv, args, nargs, typelist, onlyOneFunction, true/* Check types*/, impl,isExternalObject,st,pre,info)
"The constness of a function depends on the inputs. If all inputs are constant the call itself is constant." ;
"The constness of a function depends on the inputs. If all inputs are constant the call itself is constant.";

(fn_1,functype) := deoverloadFuncname(fn, functype, inEnv);
tuple_ := Types.isTuple(restype);
(isBuiltin,builtin,fn_1) := isBuiltinFunc(fn_1,functype);
Expand Down
2 changes: 1 addition & 1 deletion Compiler/FrontEnd/Types.mo
Expand Up @@ -5905,7 +5905,7 @@ public function matchType
input DAE.Exp inExp;
input DAE.Type inActualType;
input DAE.Type inExpectedType;
input Boolean inPrintFailtrace;
input Boolean inPrintFailtrace=false;
output DAE.Exp outExp;
output DAE.Type outType;
algorithm
Expand Down
2 changes: 2 additions & 0 deletions Compiler/Util/Error.mo
Expand Up @@ -712,6 +712,8 @@ public constant Message EACH_ON_NON_ARRAY = MESSAGE(292, TRANSLATION(), ERROR(),
Util.gettext("'each' used when modifying non-array element %s."));
public constant Message BUILTIN_EXTENDS_INVALID_ELEMENTS = MESSAGE(293, TRANSLATION(), ERROR(),
Util.gettext("A class extending from builtin type %s may not have other elements."));
public constant Message INITIAL_CALL_WARNING = MESSAGE(294, TRANSLATION(), WARNING(),
Util.gettext("The standard says that initial() may only be used as a when condition (when initial() or when {..., initial(), ...}), but got condition %s."));
public constant Message INITIALIZATION_NOT_FULLY_SPECIFIED = MESSAGE(496, TRANSLATION(), WARNING(),
Util.gettext("The initial conditions are not fully specified. %s."));
public constant Message INITIALIZATION_OVER_SPECIFIED = MESSAGE(497, TRANSLATION(), WARNING(),
Expand Down

0 comments on commit de28a22

Please sign in to comment.