Skip to content

Commit

Permalink
Fix argument order of partial function application (#12504)
Browse files Browse the repository at this point in the history
- Rewrite `Function.typePartialApplication` to use a slot-based approach
  like normal function calls, to make sure the arguments of the partial
  application have the same order as the corresponding input parameters.
- Change the "no such parameter" error to "no such input parameter" in a
  few places to be more consistent.

Fixes #12491
  • Loading branch information
perost committed Jun 5, 2024
1 parent 6b262ba commit e7e9366
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 50 deletions.
8 changes: 4 additions & 4 deletions OMCompiler/Compiler/NFFrontEnd/NFBuiltinCall.mo
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ protected
input SourceInfo info;
algorithm
if not listEmpty(namedArgs) then
Error.addSourceMessage(Error.NO_SUCH_PARAMETER,
Error.addSourceMessage(Error.NO_SUCH_INPUT_PARAMETER,
{fnName, Util.tuple21(listHead(namedArgs))}, info);
fail();
end if;
Expand Down Expand Up @@ -1468,7 +1468,7 @@ protected
if name == "priority" then
args := List.appendElt(arg2, args);
else
Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER,
Error.addSourceMessageAndFail(Error.NO_SUCH_INPUT_PARAMETER,
{ComponentRef.toString(fn_ref), name}, info);
end if;
end for;
Expand Down Expand Up @@ -1613,7 +1613,7 @@ protected
if name == "message" then
args := List.appendElt(arg2, args);
else
Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER,
Error.addSourceMessageAndFail(Error.NO_SUCH_INPUT_PARAMETER,
{ComponentRef.toString(fn_ref), name}, info);
end if;
end for;
Expand Down Expand Up @@ -1686,7 +1686,7 @@ protected
if name == "message" then
args := List.appendElt(arg3, args);
else
Error.addSourceMessageAndFail(Error.NO_SUCH_PARAMETER,
Error.addSourceMessageAndFail(Error.NO_SUCH_INPUT_PARAMETER,
{ComponentRef.toString(fn_ref), name}, info);
end if;
end for;
Expand Down
89 changes: 44 additions & 45 deletions OMCompiler/Compiler/NFFrontEnd/NFFunction.mo
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ uniontype Function
end if;
// No slot could be found, so it doesn't exist.
Error.addSourceMessage(Error.NO_SUCH_PARAMETER,
Error.addSourceMessage(Error.NO_SUCH_INPUT_PARAMETER,
{InstNode.name(instance(fn)), arg_name}, info);
end for;
Expand Down Expand Up @@ -1696,79 +1696,78 @@ uniontype Function
InstContext.Type next_context = InstContext.set(context, NFInstContext.SUBEXPRESSION);
list<InstNode> inputs;
list<Slot> slots;
array<Slot> slots_arr;
TypedArg ty_arg;
TypeCheck.MatchKind mk;
algorithm
Expression.PARTIAL_FUNCTION_APPLICATION(fn = fn_ref, args = args, argNames = arg_names) := exp;
// TODO: Handle overloaded functions?
fn :: _ := typeRefCache(fn_ref);
inputs := fn.inputs;
slots := fn.slots;
rest_names := arg_names;
slots_arr := listArray(fn.slots);
purity := if Function.isImpure(fn) or Function.isOMImpure(fn) then Purity.IMPURE else Purity.PURE;
variability := Variability.CONSTANT;
// Type the arguments and add them to the slots.
for arg in args loop
(arg, arg_ty, arg_var, arg_pur) := Typing.typeExp(arg, next_context, info);
arg_name :: rest_names := rest_names;
(arg, inputs, slots) :=
applyPartialApplicationArg(arg_name, arg, arg_ty, inputs, slots, fn, info);
ty_args := Expression.box(arg) :: ty_args;
arg_name :: arg_names := arg_names;
ty_arg := TypedArg.TYPED_ARG(SOME(arg_name), arg, arg_ty, arg_var, arg_pur);
(slots_arr, true) := fillNamedArg(ty_arg, slots_arr, fn, info);
variability := Prefixes.variabilityMax(variability, arg_var);
purity := Prefixes.purityMin(purity, arg_pur);
end for;
fn.inputs := inputs;
fn.slots := slots;
ty := Type.FUNCTION(fn, NFType.FunctionType.FUNCTIONAL_VARIABLE);
exp := Expression.PARTIAL_FUNCTION_APPLICATION(fn_ref, listReverseInPlace(ty_args), arg_names, ty);
exp := makePartialApplicationFromSlots(slots_arr, fn, fn_ref, info);
ty := Expression.typeOf(exp);
end typePartialApplication;
function applyPartialApplicationArg
input String argName;
input output Expression argExp;
input Type argType;
input list<InstNode> inputs;
input list<Slot> slots;
function makePartialApplicationFromSlots
input array<Slot> slotsArray;
input Function fn;
input ComponentRef fnRef;
input SourceInfo info;
output list<InstNode> outInputs = {};
output list<Slot> outSlots = {};
output Expression outExp;
protected
InstNode i;
list<InstNode> rest_inputs = inputs;
Slot s;
list<Slot> rest_slots = slots;
list<InstNode> inputs = {};
list<Slot> slots = {};
list<Expression> args = {};
list<String> arg_names = {};
TypedArg ty_arg;
Expression arg;
TypeCheck.MatchKind mk;
Type fn_ty;
algorithm
while not listEmpty(rest_inputs) loop
i :: rest_inputs := rest_inputs;
s :: rest_slots := rest_slots;
if InstNode.name(s.node) == argName then
(argExp, _, mk) := TypeCheck.matchTypes(argType, InstNode.getType(i), argExp, true);
for slot in slotsArray loop
if isSome(slot.arg) then
// For each slot that's filled, type check the argument and add it to
// the arguments of the partial function application.
SOME(ty_arg) := slot.arg;
(arg, _, mk) := TypeCheck.matchTypes(ty_arg.ty, InstNode.getType(slot.node), ty_arg.value, true);
if TypeCheck.isIncompatibleMatch(mk) then
Error.addSourceMessage(Error.NAMED_ARG_TYPE_MISMATCH,
{AbsynUtil.pathString(name(fn)), argName, Expression.toString(argExp),
Type.toString(argType), Type.toString(InstNode.getType(i))}, info);
{AbsynUtil.pathString(name(fn)), Util.getOption(ty_arg.name), Expression.toString(ty_arg.value),
Type.toString(ty_arg.ty), Type.toString(InstNode.getType(slot.node))}, info);
fail();
end if;
outInputs := listAppend(listReverseInPlace(outInputs), rest_inputs);
outSlots := listAppend(listReverseInPlace(outSlots), rest_slots);
return;
args := Expression.box(arg) :: args;
arg_names := Util.getOption(ty_arg.name) :: arg_names;
else
// For each slot that's not filled, add it as an input of the partially evaluated function.
inputs := slot.node :: inputs;
slots := slot :: slots;
end if;
end for;
outInputs := i :: outInputs;
outSlots := s :: outSlots;
end while;
Error.addSourceMessage(Error.NO_SUCH_INPUT_PARAMETER,
{AbsynUtil.pathString(name(fn)), argName}, info);
fail();
end applyPartialApplicationArg;
fn.inputs := listReverseInPlace(inputs);
fn.slots := listReverseInPlace(slots);
fn_ty := Type.FUNCTION(fn, NFType.FunctionType.FUNCTIONAL_VARIABLE);
args := listReverseInPlace(args);
arg_names := listReverseInPlace(arg_names);
outExp := Expression.PARTIAL_FUNCTION_APPLICATION(fnRef, args, arg_names, fn_ty);
end makePartialApplicationFromSlots;
function isBuiltin
input Function fn;
Expand Down
1 change: 1 addition & 0 deletions testsuite/flattening/modelica/scodeinst/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ ParameterBug.mos \
ParameterDer.mo \
PartialApplication1.mo \
PartialApplication2.mo \
PartialApplication3.mo \
PartialApplicationInvalidArg1.mo \
PartialApplicationInvalidArg2.mo \
PartialClass1.mo \
Expand Down
66 changes: 66 additions & 0 deletions testsuite/flattening/modelica/scodeinst/PartialApplication3.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// name: PartialApplication3
// keywords:
// status: correct
// cflags: -d=newInst
//

partial function pf
input Real x;
output Real z;
end pf;

function f1
input Real x;
input pf f;
output Real z;
algorithm
z := f(x);
end f1;

function f2
input Real x;
input Real y;
input Real w;
output Real z = x + y + w;
end f2;

function f3
input Real x;
input Real y;
output Real z;
algorithm
z := f1(x, function f2(w = y, y = x));
end f3;

model PartialApplication3
Real x = f3(time, time);
end PartialApplication3;

// Result:
// function f1
// input Real x;
// input f<function>(#Real x) => #Real f;
// output Real z;
// algorithm
// z := unbox(f(#(x)));
// end f1;
//
// function f2
// input Real x;
// input Real y;
// input Real w;
// output Real z = x + y + w;
// end f2;
//
// function f3
// input Real x;
// input Real y;
// output Real z;
// algorithm
// z := f1(x, function f2(#(x), #(y)));
// end f3;
//
// class PartialApplication3
// Real x = f3(time, time);
// end PartialApplication3;
// endResult
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ end SizeInvalidArgs2;

// Result:
// Error processing file: SizeInvalidArgs2.mo
// [flattening/modelica/scodeinst/SizeInvalidArgs2.mo:11:3-11:31:writable] Error: Function size has no parameter named dim.
// [flattening/modelica/scodeinst/SizeInvalidArgs2.mo:11:3-11:31:writable] Error: Function size has no input parameter named dim.
//
// # Error encountered! Exiting...
// # Please check the error message and the flags.
Expand Down

0 comments on commit e7e9366

Please sign in to comment.