001/** A class representing the type of a UnionToken. 002 003 Copyright (c) 2006-2015 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 java.util.HashMap; 030import java.util.HashSet; 031import java.util.Iterator; 032import java.util.Map; 033import java.util.Set; 034 035import ptolemy.data.Token; 036import ptolemy.data.UnionToken; 037import ptolemy.graph.CPO; 038import ptolemy.graph.InequalityTerm; 039import ptolemy.kernel.util.IllegalActionException; 040import ptolemy.kernel.util.InternalErrorException; 041 042/////////////////////////////////////////////////////////////////// 043//// UnionType 044 045/** 046 A class representing the type of a UnionToken. 047 To set the type of a typeable object (such as a port or parameter) 048 to a union with particular fields, create an instance of this 049 class and call setTypeEquals() with that instance as an argument. 050 <p> 051 The depth subtyping is similar to that of <code>RecordTypes</code>. However, 052 the width subtyping for <code>UnionType</code> is opposite compared to 053 <code>RecordType</code> i.e., a <code>UnionType</code> with more fields 054 is a supertype of a <code>UnionType</code> with a subset of the fields. 055 For example, {|x = double, y = int} is a supertype of {|x = double}. 056 057 @author Yuhong Xiong, Elaine Cheong and Steve Neuendorffer 058 @version $Id$ 059 @since Ptolemy II 5.2 060 @Pt.ProposedRating Red (yuhongx) 061 @Pt.AcceptedRating Red (cxh) 062 */ 063public class UnionType extends AssociativeType implements Cloneable { 064 /** Construct a new UnionType with the specified labels and types. 065 * To leave the types of some fields undeclared, use BaseType.UNKNOWN. 066 * The labels and the types are specified in two arrays. These two 067 * arrays must have the same length, and their elements have one to 068 * one correspondence. That is, the i'th entry in the types array is 069 * the type for the i'th label in the labels array. To construct the 070 * empty record type, set the length of the argument arrays to 0. 071 * @param labels An array of String. 072 * @param types An array of Type. 073 * @exception IllegalArgumentException If the two arrays do not have 074 * the same size. 075 * @exception NullPointerException If one of the arguments is null. 076 */ 077 public UnionType(String[] labels, Type[] types) { 078 if (labels.length != types.length) { 079 throw new IllegalArgumentException("UnionType: the labels " 080 + "and types arrays do not have the same size."); 081 } 082 083 for (int i = 0; i < labels.length; i++) { 084 FieldType fieldType = new FieldType(types[i]); 085 _fields.put(labels[i], fieldType); 086 } 087 } 088 089 /////////////////////////////////////////////////////////////////// 090 //// public methods //// 091 092 /** Return a deep copy of this UnionType if it is a variable, or 093 * itself if it is a constant. 094 * @return A UnionType. 095 */ 096 @Override 097 public Object clone() { 098 if (isConstant()) { 099 return this; 100 } 101 102 // empty union is a constant, so this record type is not empty. 103 // construct the labels and declared types array 104 Object[] labelsObj = _fields.keySet().toArray(); 105 String[] labels = new String[labelsObj.length]; 106 Type[] types = new Type[labelsObj.length]; 107 108 for (int i = 0; i < labels.length; i++) { 109 labels[i] = (String) labelsObj[i]; 110 111 FieldType fieldType = _fields.get(labels[i]); 112 types[i] = fieldType._declaredType; 113 } 114 115 UnionType newObj = new UnionType(labels, types); 116 117 try { 118 newObj.updateType(this); 119 } catch (IllegalActionException ex) { 120 throw new InternalErrorException("UnionType.clone: Cannot " 121 + "update new instance. " + ex.getMessage()); 122 } 123 124 return newObj; 125 } 126 127 /** Convert the argument token into a UnionToken having this 128 * type, if lossless conversion can be done. The argument must 129 * be a UnionToken, and its type must be a subtype of this 130 * record type. The argument token must have at least the fields 131 * of this type. Extra fields in the argument token that are not 132 * in this type are removed. 133 * @param token A token. 134 * @return An UnionToken. 135 * @exception IllegalActionException If lossless conversion 136 * cannot be done. 137 */ 138 @Override 139 public Token convert(Token token) throws IllegalActionException { 140 if (!isCompatible(token.getType())) { 141 throw new IllegalArgumentException(Token 142 .notSupportedConversionMessage(token, this.toString())); 143 } 144 145 UnionToken unionToken = (UnionToken) token; 146 147 // The converted token has the same label as this one. 148 String label = unionToken.label(); 149 Type newType = get(label); 150 Token newValue = newType.convert(unionToken.value()); 151 return new UnionToken(label, newValue); 152 } 153 154 /** Return the depth of a union type. The depth of a 155 * union type is the number of times it 156 * contains other structured types. 157 * @return the depth of a union type. 158 */ 159 @Override 160 public int depth() { 161 Object[] labelsObj = _fields.keySet().toArray(); 162 String[] labels = new String[labelsObj.length]; 163 int[] depth = new int[labelsObj.length]; 164 int maxDepth = 1; 165 for (int i = 0; i < labels.length; i++) { 166 labels[i] = (String) labelsObj[i]; 167 Type fieldType = get(labels[i]); 168 depth[i] = 1; 169 if (fieldType instanceof StructuredType) { 170 depth[i] += ((StructuredType) fieldType).depth(); 171 } 172 if (depth[i] > maxDepth) { 173 maxDepth = depth[i]; 174 } 175 } 176 return maxDepth; 177 } 178 179 /** Determine if the argument represents the same UnionType as this 180 * object. Two record types are equal if they have the same field names 181 * and the type of each field is the same. 182 * @param object Another object. 183 * @return True if the argument represents the same UnionType as 184 * this object. 185 */ 186 @Override 187 public boolean equals(Object object) { 188 if (!(object instanceof UnionType)) { 189 return false; 190 } 191 192 UnionType unionType = (UnionType) object; 193 194 // Check that the label sets are equal 195 Set myLabelSet = _fields.keySet(); 196 Set argLabelSet = unionType._fields.keySet(); 197 198 if (!myLabelSet.equals(argLabelSet)) { 199 return false; 200 } 201 202 Iterator fieldNames = myLabelSet.iterator(); 203 204 while (fieldNames.hasNext()) { 205 String label = (String) fieldNames.next(); 206 Type myType = this.get(label); 207 Type argType = unionType.get(label); 208 209 if (!myType.equals(argType)) { 210 return false; 211 } 212 } 213 214 return true; 215 } 216 217 /** Return the type of the specified label. If this type does not 218 * contain the specified label, return null. 219 * @param label The specified label. 220 * @return a Type. 221 */ 222 @Override 223 public Type get(String label) { 224 FieldType fieldType = _fields.get(label); 225 226 if (fieldType == null) { 227 return null; 228 } 229 230 return fieldType._resolvedType; 231 } 232 233 /** Return the class for tokens that this type represents. 234 * @return The class for tokens that this type represents. 235 */ 236 @Override 237 public Class getTokenClass() { 238 return UnionToken.class; 239 } 240 241 /** Return the InequalityTerm representing the type of the specified 242 * label. 243 * @param label The specified label. 244 * @return An InequalityTerm. 245 * @see ptolemy.graph.InequalityTerm 246 */ 247 public InequalityTerm getTypeTerm(String label) { 248 return _fields.get(label); 249 } 250 251 /** Return a hash code value for this object. 252 */ 253 @Override 254 public int hashCode() { 255 return _fields.keySet().hashCode() + 2917; 256 } 257 258 /** Set the elements that have declared type BaseType.UNKNOWN (the leaf 259 * type variable) to the specified type. 260 * @param type the type to set the leaf type variable to. 261 */ 262 @Override 263 public void initialize(Type type) { 264 try { 265 for (Map.Entry<String, FieldType> fields : _fields.entrySet()) { 266 FieldType fieldType = fields.getValue(); 267 if (fieldType.isSettable()) { 268 fieldType.initialize(type); 269 } 270 } 271 } catch (IllegalActionException iae) { 272 throw new InternalErrorException("UnionType.initialize: Cannot " 273 + "initialize the element type to " + type + " " 274 + iae.getMessage()); 275 } 276 } 277 278 /** Test if this type corresponds to an abstract token 279 * class. A UnionType is abstract if any field is abstract 280 * @return True if this type is instantiable. 281 */ 282 @Override 283 public boolean isAbstract() { 284 // Loop through all of the fields. 285 Iterator fieldNames = _fields.keySet().iterator(); 286 287 while (fieldNames.hasNext()) { 288 String label = (String) fieldNames.next(); 289 Type type = this.get(label); 290 291 // Return false if the field is not instantiable. 292 if (type.isAbstract()) { 293 return true; 294 } 295 } 296 297 return false; 298 } 299 300 /** Test if the argument type is compatible with this type. The 301 * given type will be compatible with this type if it is 302 * BaseType.UNKNOWN, or a UnionType that contains at most as 303 * many fields. 304 * @param type An instance of Type. 305 * @return True if the argument is compatible with this type. 306 */ 307 @Override 308 public boolean isCompatible(Type type) { 309 if (type.equals(BaseType.UNKNOWN)) { 310 return true; 311 } 312 313 if (!(type instanceof UnionType)) { 314 return false; 315 } 316 317 UnionType argumentUnionType = (UnionType) type; 318 319 // Loop through all of the fields of argument type... 320 Iterator iterator = argumentUnionType.labelSet().iterator(); 321 322 while (iterator.hasNext()) { 323 String label = (String) iterator.next(); 324 325 // The given type cannot be losslessly converted to this type 326 // if it contains extra fields 327 Type myFieldType = this.get(label); 328 329 if (myFieldType == null) { 330 // This token does not contain a label in the argument 331 return false; 332 } 333 334 // The given type cannot be losslessly converted to this type 335 // if the individual fields are not compatible. 336 Type argumentFieldType = argumentUnionType.get(label); 337 338 if (!myFieldType.isCompatible(argumentFieldType)) { 339 return false; 340 } 341 } 342 343 return true; 344 } 345 346 /** Test if this UnionType is a constant. A UnionType is a constant if 347 * the declared type of all of its fields are constant. 348 * @return True if this type is a constant. 349 */ 350 @Override 351 public boolean isConstant() { 352 // Loop through all of the fields. 353 Iterator fieldTypes = _fields.values().iterator(); 354 355 while (fieldTypes.hasNext()) { 356 FieldType fieldType = (FieldType) fieldTypes.next(); 357 Type type = fieldType._declaredType; 358 359 // Return false if the field is not constant. 360 if (!type.isConstant()) { 361 return false; 362 } 363 } 364 365 return true; 366 } 367 368 /** Test if this type corresponds to an instantiable token 369 * class. A UnionType is instantiable if all of its fields are 370 * instantiable. 371 * @return True if this type is instantiable. 372 */ 373 @Override 374 public boolean isInstantiable() { 375 // Loop through all of the fields. 376 Iterator fieldNames = _fields.keySet().iterator(); 377 378 while (fieldNames.hasNext()) { 379 String label = (String) fieldNames.next(); 380 Type type = this.get(label); 381 382 // Return false if the field is not instantiable. 383 if (!type.isInstantiable()) { 384 return false; 385 } 386 } 387 388 return true; 389 } 390 391 /** Test if the specified type is a substitution instance of this 392 * type. One union is a substitution instance of another if they 393 * have fields with the same names and each field of the given type is 394 * a substitution instance of the corresponding field in this type. 395 * @param type A Type. 396 * @return True if the argument is a substitution instance of this type. 397 * @see Type#isSubstitutionInstance 398 */ 399 @Override 400 public boolean isSubstitutionInstance(Type type) { 401 if (!(type instanceof UnionType)) { 402 return false; 403 } 404 405 UnionType unionType = (UnionType) type; 406 407 // Check if this union type and the argument have the same 408 // label set. 409 Set myLabelSet = _fields.keySet(); 410 Set argLabelSet = unionType._fields.keySet(); 411 412 if (!myLabelSet.equals(argLabelSet)) { 413 return false; 414 } 415 416 // Loop over all the labels. 417 for (Map.Entry<String, FieldType> fields : _fields.entrySet()) { 418 FieldType fieldType = fields.getValue(); 419 420 Type myDeclaredType = fieldType._declaredType; 421 Type argType = unionType.get(fields.getKey()); 422 423 if (!myDeclaredType.isSubstitutionInstance(argType)) { 424 return false; 425 } 426 } 427 428 return true; 429 } 430 431 /** Return the labels of this record type as a Set. 432 * @return A Set containing strings. 433 */ 434 public Set labelSet() { 435 return _fields.keySet(); 436 } 437 438 /** Return the string representation of this type. The format is 439 * {|<i>label</i> = <i>type</i>, <i>label</i> = <i>type</i>, ...|}. 440 * The record fields are listed in the lexicographical order of the 441 * labels determined by the java.lang.String.compareTo() method. 442 * @return A String. 443 */ 444 @Override 445 public String toString() { 446 Object[] labelArray = _fields.keySet().toArray(); 447 448 // Order the labels 449 int size = labelArray.length; 450 451 for (int i = 0; i < size - 1; i++) { 452 for (int j = i + 1; j < size; j++) { 453 String labeli = (String) labelArray[i]; 454 String labelj = (String) labelArray[j]; 455 456 if (labeli.compareTo(labelj) >= 0) { 457 Object temp = labelArray[i]; 458 labelArray[i] = labelArray[j]; 459 labelArray[j] = temp; 460 } 461 } 462 } 463 464 // construct the string representation of this token. 465 StringBuffer results = new StringBuffer("{|"); 466 467 for (int i = 0; i < size; i++) { 468 String label = (String) labelArray[i]; 469 String type = this.get(label).toString(); 470 471 if (i != 0) { 472 results.append(", "); 473 } 474 475 results.append(label + " = " + type); 476 } 477 478 return results.toString() + "|}"; 479 } 480 481 /** Update this Type to the specified UnionType. 482 * The specified type must be a UnionType and have the same structure 483 * as this one. 484 * This method will only update the component whose declared type is 485 * BaseType.UNKNOWN, and leave the constant part of this type intact. 486 * @param newType A StructuredType. 487 * @exception IllegalActionException If the specified type is not a 488 * UnionType or it does not have the same structure as this one. 489 */ 490 @Override 491 public void updateType(StructuredType newType) 492 throws IllegalActionException { 493 if (this.isConstant()) { 494 if (this.equals(newType)) { 495 return; 496 } 497 498 throw new IllegalActionException("UnionType.updateType: " 499 + "This type is a constant and the argument is not the" 500 + " same as this type. This type: " + this.toString() 501 + " argument: " + newType.toString()); 502 } 503 504 // This type is a variable. 505 if (!this.isSubstitutionInstance(newType)) { 506 throw new IllegalActionException("UnionType.updateType: " 507 + "Cannot update this type to the new type."); 508 } 509 510 for (Map.Entry<String, FieldType> fields : _fields.entrySet()) { 511 FieldType fieldType = fields.getValue(); 512 if (fieldType.isSettable()) { 513 //Type newFieldType = ((UnionType) newType).get(label); 514 Type newFieldType = ((UnionType) newType).get(fields.getKey()); 515 fieldType.setValue(newFieldType); 516 } 517 } 518 } 519 520 /////////////////////////////////////////////////////////////////// 521 //// protected methods //// 522 523 /** Compare this type with the specified type. The specified type 524 * must be a UnionType, otherwise an exception will be thrown. 525 * 526 * This method returns one of ptolemy.graph.CPO.LOWER, 527 * ptolemy.graph.CPO.SAME, ptolemy.graph.CPO.HIGHER, 528 * ptolemy.graph.CPO.INCOMPARABLE, indicating this type is lower 529 * than, equal to, higher than, or incomparable with the 530 * specified type in the type hierarchy, respectively. 531 * @param type a UnionType. 532 * @return An integer. 533 * @exception IllegalArgumentException If the specified type is 534 * not a UnionType. 535 */ 536 @Override 537 protected int _compare(StructuredType type) { 538 if (!(type instanceof UnionType)) { 539 throw new IllegalArgumentException("UnionType._compare: " 540 + "The argument is not a UnionType."); 541 } 542 543 if (this.equals(type)) { 544 return CPO.SAME; 545 } 546 547 if (_isLessThanOrEqualTo(this, (UnionType) type)) { 548 return CPO.LOWER; 549 } 550 551 if (_isLessThanOrEqualTo((UnionType) type, this)) { 552 return CPO.HIGHER; 553 } 554 555 return CPO.INCOMPARABLE; 556 } 557 558 /** Return a static instance of RecordType. 559 * @return a UnionType. 560 */ 561 @Override 562 protected StructuredType _getRepresentative() { 563 return _representative; 564 } 565 566 /** Return the greatest lower bound of this type with the specified 567 * type. The specified type must be a UnionType, otherwise an 568 * exception will be thrown. 569 * @param type a UnionType. 570 * @return a UnionType. 571 * @exception IllegalArgumentException If the specified type is 572 * not a UnionType. 573 */ 574 @Override 575 protected StructuredType _greatestLowerBound(StructuredType type) { 576 if (!(type instanceof UnionType)) { 577 throw new IllegalArgumentException( 578 "UnionType.greatestLowerBound: The argument is not a " 579 + "UnionType."); 580 } 581 582 UnionType unionType = (UnionType) type; 583 584 // the label set of the GLB is the intersection of the two label sets. 585 Set intersectionSet = new HashSet(); 586 Set myLabelSet = _fields.keySet(); 587 Set argLabelSet = unionType._fields.keySet(); 588 589 intersectionSet.addAll(myLabelSet); 590 intersectionSet.retainAll(argLabelSet); 591 592 // construct the GLB UnionToken 593 Object[] labelArray = intersectionSet.toArray(); 594 int size = labelArray.length; 595 String[] labels = new String[size]; 596 Type[] types = new Type[size]; 597 598 for (int i = 0; i < size; i++) { 599 labels[i] = (String) labelArray[i]; 600 601 Type type1 = this.get(labels[i]); 602 Type type2 = unionType.get(labels[i]); 603 types[i] = (Type) TypeLattice.lattice().greatestLowerBound(type1, 604 type2); 605 } 606 607 return new UnionType(labels, types); 608 } 609 610 /** Return the least Upper bound of this type with the specified 611 * type. The specified type must be a UnionType, otherwise an 612 * exception will be thrown. 613 * @param type a UnionType. 614 * @return a UnionType. 615 * @exception IllegalArgumentException If the specified type is 616 * not a UnionType. 617 */ 618 @Override 619 protected StructuredType _leastUpperBound(StructuredType type) { 620 if (!(type instanceof UnionType)) { 621 throw new IllegalArgumentException("UnionType.leastUpperBound: " 622 + "The argument is not a UnionType."); 623 } 624 625 UnionType unionType = (UnionType) type; 626 627 // the label set of the LUB is the union of the two label sets. 628 Set unionSet = new HashSet(); 629 Set myLabelSet = _fields.keySet(); 630 Set argLabelSet = unionType._fields.keySet(); 631 632 unionSet.addAll(myLabelSet); 633 unionSet.addAll(argLabelSet); 634 635 // construct the GLB UnionToken 636 Object[] labelArray = unionSet.toArray(); 637 int size = labelArray.length; 638 String[] labels = new String[size]; 639 Type[] types = new Type[size]; 640 641 for (int i = 0; i < size; i++) { 642 labels[i] = (String) labelArray[i]; 643 644 Type type1 = this.get(labels[i]); 645 Type type2 = unionType.get(labels[i]); 646 647 if (type1 == null) { 648 types[i] = type2; 649 } else if (type2 == null) { 650 types[i] = type1; 651 } else { 652 types[i] = (Type) TypeLattice.lattice().leastUpperBound(type1, 653 type2); 654 } 655 } 656 657 return new UnionType(labels, types); 658 } 659 660 /////////////////////////////////////////////////////////////////// 661 //// private methods //// 662 // Test if the first UnionType is less than or equal to the second 663 private boolean _isLessThanOrEqualTo(UnionType t1, UnionType t2) { 664 Set labelSet1 = t1._fields.keySet(); 665 Set labelSet2 = t2._fields.keySet(); 666 667 if (!labelSet2.containsAll(labelSet1)) { 668 return false; 669 } 670 671 // iterate over the labels of the first type 672 Iterator iter = labelSet1.iterator(); 673 674 while (iter.hasNext()) { 675 String label = (String) iter.next(); 676 Type type1 = t1.get(label); 677 Type type2 = t2.get(label); 678 int result = TypeLattice.compare(type1, type2); 679 680 if (result == CPO.HIGHER || result == CPO.INCOMPARABLE) { 681 return false; 682 } 683 } 684 685 return true; 686 } 687 688 /////////////////////////////////////////////////////////////////// 689 //// private variables //// 690 // Mapping from label to field information. 691 private Map<String, FieldType> _fields = new HashMap<String, FieldType>(); 692 693 // the representative in the type lattice is the empty record. 694 private static UnionType _representative = new UnionType(new String[0], 695 new Type[0]); 696 697 /////////////////////////////////////////////////////////////////// 698 //// inner class //// 699 // A class that encapsulates the declared and resolved types of a 700 // field and implements the InequalityTerm interface. 701 private class FieldType implements InequalityTerm { 702 // Construct an instance of FieldType. 703 private FieldType(Type declaredType) { 704 try { 705 _declaredType = (Type) declaredType.clone(); 706 _resolvedType = _declaredType; 707 } catch (CloneNotSupportedException cnse) { 708 throw new InternalErrorException("UnionType.FieldType: " 709 + "The specified type cannot be cloned."); 710 } 711 } 712 713 /////////////////////////////////////////////////////////////// 714 //// public inner methods //// 715 716 /** Return this UnionType. 717 * @return a UnionType. 718 */ 719 @Override 720 public Object getAssociatedObject() { 721 return UnionType.this; 722 } 723 724 /** Return the resolved type. 725 * @return a Type. 726 */ 727 @Override 728 public Object getValue() { 729 return _resolvedType; 730 } 731 732 /** Return this FieldType in an array if it represents a type 733 * variable. Otherwise, return an array of size zero. 734 * @return An array of InequalityTerm. 735 */ 736 @Override 737 public InequalityTerm[] getVariables() { 738 if (isSettable()) { 739 InequalityTerm[] variable = new InequalityTerm[1]; 740 variable[0] = this; 741 return variable; 742 } 743 744 return new InequalityTerm[0]; 745 } 746 747 /** Reset the variable part of the element type to the specified 748 * type. 749 * @param e A Type. 750 * @exception IllegalActionException If this type is not settable, 751 * or the argument is not a Type. 752 */ 753 @Override 754 public void initialize(Object e) throws IllegalActionException { 755 if (!isSettable()) { 756 throw new IllegalActionException("UnionType$FieldType." 757 + "initialize: The type is not settable."); 758 } 759 760 if (!(e instanceof Type)) { 761 throw new IllegalActionException("FieldType.initialize: " 762 + "The argument is not a Type."); 763 } 764 765 if (_declaredType == BaseType.UNKNOWN) { 766 _resolvedType = (Type) e; 767 } else { 768 // this field type is a structured type. 769 ((StructuredType) _resolvedType).initialize((Type) e); 770 } 771 } 772 773 /** Test if this field type is a type variable. 774 * @return True if this field type is a type variable. 775 */ 776 @Override 777 public boolean isSettable() { 778 return !_declaredType.isConstant(); 779 } 780 781 /** Check whether the current element type is acceptable. 782 * The element type is acceptable if it represents an 783 * instantiable object. 784 * @return True if the element type is acceptable. 785 */ 786 @Override 787 public boolean isValueAcceptable() { 788 return _resolvedType.isInstantiable(); 789 } 790 791 /** Set the element type to the specified type. 792 * @param e a Type. 793 * @exception IllegalActionException If the specified type violates 794 * the declared field type. 795 */ 796 @Override 797 public void setValue(Object e) throws IllegalActionException { 798 if (!isSettable()) { 799 throw new IllegalActionException( 800 "UnionType$FieldType.setValue: The type is not " 801 + "settable."); 802 } 803 804 if (!_declaredType.isSubstitutionInstance((Type) e)) { 805 throw new IllegalActionException("FieldType.setValue: " 806 + "Cannot update the field type of this UnionType " 807 + "to the new type." + " Field type: " 808 + _declaredType.toString() + ", New type: " 809 + e.toString()); 810 } 811 812 if (_declaredType == BaseType.UNKNOWN) { 813 try { 814 _resolvedType = (Type) ((Type) e).clone(); 815 } catch (CloneNotSupportedException cnse) { 816 throw new InternalErrorException( 817 "UnionType$FieldType.setValue: " 818 + "The specified type cannot be cloned."); 819 } 820 } else { 821 ((StructuredType) _resolvedType).updateType((StructuredType) e); 822 } 823 } 824 825 /** Return a string representation of this term. 826 * @return A String. 827 */ 828 @Override 829 public String toString() { 830 return "(UnionFieldType, " + getValue() + ")"; 831 } 832 833 /////////////////////////////////////////////////////////////// 834 //// private inner variables //// 835 private Type _declaredType = null; 836 837 private Type _resolvedType = null; 838 } 839}