< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java

Print this page
@@ -99,10 +99,11 @@
      private final TransTypes transTypes;
      private final boolean debugLower;
      private final boolean disableProtectedAccessors; // experimental
      private final PkgInfo pkginfoOpt;
      private final boolean optimizeOuterThis;
+     private final boolean allowPrimitiveClasses;
      private final boolean useMatchException;
  
      @SuppressWarnings("this-escape")
      protected Lower(Context context) {
          context.put(lowerKey, this);

@@ -128,10 +129,11 @@
          optimizeOuterThis =
              target.optimizeOuterThis() ||
              options.getBoolean("optimizeOuterThis", false);
          disableProtectedAccessors = options.isSet("disableProtectedAccessors");
          Source source = Source.instance(context);
+         allowPrimitiveClasses = Source.Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
          Preview preview = Preview.instance(context);
          useMatchException = Feature.PATTERN_SWITCH.allowedInSource(source) &&
                              (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH));
      }
  

@@ -904,11 +906,11 @@
          for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
              ClassSymbol c = l.head;
              if (isTranslatedClassAvailable(c))
                  continue;
              // Create class definition tree.
-             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
+             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE,
                      c.outermostClass(), c.flatname, false);
              swapAccessConstructorTag(c, cdec.sym);
              translated.append(cdec);
          }
      }

@@ -1141,11 +1143,11 @@
          if (target.hasNestmateAccess()) {
              return false;
          }
          if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
              return false;
