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

Commit b873818

Browse files
sjoelundOpenModelica-Hudson
authored andcommitted
Partially type-check for min,max,smooth
Does not handle all cases yet (min/max does not check if `<` or `>` can be used on the expressions; smooth does not check for all allowed expressions, like records containing only arrays of reals, etc). Belonging to [master]: - #2017
1 parent 5e28f3c commit b873818

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

Compiler/NFFrontEnd/NFCall.mo

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ import Binding = NFBinding;
4343
import NFComponent.Component;
4444
import NFInstNode.CachedData;
4545
import ComponentRef = NFComponentRef;
46+
import Dimension = NFDimension;
4647
import NFFunction.Function;
4748
import Inst = NFInst;
4849
import NFInstNode.InstNodeType;
4950
import Lookup = NFLookup;
5051
import Typing = NFTyping;
52+
import TypeCheck = NFTypeCheck;
5153
import ExpOrigin = NFTyping.ExpOrigin;
5254
import Types;
5355
import List;
@@ -315,6 +317,12 @@ uniontype Call
315317
(call, ty, variability) := match callExp
316318
case Expression.CALL(UNTYPED_CALL(ref=ComponentRef.CREF(node=InstNode.CLASS_NODE(name="pre"))))
317319
then typePreCall(callExp.call, info);
320+
case Expression.CALL(UNTYPED_CALL(ref=ComponentRef.CREF(node=InstNode.CLASS_NODE(name="min"))))
321+
then typeMinMaxCall(callExp.call, info, "min");
322+
case Expression.CALL(UNTYPED_CALL(ref=ComponentRef.CREF(node=InstNode.CLASS_NODE(name="max"))))
323+
then typeMinMaxCall(callExp.call, info, "max");
324+
case Expression.CALL(UNTYPED_CALL(ref=ComponentRef.CREF(node=InstNode.CLASS_NODE(name="smooth"))))
325+
then typeSmoothCall(callExp.call, info);
318326
case Expression.CALL(UNTYPED_CALL()) then typeNormalCall(callExp.call, info);
319327
case Expression.CALL(UNTYPED_MAP_CALL()) then typeMapIteratorCall(callExp.call, info);
320328
end match;
@@ -516,6 +524,170 @@ uniontype Call
516524
end match;
517525
end typePreCall;
518526

