source: branches/dev-mo-2617/Compiler/ModelicaFrontEnd/src/jastadd/errorcheck/TypeCheck.jrag @ 13898

Last change on this file since 13898 was 13898, checked in by molsson, 7 weeks ago

#5843 Moved type checking of conditional attributes so that it is always done.

File size: 92.8 KB
Line 
1/*
2    Copyright (C) 2009-2013 Modelon AB
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, version 3 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17import java.util.Arrays;
18import java.util.Collections;
19import java.util.Set;
20import java.util.HashSet;
21import java.util.ArrayList;
22import org.jmodelica.util.Criteria;
23import org.jmodelica.util.ErrorCheckType;
24import org.jmodelica.util.problemHandling.ErrorProducerUnlessDisabled;
25import org.jmodelica.util.problemHandling.AbstractErrorProducerUnlessDisabled;
26import org.jmodelica.util.collections.ReverseListIterable;
27
28aspect FlatTypeCheck {
29
30    public void ASTNode.typeCheck(ErrorCheckType checkType) {}
31
32    public abstract class ErrorChecker {
33        public static class TypeChecker extends ErrorChecker {
34            public TypeChecker() {
35                super("TypeCheck");
36            }
37
38            @Override
39            public void check(ASTNode node, ErrorCheckType checkType) {
40                node.typeCheck(checkType);
41            }
42        }
43    }
44
45    private static ErrorChecker ASTNode.TYPE_CHECKER = addErrorChecker(new ErrorChecker.TypeChecker());
46
47    public static final SimpleProblemProducer ASTNode.CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS =
48            new SimpleErrorProducer("CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS", ProblemKind.SEMANTIC,
49                    "In the declaration '%s', the declared class is not a subtype of the " + 
50                    "constraining class,\n    because %s");
51    public static final SimpleProblemProducer ASTNode.REPLACING_CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS =
52            new SimpleErrorProducer("REPLACING_CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS", ProblemKind.SEMANTIC,
53                    "In the declaration '%s', the replacing class is not a subtype of the " + 
54                    "constraining class from the declaration '%s',\n    because %s");
55    public static final SimpleProblemProducer ASTNode.PREV_REDECLARE_NOT_REPLACEABLE =
56            new SimpleWarningProducer("PREV_REDECLARE_NOT_REPLACEABLE", ProblemKind.SEMANTIC,
57                    "In the declaration '%s', %s can't be redeclared since it has already been " + 
58                    "redeclared without 'replaceable'");
59
60    public void InstComposite.typeCheck(ErrorCheckType checkType) {
61        super.typeCheck(checkType);
62        // Note that modifiers (including redeclarations) in a constraining clause
63        // are applied to the declaration itself and is therefore also type checked.
64        if (hasInstConstrainingComponent()) {
65              InstNode superType = getInstConstrainingComponent().getInstNode();
66              InstComponentDecl declaredType = this;
67              String subTypeMsg = declaredType.subType(superType);
68              if (subTypeMsg != null) {
69                  SrcComponentClause cc = declaredType.myComponentClause();
70                  CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(declaredType, cc, subTypeMsg);
71              }
72        }
73    }
74
75    public void InstReplacingRecord.typeCheck(ErrorCheckType checkType) {
76        typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
77    }
78
79    public void InstReplacingComposite.typeCheck(ErrorCheckType checkType) {
80        typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
81    }
82
83    public void InstReplacingPrimitive.typeCheck(ErrorCheckType checkType) {
84        typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
85    }
86
87    public void InstReplacingExpandableConnectorDecl.typeCheck(ErrorCheckType checkType) {
88        typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
89    }
90
91    public void InstComponentDecl.typeCheckReplacingComponent(InstComponentDecl declaredType, ErrorCheckType checkType) {
92        super.typeCheck(checkType);
93       
94        // Type check the original component
95        InstComponentDecl superType = declaredType.constrainingInstComponentDecl();
96        if (declaredType.hasInstConstrainingComponent()) {
97            String subTypeMsg = declaredType.subType(superType);
98            if (subTypeMsg != null) {
99                SrcComponentClause cc = declaredType.myComponentClause();
100                CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(declaredType, cc, subTypeMsg);
101            }
102        }
103
104        // The environment should be traversed backwards in order to perform correct
105        // subtype tests in redeclaration chains.
106        InstComponentRedeclare prevRedeclare = null;
107        for (InstComponentRedeclare redeclare : myEnvironment().reverseComponentRedeclares(name())) {
108            InstComponentDecl declaredSubType = redeclare.getInstComponentDecl();
109            InstComponentDecl constrainingSubType = declaredSubType.constrainingInstComponentDecl();
110               
111            // Check consistency of the redeclaring component
112            if (declaredSubType.hasInstConstrainingComponent()) {
113                String subTypeMsg = declaredSubType.subType(constrainingSubType);
114                if (subTypeMsg != null) {
115                    SrcComponentClause cc = declaredSubType.myComponentClause();
116                    CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(declaredSubType, cc, subTypeMsg);
117                }
118            }
119
120            // It is ok to check against the constrainingSubType, since the declaredSubType is a subtype
121            // of the constrainingSubType. Then if constrainingSubType is a subtype of superType, then it
122            // follows that declaredSubType is a subtype of superType by transitivity.
123            String subTypeMsg = constrainingSubType.subType(superType);
124            if (subTypeMsg != null) {
125                SrcComponentClause cc = constrainingSubType.myComponentClause();
126                SrcComponentClause scc = superType.myComponentClause();
127                REPLACING_CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(constrainingSubType, 
128                        cc, scc, subTypeMsg);
129            }
130       
131            // If the redeclaring declaration has a constraining clause, the constraining
132            // type of the redeclaring declaration of should be used in following subtype-test
133            // instead of the constraining type of the original declaration.
134            if (declaredSubType.hasInstConstrainingComponent()) 
135                superType = constrainingSubType;
136           
137            // If the previous redeclare is declared without "replaceable", then it is illegal
138            // to redeclare further. The check on commonAncestor() checks that this redeclare actually
139            // replaces the previous one.
140            InstNode containingNode = redeclare.myInstNode();
141            if (prevRedeclare != null && !prevRedeclare.getInstComponentDecl().isReplaceable() && 
142                    prevRedeclare.myInstNode().commonAncestor(containingNode) == containingNode) {
143                PREV_REDECLARE_NOT_REPLACEABLE.invoke(declaredSubType, 
144                        declaredSubType.myComponentClause(), declaredSubType.name());
145            }
146           
147            prevRedeclare = redeclare;
148        }
149    }
150   
151    public Iterable<InstComponentRedeclare> Environment.reverseComponentRedeclares(String name) {
152        Set<SrcModificationOrRedeclareElement> seen = new HashSet<>();
153        ArrayList<InstComponentRedeclare> list = new ArrayList<>();
154       
155        for (InstModification im : this) {
156            InstComponentRedeclare red = im.matchInstComponentRedeclare(name);
157            if (red != null) {
158                SrcModificationOrRedeclareElement mod = red.getSrcModification();
159                if (!seen.contains(mod)) {
160                    seen.add(mod);
161                    list.add(red);
162                }
163            }
164        }
165       
166        return new ReverseListIterable(list);
167    }
168   
169   
170    public static final SimpleProblemProducer ASTNode.CANNOT_INFER_ARRAY_SIZE_OF_VARIABLE =
171            new SimpleErrorProducer("CANNOT_INFER_ARRAY_SIZE_OF_VARIABLE", ProblemKind.SEMANTIC,
172                    "Can not infer array size of the variable %s");
173    public static final SimpleProblemProducer ASTNode.CANNOT_INFER_ARRAY_SIZE_OF_FUNCTION_OUTPUT =
174            new SimpleErrorProducer("CANNOT_INFER_ARRAY_SIZE_OF_FUNCTION_OUTPUT", ProblemKind.COMPLIANCE,
175                    "Can not infer array size of the function output %s");
176    public static final SimpleProblemProducer ASTNode.BINDING_EXPRESSION_TYPE_MISMATCH =
177            new SimpleErrorProducer("BINDING_EXPRESSION_TYPE_MISMATCH", ProblemKind.SEMANTIC,
178                    "The binding expression of the variable %s does not match the declared type of the variable");
179    public static final SimpleProblemProducer ASTNode.ASSUMING_EACH =
180            new SimpleWarningProducer("ASSUMING_EACH", ProblemKind.SEMANTIC, "Assuming 'each' for the modification '%s'");
181    public static final SimpleProblemProducer ASTNode.IGNORING_EACH =
182            new SimpleWarningProducer("IGNORING_EACH", ProblemKind.SEMANTIC, "Ignoring erroneous 'each' for the modification '%s'");
183    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_DECLARATION =
184            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_DECLARATION", ProblemKind.SEMANTIC,
185                    "Array size mismatch in declaration of %s, size of declaration is %s and size of binding expression is %s");
186    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_MODIFICATION =
187            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_MODIFICATION", ProblemKind.SEMANTIC,
188                    "Array size mismatch in modification of %s, expected size is %s and size of binding expression is %s");
189    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_MODIFICATION_DUE_TO_EACH =
190            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_MODIFICATION_DUE_TO_EACH", ProblemKind.SEMANTIC,
191                    "Array size mismatch in modification of %s, expected size is (due to 'each') %s and size of binding expression is %s");
192    public static final SimpleProblemProducer ASTNode.NON_SCALAR_CONDITIONAL_GUARD =
193            new SimpleErrorProducer("NON_SCALAR_CONDITIONAL_GUARD", ProblemKind.SEMANTIC,
194                    "The guard expression of a conditional component should be a scalar expression");
195    public static final SimpleProblemProducer ASTNode.NON_BOOLEAN_CONDITIONAL_GUARD =
196            new SimpleErrorProducer("NON_BOOLEAN_CONDITIONAL_GUARD", ProblemKind.SEMANTIC,
197                    "The guard expression of a conditional component should be a boolean expression");
198    public static final SimpleProblemProducer ASTNode.NON_FIXED_CONDITIONAL_GUARD =
199            new SimpleErrorProducer("NON_FIXED_CONDITIONAL_GUARD", ProblemKind.SEMANTIC,
200                    "The guard expression of a conditional component should have parameter or constant variability");
201
202    @Override
203    public void InstAssignable.typeCheck(ErrorCheckType checkType) {
204        FExp bexp = myBindingInstExp();
205        boolean function = inFunction();
206        boolean record = inRecordDecl();
207        boolean output = isOutput();
208        boolean incompleteAllowed = (function && !output) || record;
209        boolean unknownAllowed = function || record;
210        Size componentSize = size();
211        if (!componentSize.isComplete() && !incompleteAllowed && !checkType.allowIncompleteSizes()) {
212            if (function && output) {
213                CANNOT_INFER_ARRAY_SIZE_OF_FUNCTION_OUTPUT.invoke(surroundingInstClass(), qualifiedName());
214            } else {
215                CANNOT_INFER_ARRAY_SIZE_OF_VARIABLE.invoke(this, name());
216            }
217        }
218        if (bexp != null && !inRecordWithBindingExp() && !bexp.type().isUnknown() && checkType.checkTypes()) {
219            Index arrayIndex = indexInModification();
220           
221            CommonType expectedBT = expectedBindingType();
222            CommonType actualBT = actualBindingType();
223           
224            boolean reportedError = false;
225            if (!expectedBT.size().equivalent(actualBT.size(), unknownAllowed)) {
226                InstValueModification ivm = myInstValueMod();
227                InstModification needsEach = ivm.findModificationLackingEach(actualBT.size());
228                if (!expectedBT.scalarType().typeCompatible(actualBT.scalarType())) {
229                    BINDING_EXPRESSION_TYPE_MISMATCH.invoke(bexp, name());
230                    reportedError = true;
231                } else if (needsEach != null) {
232                    ASSUMING_EACH.invoke(needsEach, needsEach);
233                    actualBT = actualBT.expand(expectedBT.size().contractLeft(expectedBT.ndims() - actualBT.ndims()));
234                } else if (ivm.expectedSizeNoEach().equivalent(actualBT.size(), unknownAllowed)) {
235                    InstModification parIM = ivm.parentInstModification();
236                    IGNORING_EACH.invoke(parIM, parIM);
237                    expectedBT = expectedBindingTypeNoEach();
238                    arrayIndex = indexInModificationNoEach();
239                } else {
240                    ErrorProducerUnlessDisabled reporter;
241                    if (ivm.myInstNode() == this) {
242                        reporter = ARRAY_SIZE_MISMATCH_IN_DECLARATION;
243                    } else if (ivm.hasEach()) {
244                        reporter = ARRAY_SIZE_MISMATCH_IN_MODIFICATION_DUE_TO_EACH;
245                    } else {
246                        reporter = ARRAY_SIZE_MISMATCH_IN_MODIFICATION;
247                    }
248                    reporter.invokeWithCondition(bexp, expectedBT.ndims() == actualBT.ndims(), name(), expectedBT.size(), actualBT.size());
249                    reportedError = true;
250                }
251            }
252           
253            if (!reportedError) {
254                if (expectedBT.size().isEmpty() || expectedBT.size().isUnknown() || actualBT.size().isUnknown()) {
255                    typeCheckCell(expectedBT.scalarType(), actualBT.scalarType(), bexp, unknownAllowed);
256                } else {
257                    Size arraySize = expectedBT.size().contractLeft(expectedBT.ndims() - arrayIndex.ndims());
258                    for (Index index : Indices.create(arraySize)) {
259                        index = arrayIndex.expand(index);
260                        CommonType expected = expectedBT.cell(index);
261                        CommonType actual = actualBT.cell(index);
262                       
263                        typeCheckCell(expected, actual, bexp, unknownAllowed);
264                    }
265                }
266            }
267        }
268       
269        typeCheckAttributes();
270        super.typeCheck(checkType);
271    }
272   
273    private void InstAssignable.typeCheckCell(CommonType expectedBT, CommonType actualBT, FExp bexp, boolean unknownAllowed) {
274        if (!expectedBT.typeCompatible(actualBT, unknownAllowed) && !expectedBT.isUnknown()) {
275            if (!expectedBT.scalarType().typeCompatible(actualBT.scalarType())) {
276                BINDING_EXPRESSION_TYPE_MISMATCH.invoke(bexp, name());
277            }
278        }
279    }
280
281    inh InstModification InstModification.parentInstModification();
282    eq InstComponentModification.getChild().parentInstModification()             = this;
283    eq InstNode.getElementInstModification(int i).parentInstModification()       = getElementInstModification(i);
284    eq InstComponentDecl.getInstModification().parentInstModification()          = getInstModification();
285    eq InstComponentDecl.getAnnotation().parentInstModification()                = getAnnotation();
286    eq InstClassDecl.getClassAnnotation().parentInstModification()               = getClassAnnotation();
287    eq InstConstraining.getInstClassModification().parentInstModification()      = getInstClassModification();
288    eq InstRecordConstructor.getInstModification(int i).parentInstModification() = getInstModification(i);
289
290    inh boolean InstComponentDecl.inRecordWithBindingExp();
291    eq InstRecord.getChild().inRecordWithBindingExp()             = myBindingInstExp() != null;
292    eq InstArrayComponentDecl.getChild().inRecordWithBindingExp() = inRecordWithBindingExp();
293    eq InstComponentDecl.getChild().inRecordWithBindingExp()      = false;
294    eq InstClassDecl.getChild().inRecordWithBindingExp()          = false;
295    eq Root.getChild().inRecordWithBindingExp()                   = false;
296   
297    public void InstAssignable.typeCheckAttributes() {}
298   
299    public void InstPrimitive.typeCheckAttributes() {
300            for (InstModification im : totalMergedEnvironment()) 
301                im.typeCheckAttribute(this);
302     }
303
304    public void InstModification.typeCheckAttribute(InstNode owner) {}
305
306    public static final SimpleProblemProducer ASTNode.TYPE_MISMATCH_IN_ATTRIBUTE_MODIFICATION =
307            new SimpleErrorProducer("TYPE_MISMATCH_IN_ATTRIBUTE_MODIFICATION", ProblemKind.SEMANTIC,
308                    "The type of the binding expression of the attribute %s for the %s %s does not match the declared type of the variable");
309    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION =
310            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION", ProblemKind.SEMANTIC,
311                    "Array size mismatch in modification of the attribute %s for the %s %s, expected size is %s and size of %s expression is %s");
312    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION_DUE_TO_EACH =
313            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION_DUE_TO_EACH", ProblemKind.SEMANTIC,
314                    "Array size mismatch in modification of the attribute %s for the %s %s, expected size is (due to 'each') %s and size of %s expression is %s");
315
316    public void InstComponentModification.typeCheckAttribute(InstNode owner) {
317        if (hasInstModification() && getInstModification().hasInstValueMod()) {
318            FExp valMod = getInstModification().instValueMod();
319            if (!type().isUnknown() && !valMod.type().isUnknown()) {
320                Size attrSize = expectedSize();
321                Size modSize = valMod.size();
322                if (!type().typeCompatible(valMod.type().scalarType())) {
323                    TYPE_MISMATCH_IN_ATTRIBUTE_MODIFICATION.invoke(this, name(), owner.kindDescription(), owner.name());
324                } else if (!attrSize.equivalent(modSize, true)) {
325                    InstModification im = findModificationLackingEach(modSize);
326                    if (im != null) {
327                        ASSUMING_EACH.invoke(im, im);
328                    } else if (expectedSizeNoEach().equivalent(modSize, false)) {
329                        IGNORING_EACH.invoke(this, this);
330                    } else {
331                        ErrorProducerUnlessDisabled producer;
332                        if (hasEach()) {
333                            producer = ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION_DUE_TO_EACH;
334                        } else {
335                            producer = ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION;
336                        }
337                        producer.invokeWithCondition(this, attrSize.ndims() != valMod.ndims(), name(),
338                                owner.kindDescription(), owner.name(), attrSize, name(), modSize);
339                    }
340                } else {
341                    if (name().equals("nominal")) {
342                        checkNominalAttribute(owner, valMod);
343                    }
344                }
345            }
346        }
347    }
348
349    public static final SimpleProblemProducer ASTNode.NOMINAL_EQUAL_TO_ZERO =
350            new SimpleErrorProducer("NOMINAL_EQUAL_TO_ZERO", ProblemKind.SEMANTIC,
351                    "The attribute nominal for the %s %s is set to %s, evaluating to 0.0. A nominal value of zero is not meaningful. Please set the nominal value to the expected magnitude of the variable.");
352    public static final SimpleProblemProducer ASTNode.NOMINAL_ELEMENT_EQUAL_TO_ZERO =
353            new SimpleErrorProducer("NOMINAL_ELEMENT_EQUAL_TO_ZERO", ProblemKind.SEMANTIC,
354                    "The attribute nominal for the %s %s is set to %s, where element %s evaluates to 0.0. A nominal value of zero is not meaningful. Please set the nominal value to the expected magnitude of the variable.");
355
356    public void InstComponentModification.checkNominalAttribute(InstNode owner, FExp valMod) {
357        try {
358            CValue val = valMod.ceval();
359            if (val.isArray()) {
360                CValueArray arr = (CValueArray) val;
361                for (Index i : arr.indices()) {
362                    CValue cell = arr.getCell(i);
363                    if (hasZeroNominal(owner, cell)) {
364                        NOMINAL_ELEMENT_EQUAL_TO_ZERO.invoke(this, owner.kindDescription(), owner.name(), valMod, i);
365                        break;
366                    }
367                }
368            } else {
369                if (hasZeroNominal(owner, val)) {
370                    NOMINAL_EQUAL_TO_ZERO.invoke(this, owner.kindDescription(), owner.name(), valMod);
371                }
372            }
373        } catch (ConstantEvaluationException e) {}
374    }
375   
376    public boolean InstComponentModification.hasZeroNominal(InstNode owner, CValue val) {
377        return val.hasRealValue() && val.realValue() == 0.0;
378    }
379
380    syn String InstNode.kindDescription() {
381        throw new UnsupportedOperationException();
382    }
383    eq InstComponentDecl.kindDescription() = myInstClass().kindDescription() + " instance";
384    eq InstPrimitive.kindDescription()     = "variable";
385    eq InstBaseClassDecl.kindDescription() = getInstRestriction().toString();
386
387    public static final SimpleProblemProducer ASTNode.EACH_APPLIED_ON_SCALAR =
388            new SimpleWarningProducer("EACH_APPLIED_ON_SCALAR", ProblemKind.SEMANTIC,
389                    "The 'each' keyword should not be applied to a modification of a scalar component: %s");
390
391    public void InstArgument.typeCheck(ErrorCheckType checkType) {
392        if (checkType.checkTypes() && getEach() && expectedSizeFromParent() == Size.SCALAR) 
393            EACH_APPLIED_ON_SCALAR.invoke(this, this);
394    }
395
396    inh boolean InstNode.isInRedeclareMod();
397    eq InstElementRedeclare.getChild().isInRedeclareMod() = true;
398    eq InstClassDecl.getChild().isInRedeclareMod()        = false;
399    eq InstRoot.getChild().isInRedeclareMod()             = false;
400    eq Root.getChild().isInRedeclareMod()                 = false;
401
402    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_EQUATION =
403            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_EQUATION", ProblemKind.SEMANTIC,
404                    "The array sizes of right and left hand side of equation are not compatible, size of left-hand side is %s, and size of right-hand side is %s");
405    public static final SimpleProblemProducer ASTNode.TYPE_MISMATCH_IN_EQUATION =
406            new SimpleErrorProducer("TYPE_MISMATCH_IN_EQUATION", ProblemKind.SEMANTIC,
407                    "The right and left expression types of equation are not compatible, type of left-hand side is %s, and type of right-hand side is %s");
408
409    public void FEquation.typeCheck(ErrorCheckType checkType) {
410        typeCheckLocalIteration(checkType);
411        FType left = getLeft().type();
412        FType right = getRight().type();
413        if (!left.isUnknown() && !right.isUnknown()) {
414            if (!left.equivalentTo(right)) {
415                if (left.equivalentExceptLengths(right)) {
416                    if (!lockBranch(checkType))
417                        ARRAY_SIZE_MISMATCH_IN_EQUATION.invoke(this, left.size(), right.size());
418                } else {
419                    TYPE_MISMATCH_IN_EQUATION.invoke(this, left, right);
420                }
421            }
422        }
423    }
424
425    public static final SimpleProblemProducer ASTNode.CONNECT_WITH_INVALID_TYPE =
426            new SimpleErrorProducer("CONNECT_WITH_INVALID_TYPE", ProblemKind.SEMANTIC,
427                    "Connecting to an instance of a non-connector type is not allowed");
428    public static final SimpleProblemProducer ASTNode.CONNECT_EXPANDABLE_AND_NON_EXPANDABLE_TYPE =
429            new SimpleErrorProducer("CONNECT_EXPANDABLE_AND_NON_EXPANDABLE_TYPE", ProblemKind.SEMANTIC,
430                    "Connecting an expandable connector to a non-expandable connector is not allowed");
431    public static final SimpleProblemProducer ASTNode.TYPE_MISMATCH_IN_CONNECT =
432            new SimpleErrorProducer("TYPE_MISMATCH_IN_CONNECT", ProblemKind.SEMANTIC,
433                    "Types of connected components do not match");
434    public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_CONNECT =
435            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_CONNECT", ProblemKind.SEMANTIC,
436                    "Sizes do not match in connection, size of '%s' is %s and size of '%s' is %s");
437    public static final ErrorProducerUnlessDisabled ASTNode.EXPANDABLE_ARRAY_SIZE_MISMATCH_IN_CONNECT =
438            new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_CONNECT", ProblemKind.SEMANTIC,
439                    "Sizes do not match in connection, size of the part of '%s' referring to " + 
440                    "the expandable connector is %s and size of '%s' is %s");
441
442    public void FConnectClause.typeCheck(ErrorCheckType checkType) {
443        InstAccess left  = getConnector1();
444        InstAccess right = getConnector2();
445        boolean checkTypes = !isDisabled();
446        boolean isExpandable = false;
447        boolean expandableSame = true;
448        for (InstAccess access = left; access != null; access = (access == left) ? right : null) {
449            if (access.isExpandableConnectorPart()) {
450                isExpandable = true;
451            } else if (!access.isUnknown() && !access.myInstComponentDecl().myInstClass().isUnknown()) {
452                if (!access.myInstComponentDecl().isConnector())
453                    CONNECT_WITH_INVALID_TYPE.invoke(access);
454            } else {
455                checkTypes = false;
456            }
457            if (access.myInstComponentDecl().isExpandableConnector()) {
458                expandableSame = !expandableSame;
459            }
460        }
461        if (!expandableSame && !left.isUnknown() && !right.isUnknown()) {
462            CONNECT_EXPANDABLE_AND_NON_EXPANDABLE_TYPE.invoke(this);
463        }
464        if (checkTypes) { 
465            if (isExpandable) {
466                boolean leftUnknown = left.isExpandableConnectorPart();
467                InstAccess known   = leftUnknown ? right : left;
468                InstAccess unknown = leftUnknown ? left  : right;
469                Size knownSize   = known.size();
470                Size unknownSize = unknown.findExpandableConnectorPart().partSize();
471                if (knownSize.ndims() < unknownSize.ndims() || 
472                        !unknownSize.equivalent(knownSize.contractRight(unknownSize.ndims()), false)) {
473                    EXPANDABLE_ARRAY_SIZE_MISMATCH_IN_CONNECT.invoke(
474                            this, unknown, unknownSize, known, knownSize);
475                }
476            } else {
477                InstComponentDecl leftComp  = left.lookupEvaluatingIndices();
478                InstComponentDecl rightComp = right.lookupEvaluatingIndices();
479                if (!leftComp.connectableTo(rightComp)) {
480                    TYPE_MISMATCH_IN_CONNECT.invoke(this);
481                } else if (!left.size().equivalent(right.size(), false)) {
482                    ARRAY_SIZE_MISMATCH_IN_CONNECT.invokeWithCondition(this, left.ndims() == right.ndims(), 
483                            left, left.size(), right, right.size());
484                }
485            }
486        }
487    }
488
489    // Generic typeCheck(checkType) that calls typeError() if type is unknown and no FExp child has unknown type
490    public void FExp.typeCheck(ErrorCheckType checkType) {
491        if (generateTypeError()) {
492            for (FExp exp : childFExps())
493                if (exp.type().isUnknown())
494                    return;
495            typeError(checkType);
496        } else {
497            size().markAsStructuralParameter(checkType, this);
498        }
499    }
500
501    syn boolean FExp.generateTypeError() = type().isUnknown();
502    eq FEqRelExp.generateTypeError()     = super.generateTypeError() ||
503            (getLeft().type().isReal() || getRight().type().isReal()) && !inFunction();
504
505    public void InstIfExp.typeCheck(ErrorCheckType checkType) {
506        if (!generateTypeError()) {
507            if (!getThenExp().type().equivalentTo(getElseExp().type())) {
508                getIfExp().markAsStructuralParameter(checkType);
509            }
510        }
511        super.typeCheck(checkType);
512    }
513
514    public void Size.markAsStructuralParameter(ErrorCheckType checkType, FExp src) {}
515   
516    public void MutableSize.markAsStructuralParameter(ErrorCheckType checkType, FExp src) {
517        if (src.errorCheckUnknownSize()) {
518            for (int i = 0; i < ndims(); i++) {
519                FExp exp = exps[i];
520                if (exp != null) {
521                    exp.markAsStructuralParameter(checkType);
522                    if (!exp.variability().parameterOrLess()) {
523                        ASTNode.NON_PARAMETER_SIZE_IN_EXPRESSION.invoke(src, exp, i, src);
524                    }
525                }
526            }
527        }
528    }
529   
530    syn boolean FExp.errorCheckUnknownSize() = !inFunction() && !allowUnknownSize();
531
532    syn boolean BaseNode.allowUnknownSize()    = false;
533    eq InstFunctionArgument.allowUnknownSize() = inAllowUnknownSize();
534    eq FIfExp.allowUnknownSize()               = inAllowUnknownSize();
535    eq InstFunctionCall.allowUnknownSize()     = inAllowUnknownSize() && callsExternal();
536    eq FFunctionCall.allowUnknownSize()        = inAllowUnknownSize() && callsExternal();
537
538    inh boolean BaseNode.inAllowUnknownSize();
539    eq BaseNode.getChild().inAllowUnknownSize()         = allowUnknownSize();
540    eq InstFunctionCall.getChild().inAllowUnknownSize() = allowUnknownSize() || callsExternal();
541    eq FFunctionCall.getChild().inAllowUnknownSize()    = allowUnknownSize() || callsExternal();
542
543    class FFunctionDecl {
544        public enum FunctionType {
545            EXTERNAL, LOADRESOURCE;
546           
547            public boolean containsFunction(CommonCallable cc) {
548                if (this == EXTERNAL) {
549                    return cc.isExternalFunction();
550                } else {
551                    return cc.containsFunction(this);
552                }
553            }
554        }
555    }
556
557    interface CommonCallable {
558        public boolean containsFunction(FFunctionDecl.FunctionType ft);
559        public boolean isExternalFunction();
560    }
561
562    syn boolean InstPartialFunction.isExternalFunction() = false;
563    syn boolean FFunctionVariable.isExternalFunction()   = false;
564
565    syn boolean InstClassDecl.isExternalFunction() = findFunctionExternal() != null;
566    syn boolean FFunctionDecl.isExternalFunction() = getFirstExternalStmt() != null;
567
568    syn FExternalStmt FFunctionDecl.getFirstExternalStmt() {
569        for (FStatement stmt : getFAlgorithm().getFStatements()) {
570            if (stmt.isExternalStatement()) {
571                return (FExternalStmt) stmt;
572            }
573        }
574        return null;
575    }
576
577    syn boolean FStatement.isExternalStatement() = false;
578    eq FExternalStmt.isExternalStatement()       = true;
579
580    syn boolean FAbstractFunctionCall.callsExternal() =
581            FFunctionDecl.FunctionType.EXTERNAL.containsFunction(myCommonCallable());
582    syn boolean FAbstractFunctionCall.callsLoadResource() =
583            FFunctionDecl.FunctionType.LOADRESOURCE.containsFunction(myCommonCallable());
584   
585    syn boolean ASTNode.containsFunction(FFunctionDecl.FunctionType ft) {
586        for (ASTNode n : this) {
587            if (n.containsFunction(ft)) {
588                return true;
589            }
590        }
591        return false;
592    }
593
594    @Override
595    syn boolean InstNode.containsFunction(FFunctionDecl.FunctionType ft) =
596        getInstComponentDecls().containsFunction(ft) || getInstExtendss().containsFunction(ft) ||
597        getFAbstractEquations().containsFunction(ft) || super.containsFunction(ft);
598
599    eq InstComponentDecl.containsFunction(FFunctionDecl.FunctionType ft) =
600        (hasInstModification() && getInstModification().containsFunction(ft)) ||  super.containsFunction(ft);
601    eq InstValueModification.containsFunction(FFunctionDecl.FunctionType ft) =
602        getFExp().containsFunction(ft) ||  super.containsFunction(ft);
603    eq InstFunctionCall.containsFunction(FFunctionDecl.FunctionType ft) =
604        ft.containsFunction(myCommonCallable()) || super.containsFunction(ft);
605    eq FFunctionCall.containsFunction(FFunctionDecl.FunctionType ft) =
606        ft.containsFunction(myCommonCallable()) || super.containsFunction(ft);
607    eq FLoadResource.containsFunction(FFunctionDecl.FunctionType ft) =
608        ft == FFunctionDecl.FunctionType.LOADRESOURCE || super.containsFunction(ft);
609
610    syn lazy boolean InstClassDecl.containsFunction(FFunctionDecl.FunctionType ft) circular [false] =
611            super.containsFunction(ft);
612    eq InstSimpleShortClassDecl.containsFunction(FFunctionDecl.FunctionType ft) =
613            actualInstClass().containsFunction(ft);
614
615    public static final ErrorProducerUnlessDisabled ASTNode.NON_PARAMETER_SIZE_IN_EXPRESSION =
616            new ErrorProducerUnlessDisabled("NON_PARAMETER_SIZE_IN_EXPRESSION", ProblemKind.COMPLIANCE,
617                    "Non-parameter expression sizes not supported, '%s', dimension %d in '%s'");
618   
619    @Override
620    public void FLoadResource.typeCheck(ErrorCheckType checkType) {
621        super.complianceCheck(checkType);
622        getFExp().forceVariability(checkType, Variability.LOADRESOURCEPARAMETER);
623    }
624   
625    public class FExp {
626        public static class ExpTypeErrorProducer extends AbstractErrorProducerUnlessDisabled<ReporterNode> {
627            private final String message;
628           
629            public ExpTypeErrorProducer(String identifier, String message) {
630                super(identifier, ProblemKind.SEMANTIC);
631                this.message = message;
632            }
633
634            public void invoke(FExp node) {
635                StringBuilder buf = new StringBuilder(message);
636                buf.append(": ");
637                buf.append(node);
638                for (FExp exp : node.childFExps()) {
639                    buf.append("\n    type of '");
640                    buf.append(exp);
641                    buf.append("' is ");
642                    buf.append(exp.type());
643                }
644                super.invokeWithCondition(node, node.typeErrorOnlyLengths(), buf.toString());
645            }
646
647            @Override
648            public String description() {
649                return message;
650            }
651           
652        }
653    }
654   
655    public static final FExp.ExpTypeErrorProducer ASTNode.TYPE_MISMATCH_IN_EXPRESSION =
656            new FExp.ExpTypeErrorProducer("TYPE_MISMATCH_IN_EXPRESSION", "Type error in expression");
657
658    public void FExp.typeError(ErrorCheckType checkType) {
659        TYPE_MISMATCH_IN_EXPRESSION.invoke(this);
660    }
661
662    /**
663     * Check if type error is only in array lengths.
664     */
665    syn boolean FExp.typeErrorOnlyLengths() = typeErrorOnlyLengths(childFExps());
666    eq FAbstractCat.typeErrorOnlyLengths()  = typeErrorOnlyLengths(getFExps());
667
668    /**
669     * Check if type error is only in array lengths.
670     */
671    syn boolean FExp.typeErrorOnlyLengths(Iterable<FExp> exps) {
672        FType first = null;
673        for (FExp exp : exps) {
674            FType cur = exp.type();
675            if (first == null) {
676                first = cur;
677            } else if (!first.equivalentExceptLengths(cur)) {
678                return false;
679            }
680        }
681        return true;
682    }
683
684    /**
685     * The message to use in default type error.
686     */
687    public static final FExp.ExpTypeErrorProducer ASTNode.EQUALITY_COMPARISON_OF_REAL =
688            new FExp.ExpTypeErrorProducer("EQUALITY_COMPARISON_OF_REALS", "Equality comparisons do not allow real operands");
689
690    @Override
691    public void FEqRelExp.typeError(ErrorCheckType checkType) {
692        if ((getLeft().type().isRealScalar() || getRight().type().isRealScalar()) && !inFunction()) {
693            EQUALITY_COMPARISON_OF_REAL.invoke(this);
694        } else {
695            super.typeError(checkType);
696        }
697    }
698   
699    public void FLinspace.typeCheck(ErrorCheckType checkType) {
700        getN().markAsStructuralParameter(checkType);
701        super.typeCheck(checkType);
702    }
703
704    public void FLinspace.typeError(ErrorCheckType checkType) {
705        boolean badVar = !getN().variability().fixedParameterOrLess();
706        boolean canCeval = getN().canCeval();
707        boolean badVal = canCeval && getN().ceval().intValue() < 2;
708        if (badVar || !canCeval || badVal) {
709            String msg = "Third argument of linspace() must be a scalar parameter Integer expression that is greater than 1";
710            if (badVar)
711                error("%s\n    '%s' is of %s variability", msg, getN(), getN().variability().toStringLiteral());
712            else if (canCeval && !lockBranch(checkType))
713                errorUnlessDisabled("%s\n    '%s' evaluates to %d", msg, getN(), getN().ceval().intValue());
714        } else {
715            super.typeError(checkType);
716        }
717    }
718
719    public void FIdentity.typeCheck(ErrorCheckType checkType) {
720        getFExp().markAsStructuralParameter(checkType);
721        super.typeCheck(checkType);
722    }
723
724    public void FIdentity.typeError(ErrorCheckType checkType) {
725        if (!getFExp().variability().parameterOrLess()) 
726            error("Argument of identity() must be a scalar parameter Integer expression\n    '%s' is of %s variability", 
727                    getFExp(), getFExp().variability().toStringLiteral());
728        else 
729            super.typeError(checkType);
730    }
731
732    public void FSizeExp.typeCheck(ErrorCheckType checkType) {
733        if (hasDim())
734            getDim().markAsStructuralParameter(checkType);
735        super.typeCheck(checkType);
736    }
737
738    public void FSizeExp.typeError(ErrorCheckType checkType) {
739        if (hasDim()) {
740            if (!getDim().type().isIntegerScalar())
741                return;  // Error is reported for argument in this case
742            boolean badVar = !getDim().variability().parameterOrLess();
743            boolean canCeval = getDim().canCeval();
744            int dimVal = canCeval ? getDim().ceval().intValue() : 1;
745            int ndims = getFExp().ndims();
746            if (badVar || !canCeval || dimVal < 1 || dimVal > ndims) {
747                String msg = "Second argument of size() must be a scalar parameter Integer expression that evaluates to a valid dimension of the first argument";
748                if (badVar)
749                    error("%s\n    '%s' is of %s variability", msg, getDim(), getDim().variability().toStringLiteral());
750                else if (canCeval)
751                    error("%s\n    '%s' evaluates to %d, and '%s' has %d dimensions", msg, getDim(), dimVal, getFExp(), ndims);
752                return;
753            }
754        }
755        super.typeError(checkType);
756    }
757
758    public void CommonAccess.typeError(ErrorCheckType checkType, CommonAccessExp access) {
759        access.typeError(checkType);
760    }
761
762    public void InstAccess.typeError(ErrorCheckType checkType, CommonAccessExp access) {
763        typeError();
764    }
765
766  public void InstAccess.typeError() {
767          typeError(this);
768  }
769 
770  protected void InstAccess.typeError(InstAccess top) {}
771 
772  protected void InstDot.typeError(InstAccess top) {
773          getLastInstAccess().typeError(top);
774  }
775 
776  protected void InstGlobalAccess.typeError(InstAccess top) {
777          getInstAccess().typeError(top);
778  }
779 
780    protected void InstComponentAccess.typeError(InstAccess top) {
781        InstComponentDecl icd = myInstComponentDecl();
782        if (!icd.isUnknown() && !icd.myInstClass().isUnknown() && !inCardinality()) {
783            if (!icd.isPrimitive() && !icd.isRecord()) {
784                top.error("Accesses to composite components other than records are not allowed: " + top.name());
785            }
786        }
787    }
788 
789    protected void InstComponentArrayAccess.typeError(InstAccess top) {
790        InstComponentDecl icd = myInstComponentDecl();
791        if (!icd.isUnknown() && !icd.myInstClass().isUnknown() && !inCardinality()) {
792            if (!icd.isPrimitive() && !icd.isRecord()) {
793                top.error("Accesses to composite components other than records are not allowed: " + top.name());
794            }
795        }
796    }
797 
798  inh boolean InstAccess.inCardinality();
799  eq FCardinality.getChild().inCardinality() = true;
800  eq InstNode.getChild().inCardinality()     = false;
801  eq Root.getChild().inCardinality()         = false;
802 
803  protected void InstClassAccess.typeError(InstAccess top) {
804          if (!isComponentSizeClass() || !isInstComponentSize())
805                  top.error("Illegal access to class in expression: " + top.name());
806  }
807
808    public void InstIfExp.typeError(ErrorCheckType checkType) {
809        FType thenType = getThenExp().type();
810        FType elseType = getElseExp().type();
811        FType scalar = thenType.scalarType().typePromotion(elseType.scalarType());
812       
813        if (!getIfExp().isOKTestExp()) {
814            getIfExp().error("Test expression of if expression must be scalar boolean:\n    %s is %s", 
815                    getIfExp(), getIfExp().type());
816        } else if (thenType.ndims() != elseType.ndims()) { 
817            error("Branches of if expression have different number of array dimensions:" + 
818                    "\n    %s has size %s\n    %s has size %s", 
819                getThenExp(), thenType.size(), getElseExp(), elseType.size());
820        } else if (scalar.isUnknown()) { 
821            error("Branches of if expression have incompatible types:\n    %s is %s\n    %s is %s", 
822                    getThenExp(), thenType, getElseExp(), elseType);
823        } else {
824            if (isParameterIf())
825                error("Failed to evaluate test expression in if expression with branches that have different array sizes:" + 
826                        "\n    %s has size %s\n    %s has size %s", 
827                    getThenExp(), thenType.size(), getElseExp(), elseType.size());
828            else
829                error("If expression with branches that have different array sizes must have parameter test expression:" + 
830                        "\n    %s has size %s\n    %s has size %s", 
831                    getThenExp(), thenType.size(), getElseExp(), elseType.size());
832        }
833    }
834
835  public void CommonAccessExp.typeCheck(ErrorCheckType checkType) {
836          if (!getAccess().isUnknown() && type().isUnknown() && !accessToModelOK())
837            getAccess().typeError(checkType, this);
838  }
839 
840        public void CommonAccess.typeCheck(ErrorCheckType checkType) {
841        if (inAlgorithm() && useIsAssignment()) {
842            if (variability().constantVariability()) {
843                error("Assignments to constants is not allowed in algorithms");
844            } else if (variability().parameterVariability()) {
845                if (isForIndex()) {
846                    error("Can not assign a value to a for loop index");
847                } else if (!(myFAlgorithm().getType().isInitial())) {
848                    error("Assignments to parameters in algorithms is only allowed in initial algorithms");
849                }
850            }
851        }
852        }
853
854  inh boolean CommonAccessExp.accessToModelOK();
855  inh boolean InstFunctionArgument.accessToModelOK();
856  eq BaseNode.getChild().accessToModelOK()             = false;
857  eq InstFunctionArgument.getChild().accessToModelOK() = accessToModelOK();
858  eq FSizeExp.getFExp().accessToModelOK()              = true;
859  eq FSizeExp.getOriginalArg(int i).accessToModelOK()  = i == 0;
860 
861 
862  /**
863   * Check if the FExp of this FIterExp must be scalar.
864   */
865  inh boolean FIterExp.iterExpMustBeScalar();
866  eq FExp.getChild().iterExpMustBeScalar()       = false;
867  eq Root.getChild().iterExpMustBeScalar()       = false;
868  eq InstNode.getChild().iterExpMustBeScalar()   = false;
869  eq FMinMaxExp.getChild().iterExpMustBeScalar() = true;
870  // TODO: Add product() when it is implemented
871
872    public void FMulExp.typeCheck(ErrorCheckType checkType) {
873        if (type().isOperatorRecord() && !isElementWise()) {
874            int left = getLeft().size().get(1);
875            int inner = (left == Size.UNKNOWN) ? getRight().size().get(0) : left;
876            if ((inner == 0 || inner == Size.UNKNOWN) && type().matchOverloadedZero() == null) 
877                error("Matrix multiplication of operator records with an inner dimension of 0 or : requires that an '0' operator is defined");
878        }
879        super.typeCheck(checkType);
880    }
881
882  public void FIterExp.typeCheck(ErrorCheckType checkType) {
883          super.typeCheck(checkType);
884          if (iterExpMustBeScalar() && !getFExp().type().isUnknown() && getFExp().ndims() != 0)
885                  error("The expression of a reduction-expression must be scalar, except for sum(): " +
886                                  getFExp() + " has " + getFExp().ndims() + " dimension(s)");
887  }
888 
889  public void FStreamBuiltIn.typeCheck(ErrorCheckType checkType) {
890          if (!getFExp().isAccessToStream()) 
891                  error("Argument of " + builtInName() + "() must be a stream variable");
892  }
893 
894  /**
895   * Returns true if this expression can be interpreted as some form of Access
896   */
897  syn boolean FExp.isAccessLikeExp() = false;
898  eq CommonAccessExp.isAccessLikeExp() = true;
899 
900  syn boolean FExp.isAccess()  = false;
901  eq CommonAccessExp.isAccess()= true;
902  syn CommonAccess FExp.asCommonAccess() {
903          throw new UnsupportedOperationException("asCommonAccess() is not supported for class type " + getClass().getSimpleName());
904  }
905  eq CommonAccessExp.asCommonAccess() = getAccess();
906 
907  syn CommonAccessExp FExp.asCommonAccessExp() {
908      throw new UnsupportedOperationException("asCommonAccessExp() is not supported for class type " + getClass().getSimpleName());
909  }
910  eq CommonAccessExp.asCommonAccessExp() = this;
911 
912  syn FAccessExp FExp.asFAccessExp() {
913      throw new UnsupportedOperationException("asFAccessExp() is not supported for class type " + getClass().getSimpleName());
914  }
915  eq FAccessExp.asFAccessExp() = this;
916 
917    syn boolean CommonAccess.isInstAccess() = false;
918    eq InstAccess.isInstAccess() = true;
919    syn boolean CommonAccess.isFAccess() = false;
920    eq FAccess.isFAccess() = true;
921   
922        syn InstAccess FExp.asInstAccess() {
923                throw new UnsupportedOperationException();
924        }
925    eq InstAccessExp.asInstAccess() = getInstAccess();
926   
927    syn InstAccess CommonAccess.asInstAccess() {
928        throw new UnsupportedOperationException();
929    }
930    eq InstAccess.asInstAccess() = this;
931   
932  syn boolean FExp.isAccessToStream()  = false;
933  eq CommonAccessExp.isAccessToStream()= getAccess().isAccessToStream();
934 
935  syn boolean CommonAccess.isAccessToStream() = false;
936  eq InstAccess.isAccessToStream()      = myInstComponentDecl().isStream();
937
938
939
940    public void InstForIndexWithExp.typeCheck(ErrorCheckType checkType) {
941        if (!getFExp().type().isUnknown() && getFExp().ndims() != 1)
942            error("The expression of for index " + name() + " must be a vector expression: " + 
943                    getFExp() + " has " + getFExp().ndims() + " dimension(s)");
944    }
945
946    public void InstForIndexNoExp.typeCheck(ErrorCheckType checkType) {
947        hasFExp(); // Force eval of NTA, thus checking if a consistent range can be computed
948    }
949
950    public static final SimpleErrorProducer InstForIndexNoExp.IMPLICIT_FOR_RANGE_NON_INTEGER =
951            new SimpleErrorProducer("IMPLICIT_FOR_RANGE_NON_INTEGER", ProblemKind.COMPLIANCE, 
952                    "Non-integer for iteration range not supported");
953
954    public static final SimpleErrorProducer InstForIndexNoExp.IMPLICIT_FOR_RANGE_INCONSISTENT =
955            new SimpleErrorProducer("IMPLICIT_FOR_RANGE_INCONSISTENT", ProblemKind.SEMANTIC, 
956                    "For index with implicit iteration range used for inconsistent sizes, here used for size %s and earlier for size %s");
957
958    public static final SimpleErrorProducer InstForIndexNoExp.IMPLICIT_FOR_RANGE_NOT_USED =
959            new SimpleErrorProducer("IMPLICIT_FOR_RANGE_NOT_USED", ProblemKind.SEMANTIC, 
960                    "For index with implicit iteration range must be used as array index");
961
962    // TODO: handle other index types than integer (see #3597)
963    syn lazy Opt<FExp> InstForIndexNoExp.getFExpOpt() {
964        Size size = null;
965        for (FExpSubscript use : mySubscriptUses()) {
966            Size useSize = use.mySize();
967            if (!use.myIndexType().isInteger()) {
968                IMPLICIT_FOR_RANGE_NON_INTEGER.invoke(use);
969            }
970            if (size == null) {
971                size = useSize;
972            } else if (!size.equivalent(useSize, true)) {
973                IMPLICIT_FOR_RANGE_INCONSISTENT.invoke(use, useSize, size);
974            }
975        }
976        if (size == null) {
977            IMPLICIT_FOR_RANGE_NOT_USED.invoke(this);
978            return new Opt();
979        } else {
980            return new Opt(size.createRangeExp(0));
981        }
982    }
983
984    syn lazy Collection<FExpSubscript> InstForIndexNoExp.mySubscriptUses() = mySubscriptUses(name());
985
986    inh Collection<FExpSubscript> InstForIndexNoExp.mySubscriptUses(String name);
987    eq InstForClauseE.getInstForIndex(int i).mySubscriptUses(String name) = collectSubscriptUses(name);
988    eq InstForStmt.getInstForIndex(int i).mySubscriptUses(String name)    = collectSubscriptUses(name);
989    eq FIterExp.getForIndex(int i).mySubscriptUses(String name)           = collectSubscriptUses(name);
990
991    public Collection<FExpSubscript> ASTNode.collectSubscriptUses(String name) {
992        Collection<FExpSubscript> nodes = new ArrayList<FExpSubscript>();
993        collectSubscriptUses(name, nodes);
994        return nodes;
995    }
996
997    public void ASTNode.collectSubscriptUses(String name, Collection<FExpSubscript> nodes) {
998        for (ASTNode n : this) {
999            n.collectSubscriptUses(name, nodes);
1000        }
1001    }
1002
1003    public void FExpSubscript.collectSubscriptUses(String name, Collection<FExpSubscript> nodes) {
1004        if (getFExp().isIdentifier(name)) {
1005            nodes.add(this);
1006        }
1007        super.collectSubscriptUses(name, nodes);
1008    }
1009
1010    public void FSubscript.typeCheckAsSize(ErrorCheckType checkType) {
1011        if (ndims() > 0) { 
1012            error("Array size must be scalar expression: " + toString());
1013        } else if (!type().isUnknown() && !canBeComponentSize()) {
1014            error("Array size must be Integer expression, Boolean type or enumeration type: " + toString());
1015        } else if (!inFunction()) { 
1016            if (!variability().parameterOrLess()) {
1017                error("Array size must be constant or parameter: " + toString());
1018            } else if (!checkType.allowIncompleteSizes()) {
1019                boolean ok = false;
1020                try {
1021                    ok = ceval().hasIntValue();
1022                } catch (ConstantEvaluationException e) {}
1023                if (!ok) {
1024                    error("Could not evaluate array size expression: " + toString());
1025                }
1026            }
1027        }
1028    }
1029
1030    public void FSubscript.typeCheckAsIndex(ErrorCheckType checkType) {
1031        if (ndims() > 1) { 
1032            error("Array index must be scalar or vector expression: " + toString());
1033        } else if (!type().isUnknown() && !type().canBeIndex()) {
1034            error("Array index must be Integer, Boolean, or enumeration expression: " + toString());
1035        } else if (!type().isUnknown() && !myIndexType().isUnknown() && !type().scalarType().typeCompatible(myIndexType())) {
1036            error("Expected array index of type '%s' found '%s'", myIndexType().name(), type().scalarType().name());
1037        } else if (!inFunction()) { 
1038            if (!variability().fixedParameterOrLess()) {
1039                warning("Variable array index in equation can result in slow simulation time");
1040            } else if (!inUnknownAccess() && !mySize().isUnknown()) {
1041                typeCheckOutOfBounds(checkType);
1042            }
1043        }
1044    }
1045
1046    public void FSubscript.typeCheckOutOfBounds(ErrorCheckType checkType) {}
1047    public void FExpSubscript.typeCheckOutOfBounds(ErrorCheckType checkType) {
1048        if (!reportedOutOfBound) {
1049            // Check array bounds
1050            // TODO: Perform bounds check in functions if index has parameter variability or lower?
1051            try {
1052                int max = mySize().get(0);
1053                for (FExp e : getFExp().getArray().iterable()) {
1054                    CValue cval = e.ceval();
1055                    if (cval.hasIntValue()) {
1056                        int i = cval.intValue();
1057                        if (i < 1 || i > max) {
1058                            if (!lockBranch(checkType)) {
1059                                errorUnlessDisabled("Array index out of bounds: " + i + 
1060                                                    ", index expression: " + getFExp());
1061                            }
1062                            reportedOutOfBound = true;
1063                            return;
1064                        }
1065                    }
1066                }
1067            } catch (ConstantEvaluationException e) {
1068            }
1069        }
1070    }
1071    public void FIntegerSubscript.typeCheckOutOfBounds(ErrorCheckType checkType) {
1072        int max = mySize().get(0);
1073        int i = getValue();
1074        if ((i < 1 || i > max) && !lockBranch(checkType)) {
1075            errorUnlessDisabled("Array index out of bounds: " + i +
1076                                ", index expression: " + i);
1077        }
1078    }
1079
1080  syn FType FSubscript.myIndexType() = myIndexType(myDim());
1081  inh FType FSubscript.myIndexType(int i);
1082  eq Root.getChild().myIndexType(int i)                                = fUnknownType();
1083  eq InstArrayAccess.getFArraySubscripts().myIndexType(int i)          = fUnknownType();
1084  eq InstComponentArrayAccess.getFArraySubscripts().myIndexType(int i) = myInstComponentDecl().myIndexType(i);
1085 
1086  syn FType InstComponentDecl.myIndexType(int dim) {
1087    FArraySubscripts fas = getFArraySubscripts();
1088    if (fas != null && fas.ndims() > dim)
1089        return fas.subscript(dim).type().scalarType();
1090    else
1091        return fUnknownType();
1092  }
1093 
1094  private boolean FExpSubscript.reportedOutOfBound = false;
1095 
1096 
1097  public void FSubscript.typeCheck(ErrorCheckType checkType) {
1098          if (isInstComponentSize()) 
1099                  typeCheckAsSize(checkType);
1100          else 
1101                  typeCheckAsIndex(checkType);
1102  }
1103  public void FColonSubscript.typeCheck(ErrorCheckType checkType) {}
1104 
1105  inh boolean FSubscript.inUnknownAccess();
1106  eq FAccess.getChild().inUnknownAccess()                  = myFV().isUnknown();
1107  eq InstScalarAccess.getChild().inUnknownAccess()        = myInstComponentDecl().isUnknown();
1108  eq InstArrayAccess.getChild().inUnknownAccess()         = myInstComponentDecl().isUnknown();
1109  eq FlatRoot.getChild().inUnknownAccess()                = false;
1110  eq InstRoot.getChild().inUnknownAccess()                = false;
1111 
1112  syn boolean FExp.canBeComponentSize()  = type().isInteger();
1113  eq CommonAccessExp.canBeComponentSize()= type().isInteger() || getAccess().isComponentSizeClass();
1114 
1115  syn boolean FSubscript.canBeComponentSize() = true;
1116  eq FExpSubscript.canBeComponentSize() = getFExp().canBeComponentSize();
1117 
1118  syn boolean CommonAccess.isComponentSizeClass() = false;
1119  eq InstAccess.isComponentSizeClass()      = myInstClassDecl().isComponentSizeClass();
1120 
1121  syn boolean InstClassDecl.isComponentSizeClass() = isBoolean();
1122  eq InstEnumClassDecl.isComponentSizeClass()      = true;
1123 
1124  inh boolean InstClassAccess.isInstComponentSize();
1125    inh boolean CommonAccessExp.isInstComponentSize();
1126  inh boolean FSubscript.isInstComponentSize();
1127  inh boolean FArraySubscripts.isInstComponentSize();
1128  eq InstComponentDecl.getLocalFArraySubscripts().isInstComponentSize() = true;
1129  eq InstComponentDecl.getFArraySubscripts().isInstComponentSize()      = true;
1130  eq InstShortClassDecl.getFArraySubscripts().isInstComponentSize()     = true;
1131  eq InstAccess.getChild().isInstComponentSize()                        = false;
1132  eq FAccessPart.getChild().isInstComponentSize()                       = false;
1133  eq CommonAccess.getChild().isInstComponentSize()                      = false;
1134  eq FExp.getChild().isInstComponentSize()                              = false;
1135    eq CommonAccessExp.getChild().isInstComponentSize()                 = isInstComponentSize();
1136  eq FAbstractVariable.getChild().isInstComponentSize()                 = false;
1137  eq FAbstractEquation.getChild().isInstComponentSize()                 = false;
1138  eq InstNode.getChild().isInstComponentSize()                          = false;
1139  eq FlatRoot.getChild().isInstComponentSize()                          = false;
1140       
1141  syn boolean FArraySubscripts.isFullSize() = false;
1142  eq FArrayExpSubscripts.isFullSize() {
1143      for (FSubscript fs : getFSubscripts())
1144          if (!fs.isColon())
1145              return false;
1146      return true;
1147  }
1148
1149  public void FAssignStmt.typeCheck(ErrorCheckType checkType) {
1150      FType left = getLeft().type();
1151      FType right = getRight().type();
1152      if (!left.isUnknown() && !right.isUnknown()) {
1153          if (!left.typeCompatible(right, true)) {
1154              if (left.typeCompatibleExceptLengths(right)) {
1155                  // TODO: should use lockBranch() here as well, but no support yet
1156                  errorUnlessDisabled("The array sizes of right and left hand side of assignment are not compatible, " + 
1157                          "size of left-hand side is %s, and size of right-hand side is %s", left.size(), right.size());
1158              } else {
1159                  error("The right and left expression types of assignment are not compatible, " + 
1160                          "type of left-hand side is %s, and type of right-hand side is %s", left, right);
1161              }
1162          }
1163      }
1164  }
1165
1166  public void FWhileStmt.typeCheck(ErrorCheckType checkType) {
1167          if (!getTest().type().isUnknown() && !fBooleanScalarType().typeCompatible(getTest().type())) 
1168                  error("Type of test expression of while statement is not Boolean");
1169  }
1170 
1171  public void FIfClause.typeCheck(ErrorCheckType checkType) {
1172          if (!getTest().type().isUnknown() && !fBooleanScalarType().typeCompatible(getTest().type())) 
1173                  error("Type of test expression of if statement is not Boolean");
1174  }
1175 
1176  public void FWhenClause.typeCheck(ErrorCheckType checkType) {
1177          if (!getTest().type().isUnknown()) {
1178                  if (!getTest().type().isBoolean() || getTest().type().ndims() > 1) 
1179                          error("Test expression of when statement isn't Boolean scalar or vector expression");
1180          }
1181  }
1182 
1183  public void FIfEquation.typeCheck(ErrorCheckType checkType) {
1184          if (!getTest().type().isUnknown() && !fBooleanScalarType().typeCompatible(getTest().type())) 
1185                  error("Type of test expression of if equation is not Boolean");
1186  }
1187 
1188  public void FWhenEquation.typeCheck(ErrorCheckType checkType) {
1189          if (!getTest().type().isUnknown()) {
1190                  if (!getTest().type().isBoolean() || getTest().type().ndims() > 1) 
1191                          error("Test expression of when equation isn't Boolean scalar or vector expression");
1192          }
1193  }
1194
1195
1196    public void FInfArgsFunctionCall.typeCheck(ErrorCheckType checkType) {
1197        super.typeCheck(checkType);
1198        if (numArgs() < minNumArgs()) 
1199            error("Too few arguments to " + builtInName() + "(), must have at least " + minNumArgs());
1200        else 
1201            typeCheckFExps();
1202    }
1203
1204  public void FInfArgsFunctionCall.typeCheckFExps() {
1205      for (FExp exp : getFExps()) {
1206          if (!exp.type().isUnknown() && !typeOfArgIsOK(exp)) {
1207              exp.error("Argument of " + builtInName() + "() is not " + 
1208                          getOKArgTypeString() + ": " + exp);
1209          } else if (!variabilityOfArgIsOK(exp)) {
1210                  exp.error("Argument of " + builtInName() + "() does not have " + 
1211                                  getOKArgVariabilityString() + " variability: " + exp);
1212          }
1213      }
1214  }
1215 
1216  public void FCatExp.typeCheckFExps() {
1217          if (!getDim().type().isUnknown() && !fIntegerScalarType().typeCompatible(getDim().type()))
1218                  error("Dimension argument of cat() is not compatible with Integer: " + getDim());
1219          else if (!getDim().type().isUnknown() && !getDim().variability().parameterOrLess())
1220                  error("Dimension argument of cat() does not have constant variability: " + getDim());
1221  }
1222
1223    public void FAbstractCat.typeCheckFExps() {}
1224
1225    public void FAbstractCat.typeError(ErrorCheckType checkType) {
1226        errorUnlessDisabledAnd(typeErrorOnlyLengths(), "Types do not match in array concatenation");
1227    }
1228
1229    syn int FInfArgsFunctionCall.minNumArgs() = 1;
1230    eq FFillExp.minNumArgs()                  = 2;
1231    eq FCatExp.minNumArgs()                   = 2;
1232    eq FAbstractCat.minNumArgs()              = 0;
1233
1234    syn int FInfArgsFunctionCall.numArgs() = getNumFExp();
1235    eq FFillExp.numArgs()                  = getNumFExp() + 1;
1236    eq FCatExp.numArgs()                   = getNumFExp() + 1;
1237
1238  syn boolean FInfArgsFunctionCall.typeOfArgIsOK(FExp exp)        = 
1239                  fIntegerScalarType().typeCompatible(exp.type());
1240  syn boolean FInfArgsFunctionCall.variabilityOfArgIsOK(FExp exp) = 
1241                  exp.variability().parameterOrLess() || inFunction();
1242  syn String FInfArgsFunctionCall.getOKArgTypeString()            = 
1243                  "compatible with Integer";
1244  syn String FInfArgsFunctionCall.getOKArgVariabilityString()     = 
1245                  "constant or parameter";
1246
1247    public void FBuiltInFunctionCall.typeCheck(ErrorCheckType checkType) {
1248        if (checkTypeAsExpression()) {
1249            super.typeCheck(checkType);
1250        } else if (!inFunction()) {
1251            size().markAsStructuralParameter(checkType, this);
1252        }
1253        int n = builtInNumOutput();
1254        if (myLefts().size() > n)
1255            error("Too many components assigned from function call: " + builtInName() + 
1256                    "() has " + n + " output(s)");
1257        else if (!isFunctionCallClause() && n == 0)
1258            error("Function " + builtInName() + "() has no outputs, but is used in expression");
1259    }
1260
1261    public void FSemiLinearExp.typeCheck(ErrorCheckType checkType) {
1262        checkVectorizedSizes(checkType);
1263        super.typeCheck(checkType);
1264    }
1265
1266    public void FBuiltInFunctionCall.checkVectorizedSizes(ErrorCheckType checkType) {
1267        if (isArray()) {
1268            boolean error = false;
1269            boolean onlyLengths = true;
1270            Size s = size();
1271            for (FExp arg : myArgs()) {
1272                if (arg.isArray() && !arg.size().equivalent(s, false)) {
1273                    error = true;
1274                    if (arg.ndims() != s.ndims()) {
1275                        onlyLengths = false;
1276                        break;
1277                    }
1278                }
1279            }
1280            if (error) {
1281                errorUnlessDisabledAnd(onlyLengths, 
1282                        "Mismatching sizes in %s. All non-scalar arguments need matching sizes", builtInName());
1283            }
1284        }
1285    }
1286
1287  public void FEnumIntegerExp.typeCheck(ErrorCheckType checkType) {
1288          super.typeCheck(checkType);
1289          // We can't define the function Integer in PredefinedTypes.jrag - conflict with the type Integer
1290          int n = getNumOriginalArg();
1291          if (n != 1)
1292                  error("Calling function Integer(): too " + (n > 1 ? "many" : "few") + " arguments");
1293  }
1294 
1295  public void InstPreExp.typeCheck(ErrorCheckType checkType) {
1296        if (!getFExp().isAccess()) {
1297                error("Calling function pre(): argument must be variable access");
1298                return;
1299        }
1300  }
1301 
1302  public void FAssert.typeCheck(ErrorCheckType checkType) {
1303          if (hasLevel()) {
1304                  if (getLevel().isParameterExp())
1305                          getLevel().markAsStructuralParameter(checkType);
1306                  else if (!getLevel().isConstantExp())
1307                          error("Level of assert() must be constant or parameter");
1308          }
1309  }
1310 
1311  public void FReinit.typeCheck(ErrorCheckType checkType) {
1312      if (!getVar().isAccess() || !getVar().type().isReal())
1313          error("First argument to reinit() must be an access to a Real variable");
1314      else if (!getVar().type().typeCompatible(getFExp().type()))
1315          error("Arguments to reinit() must be of compatible types");
1316  }
1317
1318    public void FEdgeExp.typeCheck(ErrorCheckType checkType) {
1319        if (!getFExp().isAccess() || !getFExp().type().isBoolean()) 
1320            error("Calling function edge(): argument must be a boolean variable access");
1321    }
1322
1323    public void FChangeExp.typeCheck(ErrorCheckType checkType) {
1324        if (!getFExp().isAccess()) 
1325            error("Calling function change(): argument must be a variable access");
1326    }
1327
1328    public static final SimpleProblemProducer ASTNode.DELAY_MAX_NOT_PARAMETER =
1329            new SimpleErrorProducer("DELAY_MAX_NOT_PARAMETER", ProblemKind.SEMANTIC,
1330                    "Calling function delay(): third argument must be of parameter variability: %s");
1331    public static final SimpleProblemProducer ASTNode.DELAY_NOT_PARAMETER =
1332            new SimpleErrorProducer("DELAY_NOT_PARAMETER", ProblemKind.SEMANTIC,
1333                    "Calling function delay(): second argument must be of parameter variability when third argument is not given: %s");
1334    public static final SimpleProblemProducer ASTNode.DELAY_OVER_MAX =
1335            new SimpleErrorProducer("DELAY_OVER_MAX", ProblemKind.SEMANTIC,
1336                    "Calling function delay(): second argument may not be larger than third argument: %s = %s > %s = %s");
1337    public static final SimpleProblemProducer ASTNode.DELAY_NEGATIVE =
1338            new SimpleErrorProducer("DELAY_NEGATIVE", ProblemKind.SEMANTIC,
1339                    "Calling function delay(): second argument may not be negative: %s = %s < 0");
1340    public static final SimpleProblemProducer ASTNode.DELAY_MAX_NEGATIVE =
1341            new SimpleErrorProducer("DELAY_MAX_NEGATIVE", ProblemKind.SEMANTIC,
1342                    "Calling function delay(): third argument may not be negative: %s = %s < 0");
1343
1344    public void FDelayExp.typeCheck(ErrorCheckType checkType) {
1345        boolean max = hasMax();
1346        boolean maxParam = max ? getMax().variability().parameterOrLess() : false;
1347        boolean delayParam = getDelay().variability().parameterOrLess();
1348        if (max && !maxParam) {
1349            DELAY_MAX_NOT_PARAMETER.invoke(this, getMax());
1350        }
1351        if (!max && !delayParam) {
1352            DELAY_NOT_PARAMETER.invoke(this, getDelay());
1353        }
1354       
1355        double maxVal = 0.0;
1356        boolean maxEval = false;
1357        if (max && maxParam) {
1358            try {
1359                CValue maxCVal = getMax().ceval();
1360                if (maxCVal.hasRealValue()) {
1361                    maxVal = maxCVal.realValue();
1362                    maxEval = true;
1363                }
1364            } catch (ConstantEvaluationException e) {}
1365        }
1366        double delayVal = 0.0;
1367        boolean delayEval = false;
1368        if (delayParam) {
1369            try {
1370                CValue delayCVal = getDelay().ceval();
1371                if (delayCVal.hasRealValue()) {
1372                    delayVal = delayCVal.realValue();
1373                    delayEval = true;
1374                }
1375            } catch (ConstantEvaluationException e) {}
1376        }
1377        if (maxEval && delayEval && delayVal > maxVal) {
1378            DELAY_OVER_MAX.invoke(this, getDelay(), delayVal, getMax(), maxVal);
1379        }
1380        if (delayEval && delayVal < 0.0) {
1381            DELAY_NEGATIVE.invoke(this, getDelay(), delayVal);
1382        }
1383        if (maxEval && maxVal < 0.0) {
1384            DELAY_MAX_NEGATIVE.invoke(this, getMax(), maxVal);
1385        }
1386    }
1387   
1388    public void FSpatialDistExp.typeCheck(ErrorCheckType checkType) {
1389        super.typeCheck(checkType);
1390        if (!getIn0().size().equivalent(getIn1().size(), true)) {
1391            errorUnlessDisabledAnd(getIn0().ndims() == getIn1().ndims(), 
1392                    "Calling function spatialDistribution(): first and second arguments 'in0' and 'in1' needs equivalent sizes");
1393        }
1394        if (isArray()) {
1395            if (getX().isArray()) {
1396                error("Calling function spatialDistribution(): third argument 'x' cannot be vectorized");
1397            }
1398            if (getPositiveVelocity().isArray()) {
1399                error("Calling function spatialDistribution(): fourth argument 'positiveVelocity' cannot be vectorized");
1400            }
1401        }
1402    }
1403
1404        public void FStringExp.typeCheck(ErrorCheckType checkType) {
1405                FType valueType = getValue().type();
1406                if (hasSignificantDigits() && !valueType.isReal())
1407                        error("Calling function String(): named argument significantDigits can only be used when first argument is real");
1408                if (hasFormat() && (hasMinimumLength() || hasLeftJustified() || hasSignificantDigits()))
1409                        error("Calling function String(): named argument format can not be used together with minimumLength, leftJustified or significantDigits");
1410        }
1411
1412    public void FHomotopyExp.typeCheck(ErrorCheckType checkType) {
1413        checkVectorizedSizes(checkType);
1414        super.typeCheck(checkType);
1415    }
1416 
1417    public void InstDerExp.typeCheck(ErrorCheckType checkType) {
1418        FType type = getFExp().type();
1419        if (!(type.isReal() && (type.isScalar() || type.isArray())))
1420            error("Only real typed expressions are allowed in der() operator");
1421    }
1422 
1423  syn int FBuiltInFunctionCall.builtInNumOutput() = 1;
1424  eq FIgnoredBuiltIn.builtInNumOutput() = 0;
1425  eq FConnectionsOp.builtInNumOutput()  = 0;
1426  eq FConnBoolOp.builtInNumOutput()     = 1;
1427  eq FSpatialDistExp.builtInNumOutput() = 2;
1428 
1429  syn boolean FBuiltInFunctionCall.checkTypeAsExpression() = false;
1430  eq FSizeExp.checkTypeAsExpression()     = true;
1431  eq FMinMaxExp.checkTypeAsExpression()   = true;
1432  eq FIdentity.checkTypeAsExpression()    = true;
1433  eq FLinspace.checkTypeAsExpression()    = true;
1434  eq FAbstractCat.checkTypeAsExpression() = dimensionIsOk();
1435 
1436  syn boolean FAbstractCat.dimensionIsOk(); 
1437  eq FCatExp.dimensionIsOk()    = getDim().isConstantExp() && 
1438                                                                  getDim().type().isInteger() && getDim().type().isScalar();
1439  eq FMatrix.dimensionIsOk()    = true;
1440  eq FMatrixRow.dimensionIsOk() = true;
1441    public static final SimpleProblemProducer ASTNode.CANNOT_INFER_ARRAY_SIZE_OF_OUTPUT =
1442            new SimpleErrorProducer("CANNOT_INFER_ARRAY_SIZE_OF_OUTPUT", ProblemKind.SEMANTIC,
1443                    "Could not evaluate array size of output %s");
1444
1445    public void InstFunctionCall.typeCheck(ErrorCheckType checkType) {
1446        if (!isFunctionCallClause() && !getName().myInstClassDecl().isRecord() && !hasOutputs() && !isPartialFunctionCall()) {
1447            error("Function " + getName().name() + "() has no outputs, but is used in expression");
1448        } else if (!isFunctionCallClause() && size().isUnknown() && errorCheckUnknownSize()) {
1449            CANNOT_INFER_ARRAY_SIZE_OF_OUTPUT.invoke(this, expOutput().name());
1450        }
1451        if (myCallOutputs().size() < myLefts().size()) {
1452            error("Too many components assigned from function call: " + getName().name() + 
1453                    "() has " + myCallOutputs().size() + " output(s)");
1454        }
1455        if (isFunctionCallClause()) {
1456            for (int i = 0, n = myCallOutputs().size(); i < n; i++) {
1457                sizeOfOutput(i).markAsStructuralParameter(checkType, this);
1458            }
1459        } else {
1460            size().markAsStructuralParameter(checkType, this);
1461        }
1462        if (callsLoadResource()) {
1463            getArgs().forceUsesVariability(checkType, Variability.LOADRESOURCEPARAMETER);
1464        }
1465    }
1466 
1467  syn boolean InstFunctionCall.isPartialFunctionCall() = false;
1468  eq InstPartialFunctionCall.isPartialFunctionCall()   = true;
1469
1470    public void FFunctionCallLeft.typeCheck(ErrorCheckType checkType) {
1471        if (hasFExp() && !myOutput().isUnknown() && !type().isUnknown()) { // Avoid duplicate error
1472            if (getFExp() instanceof CommonAccessExp) {  // Should never be false - add check?
1473                CommonAccess use = getFExp().asCommonAccess();
1474                FType useType = getFExp().type();
1475                FType outType = type();
1476                if (!use.isForIndex()) {
1477                    if (outType.size().isUnknown() && !inFunction() && !checkType.allowIncompleteSizes()) {
1478                        error(functionCallDecription() + ": could not evaluate array size of output " + 
1479                                myOutput().name());
1480                    } else if (!useType.typeCompatible(outType, true)) {
1481                        if (useType.typeCompatibleExceptLengths(outType)) {
1482                            if (!lockBranch(checkType))
1483                                errorUnlessDisabled("%s: component %s is of size %s and output %s is of size %s - they are not compatible", 
1484                                        functionCallDecription(), use.name(), useType.size(), myOutput().name(), outType.size());
1485                        } else {
1486                            error("%s: component %s is of type %s and output %s is of type %s - they are not compatible", 
1487                                    functionCallDecription(), use.name(), useType, myOutput().name(), outType);
1488                        }
1489                    }
1490                }
1491            }
1492        }
1493    }
1494
1495  inh String InstFunctionArgument.functionCallDecription();
1496  inh String FFunctionCallLeft.functionCallDecription();
1497  eq FAbstractFunctionCall.getChild().functionCallDecription() = functionCallDecription();
1498  eq FFunctionCallEquation.getChild().functionCallDecription() = getCall().functionCallDecription();
1499  eq FFunctionCallStmt.getChild().functionCallDecription()     = getCall().functionCallDecription();
1500
1501    public void InstFunctionArgument.typeCheck(ErrorCheckType checkType) {
1502        boolean typeOk = true;
1503        FType type = getFExp().type();
1504        if (!type.isUnknown()) {
1505            if (argumentDefinedTypeValid()) {
1506                FType boundType = getBoundInput().type();
1507                if (!boundType.isUnknown()) {
1508                    if (isVectorized()) 
1509                        boundType = boundType.sizedType(boundType.size().expand(vectorizedSize()));
1510                    else if (isDestructorArgument())
1511                        boundType = boundType.sizedType(type.size());
1512                    typeOk = boundType.typeCompatible(type, true) || lockBranch(checkType);
1513                }
1514            } else {
1515                typeOk = argumentTypeValid(type);
1516            }
1517        }
1518        if (!typeOk) {
1519            String msg = argumentTypeError();
1520            if (msg != null) {
1521                error(msg);
1522            } else {
1523                error("%s: types of %s and input %s are not compatible\n" + 
1524                      "    type of '%s' is %s\n" + 
1525                      "    expected type is %s", 
1526                      functionCallDecription(), argumentDesc(), getBoundInput().name(), 
1527                      getFExp(), getFExp().type(),
1528                      argumentDefinedTypeValid() ? getBoundInput().type().toString() : expectedArgumentType());
1529            }
1530        }
1531    }
1532
1533    public void InstBadArgument.typeCheck(ErrorCheckType checkType) {
1534        if (!isDestructorArgument()) {
1535            error(functionCallDecription() + ": " + errorString() + " " + getBoundInput().name());
1536        }
1537    }
1538
1539    syn String InstBadArgument.errorString();
1540    eq InstMissingArgument      .errorString() = "missing argument for required input";
1541    eq InstUnknownArgument      .errorString() = "could not resolve argument for required input";
1542    eq InstMultipleBoundArgument.errorString() = "multiple arguments matches input";
1543
1544    inh boolean InstFunctionArgument.isDestructorArgument();
1545    eq InstFunctionCall.getArg().isDestructorArgument() = isDestructorCall();
1546    eq BaseNode.getChild().isDestructorArgument()       = false;
1547
1548    inh boolean InstClassDecl.inExternalObject();
1549    eq InstNode.getChild().inExternalObject()              = isExternalObject();
1550    eq InstRecordConstructor.getChild().inExternalObject() = false;
1551
1552    public void InstDefaultArgument.typeCheck(ErrorCheckType checkType) {}
1553
1554  inh String InstFunctionArgument.argumentTypeError();
1555  eq FExp.getChild().argumentTypeError()         = null;
1556  eq FCardinality.getChild().argumentTypeError() = "The argument of cardinality() must be a scalar reference to a connector";
1557
1558    syn String InstFunctionArgument.argumentDesc() = null;
1559    eq InstPositionalArgument.argumentDesc() = "positional argument " + (getPos() + 1);
1560    eq InstNamedArgument.argumentDesc()      = "named argument " + getName();
1561
1562  public void InstAccess.typeCheck(ErrorCheckType checkType) {
1563      if (myInstComponentDecl().size().isUndefined() && myInstComponentDecl().inFunction() && 
1564              !myInstComponentDecl().isInput() && !checkType.allowIncompleteSizes()) {
1565          compliance("Using variables with undefined size is not supported");
1566      }
1567      super.typeCheck(checkType);
1568  }
1569 
1570  public boolean Size.isUndefined() {
1571      for (int i = 0; i < ndims(); i++) {
1572          if (size[i] == Size.UNKNOWN) {
1573              return true;
1574          }
1575      }
1576      return false;
1577  }
1578
1579  public boolean MutableSize.isUndefined() {
1580      for (int i = 0; i < ndims(); i++) {
1581          if (size[i] == Size.UNKNOWN && (exps[i] == null || exps[i] instanceof FColonSizeExp)) {
1582              return true;
1583          }
1584      }
1585      return false;
1586  }
1587
1588    public static final SimpleProblemProducer ASTNode.ACCESS_TO_CLASS_THROUGH_COMPONENT = 
1589            new SimpleErrorProducer("ACCESS_TO_CLASS_THROUGH_COMPONENT", ProblemKind.SEMANTIC,
1590                    "Can not access non-function class through component access: '%s'");
1591    public static final SimpleProblemProducer ASTNode.ACCESS_TO_FUNCTION_THROUGH_MULTIPLE_COMPONENTS = 
1592            new SimpleErrorProducer("ACCESS_TO_FUNCTION_THROUGH_MULTIPLE_COMPONENTS", ProblemKind.SEMANTIC,
1593                    "Can not access function through component unless only the first part of the name is a component: '%s'");
1594    public static final SimpleProblemProducer ASTNode.ACCESS_TO_FUNCTION_THROUGH_ARRAY_COMPONENT = 
1595            new SimpleErrorProducer("ACCESS_TO_FUNCTION_THROUGH_ARRAY_COMPONENT", ProblemKind.SEMANTIC,
1596                    "Can not access function through array component access: '%s'");
1597
1598    public void InstDot.typeCheck(ErrorCheckType checkType) {
1599        // Check for accesses to component in class or class in component
1600        int n = getNumInstAccess();
1601        for (int i = 0; i < n - 1; i++)
1602            getInstAccess(i).checkMixedAccessLeft(getInstAccess(i + 1), this, checkType, i, n);
1603        super.typeCheck(checkType);
1604    }
1605
1606    public void InstAccess.checkMixedAccessLeft(
1607            InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) {}
1608
1609    public void InstClassAccess.checkMixedAccessLeft(
1610            InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) {
1611        right.checkMixedAccessRight(myInstClassDecl(), top, checkType, i, n);
1612    }
1613
1614    public void InstComponentAccess.checkMixedAccessLeft(
1615            InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) {
1616        right.checkMixedAccessRight(myInstComponentDecl(), top, checkType, isArray(), i, n);
1617    }
1618
1619    public void InstComponentArrayAccess.checkMixedAccessLeft(
1620            InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) {
1621        right.checkMixedAccessRight(myInstComponentDecl(), top, checkType, true, i, n);
1622    }
1623
1624    public void InstAccess.checkMixedAccessRight(
1625            InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) {}
1626
1627    public void InstComponentAccess.checkMixedAccessRight(
1628            InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) {
1629        checkMixedAccessRightForComponent(left, top, checkType, i, n);
1630    }
1631
1632    public void InstComponentArrayAccess.checkMixedAccessRight(
1633            InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) {
1634        checkMixedAccessRightForComponent(left, top, checkType, i, n);
1635    }
1636
1637    public void InstAccess.checkMixedAccessRightForComponent(
1638            InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) {
1639        String type = null;
1640        if (left.extendsEnum()) {
1641            if (!myInstComponentDecl().isEnumLiteral())
1642                type = "attribute of primitive with dot notation";
1643        } else if (left.isPackage()) {
1644            left.checkRestriction(checkType);
1645        } else if (!left.isOkPackage()) {
1646            type = "component in non-package class";
1647        }
1648        if (type != null) {
1649            top.error("Can not access " + type + ": " + top.name());
1650        }
1651    }
1652
1653    public void InstAccess.checkMixedAccessRight(
1654            InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) {}
1655
1656    public void InstClassAccess.checkMixedAccessRight(
1657            InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) {
1658        if (!top.myInstClassDecl().isFunction()) {
1659            ACCESS_TO_CLASS_THROUGH_COMPONENT.invoke(top, top);
1660        } else if (i != 0) {
1661            ACCESS_TO_FUNCTION_THROUGH_MULTIPLE_COMPONENTS.invoke(top, top);
1662        } else if (array) {
1663            ACCESS_TO_FUNCTION_THROUGH_ARRAY_COMPONENT.invoke(top, top);
1664         }
1665    }
1666
1667    public void InstComponentAccess.checkMixedAccessRight(
1668            InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) {
1669        checkMixedAccessRightForComponent(left, top, checkType, array, i, n);
1670    }
1671
1672    public void InstComponentArrayAccess.checkMixedAccessRight(
1673            InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) {
1674        checkMixedAccessRightForComponent(left, top, checkType, array, i, n);
1675    }
1676
1677    public void InstAccess.checkMixedAccessRightForComponent(
1678            InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) {
1679        if (left.isPrimitive()) {
1680            top.error("Can not access attribute of primitive with dot notation: " + top.name());
1681        }
1682    }
1683
1684    /**
1685     * Check if the type defined for this argument in the built-in function list
1686     * is valid.
1687     */
1688    inh boolean InstFunctionArgument.argumentDefinedTypeValid();
1689    eq FAbstractFunctionCall.getChild().argumentDefinedTypeValid()           = true;
1690    eq FTranspose.getOriginalArg().argumentDefinedTypeValid()                = false;
1691    eq FSymmetric.getOriginalArg().argumentDefinedTypeValid()                = false;
1692    eq FMinMaxExp.getOriginalArg().argumentDefinedTypeValid()                = false;
1693    eq FReductionExp.getOriginalArg().argumentDefinedTypeValid()             = false;
1694    eq FHomotopyExp.getOriginalArg().argumentDefinedTypeValid()              = false;
1695    eq FSemiLinearExp.getOriginalArg().argumentDefinedTypeValid()            = false;
1696    eq FNdimsExp.getOriginalArg().argumentDefinedTypeValid()                 = false;
1697    eq FInfArgsFunctionCall.getOriginalArg().argumentDefinedTypeValid()      = false;
1698    eq FEnumIntegerExp.getOriginalArg().argumentDefinedTypeValid()           = false;
1699    eq FVectUnaryBuiltIn.getOriginalArg().argumentDefinedTypeValid()         = false;
1700    eq FDimensionConvert.getOriginalArg().argumentDefinedTypeValid()         = false;
1701    eq FEventGenExp.getOriginalArg().argumentDefinedTypeValid()              = false;
1702    eq FCardinality.getOriginalArg().argumentDefinedTypeValid()              = false;
1703    eq FDecouple.getOriginalArg().argumentDefinedTypeValid()                 = false;
1704    eq FMathematicalFunctionCall.getOriginalArg().argumentDefinedTypeValid() = false;
1705    eq FConnectionsOp.getOriginalArg().argumentDefinedTypeValid()            = false;
1706    eq FStringExp.getOriginalArg(int i).argumentDefinedTypeValid()           = i > 0;
1707    eq FConnPotentialRoot.getOriginalArg(int i).argumentDefinedTypeValid()   = i == 1;
1708    eq FSizeExp.getOriginalArg(int i).argumentDefinedTypeValid()             = i != 0;
1709    eq FSmoothExp.getOriginalArg(int i).argumentDefinedTypeValid()           = i == 0;
1710    eq InstPreExp.getOriginalArg().argumentDefinedTypeValid()                = false;
1711    eq FEdgeExp.getOriginalArg().argumentDefinedTypeValid()                  = false;
1712    eq FChangeExp.getOriginalArg().argumentDefinedTypeValid()                = false;
1713    eq FReinit.getOriginalArg().argumentDefinedTypeValid()                   = false;
1714
1715    /**
1716     * Check if the type supplied is valid for this argument.
1717     *
1718     * Only used if argumentDefinedTypeValid() returns <code>false</code>.
1719     */
1720    inh boolean InstFunctionArgument.argumentTypeValid(FType type);
1721    eq FAbstractFunctionCall.getChild().argumentTypeValid(FType type)     = type.isPrimitive();
1722    eq FTranspose.getChild().argumentTypeValid(FType type)                = type.ndims() >= 2 && type.isPrimitive();
1723    eq FSymmetric.getChild().argumentTypeValid(FType type)                = 
1724        type.ndims() == 2 && type.size().get(0) == type.size().get(1);
1725    eq FReductionExp.getChild().argumentTypeValid(FType type)             = type.ndims() > 0 && type.hasAdd();
1726    eq FSemiLinearExp.getChild().argumentTypeValid(FType type)            = type.isNumeric();
1727    eq FAbsExp.getChild().argumentTypeValid(FType type)                   = type.isNumeric();
1728    eq FSignExp.getChild().argumentTypeValid(FType type)                  = type.isNumeric();
1729    eq FEnumIntegerExp.getChild().argumentTypeValid(FType type)           = type.isEnum();
1730    eq FEventGenExp.getChild().argumentTypeValid(FType type)              = type.isNumeric();
1731    eq FMathematicalFunctionCall.getChild().argumentTypeValid(FType type) = type.isNumeric();
1732    eq FMinMaxExp.getOriginalArg(int i).argumentTypeValid(FType type)     = 
1733        hasY() != getOriginalArg(i).getFExp().isArray() && type.isPrimitive();
1734    eq FSmoothExp.getChild().argumentTypeValid(FType type)                = type.onlyContainsReal();
1735    eq FDimensionConvert.getChild().argumentTypeValid(FType type)         = argumentSizeValid(type.size());
1736    eq FCardinality.getChild().argumentTypeValid(FType type)              = 
1737        type.isScalar() && getFExp().isComponentReference(ALLOWED_COMPONENTS);
1738    eq FDecouple.getChild().argumentTypeValid(FType type)                 = true;
1739    eq FConnectionsOp.getOriginalArg(int i).argumentTypeValid(FType type) = 
1740        getOriginalArg(i).getFExp().isComponentReference(ALLOWED_COMPONENTS);
1741    eq FStringExp.getChild().argumentTypeValid(FType type)                = 
1742        type.isScalar() && (type.isReal() || type.isInteger() || type.isBoolean() || type.isEnum());
1743    eq FInfArgsFunctionCall.getChild().argumentTypeValid(FType type)      = true;  // Type checked in FInfArgsFunctionCall.typeCheck()
1744    eq FReinit.getChild().argumentTypeValid(FType type)                   = true;  // Type checked in Reinit.typeCheck()
1745    eq FHomotopyExp.getChild().argumentTypeValid(FType type)              = type.isNumeric();
1746    // All types allowed for these:
1747    eq FNoEventExp.getChild().argumentTypeValid(FType type)               = true;
1748    eq FSizeExp.getChild().argumentTypeValid(FType type)                  = true;
1749
1750    /**
1751     * Description of expexted type of argument.
1752     *
1753     * Should be defined for cases where argumentDefinedTypeValid() returns and
1754     * argumentTypeValid() both return false.
1755     */
1756    inh String InstFunctionArgument.expectedArgumentType();
1757    eq FAbstractFunctionCall.getChild().expectedArgumentType()     = 
1758        "Real, Integer, Boolean, String or enumeration";
1759    eq FTranspose.getChild().expectedArgumentType()                = 
1760        "matrix of Real, Integer, Boolean, String or enumeration";
1761    eq FSymmetric.getChild().expectedArgumentType()                = "square matrix";
1762    eq FReductionExp.getChild().expectedArgumentType()             = "Real array";
1763    eq FEnumIntegerExp.getChild().expectedArgumentType()           = "enumeration";
1764    eq FSemiLinearExp.getChild().expectedArgumentType()            = "Real";
1765    eq FAbsExp.getChild().expectedArgumentType()                   = "Real";
1766    eq FSignExp.getChild().expectedArgumentType()                  = "Real";
1767    eq FEventGenExp.getChild().expectedArgumentType()              = "Real";
1768    eq FMathematicalFunctionCall.getChild().expectedArgumentType() = "Real";
1769    eq FSmoothExp.getChild().expectedArgumentType()                = "Real";
1770    eq FHomotopyExp.getChild().expectedArgumentType()              = "Real";
1771    eq FMinMaxExp.getOriginalArg(int i).expectedArgumentType()     = 
1772        (hasY() ? "scalar" : "array of") + " Real, Integer, Boolean, String or enumeration";
1773    eq FScalarExp.getChild().expectedArgumentType()                = "array with exactly 1 element";
1774    eq FVectorExp.getChild().expectedArgumentType()                = "scalar or vector-shaped array";
1775    eq FMatrixExp.getChild().expectedArgumentType()                = "scalar, vector or matrix-shaped array";
1776    eq FCardinality.getChild().expectedArgumentType()              = "scalar connector";
1777    eq FConnectionsOp.getChild().expectedArgumentType()            = "connector";
1778    eq FStringExp.getChild().expectedArgumentType()                = "scalar Real, Integer, Boolean or enumeration";
1779
1780  protected static final Criteria<InstComponentDecl> FCardinality.ALLOWED_COMPONENTS = new Criteria<InstComponentDecl>() {
1781      public boolean test(InstComponentDecl elem) { return elem.isConnector() || elem.isPrimitive(); }
1782  };
1783
1784  protected static final Criteria<InstComponentDecl> FConnectionsOp.ALLOWED_COMPONENTS = new Criteria<InstComponentDecl>() {
1785      public boolean test(InstComponentDecl elem) { return elem.isOverconstrainedType(); }
1786  };
1787
1788  /**
1789   * Check if this expression is a reference to a component matching specified criteria.
1790   *
1791   * Only valid in instance tree.
1792   */
1793  syn boolean FExp.isComponentReference(Criteria<InstComponentDecl> criteria)  = false;
1794    eq CommonAccessExp.isComponentReference(Criteria<InstComponentDecl> criteria) = getAccess().isComponentReference(criteria);
1795   
1796    syn boolean CommonAccess.isComponentReference(Criteria<InstComponentDecl> criteria) = false;
1797    eq InstAccess.isComponentReference(Criteria<InstComponentDecl> criteria) = 
1798            criteria.test(myInstComponentDecl());
1799
1800  /**
1801   * Check if the given Size is valid for the argument of the operator.
1802   */
1803  syn boolean FDimensionConvert.argumentSizeValid(Size s) {
1804      if (s.isUnknown())
1805          return true;
1806     
1807          boolean[] useDim = new boolean[s.ndims()];
1808          for (int d : dimensionsToKeep())
1809                  if (d < useDim.length)
1810                          useDim[d] = true;
1811          for (int i = 0; i < s.ndims(); i++)
1812                  if (!useDim[i] && s.get(i) != 1)
1813                          return false;
1814          return true;
1815  }
1816
1817    protected static void ASTNode.typeCheckEnabled(ErrorCheckType checkType, FExp enabledExp, FType parentType, boolean eachSet) {
1818        enabledExp.collectErrors(checkType);
1819        if (checkType.checkTypes()) {
1820            if (!enabledExp.type().isBoolean() && !enabledExp.type().isUnknown()) {
1821                enabledExp.error("The type of the enabled expression is not boolean");
1822            } else if (!eachSet && !parentType.dimensionCompatible(enabledExp.type())) { 
1823                if (enabledExp.ndims() == 0) {
1824                    enabledExp.warning("Assuming 'each' for enabled expression");
1825                } else {
1826                    enabledExp.errorUnlessDisabledAnd(parentType.ndims() == enabledExp.ndims(), 
1827                            "Array size mismatch for the enabled attribute, " + 
1828                            "size of component declaration is %s and size of expression is %s", 
1829                            parentType.size(), enabledExp.size());
1830                }
1831            } else if (eachSet) { 
1832                if (parentType.ndims() == 0) {
1833                    enabledExp.warning("The 'each' keyword should not be applied to attributes of scalar components");
1834                } else if (enabledExp.ndims() > 0) {
1835                    enabledExp.error("The enabled attribute is declared 'each' and the expression is not scalar");
1836                }
1837            }
1838        }
1839    }
1840
1841}
1842
1843aspect VariabilityCheck {
1844   
1845    private FExp FPreExp.instanceTreeSource = null;
1846    private FExp FReinit.instanceTreeSource = null;
1847   
1848    public void FExp.setInstanceTreeSource(FExp source) {}
1849   
1850    public void FPreExp.setInstanceTreeSource(FExp source) {
1851        instanceTreeSource = source;
1852    }
1853   
1854    public void FReinit.setInstanceTreeSource(FExp source) {
1855        instanceTreeSource = source;
1856    }
1857   
1858    /**
1859     * Surrounds the FExp <code>exp</code> with pre if it is an non literal exp, else return exp.
1860     *
1861     * Also sets the <code>instanceTreeSource</code> field of the FPreExp (if any)
1862     * to <code>source</code>.
1863     */
1864    public static FExp FPreExp.create(FExp exp, FExp source) {
1865        exp = exp.createFPreExp();
1866        exp.setInstanceTreeSource(source);
1867        return exp;
1868    }
1869   
1870    /**
1871     * Check operations that are allowed on discrete expressions or variables,
1872     * but not on continuous ones or vice-versa.
1873     *
1874     * Also breaks connections back to instance tree that was added during flattening
1875     * to be able to report these errors in the correct place.
1876     */
1877    public void ASTNode.checkDiscreteOperations() {
1878        for (ASTNode n : this)
1879            n.checkDiscreteOperations();
1880    }
1881   
1882    public void FPreExp.checkDiscreteOperations() {
1883        if (instanceTreeSource != null && getFAccess().myFV().isContinuous() && !inWhen() && !inInitialEquationSection()) 
1884            instanceTreeSource.discreteArgError();
1885        instanceTreeSource = null;
1886    }
1887   
1888    public void FReinit.checkDiscreteOperations() {
1889        if (instanceTreeSource != null && !myFV().isContinuous()) 
1890            instanceTreeSource.discreteArgError();
1891        instanceTreeSource = null;
1892    }
1893   
1894    /**
1895     * Generate error for operator that got wrong variability of argument
1896     */
1897    public void FExp.discreteArgError() {
1898        throw new UnsupportedOperationException();
1899    }
1900   
1901    public void InstPreExp.discreteArgError() {
1902        error("Calling built-in operator pre() with a continuous variable access as argument can only be done in when clauses and initial equations");
1903    }
1904   
1905    public void FChangeExp.discreteArgError() {
1906        error("Calling built-in operator change() with a continuous variable access as argument can only be done in when clauses and initial equations");
1907    }
1908   
1909    public void FReinit.discreteArgError() {
1910        error("Built-in operator reinit() must have a continuous variable access as its first argument");
1911    }
1912   
1913}
Note: See TracBrowser for help on using the repository browser.