< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java

Print this page
@@ -35,10 +35,11 @@
  import java.util.function.Predicate;
  
  import javax.lang.model.type.*;
  
  import com.sun.tools.javac.code.Symbol.*;
+ import com.sun.tools.javac.code.Type.ClassType.Flavor;
  import com.sun.tools.javac.code.TypeMetadata.Annotations;
  import com.sun.tools.javac.code.TypeMetadata.ConstantValue;
  import com.sun.tools.javac.code.Types.TypeMapping;
  import com.sun.tools.javac.code.Types.UniqueType;
  import com.sun.tools.javac.comp.Infer.IncorporationAction;

@@ -229,10 +230,79 @@
          Assert.checkNonNull(metadata);
          this.tsym = tsym;
          this.metadata = metadata;
      }
  
+     public boolean isPrimitiveClass() {
+         return false;
+     }
+ 
+     public boolean isValueClass() {
+         return false;
+     }
+ 
+     public boolean isValueInterface() {
+         return false;
+     }
+ 
+     public boolean isIdentityClass() {
+         return false;
+     }
+ 
+     public boolean isIdentityInterface() {
+         return false;
+     }
+ 
+     // Does this type need to be preloaded in the context of the referring class ??
+     public boolean requiresPreload(Symbol referringClass) {
+         if (this.tsym == referringClass)
+             return false; // pointless
+         if (this.isReferenceProjection())
+             return true;
+         return this.isValueClass() && !this.isPrimitiveClass();
+     }
+ 
+     /**
+      * Return the `flavor' associated with a ClassType.
+      * @see ClassType.Flavor
+      */
+     public Flavor getFlavor() {
+         throw new AssertionError("Unexpected call to getFlavor() on a Type that is not a ClassType: " + this);
+     }
+ 
+     /**
+      * @return true IFF the receiver is a reference projection of a primitive class type and false
+      * for primitives or plain references
+      */
+     public boolean isReferenceProjection() {
+         return false;
+     }
+ 
+     /**
+      * @return the value projection type IFF the receiver is a reference projection of a primitive class type
+      * and null otherwise
+      */
+     public Type valueProjection() {
+         return null;
+     }
+ 
+     /**
+      * @return the reference projection type IFF the receiver is a primitive class type
+      * and null otherwise
+      */
+     public Type referenceProjection() {
+         return null;
+     }
+ 
+     /**
+      * @return the reference projection type IFF the receiver is a primitive class type or self otherwise.
+      */
+     public Type referenceProjectionOrSelf() {
+         Type projection = referenceProjection();
+         return projection != null ? projection : this;
+     }
+ 
      /**
       * A subclass of {@link Types.TypeMapping} which applies a mapping recursively to the subterms
       * of a given type expression. This mapping returns the original type is no changes occurred
       * when recursively mapping the original type's subterms.
       */

@@ -243,11 +313,11 @@
              Type outer = t.getEnclosingType();
              Type outer1 = visit(outer, s);
              List<Type> typarams = t.getTypeArguments();
              List<Type> typarams1 = visit(typarams, s);
              if (outer1 == outer && typarams1 == typarams) return t;
-             else return new ClassType(outer1, typarams1, t.tsym, t.metadata) {
+             else return new ClassType(outer1, typarams1, t.tsym, t.metadata, t.getFlavor()) {
                  @Override
                  protected boolean needsStripping() {
                      return true;
                  }
              };

@@ -981,13 +1051,125 @@
          public <R, P> R accept(TypeVisitor<R, P> v, P p) {
              return v.visitWildcard(this, p);
          }
      }
  