527+
function typeMinMaxCall
528+
input output Call call;
529+
input SourceInfo info;
530+
input String name;
531+
output Type ty;
532+
output Variability variability;
533+
protected
534+
Call argtycall;
535+
InstNode fn_node;
536+
list<Function> fnl;
537+
Boolean fn_typed, special;
538+
Function fn;
539+
Expression e, e1, e2;
540+
Type ty1, ty2;
541+
list<Expression> es;
542+
list<Type> arg_ty;
543+
list<Variability> arg_var;
544+
CallAttributes ca;
545+
list<TypedArg> tyArgs;
546+
list<TypedNamedArg> nargs;
547+
Integer nArgs;
548+
Variability variability1, variability2;
549+
TypeCheck.MatchKind ty_match;
550+
algorithm
551+
(call , ty, variability) := match call
552+
case UNTYPED_CALL(ref = ComponentRef.CREF(node = fn_node))
553+
algorithm
554+
// Fetch the cached function(s).
555+
CachedData.FUNCTION({fn}, fn_typed, special) := InstNode.getFuncCache(fn_node);
556+
557+
// Type the function(s) if not already done.
558+
if not fn_typed then
559+
fn := Function.typeFunction(fn);
560+
InstNode.setFuncCache(fn_node, CachedData.FUNCTION({fn}, true, special));
561+
end if;
562+
563+
// Type the arguments.
564+
ARG_TYPED_CALL(arguments=tyArgs, named_args=nargs) := typeArgs(call,info);
565+
nArgs := listLength(tyArgs);
566+
if not listEmpty(nargs) or not (nArgs == 1 or nArgs == 2) then
567+
Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND, {toString(call), "<REMOVE ME>", name + "(<T>) => <T>, " + name + "(<T>,<T>) => <T>"}, info);
568+
end if;
569+
570+
if nArgs == 1 then
571+
{(e,ty,variability)} := tyArgs;
572+
es := {e};
573+
else
574+
{(e1,ty1,variability1),(e2,ty2,variability2)} := tyArgs;
575+
es := {e1,e2};
576+
variability := Prefixes.variabilityMax(variability1, variability2);
577+
(e1,e2,ty,ty_match) := TypeCheck.matchExpressions(e1,ty1,e2,ty2);
578+
if not TypeCheck.isCompatibleMatch(ty_match) then
579+
Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND, {toString(call), "<REMOVE ME>", "Incompatible types"}, info);
580+
end if;
581+
end if;
582+
583+
// TODO: Check that '<' or '>' operator is defined for the expression...
584+
585+
ca := CallAttributes.CALL_ATTR(
586+
ty,
587+
Type.isTuple(ty),
588+
Function.isBuiltin(fn),
589+
Function.isImpure(fn),
590+
Function.isFunctionPointer(fn),
591+
Function.inlineBuiltin(fn),
592+
DAE.NO_TAIL());
593+
594+
then
595+
(TYPED_CALL(fn, es, ca), ty, variability);
596+
597+
else
598+
algorithm
599+
assert(false, getInstanceName() + " got invalid function call expression");
600+
then
601+
fail();
602+
end match;
603+
end typeMinMaxCall;
604+
605+
function typeSmoothCall
606+
input output Call call;
607+
input SourceInfo info;
608+
output Type ty;
609+
output Variability variability;
610+
protected
611+
Call argtycall;
612+
InstNode fn_node;
613+
list<Function> fnl;
614+
Boolean fn_typed, special;
615+
Function fn;
616+
Expression e, e1, e2;
617+
Type ty1, ty2;
618+
list<Type> arg_ty;
619+
list<Variability> arg_var;
620+
CallAttributes ca;
621+
list<TypedArg> tyArgs;
622+
list<TypedNamedArg> nargs;
623+
Integer nArgs;
624+
Variability variability1, variability2;
625+
TypeCheck.MatchKind ty_match;
626+
algorithm
627+
(call , ty, variability) := match call
628+
case UNTYPED_CALL(ref = ComponentRef.CREF(node = fn_node))
629+
algorithm
630+
// Fetch the cached function(s).
631+
CachedData.FUNCTION({fn}, fn_typed, special) := InstNode.getFuncCache(fn_node);
632+
633+
// Type the function(s) if not already done.
634+
if not fn_typed then
635+
fn := Function.typeFunction(fn);
636+
InstNode.setFuncCache(fn_node, CachedData.FUNCTION({fn}, true, special));
637+
end if;
638+
639+
// Type the arguments.
640+
ARG_TYPED_CALL(arguments=tyArgs, named_args=nargs) := typeArgs(call,info);
641+
nArgs := listLength(tyArgs);
642+
if not listEmpty(nargs) or nArgs <> 2 then
643+
Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND, {toString(call), "<REMOVE ME>", "smooth(i, <T>) => <T>"}, info);
644+
end if;
645+
646+
{(e1,ty1,variability1),(e2,ty2,variability2)} := tyArgs;
647+
648+
if variability1 > Variability.PARAMETER then
649+
Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND, {toString(call), "<REMOVE ME>", "First argument of smooth must be a parameter or constant expression"}, info);
650+
end if;
651+
652+
(e1, ty1, ty_match) := TypeCheck.matchTypes(ty1, Type.INTEGER(), e1);
653+
654+
if not TypeCheck.isCompatibleMatch(ty_match) then
655+
Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND, {toString(call), "<REMOVE ME>", "First argument of smooth must be an Integer expression"}, info);
656+
end if;
657+
658+
variability := Prefixes.variabilityMax(variability1, variability2);
659+
660+
(e2, ty2, ty_match) := TypeCheck.matchTypes(ty2, Type.REAL(), e2);
661+
if not TypeCheck.isCompatibleMatch(ty_match) then
662+
(e2, ty2, ty_match) := TypeCheck.matchTypes(ty2, Type.ARRAY(Type.REAL(),{Dimension.UNKNOWN()}), e2);
663+
end if;
664+
// TODO: Allow ty2 is record with only allowed types...
665+
// TODO: Allow ty2 is multi-dim array
666+
667+
if not TypeCheck.isCompatibleMatch(ty_match) then
668+
Error.addSourceMessage(Error.NO_MATCHING_FUNCTION_FOUND, {toString(call), "<REMOVE ME>", "Second argument of smooth must be a Real scalar or record with only Real components, or array expression of these (TODO: Not fully checked)"}, info);
669+
end if;
670+
671+
ca := CallAttributes.CALL_ATTR(
672+
ty2,
673+
Type.isTuple(ty2),
674+
Function.isBuiltin(fn),
675+
Function.isImpure(fn),
676+
Function.isFunctionPointer(fn),
677+
Function.inlineBuiltin(fn),
678+
DAE.NO_TAIL());
679+
680+
then
681+
(TYPED_CALL(fn, {e1,e2}, ca), ty2, variability);
682+
683+
else
684+
algorithm
685+
assert(false, getInstanceName() + " got invalid function call expression");
686+
then
687+
fail();
688+
end match;
689+
end typeSmoothCall;
690+
519691
function typeArgs
520692
input output Call call;
521693
input SourceInfo info;

0 commit comments

Comments
 (0)