Skip to content

Commit

Permalink
Improve typing of function calls (#7387)
Browse files Browse the repository at this point in the history
- Type default arguments for each call with the input arguments taken
  into account, instead of typing them only once for the function.
- Improve the insertion of input arguments into the default arguments
  such that it handles subscripts and complex component references.
- Fixes #7384 and #7385.
  • Loading branch information
perost committed Apr 16, 2021
1 parent 48bf0c8 commit f450566
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 33 deletions.
12 changes: 12 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFBinding.mo
Expand Up @@ -257,6 +257,18 @@ public
end match;
end getExp;

function getExpOpt
input Binding binding;
output Option<Expression> exp;
algorithm
exp := match binding
case UNTYPED_BINDING() then SOME(binding.bindingExp);
case TYPED_BINDING() then SOME(binding.bindingExp);
case FLAT_BINDING() then SOME(binding.bindingExp);
else NONE();
end match;
end getExpOpt;

function setExp
input Expression exp;
input output Binding binding;
Expand Down
85 changes: 52 additions & 33 deletions OMCompiler/Compiler/NFFrontEnd/NFFunction.mo
Expand Up @@ -1006,6 +1006,9 @@ uniontype Function
outArg := match slot.evalStatus
local
Expression exp;
Type ty;
Variability var;
Purity pur;

// An already evaluated slot, return its binding.
case SlotEvalStatus.EVALUATED
Expand All @@ -1025,8 +1028,8 @@ uniontype Function
arrayUpdate(slots, slot.index, slot);

exp := evaluateSlotExp(Util.getOption(slot.default), slots, info);
outArg := TypedArg.TYPED_ARG(NONE(), exp, Expression.typeOf(exp),
Expression.variability(exp), Expression.purity(exp));
(exp, ty, var, pur) := Typing.typeExp(exp, NFInstContext.FUNCTION, info);
outArg := TypedArg.TYPED_ARG(NONE(), exp, ty, var, pur);

slot.arg := SOME(outArg);
slot.evalStatus := SlotEvalStatus.EVALUATED;
Expand Down Expand Up @@ -1054,28 +1057,49 @@ uniontype Function
output Expression outExp;
algorithm
outExp := match exp
local
ComponentRef cref;
Option<Slot> slot;
TypedArg arg;

case Expression.CREF(cref = cref as ComponentRef.CREF(restCref = ComponentRef.EMPTY()))
algorithm
slot := lookupSlotInArray(ComponentRef.firstName(cref), slots);

if isSome(slot) then
arg := fillDefaultSlot(Util.getOption(slot), slots, info);
outExp := arg.value;
else
outExp := exp;
end if;
then
outExp;

case Expression.CREF() then evaluateSlotCref(exp, slots, info);
else exp;
end match;
end evaluateSlotExp_traverser;

function evaluateSlotCref
input output Expression crefExp;
input array<Slot> slots;
input SourceInfo info;
protected
ComponentRef cref;
Type cref_ty;
list<ComponentRef> cref_parts;
String name;
Option<Slot> slot;
TypedArg arg;
algorithm
Expression.CREF(cref = cref, ty = cref_ty) := crefExp;

if not ComponentRef.isCref(cref) then
return;
end if;

cref :: cref_parts := ComponentRef.toListReverse(cref);
name := ComponentRef.firstName(cref);
slot := lookupSlotInArray(name, slots);

if isSome(slot) then
arg := fillDefaultSlot(Util.getOption(slot), slots, info);
crefExp := arg.value;
crefExp := Expression.applySubscripts(ComponentRef.getSubscripts(cref), crefExp);

for cr in cref_parts loop
crefExp := Expression.recordElement(ComponentRef.firstName(cr), crefExp);
crefExp := Expression.applySubscripts(ComponentRef.getSubscripts(cr), crefExp);
end for;

if Type.isKnown(cref_ty) then
crefExp := TypeCheck.matchTypes(Expression.typeOf(crefExp), cref_ty, crefExp);
end if;
end if;
end evaluateSlotCref;

function lookupSlotInArray
input String slotName;
input array<Slot> slots;
Expand Down Expand Up @@ -1353,7 +1377,7 @@ uniontype Function
end typeFunction;

function typeFunctionSignature
"Types a function's parameters, local components and default arguments."
"Types a function's parameters and local components."
input output Function fn;
protected
DAE.FunctionAttributes attr;
Expand All @@ -1368,14 +1392,6 @@ uniontype Function
ClassTree.applyComponents(Class.classTree(InstNode.getClass(node)), boxFunctionParameter);
end if;

// Type the bindings 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, NFInstContext.FUNCTION);
end for;

// Make the slots and return type for the function.
fn.slots := makeSlots(fn.inputs);
checkParamTypes(fn);
Expand All @@ -1384,14 +1400,17 @@ uniontype Function
end typeFunctionSignature;

function typeFunctionBody
"Types the body of a function, along with any bindings of local variables
and outputs."
"Types the body of a function, along with any component bindings."
input output Function fn;
protected
Boolean pure;
DAE.FunctionAttributes attr;
algorithm
// Type the bindings of the outputs and local variables.
// Type the bindings of components in the function.
for c in fn.inputs loop
Typing.typeComponentBinding(c, NFInstContext.FUNCTION);
end for;

for c in fn.outputs loop
Typing.typeComponentBinding(c, NFInstContext.FUNCTION);
end for;
Expand Down Expand Up @@ -2120,7 +2139,7 @@ protected
algorithm
try
comp := InstNode.component(component);
default := Binding.typedExp(Component.getImplicitBinding(comp));
default := Binding.getExpOpt(Component.getImplicitBinding(comp));
name := InstNode.name(component);

// Remove $in_ for OM input output arguments.
Expand Down
1 change: 1 addition & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFRecord.mo
Expand Up @@ -125,6 +125,7 @@ algorithm
ctor_node := InstNode.replaceClass(Class.NOT_INSTANTIATED(), node);
end try;

ctor_node := InstNode.setNodeType(NFInstNode.InstNodeType.ROOT_CLASS(InstNode.parent(node)), ctor_node);
ctor_node := Inst.instantiate(ctor_node, context = context, instPartial = true);
Inst.instExpressions(ctor_node, context = context);

Expand Down
28 changes: 28 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFTyping.mo
Expand Up @@ -1218,6 +1218,7 @@ algorithm
(exp, ty, variability, purity);

case Expression.IF() then typeIfExpression(exp, context, info);
case Expression.RECORD() then typeRecordExp(exp, context, info);

case Expression.CALL()
algorithm
Expand Down Expand Up @@ -1286,6 +1287,33 @@ algorithm
end for;
end typeExpl;

function typeRecordExp
input output Expression exp;
input InstContext.Type context;
input SourceInfo info;
output Type ty;
output Variability variability = Variability.CONSTANT;
output Purity purity = Purity.PURE;
protected
Absyn.Path path;
list<Expression> elems, ty_elems = {};
Variability var;
Purity pur;
InstContext.Type next_context;
algorithm
Expression.RECORD(path, ty, elems) := exp;
next_context := InstContext.set(context, NFInstContext.SUBEXPRESSION);

for e in elems loop
(e, _, var, pur) := typeExp(e, context, info);
variability := Prefixes.variabilityMax(var, variability);
purity := Prefixes.purityMin(pur, purity);
ty_elems := e :: ty_elems;
end for;

exp := Expression.makeRecord(path, ty, listReverseInPlace(ty_elems));
end typeRecordExp;

function typeSubscriptedExp
input output Expression exp;
input InstContext.Type context;
Expand Down
26 changes: 26 additions & 0 deletions testsuite/flattening/modelica/scodeinst/FuncDefaultArg3.mo
@@ -0,0 +1,26 @@
// name: FuncDefaultArg3
// keywords:
// status: correct
// cflags: -d=newInst
//
//

function f
input Real x[:];
input Real y = x[1];
output Real z[size(x, 1)] = y * x;
end f;

model FuncDefaultArg3
Real x[:] = f({2, 3, 4});
end FuncDefaultArg3;

// Result:
// class FuncDefaultArg3
// Real x[1];
// Real x[2];
// Real x[3];
// equation
// x = {4.0, 6.0, 8.0};
// end FuncDefaultArg3;
// endResult
26 changes: 26 additions & 0 deletions testsuite/flattening/modelica/scodeinst/FuncDefaultArg4.mo
@@ -0,0 +1,26 @@
// name: FuncDefaultArg4
// keywords:
// status: correct
// cflags: -d=newInst
//
//

record R
Real x;
end R;

function f
input R r;
input Real x = r.x;
output Real y = r.x * x;
end f;

model FuncDefaultArg4
Real x = f(R(2));
end FuncDefaultArg4;

// Result:
// class FuncDefaultArg4
// Real x = 4.0;
// end FuncDefaultArg4;
// endResult
27 changes: 27 additions & 0 deletions testsuite/flattening/modelica/scodeinst/FuncDefaultArg5.mo
@@ -0,0 +1,27 @@
// name: FuncDefaultArg5
// keywords:
// status: correct
// cflags: -d=newInst
//
//

function f
input Integer dim;
input Real x = f2(dim);
output Integer n = dim;
end f;

function f2
input Integer dim;
output Integer n = dim;
end f2;

model FuncDefaultArg5
parameter Real x = f(3);
end FuncDefaultArg5;

// Result:
// class FuncDefaultArg5
// parameter Real x = 3.0;
// end FuncDefaultArg5;
// endResult
3 changes: 3 additions & 0 deletions testsuite/flattening/modelica/scodeinst/Makefile
Expand Up @@ -518,6 +518,9 @@ FuncBuiltinZeros.mo \
FuncClassParam.mo \
FuncDefaultArg1.mo \
FuncDefaultArg2.mo \
FuncDefaultArg3.mo \
FuncDefaultArg4.mo \
FuncDefaultArg5.mo \
FuncDuplicateParams1.mo \
FuncExtends.mo \
FuncInnerParam.mo \
Expand Down

0 comments on commit f450566

Please sign in to comment.