001/** A class representing the type of a RecordToken.
002
003 Copyright (c) 1997-2018 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026 */
027package ptolemy.data.type;
028
029import ptolemy.data.FunctionToken;
030import ptolemy.data.Token;
031import ptolemy.graph.CPO;
032import ptolemy.graph.InequalityTerm;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.InternalErrorException;
035
036///////////////////////////////////////////////////////////////////
037//// FunctionType
038
039/**
040 A class representing the type of a FunctionToken.
041
042 @author Steve Neuendorffer
043 @version $Id$
044 @since Ptolemy II 3.0
045 @Pt.ProposedRating Red (neuendor)
046 @Pt.AcceptedRating Red (cxh)
047 */
048public class FunctionType extends StructuredType implements Cloneable {
049    /** Construct a new FunctionType with the specified argument types
050     *  and the given return type.  To leave the types of some fields
051     *  undeclared, use BaseType.UNKNOWN.  To construct the type for a
052     *  function of no arguments, set the length of the argument array
053     *  to 0.
054     *  @param types An array of Type.
055     *  @param returnType An type.
056     *  @exception IllegalArgumentException If the labels and types do
057     *  not have the same size.
058     *  @exception NullPointerException If one of the arguments is null.
059     */
060    public FunctionType(Type[] types, Type returnType) {
061        _argTypeTerms = new FieldTypeTerm[types.length];
062
063        for (int i = 0; i < types.length; i++) {
064            FieldTypeTerm fieldType = new FieldTypeTerm(types[i]);
065            _argTypeTerms[i] = fieldType;
066        }
067
068        _returnTypeTerm = new FieldTypeTerm(returnType);
069    }
070
071    ///////////////////////////////////////////////////////////////////
072    ////                         public methods                    ////
073
074    /** Return a deep copy of this FunctionType if it is a variable, or
075     *  itself if it is a constant.
076     *  @return A FunctionType.
077     */
078    @Override
079    public Object clone() {
080        if (isConstant()) {
081            return this;
082        } else {
083            // construct the labels and declared types array
084            Type[] types = new Type[_argTypeTerms.length];
085
086            for (int i = 0; i < types.length; i++) {
087                types[i] = getArgType(i);
088            }
089
090            FunctionType newObj = new FunctionType(types, getReturnType());
091
092            try {
093                newObj.updateType(this);
094            } catch (IllegalActionException ex) {
095                throw new InternalErrorException(null, ex,
096                        "Failed to update new instance.");
097            }
098
099            return newObj;
100        }
101    }
102
103    /** Convert the argument token into a FunctionToken having this type,
104     *  if lossless conversion can be done.  The argument must be an
105     *  FunctionToken, and its type must be a subtype of this record type.
106     *  @param token A token.
107     *  @return An FunctionToken.
108     *  @exception IllegalActionException If lossless conversion
109     *   cannot be done.
110     */
111    @Override
112    public Token convert(Token token) throws IllegalActionException {
113        if (!isCompatible(token.getType())) {
114            throw new IllegalArgumentException(Token
115                    .notSupportedConversionMessage(token, this.toString()));
116        }
117
118        // FIXME: This should actually return a new Function that
119        // includes the appropriate argument and return value
120        // conversions.
121        return token;
122
123        //   if (false) {
124
125        /*FunctionToken functionToken = (FunctionToken)token;
126         // The converted token has the same set of labels as the argument.
127         // That is, fields not in this type are not cut off.
128         Object[] labelArray = functionToken.labelSet().toArray();
129
130         // Arrays that will be used to create the new token.
131         String[] labelStringArray = new String[labelArray.length];
132         Token[] values = new Token[labelArray.length];
133
134         for (int i = 0; i < labelArray.length; i++) {
135         String label = (String)labelArray[i];
136
137         // Convert each field of the function.
138         Token fieldToken = functionToken.get(label);
139         Type newFieldTypeTerm = get(label);
140
141         // If the type of the field is specified, then convert it.
142         if (newFieldTypeTerm != null) {
143         values[i] = newFieldTypeTerm.convert(fieldToken);
144         } else {
145         values[i] = fieldToken;
146         }
147
148         // Store the label for each field.
149         labelStringArray[i] = label;
150         }
151
152         return new FunctionToken(labelStringArray, values);
153         }*/
154    }
155
156    /** Determine if the argument represents the same FunctionType as
157     *  this object.  Two function types are equal if they have the same
158     *  field names and the type of each field is the same, and they
159     *  have the same return type.
160     *  @param object Another object.
161     *  @return True if the argument represents the same FunctionType as
162     *  this object.
163     */
164    @Override
165    public boolean equals(Object object) {
166        // See http://www.technofundo.com/tech/java/equalhash.html
167        if (object == this) {
168            return true;
169        }
170        if (object == null || object.getClass() != getClass()) {
171            return false;
172        } else {
173            FunctionType functionType = (FunctionType) object;
174
175            if (getArgCount() != functionType.getArgCount()) {
176                return false;
177            }
178
179            for (int i = 0; i < getArgCount(); i++) {
180                Type myType = this.getArgType(i);
181                Type argType = functionType.getArgType(i);
182
183                if (!myType.equals(argType)) {
184                    return false;
185                }
186            }
187
188            if (!getReturnType().equals(functionType.getReturnType())) {
189                return false;
190            }
191        }
192
193        return true;
194    }
195
196    /** Return the number of arguments in this type.
197     *  @return The number of arguments.
198     */
199    public int getArgCount() {
200        return _argTypeTerms.length;
201    }
202
203    /** Return the type of the given argument.
204     *  @param i  The index of the type.
205     *  @return a Type.
206     */
207    public Type getArgType(int i) {
208        if (i < 0 || i >= _argTypeTerms.length) {
209            return null;
210        }
211
212        FieldTypeTerm fieldType = _argTypeTerms[i];
213
214        if (fieldType == null) {
215            return null;
216        }
217
218        return fieldType._resolvedType;
219    }
220
221    /** Return the type of the specified label.
222     *  @return a Type.
223     */
224    public Type getReturnType() {
225        return _returnTypeTerm._resolvedType;
226    }
227
228    /** Return the class for tokens that this type represents.
229     *  @return The class for tokens that this type represents.
230     */
231    @Override
232    public Class getTokenClass() {
233        return FunctionToken.class;
234    }
235
236    /** Return the InequalityTerm representing the type of the given
237     *  argument.
238     *  @param i  The index of the type.
239     *  @return An InequalityTerm.
240     *  @see ptolemy.graph.InequalityTerm
241     */
242    public FieldTypeTerm getArgTypeTerm(int i) {
243        return _argTypeTerms[i];
244    }
245
246    /** Return a hash code value for this object.
247     *  @return The hash code value for this object.
248     */
249    @Override
250    public int hashCode() {
251        // See http://www.technofundo.com/tech/java/equalhash.html
252        int hashCode = 7;
253        if (_returnTypeTerm != null) {
254            hashCode = 31 * hashCode + _returnTypeTerm.hashCode();
255        }
256        for (int i = 0; i < getArgCount(); i++) {
257            hashCode = 31 * hashCode + getArgType(i).hashCode();
258        }
259        return hashCode;
260    }
261
262    /** Set the elements that have declared type BaseType.UNKNOWN (the leaf
263     *  type variable) to the specified type.
264     *  @param type the type to set the leaf type variable to.
265     */
266    @Override
267    public void initialize(Type type) {
268        try {
269            for (int i = 0; i < getArgCount(); i++) {
270                FieldTypeTerm fieldType = getArgTypeTerm(i);
271
272                if (fieldType.isSettable()) {
273                    fieldType.initialize(type);
274                }
275            }
276        } catch (IllegalActionException iae) {
277            throw new InternalErrorException("FunctionType.initialize: Cannot "
278                    + "initialize the element type to " + type + " "
279                    + iae.getMessage());
280        }
281    }
282
283    /** Test if this type corresponds to an abstract token
284     *  class. A FunctionType is abstract only if it is not instantiable.
285     *  @return True if this type is abstract.
286     */
287    @Override
288    public boolean isAbstract() {
289        return !isInstantiable();
290    }
291
292    /** Test if the argument type is compatible with this type.  The
293     *  given type will be compatible with this type if it is
294     *  BaseType.UNKNOWN, or...
295     *  @param type An instance of Type.
296     *  @return True if the argument is compatible with this type.
297     */
298    @Override
299    public boolean isCompatible(Type type) {
300        if (type.equals(BaseType.UNKNOWN)) {
301            return true;
302        }
303
304        if (!(type instanceof FunctionType)) {
305            return false;
306        }
307
308        FunctionType argumentFunctionType = (FunctionType) type;
309
310        // The given type cannot be losslessly converted to this type
311        // if it does not contain the same number of arguments.
312        if (argumentFunctionType.getArgCount() != getArgCount()) {
313            return false;
314        }
315
316        // Loop through all of the fields of this type...
317        for (int i = 0; i < getArgCount(); i++) {
318            Type argumentFieldTypeTerm = argumentFunctionType.getArgType(i);
319
320            // The given function type cannot be losslessly converted
321            // to this type if the individual arguments are not
322            // compatible.
323            Type thisFieldTypeTerm = getArgType(i);
324
325            if (!argumentFieldTypeTerm.isCompatible(thisFieldTypeTerm)) {
326                return false;
327            }
328        }
329
330        return true;
331    }
332
333    /** Test if this FunctionType is a constant. A FunctionType is a
334     *  constant if the declared type of all of its fields are
335     *  constant.
336     *  @return True if this type is a constant.
337     */
338    @Override
339    public boolean isConstant() {
340        // Loop through all of the fields of this type...
341        for (int i = 0; i < getArgCount(); i++) {
342            FieldTypeTerm fieldType = getArgTypeTerm(i);
343            Type type = fieldType._declaredType;
344
345            // Return false if the field is not constant.
346            if (!type.isConstant()) {
347                return false;
348            }
349        }
350
351        return true;
352    }
353
354    /** Test if this type corresponds to an instantiable token
355     *  class. A FunctionType is instantiable if all of its fields are
356     *  instantiable.
357     *  @return True if this type is instantiable.
358     */
359    @Override
360    public boolean isInstantiable() {
361        // Loop through all of the fields of this type...
362        for (int i = 0; i < getArgCount(); i++) {
363            Type type = getArgType(i);
364
365            // Return false if the field is not instantiable.
366            if (!type.isInstantiable()) {
367                return false;
368            }
369        }
370
371        return true;
372    }
373
374    /** Test if the specified type is a substitution instance of this
375     *  type.  One function is a substitution instance of another if they
376     *  have arguments with the same types and each field of the given type is
377     *  a substitution instance of the corresponding field in this type.
378     *  @param type A Type.
379     *  @return True if the argument is a substitution instance of this type.
380     *  @see Type#isSubstitutionInstance
381     */
382    @Override
383    public boolean isSubstitutionInstance(Type type) {
384        if (!(type instanceof FunctionType)) {
385            return false;
386        }
387
388        FunctionType functionType = (FunctionType) type;
389
390        // Check that the argument counts are the same
391        int argCount = getArgCount();
392
393        if (functionType.getArgCount() != argCount) {
394            return false;
395        }
396
397        // Loop through all of the fields of this type...
398        for (int i = 0; i < getArgCount(); i++) {
399            Type myArgType = getArgType(i);
400            Type argType = functionType.getArgType(i);
401
402            if (!myArgType.isSubstitutionInstance(argType)) {
403                return false;
404            }
405        }
406
407        // Check the return type.
408        if (!getReturnType()
409                .isSubstitutionInstance(functionType.getReturnType())) {
410            return false;
411        }
412
413        return true;
414    }
415
416    /** Return the string representation of this type. The format is
417     *  <code>function(a0:&lt;type&gt;, a1:&lt;type&gt;, ...)
418     *  &lt;type&gt;</code> Note that the function argument names are
419     *  not semantically significant.
420     *  @return A String.
421     */
422    @Override
423    public String toString() {
424        // construct the string representation of this token.
425        StringBuffer results = new StringBuffer("(function(");
426
427        for (int i = 0; i < getArgCount(); i++) {
428            if (i != 0) {
429                results.append(", ");
430            }
431
432            results.append("a" + i + ":" + getArgType(i));
433        }
434
435        return results.toString() + ") " + getReturnType() + ")";
436    }
437
438    /** Update this type to the specified FunctionType.
439     *  The specified type must be a FunctionType and have the same structure
440     *  as this one.
441     *  This method will only update the component whose declared type is
442     *  BaseType.UNKNOWN, and leave the constant part of this type intact.
443     *  @param newType A StructuredType.
444     *  @exception IllegalActionException If the specified type is not a
445     *   FunctionType or it does not have the same structure as this one.
446     */
447    @Override
448    public void updateType(StructuredType newType)
449            throws IllegalActionException {
450        if (this.isConstant()) {
451            if (this.equals(newType)) {
452                return;
453            } else {
454                throw new IllegalActionException("FunctionType.updateType: "
455                        + "This type is a constant and the argument is not the"
456                        + " same as this type. This type: " + this.toString()
457                        + " argument: " + newType.toString());
458            }
459        }
460
461        // This type is a variable.
462        if (!this.isSubstitutionInstance(newType)) {
463            throw new IllegalActionException("FunctionType.updateType: "
464                    + "Cannot update this type to the new type.");
465        }
466
467        // Loop through all of the fields of this type...
468        for (int i = 0; i < getArgCount(); i++) {
469            FieldTypeTerm argTypeTerm = getArgTypeTerm(i);
470
471            if (argTypeTerm.isSettable()) {
472                Type newArgType = ((FunctionType) newType).getArgType(i);
473                argTypeTerm.setValue(newArgType);
474            }
475        }
476
477        if (_returnTypeTerm.isSettable()) {
478            _returnTypeTerm.setValue(((FunctionType) newType).getReturnType());
479        }
480    }
481
482    ///////////////////////////////////////////////////////////////////
483    ////                         protected methods                 ////
484
485    /** Compare this type with the specified type. The specified type
486     *  must be a FunctionType, otherwise an exception will be thrown.
487     *
488     *  This method returns one of ptolemy.graph.CPO.LOWER,
489     *  ptolemy.graph.CPO.SAME, ptolemy.graph.CPO.HIGHER,
490     *  ptolemy.graph.CPO.INCOMPARABLE, indicating this type is lower
491     *  than, equal to, higher than, or incomparable with the
492     *  specified type in the type hierarchy, respectively.
493     *  @param type a FunctionType.
494     *  @return An integer.
495     *  @exception IllegalArgumentException If the specified type is
496     *   not a FunctionType.
497     */
498    @Override
499    protected int _compare(StructuredType type) {
500        if (!(type instanceof FunctionType)) {
501            throw new IllegalArgumentException("FunctionType.compare: "
502                    + "The argument is not a FunctionType.");
503        }
504
505        if (this.equals(type)) {
506            return CPO.SAME;
507        }
508
509        if (_isLessThanOrEqualTo(this, (FunctionType) type)) {
510            return CPO.LOWER;
511        }
512
513        if (_isLessThanOrEqualTo((FunctionType) type, this)) {
514            return CPO.HIGHER;
515        }
516
517        return CPO.INCOMPARABLE;
518    }
519
520    /** Return a static instance of FunctionType.
521     *  @return a FunctionType.
522     */
523    @Override
524    protected StructuredType _getRepresentative() {
525        return _representative;
526    }
527
528    /** Return the greatest lower bound of this type with the specified
529     *  type. The specified type must be a FunctionType, otherwise an
530     *  exception will be thrown.
531     *  @param type a FunctionType.
532     *  @return a FunctionType.
533     *  @exception IllegalArgumentException If the specified type is
534     *   not a FunctionType.
535     */
536    @Override
537    protected StructuredType _greatestLowerBound(StructuredType type) {
538        if (!(type instanceof FunctionType)) {
539            throw new IllegalArgumentException(
540                    "FunctionType.greatestLowerBound: The argument is not a "
541                            + "FunctionType.");
542        }
543
544        FunctionType functionType = (FunctionType) type;
545
546        // construct the GLB FunctionToken
547        int argCount = getArgCount();
548
549        if (functionType.getArgCount() != argCount) {
550            throw new IllegalArgumentException(
551                    "Types are not comparable because they have"
552                            + " different numbers of arguments");
553        }
554
555        Type[] types = new Type[argCount];
556
557        for (int i = 0; i < argCount; i++) {
558            Type type1 = getArgType(i);
559            Type type2 = functionType.getArgType(i);
560
561            if (type1 == null) {
562                types[i] = type2;
563            } else if (type2 == null) {
564                types[i] = type1;
565            } else {
566                types[i] = (Type) TypeLattice.lattice()
567                        .greatestLowerBound(type1, type2);
568            }
569        }
570
571        Type returnType = (Type) TypeLattice.lattice().greatestLowerBound(
572                getReturnType(), functionType.getReturnType());
573
574        return new FunctionType(types, returnType);
575    }
576
577    /** Return the least upper bound of this type with the specified
578     *  type. The specified type must be a FunctionType, otherwise an
579     *  exception will be thrown.
580     *  @param type a FunctionType.
581     *  @return a FunctionType.
582     *  @exception IllegalArgumentException If the specified type is
583     *   not a FunctionType.
584     */
585    @Override
586    protected StructuredType _leastUpperBound(StructuredType type) {
587        if (!(type instanceof FunctionType)) {
588            throw new IllegalArgumentException("FunctionType.leastUpperBound: "
589                    + "The argument is not a FunctionType.");
590        }
591
592        FunctionType functionType = (FunctionType) type;
593
594        // construct the LUB FunctionToken
595        int argCount = getArgCount();
596
597        if (functionType.getArgCount() != argCount) {
598            throw new IllegalArgumentException(
599                    "Types are not comparable because they have"
600                            + " different numbers of arguments");
601        }
602
603        Type[] types = new Type[argCount];
604
605        for (int i = 0; i < argCount; i++) {
606            Type type1 = getArgType(i);
607            Type type2 = functionType.getArgType(i);
608
609            if (type1 == null) {
610                types[i] = type2;
611            } else if (type2 == null) {
612                types[i] = type1;
613            } else {
614                types[i] = (Type) TypeLattice.lattice().leastUpperBound(type1,
615                        type2);
616            }
617        }
618
619        Type returnType = (Type) TypeLattice.lattice()
620                .leastUpperBound(getReturnType(), functionType.getReturnType());
621
622        return new FunctionType(types, returnType);
623    }
624
625    ///////////////////////////////////////////////////////////////////
626    ////                         private methods                   ////
627    // Test if the first FunctionType is less than or equal to the second
628    private boolean _isLessThanOrEqualTo(FunctionType t1, FunctionType t2) {
629        // construct the LUB FunctionToken
630        int argCount = t1.getArgCount();
631
632        if (t2.getArgCount() != argCount) {
633            return false;
634        }
635
636        // iterate over the labels of the second type
637        for (int i = 0; i < argCount; i++) {
638            Type type1 = t1.getArgType(i);
639            Type type2 = t2.getArgType(i);
640            int result = TypeLattice.compare(type1, type2);
641
642            if (result == CPO.HIGHER || result == CPO.INCOMPARABLE) {
643                return false;
644            }
645        }
646
647        return true;
648    }
649
650    ///////////////////////////////////////////////////////////////////
651    ////                         private variables                 ////
652    // Mapping from label to field information.
653    private FieldTypeTerm[] _argTypeTerms;
654
655    private FieldTypeTerm _returnTypeTerm;
656
657    // the representative in the type lattice is the empty function.
658    private static FunctionType _representative = new FunctionType(new Type[0],
659            BaseType.UNKNOWN);
660
661    ///////////////////////////////////////////////////////////////////
662    ////                         inner class                       ////
663    // A class that encapsulates the declared and resolved types of a
664    // field and implements the InequalityTerm interface.
665    private class FieldTypeTerm implements InequalityTerm {
666        // Construct an instance of FieldTypeTerm.
667        private FieldTypeTerm(Type declaredType) {
668            try {
669                _declaredType = (Type) declaredType.clone();
670                _resolvedType = _declaredType;
671            } catch (CloneNotSupportedException cnse) {
672                throw new InternalErrorException("FunctionType.FieldTypeTerm: "
673                        + "The specified type cannot be cloned.");
674            }
675        }
676
677        ///////////////////////////////////////////////////////////////
678        ////                   public inner methods                ////
679
680        /** Determine if the argument represents the same FieldTypeTerm as
681         *  this object.  Two field type terms are equal if they have the same
682         *  resolved type.
683         *  @param object Another object.
684         *  @return True if the argument represents the same FieldTypeTerm as
685         *  this object.
686         */
687        @Override
688        public boolean equals(Object object) {
689            // See http://www.technofundo.com/tech/java/equalhash.html
690            if (object == this) {
691                return true;
692            }
693            if (object == null || object.getClass() != getClass()) {
694                return false;
695            } else {
696                FieldTypeTerm fieldTypeTerm = (FieldTypeTerm) object;
697                if (fieldTypeTerm.getValue().equals(getValue())) {
698                    return true;
699                }
700            }
701            return false;
702        }
703
704        /** Return this FunctionType.
705         *  @return a FunctionType.
706         */
707        @Override
708        public Object getAssociatedObject() {
709            return FunctionType.this;
710        }
711
712        /** Return the resolved type.
713         *  @return a Type.
714         */
715        @Override
716        public Object getValue() {
717            return _resolvedType;
718        }
719
720        /** Return this FieldTypeTerm in an array if it represents a type
721         *  variable. Otherwise, return an array of size zero.
722         *  @return An array of InequalityTerm.
723         */
724        @Override
725        public InequalityTerm[] getVariables() {
726            if (isSettable()) {
727                InequalityTerm[] variable = new InequalityTerm[1];
728                variable[0] = this;
729                return variable;
730            }
731
732            return new InequalityTerm[0];
733        }
734
735        /** Return a hash code value for this object.
736         *  @return The hash code value for this object.
737         */
738        @Override
739        public int hashCode() {
740            // See http://www.technofundo.com/tech/java/equalhash.html
741            // This class needed equals() and hashCode() to solve a memory
742            // leak.  See
743            // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=5576
744            int hashCode = 9;
745            if (_resolvedType != null) {
746                hashCode = 31 * hashCode + _resolvedType.hashCode();
747            }
748            return hashCode;
749        }
750
751        /** Reset the variable part of the element type to the specified
752         *  type.
753         *  @param e A Type.
754         *  @exception IllegalActionException If this type is not settable,
755         *   or the argument is not a Type.
756         */
757        @Override
758        public void initialize(Object e) throws IllegalActionException {
759            if (!isSettable()) {
760                throw new IllegalActionException("FunctionType$FieldTypeTerm."
761                        + "initialize: The type is not settable.");
762            }
763
764            if (!(e instanceof Type)) {
765                throw new IllegalActionException("FieldTypeTerm.initialize: "
766                        + "The argument is not a Type.");
767            }
768
769            if (_declaredType == BaseType.UNKNOWN) {
770                _resolvedType = (Type) e;
771            } else {
772                // this field type is a structured type.
773                ((StructuredType) _resolvedType).initialize((Type) e);
774            }
775        }
776
777        /** Test if this field type is a type variable.
778         *  @return True if this field type is a type variable.
779         */
780        @Override
781        public boolean isSettable() {
782            return !_declaredType.isConstant();
783        }
784
785        /** Check whether the current element type is acceptable.
786         *  The element type is acceptable if it represents an
787         *  instantiable object.
788         *  @return True if the element type is acceptable.
789         */
790        @Override
791        public boolean isValueAcceptable() {
792            return _resolvedType.isInstantiable();
793        }
794
795        /** Set the element type to the specified type.
796         *  @param e a Type.
797         *  @exception IllegalActionException If the specified type violates
798         *   the declared field type.
799         */
800        @Override
801        public void setValue(Object e) throws IllegalActionException {
802            if (!isSettable()) {
803                throw new IllegalActionException(
804                        "FunctionType$FieldTypeTerm.setValue: The type is not "
805                                + "settable.");
806            }
807
808            if (!_declaredType.isSubstitutionInstance((Type) e)) {
809                throw new IllegalActionException("FieldTypeTerm.setValue: "
810                        + "Cannot update the field type of this FunctionType "
811                        + "to the new type." + " Field type: "
812                        + _declaredType.toString() + ", New type: "
813                        + e.toString());
814            }
815
816            if (_declaredType == BaseType.UNKNOWN) {
817                try {
818                    _resolvedType = (Type) ((Type) e).clone();
819                } catch (CloneNotSupportedException cnse) {
820                    throw new InternalErrorException(
821                            "FunctionType$FieldTypeTerm.setValue: "
822                                    + "The specified type cannot be cloned.");
823                }
824            } else {
825                ((StructuredType) _resolvedType).updateType((StructuredType) e);
826            }
827        }
828
829        /** Return a string representation of this term.
830         *  @return A String.
831         */
832        @Override
833        public String toString() {
834            return "(FunctionFieldTypeTerm, " + getValue() + ")";
835        }
836
837        ///////////////////////////////////////////////////////////////
838        ////                  private inner variables              ////
839        private Type _declaredType = null;
840
841        private Type _resolvedType = null;
842    }
843}