-         } else if (sym.name == names.init && sym.owner.isDirectlyOrIndirectlyLocal()) {
+         } else if (names.isInitOrVNew(sym.name) && sym.owner.isDirectlyOrIndirectlyLocal()) {
              // private constructor in local class: relax protection
              sym.flags_field &= ~PRIVATE;
              return false;
          } else {
              return true;

@@ -1230,10 +1232,13 @@
          }
          JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
          switch (sym.kind) {
          case TYP:
              if (sym.owner.kind != PCK) {
+                 // Make sure not to lose type fidelity due to symbol sharing between projections
+                 boolean requireReferenceProjection = allowPrimitiveClasses &&
+                         tree.hasTag(SELECT) && ((JCFieldAccess) tree).name == names.ref && tree.type.isReferenceProjection();
                  // Convert type idents to
                  // <flat name> or <package name> . <flat name>
                  Name flatname = Convert.shortName(sym.flatName());
                  while (base != null &&
                         TreeInfo.symbol(base) != null &&

@@ -1245,13 +1250,19 @@
                  if (tree.hasTag(IDENT)) {
                      ((JCIdent) tree).name = flatname;
                  } else if (base == null) {
                      tree = make.at(tree.pos).Ident(sym);
                      ((JCIdent) tree).name = flatname;
+                     if (requireReferenceProjection) {
+                         tree.setType(tree.type.referenceProjection());
+                     }
                  } else {
                      ((JCFieldAccess) tree).selected = base;
                      ((JCFieldAccess) tree).name = flatname;
+                     if (requireReferenceProjection) {
+                         tree.setType(tree.type.referenceProjection());
+                     }
                  }
              }
              break;
          case MTH: case VAR:
              if (sym.owner.kind == TYP) {

@@ -1345,13 +1356,14 @@
                  List<Type> argtypes = constr.type.getParameterTypes();
                  if ((accOwner.flags_field & ENUM) != 0)
                      argtypes = argtypes
                          .prepend(syms.intType)
                          .prepend(syms.stringType);
+                 Name constructorName = accOwner.isConcreteValueClass() ? names.vnew : names.init;
                  aconstr = new MethodSymbol(
                      SYNTHETIC,
-                     names.init,
+                     constructorName,
                      new MethodType(
                          argtypes.append(
                              accessConstructorTag().erasure(types)),
                          constr.type.getReturnType(),
                          constr.type.getThrownTypes(),

@@ -1376,11 +1388,11 @@
              Name flatname = names.fromString("" + topClass.getQualifiedName() +
                                              target.syntheticNameChar() +
                                              i);
              ClassSymbol ctag = chk.getCompiled(topModle, flatname);
              if (ctag == null)
-                 ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
+                 ctag = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, topClass).sym;
              else if (!ctag.isAnonymous())
                  continue;
              // keep a record of all tags, to verify that all are generated as required
              accessConstrTags = accessConstrTags.prepend(ctag);
              return ctag;

@@ -1391,11 +1403,11 @@
       *  @param sym       The symbol.
       */
      void makeAccessible(Symbol sym) {
          JCClassDecl cdef = classDef(sym.owner.enclClass());
          if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
-         if (sym.name == names.init) {
+         if (names.isInitOrVNew(sym.name)) {
              cdef.defs = cdef.defs.prepend(
                  accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
          } else {
              MethodSymbol[] accessors = accessSyms.get(sym);
              for (int i = 0; i < AccessCode.numberOfAccessCodes; i++) {

@@ -1604,13 +1616,13 @@
       */
      JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
          ClassSymbol c = owner.enclClass();
          boolean isMandated =
              // Anonymous constructors
-             (owner.isConstructor() && owner.isAnonymous()) ||
+             (owner.isInitOrVNew() && owner.isAnonymous()) ||
              // Constructors of non-private inner member classes
-             (owner.isConstructor() && c.isInner() &&
+             (owner.isInitOrVNew() && c.isInner() &&
               !c.isPrivate() && !c.isStatic());
          long flags =
              FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
          VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
          owner.extraParams = owner.extraParams.prepend(outerThis);

@@ -1803,11 +1815,11 @@
          return newBlock;
      }
  
      private JCStatement makeResourceCloseInvocation(JCExpression resource) {
          // convert to AutoCloseable if needed
-         if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
+         if (types.asSuper(resource.type.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) == null) {
              resource = convert(resource, syms.autoCloseableType);
          }
  
          // create resource.close() method invocation
          JCExpression resourceClose = makeCall(resource,

@@ -1955,11 +1967,11 @@
          Scope s = clazz.members();
          for (Symbol sym : s.getSymbols(NON_RECURSIVE))
              if (sym.kind == TYP &&
                  sym.name == names.empty &&
                  (sym.flags() & INTERFACE) == 0) return (ClassSymbol) sym;
-         return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
+         return makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, clazz).sym;
      }
  
      /** Create an attributed tree of the form left.name(). */
      private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
          Assert.checkNonNull(left.type);

@@ -2007,11 +2019,11 @@
      /**Used to create an auxiliary class to hold $assertionsDisabled for interfaces.
       */
      private ClassSymbol assertionsDisabledClass() {
          if (assertionsDisabledClassCache != null) return assertionsDisabledClassCache;
  
-         assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC, outermostClassDef.sym).sym;
+         assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, outermostClassDef.sym).sym;
  
          return assertionsDisabledClassCache;
      }
  
      // This code is not particularly robust if the user has

@@ -2187,11 +2199,12 @@
      }
  
      /** Visitor method: Translate a single node, boxing or unboxing if needed.
       */
      public <T extends JCExpression> T translate(T tree, Type type) {
-         return (tree == null) ? null : boxIfNeeded(translate(tree), type);
+         return (tree == null) ? null :
+                 applyPrimitiveConversionsAsNeeded(boxIfNeeded(translate(tree), type), type);
      }
  
      /** Visitor method: Translate tree.
       */
      public <T extends JCTree> T translate(T tree, JCExpression enclOp) {

@@ -2326,11 +2339,11 @@
              seen = unseen;
          }
  
          // Convert a protected modifier to public, mask static modifier.
          if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
-         tree.mods.flags &= ClassFlags;
+         tree.mods.flags &= AdjustedClassFlags;
  
          // Convert name to flat representation, replacing '.' by '$'.
          tree.name = Convert.shortName(currentClass.flatName());
  
          // Add free variables proxy definitions to class.

@@ -2736,10 +2749,11 @@
          qualifier.type = msym.type.asMethodType().restype;
          return qualifier;
      }
  
      public void visitMethodDef(JCMethodDecl tree) {
+         // TODO - enum so is always <init>
          if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
              // Add "String $enum$name, int $enum$ordinal" to the beginning of the
              // argument list for each constructor of an enum.
              JCVariableDecl nameParam = make_at(tree.pos()).
                  Param(names.fromString(target.syntheticNameChar() +

@@ -2777,11 +2791,11 @@
              currentMethodSym = prevMethodSym;
          }
      }
  
      private void visitMethodDefInternal(JCMethodDecl tree) {
-         if (tree.name == names.init &&
+         if (names.isInitOrVNew(tree.name) &&
              !currentClass.isStatic() &&
              (currentClass.isInner() || currentClass.isDirectlyOrIndirectlyLocal())) {
              // We are seeing a constructor of an inner class.
              MethodSymbol m = tree.sym;
  

@@ -2858,11 +2872,11 @@
                  super.visitMethodDef(tree);
              } finally {
                  lambdaTranslationMap = prevLambdaTranslationMap;
              }
          }
-         if (tree.name == names.init && ((tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
+         if (names.isInitOrVNew(tree.name) && ((tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
                  (tree.sym.flags_field & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD))) {
              // lets find out if there is any field waiting to be initialized
              ListBuffer<VarSymbol> fields = new ListBuffer<>();
              for (Symbol sym : currentClass.getEnclosedElements()) {
                  if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))

@@ -3100,16 +3114,17 @@
      }
  
      public void visitApply(JCMethodInvocation tree) {
          Symbol meth = TreeInfo.symbol(tree.meth);
          List<Type> argtypes = meth.type.getParameterTypes();
-         if (meth.name == names.init && meth.owner == syms.enumSym)
+         // TODO - is enum so always <init>.
+         if (names.isInitOrVNew(meth.name) && meth.owner == syms.enumSym)
              argtypes = argtypes.tail.tail;
          tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
          tree.varargsElement = null;
          Name methName = TreeInfo.name(tree.meth);
-         if (meth.name==names.init) {
+         if (names.isInitOrVNew(meth.name)) {
              // We are seeing a this(...) or super(...) constructor call.
              // If an access constructor is used, append null as a last argument.
              Symbol constructor = accessConstructor(tree.pos(), meth);
              if (constructor != meth) {
                  tree.args = tree.args.append(makeNull());

@@ -3213,10 +3228,21 @@
              if (!anyChanges) return _args;
          }
          return result.toList();
      }
  
+     /** Apply primitive value/reference conversions as needed */
+     @SuppressWarnings("unchecked")
+     <T extends JCExpression> T applyPrimitiveConversionsAsNeeded(T tree, Type type) {
+         boolean haveValue = tree.type.isPrimitiveClass();
+         if (haveValue == type.isPrimitiveClass())
+             return tree;
+         // For narrowing conversion, insert a cast which should trigger a null check
+         // For widening conversions, insert a cast if emitting a unified class file.
+         return (T) make.TypeCast(type, tree);
+     }
+ 
      /** Expand a boxing or unboxing conversion if needed. */
      @SuppressWarnings("unchecked") // XXX unchecked
      <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
          boolean havePrimitive = tree.type.isPrimitive();
          if (havePrimitive == type.isPrimitive())

@@ -3611,21 +3637,21 @@
           * where #i is a freshly named synthetic local variable.
           */
          private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
              make_at(tree.expr.pos());
              Type iteratorTarget = syms.objectType;
-             Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type),
+             Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type.referenceProjectionOrSelf()),
                                                syms.iterableType.tsym);
              if (iterableType.getTypeArguments().nonEmpty())
                  iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
              tree.expr.type = types.erasure(types.skipTypeVars(tree.expr.type, false));
              tree.expr = transTypes.coerce(attrEnv, tree.expr, types.erasure(iterableType));
              Symbol iterator = lookupMethod(tree.expr.pos(),
                                             names.iterator,
                                             tree.expr.type,
                                             List.nil());
-             Assert.check(types.isSameType(types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)), types.erasure(syms.iteratorType)));
+             Assert.check(types.isSameType(types.erasure(types.asSuper(iterator.type.getReturnType().referenceProjectionOrSelf(), syms.iteratorType.tsym)), types.erasure(syms.iteratorType)));
              VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
                                              types.erasure(syms.iteratorType),
                                              currentMethodSym);
  
               JCStatement init = make.

@@ -3700,10 +3726,27 @@
          tree.cond = translate(tree.cond, syms.booleanType);
          tree.body = translate(tree.body);
          result = tree;
      }
  
+     public void visitWithField(JCWithField tree) {
+         Type fieldType = tree.field.type;
+         tree.field = translate(tree.field, tree);
+         tree.value = translate(tree.value, fieldType); // important to use pre-translation type.
+ 
+         // If translated field is an Apply, we are
+         // seeing an access method invocation. In this case, append
+         // right hand side as last argument of the access method.
+         if (tree.field.hasTag(APPLY)) {
+             JCMethodInvocation app = (JCMethodInvocation) tree.field;
+             app.args = List.of(tree.value).prependList(app.args);
+             result = app;
+         } else {
+             result = tree;
+         }
+     }
+ 
      public void visitForLoop(JCForLoop tree) {
          tree.init = translate(tree.init);
          if (tree.cond != null)
              tree.cond = translate(tree.cond, syms.booleanType);
          tree.step = translate(tree.step);

@@ -4196,19 +4239,27 @@
          // is a default interface subclassed by the current class.
          boolean qualifiedSuperAccess =
              tree.selected.hasTag(SELECT) &&
              TreeInfo.name(tree.selected) == names._super &&
              !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
+         /* JDK-8269956: Where a reflective (class) literal is needed, the unqualified Point.class is
+          * always the "primary" mirror - representing the primitive reference runtime type - thereby
+          * always matching the behavior of Object::getClass
+          */
+         boolean needPrimaryMirror = tree.name == names._class && tree.selected.type.isReferenceProjection();
          tree.selected = translate(tree.selected);
+         if (needPrimaryMirror && allowPrimitiveClasses && tree.selected.type.isPrimitiveClass()) {
+             tree.selected.setType(tree.selected.type.referenceProjection());
+         }
          if (tree.name == names._class) {
              result = classOf(tree.selected);
          }
          else if (tree.name == names._super &&
                  types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
              //default super call!! Not a classic qualified super call
              TypeSymbol supSym = tree.selected.type.tsym;
-             Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
+             Assert.checkNonNull(types.asSuper(currentClass.type.referenceProjectionOrSelf(), supSym));
              result = tree;
          }
          else if (tree.name == names._this || tree.name == names._super) {
              result = makeThis(tree.pos(), tree.selected.type.tsym);
          }
< prev index next >