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

Last change on this file since 13922 was 13922, checked in by molsson, 6 weeks ago

Merged revision(s) 13898-13913 from branches/dev-mo-2617:
#5843 Moved type checking of conditional attributes so that it is always done.
........
#5843 Conditional attribute requires variability fixed parameter or less.
........
#5843 Updated error message NON_BOOLEAN_CONDITIONAL_GUARD to say Boolean instead of boolean.
........
#5843 Merged non-scalar and non-boolean conditional guard error messages.
........

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