Skip to content
This repository has been archived by the owner on May 18, 2019. It is now read-only.

Commit

Permalink
[NF] Handle recursive functions.
Browse files Browse the repository at this point in the history
- Update the function cache before instantiating a function's
  expressions, to avoid instantiating it again in the case of
  a recursive call.
- Split the typing of functions so their signatures are typed
  first, then type their bodies only after updating the cache.

Belonging to [master]:
  - #2037
  - OpenModelica/OpenModelica-testsuite#787
  • Loading branch information
perost authored and OpenModelica-Hudson committed Nov 20, 2017
1 parent 3548b47 commit 34369f3
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 34 deletions.
7 changes: 7 additions & 0 deletions Compiler/NFFrontEnd/NFCall.mo
Expand Up @@ -358,6 +358,8 @@ uniontype Call
if not fn_typed then
fnl := list(Function.typeFunction(f) for f in fnl);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION(fnl, true, special));
fnl := list(Function.typeFunctionBody(f) for f in fnl);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION(fnl, true, special));
end if;


Expand Down Expand Up @@ -414,6 +416,8 @@ uniontype Call
if not fn_typed then
fnl := list(Function.typeFunction(f) for f in fnl);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION(fnl, true, special));
fnl := list(Function.typeFunctionBody(f) for f in fnl);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION(fnl, true, special));
end if;

// Type the arguments.
Expand Down Expand Up @@ -477,6 +481,7 @@ uniontype Call
// Type the function(s) if not already done.
if not fn_typed then
fn := Function.typeFunction(fn);
fn := Function.typeFunctionBody(fn);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION({fn}, true, special));
end if;

Expand Down Expand Up @@ -557,6 +562,7 @@ uniontype Call
// Type the function(s) if not already done.
if not fn_typed then
fn := Function.typeFunction(fn);
fn := Function.typeFunctionBody(fn);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION({fn}, true, special));
end if;

Expand Down Expand Up @@ -634,6 +640,7 @@ uniontype Call
// Type the function(s) if not already done.
if not fn_typed then
fn := Function.typeFunction(fn);
fn := Function.typeFunctionBody(fn);
InstNode.setFuncCache(fn_node, CachedData.FUNCTION({fn}, true, special));
end if;

Expand Down
63 changes: 38 additions & 25 deletions Compiler/NFFrontEnd/NFFunction.mo
Expand Up @@ -59,6 +59,7 @@ import ClassTree = NFClassTree.ClassTree;
import Prefixes = NFPrefixes;
import NFLookupState.LookupState;
import Record = NFRecord;
import NFTyping.ClassScope;

import MatchKind = NFTypeCheck.MatchKind;

Expand Down Expand Up @@ -288,10 +289,10 @@ uniontype Function
algorithm
fnNode := InstNode.setNodeType(NFInstNode.InstNodeType.ROOT_CLASS(), fnNode);
fnNode := Inst.instantiate(fnNode);
Inst.instExpressions(fnNode);
fn := Function.new(fnPath, fnNode);
specialBuiltin := isSpecialBuiltin(fn);
fnNode := InstNode.cacheAddFunc(fnNode, fn, specialBuiltin);
Inst.instExpressions(fnNode);
then
(fnNode, specialBuiltin);

Expand Down Expand Up @@ -668,18 +669,49 @@ uniontype Function
end isTyped;

function typeFunction
"Types a function's parameters, local components and default arguments."
input output Function fn;
protected
DAE.FunctionAttributes attr;
InstNode node = fn.node;
algorithm
if not isTyped(fn) then
Typing.typeFunction(fn.node);
// Type all the components in the function.
Typing.typeComponents(node, ClassScope.FUNCTION);

// Type the binding of the inputs only. This is done because they are
// needed when type checking a function call. The outputs are not needed
// for that and can contain recursive calls to the function, so we leave
// them for later.
for c in fn.inputs loop
Typing.typeComponentBinding(c);
end for;

// Make the slots and return type for the function.
fn.slots := list(makeSlot(i) for i in fn.inputs);
checkParamTypes(fn);
fn.slots := makeSlots(fn.inputs);
fn.returnType := makeReturnType(fn);
end if;
end typeFunction;

function typeFunctionBody
"Types the body of a function, along with any bindings of local variables
and outputs."
input output Function fn;
algorithm
// Type the bindings of the outputs and local variables.
for c in fn.outputs loop
Typing.typeComponentBinding(c);
end for;

for c in fn.locals loop
Typing.typeComponentBinding(c);
end for;

// Type the algorithm section of the function, if it has one.
Typing.typeSections(fn.node);
end typeFunctionBody;

function isBuiltin
input Function fn;
output Boolean isBuiltin = isBuiltinAttr(fn.attributes);
Expand Down Expand Up @@ -757,17 +789,17 @@ protected
input output list<InstNode> locals = {};
protected
Class cls;
array<InstNode> comps;
array<Mutable<InstNode>> comps;
InstNode n;
algorithm
assert(InstNode.isClass(node), getInstanceName() + " got non-class node");
cls := InstNode.getClass(node);

() := match cls
case Class.INSTANCED_CLASS(elements = ClassTree.FLAT_TREE(components = comps))
case Class.EXPANDED_CLASS(elements = ClassTree.INSTANTIATED_TREE(components = comps))
algorithm
for i in arrayLength(comps):-1:1 loop
n := comps[i];
n := Mutable.access(comps[i]);

// Sort the components based on their direction.
() := match paramDirection(n)
Expand Down Expand Up @@ -847,27 +879,9 @@ protected
end if;
end paramDirection;

function makeSlots
input list<InstNode> inputs;
output list<Slot> slots = {};
protected
Boolean has_default, default_required = false;
Slot s;
algorithm
for i in inputs loop
(s, has_default) := makeSlot(i, default_required);
slots := s :: slots;
default_required := default_required or has_default;
end for;

slots := listReverse(slots);
end makeSlots;

function makeSlot
input InstNode component;
input Boolean defaultRequired;
output Slot slot;
output Boolean hasDefault;
protected
Component comp;
Option<Expression> default;
Expand All @@ -877,7 +891,6 @@ protected
comp := InstNode.component(component);
default := Binding.typedExp(Component.getBinding(comp));
name := InstNode.name(component);
hasDefault := isSome(default);

// Remove $in_ for OM input output arguments.
if stringGet(name, 1) == 36 /*$*/ then
Expand Down
10 changes: 1 addition & 9 deletions Compiler/NFFrontEnd/NFTyping.mo
Expand Up @@ -99,6 +99,7 @@ uniontype TypingError
end isError;
end TypingError;

public
type EquationScope = enumeration(NORMAL, INITIAL, IF, IF_PARAMETER);
type ClassScope = enumeration(CLASS, FUNCTION);

Expand All @@ -115,14 +116,6 @@ algorithm
execStat("NFTyping.typeSections(" + name + ")");
end typeClass;

function typeFunction
input InstNode cls;
algorithm
typeComponents(cls, ClassScope.FUNCTION);
typeBindings(cls, cls);
typeSections(cls);
end typeFunction;

function typeComponents
input InstNode cls;
input ClassScope clsScope;
Expand Down Expand Up @@ -1407,7 +1400,6 @@ algorithm
variability := if listEmpty(valr) then Variability.CONSTANT else listHead(valr);
end typeTuple;

protected
function printRangeTypeError
input Expression exp1;
input Type ty1;
Expand Down

0 comments on commit 34369f3

Please sign in to comment.