+     public static class ConstantPoolQType implements PoolConstant {
+ 
+         public final Type type;
+         final Types types;
+ 
+         public ConstantPoolQType(Type type, Types types) {
+             this.type = type;
+             this.types = types;
+         }
+ 
+         @Override
+         public Object poolKey(Types types) {
+             return this;
+         }
+ 
+         @Override
+         public int poolTag() {
+             return ClassFile.CONSTANT_Class;
+         }
+ 
+         public int hashCode() {
+             return types.hashCode(type);
+         }
+ 
+         public boolean equals(Object obj) {
+             return (obj instanceof ConstantPoolQType) &&
+                     types.isSameType(type, ((ConstantPoolQType)obj).type);
+         }
+ 
+         public String toString() {
+             return type.toString();
+         }
+     }
+ 
      public static class ClassType extends Type implements DeclaredType, LoadableConstant,
                                                            javax.lang.model.type.ErrorType {
  
+         /**
+          * The 'flavor' of a ClassType indicates its reference/primitive projectionness
+          * viewed against the default nature of the associated class.
+          */
+         public enum Flavor {
+ 
+             /**
+              * Classic reference type. Also reference projection type of a reference-favoring aka
+              * reference-default primitive class type
+              */
+             L_TypeOf_L,
+ 
+             /**
+              * Reference projection type of a primitive-favoring aka primitive-default
+              * plain vanilla primitive class type,
+              */
+             L_TypeOf_Q,
+ 
+             /**
+              * Value projection type of a primitive-favoring aka primitive-default
+              * plain vanilla primitive class type,
+              */
+             Q_TypeOf_Q,
+ 
+             /**
+              * Value projection type of a reference-favoring aka
+              * reference-default primitive class type
+              */
+             Q_TypeOf_L,
+ 
+             /**
+              * Reference projection type of a class type of an as yet unknown default provenance, 'X' will be
+              * discovered to be 'L' or 'Q' in "due course" and mutated suitably.
+              */
+             L_TypeOf_X,
+ 
+             /**
+              * Value projection type of a class type of an as yet unknown default provenance, 'X' will be
+              * discovered to be 'L' or 'Q' in "due course" and mutated suitably.
+              */
+             Q_TypeOf_X,
+ 
+             /**
+              *  As yet unknown projection type of an as yet unknown default provenance class.
+              */
+             X_Typeof_X,
+ 
+             /**
+              *  An error type - we don't care to discriminate them any further.
+              */
+              E_Typeof_X;
+ 
+             // We don't seem to need X_Typeof_L or X_Typeof_Q so far.
+ 
+             // Transform a larval form into a more evolved form
+             public Flavor metamorphose(boolean isPrimtiveClass) {
+ 
+                 switch (this) {
+ 
+                     case E_Typeof_X:  // stunted form
+                     case L_TypeOf_L:
+                     case L_TypeOf_Q:
+                     case Q_TypeOf_L:
+                     case Q_TypeOf_Q:
+                             // These are fully evolved sealed forms or stunted - no futher transformation
+                             return this;
+                     case L_TypeOf_X:
+                             return isPrimtiveClass ? L_TypeOf_Q : L_TypeOf_L;
+                     case Q_TypeOf_X:
+                             return isPrimtiveClass ? Q_TypeOf_Q : Q_TypeOf_L;
+                     case X_Typeof_X:
+                             return isPrimtiveClass ? Q_TypeOf_Q : L_TypeOf_L;
+                     default:
+                             throw new AssertionError("Unexpected class type flavor");
+                 }
+             }
+         }
+ 
          /** The enclosing type of this type. If this is the type of an inner
           *  class, outer_field refers to the type of its enclosing
           *  instance class, in all other cases it refers to noType.
           */
          private Type outer_field;

@@ -1012,31 +1194,49 @@
  
          /** All the interfaces of this class, including missing ones.
           */
          public List<Type> all_interfaces_field;
  
+         /** The 'other' projection: If 'this' is type of a primitive class, then 'projection' is the
+          *  reference projection type and vice versa. Lazily initialized, not to be accessed directly.
+         */
+         public ClassType projection;
+ 
+         /** Is this L of default {L, Q, X} or Q of default {L, Q, X} ?
+          */
+         public Flavor flavor;
+ 
+         /*
+          * Use of this constructor is kinda sorta deprecated, use the other constructor
+          * that forces the call site to consider and include the class type flavor.
+          */
          public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) {
-             this(outer, typarams, tsym, List.nil());
+             this(outer, typarams, tsym, List.nil(), Flavor.L_TypeOf_L);
+         }
+ 
+         public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym, Flavor flavor) {
+             this(outer, typarams, tsym, List.nil(), flavor);
          }
  
          public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym,
-                          List<TypeMetadata> metadata) {
+                          List<TypeMetadata> metadata, Flavor flavor) {
              super(tsym, metadata);
              this.outer_field = outer;
              this.typarams_field = typarams;
              this.allparams_field = null;
              this.supertype_field = null;
              this.interfaces_field = null;
+             this.flavor = flavor;
          }
  
          public int poolTag() {
              return ClassFile.CONSTANT_Class;
          }
  
          @Override
-         protected ClassType cloneWithMetadata(List<TypeMetadata> md) {
-             return new ClassType(outer_field, typarams_field, tsym, md) {
+         public ClassType cloneWithMetadata(List<TypeMetadata> md) {
+             return new ClassType(outer_field, typarams_field, tsym, md, flavor) {
                  @Override
                  public Type baseType() { return ClassType.this.baseType(); }
              };
          }
  

@@ -1083,10 +1283,21 @@
                  } else {
                      buf.append(className(tsym, true));
                  }
              }
  
+             boolean isReferenceProjection;
+             try {
+                 isReferenceProjection = isReferenceProjection();
+             } catch (CompletionFailure cf) {
+                 isReferenceProjection = false; // handle missing types gracefully.
+             }
+             if (isReferenceProjection) {
+                 buf.append('.');
+                 buf.append(tsym.name.table.names.ref);
+             }
+ 
              if (getTypeArguments().nonEmpty()) {
                  buf.append('<');
                  buf.append(getTypeArguments().toString());
                  buf.append(">");
              }

@@ -1121,10 +1332,14 @@
                  } else {
                      return sym.name.toString();
                  }
              }
  
