< prev index next >

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

Print this page
@@ -101,10 +101,11 @@
      private final boolean disableProtectedAccessors; // experimental
      private final PkgInfo pkginfoOpt;
      private final boolean optimizeOuterThis;
      private final boolean useMatchException;
      private final HashMap<TypePairs, String> typePairToName;
+     private final boolean allowValueClasses;
  
      @SuppressWarnings("this-escape")
      protected Lower(Context context) {
          context.put(lowerKey, this);
          names = Names.instance(context);

@@ -133,10 +134,12 @@
          Source source = Source.instance(context);
          Preview preview = Preview.instance(context);
          useMatchException = Feature.PATTERN_SWITCH.allowedInSource(source) &&
                              (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH));
          typePairToName = TypePairs.initialize(syms);
+         this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+                 Feature.VALUE_CLASSES.allowedInSource(source);
      }
  
      /** The currently enclosing class.
       */
      ClassSymbol currentClass;

@@ -190,10 +193,14 @@
       * This is required when a capturing local class is created from a lambda (in which
       * case the captured symbols should be replaced with the translated lambda symbols).
       */
      Map<Symbol, Symbol> lambdaTranslationMap = null;
  
+     /** A hash table mapping local classes to a set of outer this fields
+      */
+     public Map<ClassSymbol, Set<JCExpression>> initializerOuterThis = new WeakHashMap<>();
+ 
      /** A navigator class for assembling a mapping from local class symbols
       *  to class definition trees.
       *  There is only one case; all other cases simply traverse down the tree.
       */
      class ClassMap extends TreeScanner {

@@ -906,11 +913,12 @@
          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,
+             // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE,
                      c.outermostClass(), c.flatname, false);
              swapAccessConstructorTag(c, cdec.sym);
              translated.append(cdec);
          }
      }

@@ -1390,11 +1398,12 @@
              Name flatname = names.fromString("" + topClass.getQualifiedName() +
                                              target.syntheticNameChar() +
                                              i);
              ClassSymbol ctag = chk.getCompiled(topModle, flatname);
              if (ctag == null)
-                 ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
+                 // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+                 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;

@@ -1546,18 +1555,15 @@
          }
          return proxyName;
      }
  
      /** Proxy definitions for all free variables in given list, in reverse order.
-      *  @param pos        The source code position of the definition.
-      *  @param freevars   The free variables.
-      *  @param owner      The class in which the definitions go.
+      *  @param pos               The source code position of the definition.
+      *  @param freevars          The free variables.
+      *  @param owner             The class in which the definitions go.
+      *  @param additionalFlags   Any additional flags
       */
-     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
-         return freevarDefs(pos, freevars, owner, 0);
-     }
- 
      List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
              long additionalFlags) {
          long flags = FINAL | SYNTHETIC | additionalFlags;
          List<JCVariableDecl> defs = List.nil();
          Set<Name> proxyNames = new HashSet<>();

@@ -1634,11 +1640,11 @@
      /** Definition for this$n field.
       *  @param pos        The source code position of the definition.
       *  @param owner      The class in which the definition goes.
       */
      JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
-         VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC);
+         VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC | (allowValueClasses && owner.isValueClass() ? STRICT : 0));
          return makeOuterThisVarDecl(pos, outerThis);
      }
  
      /** Return a list of trees that load the free variables in given list,
       *  in reverse order.

@@ -1841,11 +1847,10 @@
       */
      JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
          List<VarSymbol> ots = outerThisStack;
          if (ots.isEmpty()) {
              log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
-             Assert.error();
              return makeNull();
          }
          VarSymbol ot = ots.head;
          JCExpression tree = access(make.at(pos).Ident(ot));
          ot.flags_field &= ~NOOUTERTHIS;

@@ -1967,11 +1972,12 @@
          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;
+         // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+         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);

@@ -2019,11 +2025,12 @@
      /**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;
+         // IDENTITY_TYPE will be interpreted as ACC_SUPER for older class files so we are fine
+         assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC | IDENTITY_TYPE, outermostClassDef.sym).sym;
  
          return assertionsDisabledClassCache;
      }
  
      // This code is not particularly robust if the user has

@@ -2307,11 +2314,11 @@
          if (currentClass.hasOuterInstance())
              otdef = outerThisDef(tree.pos, currentClass);
  
          // If this is a local class, define proxies for all its free variables.
          List<JCVariableDecl> fvdefs = freevarDefs(
-             tree.pos, freevars(currentClass), currentClass);
+             tree.pos, freevars(currentClass), currentClass, allowValueClasses && currentClass.isValueClass() ? STRICT : 0);
  
          // Recursively translate superclass, interfaces.
          tree.extending = translate(tree.extending);
          tree.implementing = translate(tree.implementing);
  

@@ -2884,23 +2891,29 @@
              ListBuffer<VarSymbol> fields = new ListBuffer<>();
              for (Symbol sym : currentClass.getEnclosedElements()) {
                  if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))
                      fields.append((VarSymbol) sym);
              }
+             ListBuffer<JCStatement> initializers = new ListBuffer<>();
              for (VarSymbol field: fields) {
                  if ((field.flags_field & Flags.UNINITIALIZED_FIELD) != 0) {
                      VarSymbol param = tree.params.stream().filter(p -> p.name == field.name).findFirst().get().sym;
                      make.at(tree.pos);
-                     tree.body.stats = tree.body.stats.append(
-                             make.Exec(
-                                     make.Assign(
-                                             make.Select(make.This(field.owner.erasure(types)), field),
-                                             make.Ident(param)).setType(field.erasure(types))));
-                     // we don't need the flag at the field anymore
+                     initializers.add(make.Exec(
+                             make.Assign(
+                                     make.Select(make.This(field.owner.erasure(types)), field),
+                                     make.Ident(param)).setType(field.erasure(types))));
                      field.flags_field &= ~Flags.UNINITIALIZED_FIELD;
                  }
              }
+             if (initializers.nonEmpty()) {
+                 if (tree.sym.owner.isValueClass()) {
+                     TreeInfo.mapSuperCalls(tree.body, supercall -> make.Block(0, initializers.toList().append(supercall)));
+                 } else {
+                     tree.body.stats = tree.body.stats.appendList(initializers);
+                 }
+             }
          }
          result = tree;
      }
      //where
          private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {

@@ -3130,10 +3143,21 @@
                  // local class
                  thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
              } else {
                  // nested class
                  thisArg = makeOwnerThis(tree.pos(), c, false);
+                 if (currentMethodSym != null &&
+                         ((currentMethodSym.flags_field & (STATIC | BLOCK)) == BLOCK) &&
+                         currentMethodSym.owner.isValueClass()) {
+                     // instance initializer in a value class
+                     Set<JCExpression> outerThisSet = initializerOuterThis.get(currentClass);
+                     if (outerThisSet == null) {
+                         outerThisSet = new HashSet<>();
+                     }
+                     outerThisSet.add(thisArg);
+                     initializerOuterThis.put(currentClass, outerThisSet);
+                 }
              }
              tree.args = tree.args.prepend(thisArg);
          }
          tree.encl = null;
  
< prev index next >