@@ -100,13 +100,14 @@ uniontype TypingError
100100end TypingError ;
101101
102102type EquationScope = enumeration(NORMAL , INITIAL , IF , IF_PARAMETER );
103+ type ClassScope = enumeration(CLASS , FUNCTION );
103104
104105public
105106function typeClass
106107 input InstNode cls;
107108 input String name;
108109algorithm
109- typeComponents(cls);
110+ typeComponents(cls, ClassScope . CLASS );
110111 execStat("NFTyping.typeComponents(" + name + ")" );
111112 typeBindings(cls, cls);
112113 execStat("NFTyping.typeBindings(" + name + ")" );
@@ -117,13 +118,14 @@ end typeClass;
117118function typeFunction
118119 input InstNode cls;
119120algorithm
120- typeComponents(cls);
121+ typeComponents(cls, ClassScope . FUNCTION );
121122 typeBindings(cls, cls);
122123 typeSections(cls);
123124end typeFunction;
124125
125126function typeComponents
126127 input InstNode cls;
128+ input ClassScope clsScope;
127129protected
128130 Class c = InstNode . getClass(cls), c2;
129131 ClassTree cls_tree;
@@ -133,7 +135,7 @@ algorithm
133135 case Class . INSTANCED_CLASS (elements = cls_tree as ClassTree . FLAT_TREE ())
134136 algorithm
135137 for c in cls_tree. components loop
136- typeComponent(c);
138+ typeComponent(c, clsScope );
137139 end for ;
138140 then
139141 ();
@@ -147,7 +149,7 @@ algorithm
147149 // But keep the restriction.
148150 c2 := Class . setRestriction(c. restriction, c2);
149151 InstNode . updateClass(c2, cls);
150- typeComponents(cls);
152+ typeComponents(cls, clsScope );
151153 then
152154 ();
153155
@@ -204,6 +206,7 @@ end makeConnectorType;
204206
205207function typeComponent
206208 input InstNode component;
209+ input ClassScope clsScope;
207210 output Type ty;
208211protected
209212 InstNode node = InstNode . resolveOuter(component);
@@ -214,7 +217,7 @@ algorithm
214217 case Component . UNTYPED_COMPONENT ()
215218 algorithm
216219 // Type the component's dimensions.
217- typeDimensions(c. dimensions, node, c. binding, c. info);
220+ typeDimensions(c. dimensions, node, c. binding, clsScope, c. info);
218221
219222 // Construct the type of the component and update the node with it.
220223 ty := Type . liftArrayLeftList(makeClassType(c. classInst), arrayList(c. dimensions));
@@ -224,7 +227,7 @@ algorithm
224227 checkComponentAttributes(c. attributes, component);
225228
226229 // Type the component's children.
227- typeComponents(c. classInst);
230+ typeComponents(c. classInst, clsScope );
228231 then
229232 ty;
230233
@@ -349,10 +352,11 @@ function typeDimensions
349352 input output array< Dimension > dimensions;
350353 input InstNode component;
351354 input Binding binding;
355+ input ClassScope clsScope;
352356 input SourceInfo info;
353357algorithm
354358 for i in 1 :arrayLength(dimensions) loop
355- typeDimension(dimensions[i], component, binding, i, dimensions, info);
359+ typeDimension(dimensions[i], component, binding, i, clsScope, dimensions, info);
356360 end for ;
357361end typeDimensions;
358362
@@ -361,6 +365,7 @@ function typeDimension
361365 input InstNode component;
362366 input Binding binding;
363367 input Integer index;
368+ input ClassScope clsScope;
364369 input array< Dimension > dimensions;
365370 input SourceInfo info;
366371algorithm
@@ -396,10 +401,20 @@ algorithm
396401 arrayUpdate(dimensions, index, Dimension . UNTYPED (dimension. dimension, true ));
397402
398403 (exp, ty, var ) := typeExp(dimension. dimension, info, ExpOrigin . DIMENSION ());
399- TypeCheck . checkDimension (exp, ty, var , info);
404+ TypeCheck . checkDimensionType (exp, ty, info);
400405
401- exp := Ceval . evalExp(exp, Ceval . EvalTarget . DIMENSION (component, index, exp, info));
402- exp := SimplifyExp . simplifyExp(exp);
406+ if var <= Variability . PARAMETER then
407+ // Evaluate the dimension if it's a parameter expression.
408+ exp := Ceval . evalExp(exp, Ceval . EvalTarget . DIMENSION (component, index, exp, info));
409+ exp := SimplifyExp . simplifyExp(exp);
410+ else
411+ // Dimensions must be parameter expressions, unless we're in a function.
412+ if clsScope <> ClassScope . FUNCTION then
413+ Error . addSourceMessage(Error . DIMENSION_NOT_KNOWN ,
414+ {Expression . toString(exp)}, info);
415+ fail();
416+ end if ;
417+ end if ;
403418
404419 // It's possible to get an array expression here, for example if the
405420 // dimension expression is a parameter whose binding comes from a
@@ -417,7 +432,11 @@ algorithm
417432 then
418433 dim;
419434
420- // If the dimension is unknown, try to infer it from the components binding.
435+ // If the dimension is unknown in a function, keep it unknown.
436+ case Dimension . UNKNOWN () guard clsScope == ClassScope . FUNCTION
437+ then dimension;
438+
439+ // If the dimension is unknown in a class, try to infer it from the components binding.
421440 case Dimension . UNKNOWN ()
422441 algorithm
423442 dim := match binding
@@ -1123,7 +1142,7 @@ algorithm
11231142 else
11241143 error := TypingError . NO_ERROR ();
11251144 d := arrayGet(c. dimensions, dimIndex);
1126- d := typeDimension(d, node, c. binding, dimIndex, c. dimensions, c. info);
1145+ d := typeDimension(d, node, c. binding, dimIndex, ClassScope . CLASS , c. dimensions, c. info);
11271146 end if ;
11281147 then
11291148 (d, error);
@@ -1172,7 +1191,7 @@ algorithm
11721191
11731192 case ComponentRef . CREF (node = InstNode . COMPONENT_NODE ())
11741193 algorithm
1175- node_ty := typeComponent(cref. node);
1194+ node_ty := typeComponent(cref. node, ClassScope . CLASS );
11761195 variability := ComponentRef . getVariability(cref);
11771196 subs := typeSubscripts(cref. subscripts, node_ty, cref. node, info);
11781197 cref_ty := Type . subscript(node_ty, subs);
@@ -1422,38 +1441,63 @@ algorithm
14221441 fail();
14231442 end if ;
14241443
1425- // TODO: Only evaluate the index if it's a constant (parameter?),
1426- // otherwise just return a size expression.
1427- index := Ceval . evalExp(index, Ceval . EvalTarget . IGNORE_ERRORS ());
1428- index := SimplifyExp . simplifyExp(index);
1429-
1430- // TODO: Print an error if the index couldn't be evaluated to an int.
1431- Expression . INTEGER (iindex) := index;
1432-
1433- (dim, ty_err) := typeExpDim(sizeExp. exp, iindex, ExpOrigin . NO_ORIGIN (), info);
1434-
1435- () := match ty_err
1436- case NO_ERROR () then ();
1444+ if variability <= Variability . PARAMETER then
1445+ // Evaluate the index if it's a constant.
1446+ index := Ceval . evalExp(index, Ceval . EvalTarget . IGNORE_ERRORS ());
1447+ index := SimplifyExp . simplifyExp(index);
1448+
1449+ // TODO: Print an error if the index couldn't be evaluated to an int.
1450+ Expression . INTEGER (iindex) := index;
1451+
1452+ // Get the iindex'd dimension of the expression.
1453+ (dim, ty_err) := typeExpDim(sizeExp. exp, iindex, ExpOrigin . NO_ORIGIN (), info);
1454+
1455+ () := match ty_err
1456+ case NO_ERROR () then ();
1457+
1458+ // The first argument wasn't an array.
1459+ case OUT_OF_BOUNDS (0 )
1460+ algorithm
1461+ Error . addSourceMessage(Error . INVALID_ARGUMENT_TYPE_FIRST_ARRAY , {"size" }, info);
1462+ then
1463+ fail();
1464+
1465+ // The index referred to an invalid dimension.
1466+ case OUT_OF_BOUNDS ()
1467+ algorithm
1468+ Error . addSourceMessage(Error . INVALID_SIZE_INDEX ,
1469+ {String (iindex), Expression . toString(sizeExp. exp), String (ty_err. upperBound)}, info);
1470+ then
1471+ fail();
1472+ end match;
1473+
1474+ if Dimension . isKnown(dim) then
1475+ // The dimension size is known, return its size.
1476+ exp := Expression . INTEGER (Dimension . size(dim));
1477+ else
1478+ // The dimension size is unknown, return a size expression. This can
1479+ // happen in functions where unknown dimensions are allowed.
1480+ exp := typeExp(sizeExp. exp, info);
1481+ exp := Expression . SIZE (exp, SOME (index));
1482+ end if ;
14371483
1438- // The first argument wasn't an array.
1439- case OUT_OF_BOUNDS (0 )
1440- algorithm
1441- Error . addSourceMessage(Error . INVALID_ARGUMENT_TYPE_FIRST_ARRAY , {"size" }, info);
1442- then
1443- fail();
1484+ variability := Variability . PARAMETER ;
1485+ else
1486+ // If the index is not a constant, type the whole expression.
1487+ (exp, exp_ty) := typeExp(sizeExp. exp, info);
14441488
1445- // The index referred to an invalid dimension.
1446- case OUT_OF_BOUNDS ()
1447- algorithm
1448- Error . addSourceMessage(Error . INVALID_SIZE_INDEX ,
1449- {String (iindex), Expression . toString(sizeExp. exp), String (ty_err. upperBound)}, info);
1450- then
1451- fail();
1452- end match;
1489+ // Check that it's an array.
1490+ if not Type . isArray(exp_ty) then
1491+ Error . addSourceMessage(Error . INVALID_ARGUMENT_TYPE_FIRST_ARRAY , {"size" }, info);
1492+ fail();
1493+ end if ;
14531494
1454- dim_size := Dimension . size(dim);
1495+ // Since we don't know which dimension to take the size of, return a size expression.
1496+ exp := Expression . SIZE (exp, SOME (index));
1497+ variability := Variability . CONTINUOUS ;
1498+ end if ;
14551499 then
1456- (Expression . INTEGER (dim_size) , Type . INTEGER (), Variability . CONSTANT );
1500+ (exp , Type . INTEGER (), variability );
14571501
14581502 case Expression . SIZE ()
14591503 algorithm
0 commit comments