+         public Flavor getFlavor() {
+             return flavor;
+         }
+ 
          @DefinedBy(Api.LANGUAGE_MODEL)
          public List<Type> getTypeArguments() {
              if (typarams_field == null) {
                  complete();
                  if (typarams_field == null)

@@ -1137,10 +1352,13 @@
              return isRaw();
          }
  
          @DefinedBy(Api.LANGUAGE_MODEL)
          public Type getEnclosingType() {
+             if (outer_field != null && outer_field.isReferenceProjection()) {
+                 outer_field = outer_field.valueProjection();
+             }
              return outer_field;
          }
  
          public void setEnclosingType(Type outer) {
              outer_field = outer;

@@ -1168,10 +1386,84 @@
          @Override
          public boolean isReference() {
              return true;
          }
  
+         @Override
+         public boolean isPrimitiveClass() {
+             return !isReferenceProjection() && tsym != null && tsym.isPrimitiveClass();
+         }
+ 
+         @Override
+         public boolean isValueClass() {
+             return !isReferenceProjection() && tsym != null && tsym.isValueClass();
+         }
+ 
+         @Override
+         public boolean isValueInterface() {
+             return tsym != null && tsym.isValueInterface();
+         }
+ 
+         @Override
+         public boolean isIdentityClass() {
+             return !isReferenceProjection() && tsym != null && tsym.isIdentityClass();
+         }
+ 
+         @Override
+         public boolean isIdentityInterface() {
+             return isInterface() && tsym.isIdentityInterface();
+         }
+ 
+         @Override
+         public boolean isReferenceProjection() {
+             // gaurd against over-eager and/or inopportune completion
+             if (tsym != null) {
+                 if (flavor == Flavor.L_TypeOf_X || tsym.isCompleted()) {
+                     flavor = flavor.metamorphose(tsym.isPrimitiveClass());
+                 }
+             }
+             return flavor == Flavor.L_TypeOf_Q;
+         }
+ 
+         @Override
+         public Type valueProjection() {
+             if (!isReferenceProjection())
+                 return null;
+ 
+             if (projection !=  null)
+                 return projection;
+ 
+             projection = new ClassType(outer_field, typarams_field, tsym, getMetadata(), Flavor.Q_TypeOf_Q);
+             projection.allparams_field = allparams_field;
+             projection.supertype_field = supertype_field;
+ 
+             projection.interfaces_field = interfaces_field;
+             projection.all_interfaces_field = all_interfaces_field;
+             projection.projection = this;
+             return projection;
+         }
+ 
+         // return the reference projection type preserving parameterizations
+         @Override
+         public ClassType referenceProjection() {
+ 
+             if (!isPrimitiveClass())
+                 return null;
+ 
+             if (projection != null)
+                 return projection;
+ 
+             projection = new ClassType(outer_field, typarams_field, tsym, getMetadata(), Flavor.L_TypeOf_Q);
+             projection.allparams_field = allparams_field;
+             projection.supertype_field = supertype_field;
+ 
+             projection.interfaces_field = interfaces_field;
+             projection.all_interfaces_field = all_interfaces_field;
+             projection.projection = this;
+             return projection;
+         }
+ 
          @Override
          public boolean isNullOrReference() {
              return true;
          }
  

@@ -1216,11 +1508,11 @@
      }
  
      public static class ErasedClassType extends ClassType {
          public ErasedClassType(Type outer, TypeSymbol tsym,
                                 List<TypeMetadata> metadata) {
-             super(outer, List.nil(), tsym, metadata);
+             super(outer, List.nil(), tsym, metadata, tsym.type.getFlavor());
          }
  
          @Override
          public boolean hasErasedSupertypes() {
              return true;

@@ -2327,25 +2619,24 @@
              c.kind = ERR;
              c.members_field = new Scope.ErrorScope(c);
          }
  
          public ErrorType(Type originalType, TypeSymbol tsym) {
-             super(noType, List.nil(), null);
-             this.tsym = tsym;
+             super(noType, List.nil(), tsym, List.nil(), Flavor.E_Typeof_X);
              this.originalType = (originalType == null ? noType : originalType);
          }
  
          private ErrorType(Type originalType, TypeSymbol tsym,
-                           List<TypeMetadata> metadata) {
-             super(noType, List.nil(), null, metadata);
+                           List<TypeMetadata> metadata, Flavor flavor) {
+             super(noType, List.nil(), null, metadata, flavor);
              this.tsym = tsym;
              this.originalType = (originalType == null ? noType : originalType);
          }
  
          @Override
-         protected ErrorType cloneWithMetadata(List<TypeMetadata> md) {
-             return new ErrorType(originalType, tsym, md) {
+         public ErrorType cloneWithMetadata(List<TypeMetadata> md) {
+             return new ErrorType(originalType, tsym, md, getFlavor()) {
                  @Override
                  public Type baseType() { return ErrorType.this.baseType(); }
              };
          }
  
< prev index next >