< prev index next >

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

Print this page
@@ -164,10 +164,11 @@
          attrRecover = AttrRecover.instance(context);
  
          Options options = Options.instance(context);
  
          Source source = Source.instance(context);
+         allowValueClasses = Feature.VALUE_CLASSES.allowedInSource(source);
          allowReifiableTypesInInstanceof = Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source);
          allowRecords = Feature.RECORDS.allowedInSource(source);
          allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) &&
                               Feature.PATTERN_SWITCH.allowedInSource(source);
          allowUnconditionalPatternsInstanceOf =

@@ -182,10 +183,14 @@
          unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
          unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
          recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
      }
  
+     /** Switch: allow value classes ?
+      */
+     boolean allowValueClasses;
+ 
      /** Switch: reifiable types in instanceof enabled?
       */
      boolean allowReifiableTypesInInstanceof;
  
      /** Are records allowed

@@ -935,10 +940,12 @@
  
      public void visitClassDef(JCClassDecl tree) {
          Optional<ArgumentAttr.LocalCacheContext> localCacheContext =
                  Optional.ofNullable(env.info.attributionMode.isSpeculative ?
                          argumentAttr.withLocalCacheContext() : null);
+         boolean ctorProloguePrev = env.info.ctorPrologue;
+         env.info.ctorPrologue = false;
          try {
              // Local and anonymous classes have not been entered yet, so we need to
              // do it now.
              if (env.info.scope.owner.kind.matches(KindSelector.VAL_MTH)) {
                  enter.classEnter(tree, env);

@@ -957,32 +964,33 @@
                  result = null;
              } else {
                  // make sure class has been completed:
                  c.complete();
  
-                 // If this class appears as an anonymous class
-                 // in a superclass constructor call
-                 // disable implicit outer instance from being passed.
+                 // If this class appears as an anonymous class in a constructor
+                 // prologue, disable implicit outer instance from being passed.
                  // (This would be an illegal access to "this before super").
-                 if (env.info.isSelfCall &&
-                         env.tree.hasTag(NEWCLASS)) {
+                 if (ctorProloguePrev && env.tree.hasTag(NEWCLASS)) {
                      c.flags_field |= NOOUTERTHIS;
                  }
                  attribClass(tree.pos(), c);
                  result = tree.type = c.type;
              }
          } finally {
              localCacheContext.ifPresent(LocalCacheContext::leave);
+             env.info.ctorPrologue = ctorProloguePrev;
          }
      }
  
      public void visitMethodDef(JCMethodDecl tree) {
          MethodSymbol m = tree.sym;
          boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
  
          Lint lint = env.info.lint.augment(m);
          Lint prevLint = chk.setLint(lint);
+         boolean ctorProloguePrev = env.info.ctorPrologue;
+         env.info.ctorPrologue = false;
          MethodSymbol prevMethod = chk.setMethod(m);
          try {
              deferredLintHandler.flush(tree.pos());
              chk.checkDeprecatedAnnotation(tree.pos(), m);
  

@@ -1042,10 +1050,13 @@
                  Env<AttrContext> newEnv = memberEnter.methodEnv(tree, env);
                  attribType(tree.recvparam, newEnv);
                  chk.validate(tree.recvparam, newEnv);
              }
  
+             // Is this method a constructor?
+             boolean isConstructor = TreeInfo.isConstructor(tree);
+ 
              if (env.enclClass.sym.isRecord() && tree.sym.owner.kind == TYP) {
                  // lets find if this method is an accessor
                  Optional<? extends RecordComponent> recordComponent = env.enclClass.sym.getRecordComponents().stream()
                          .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
                  if (recordComponent.isPresent()) {

@@ -1069,18 +1080,15 @@
                          log.error(tree,
                                  Errors.InvalidAccessorMethodInRecord(env.enclClass.sym, Fragments.AccessorMethodMustNotBeStatic));
                      }
                  }
  
-                 if (tree.name == names.init) {
+                 if (isConstructor) {
                      // if this a constructor other than the canonical one
                      if ((tree.sym.flags_field & RECORD) == 0) {
-                         JCMethodInvocation app = TreeInfo.firstConstructorCall(tree);
-                         if (app == null ||
-                                 TreeInfo.name(app.meth) != names._this ||
-                                 !checkFirstConstructorStat(app, tree, false)) {
-                             log.error(tree, Errors.FirstStatementMustBeCallToAnotherConstructor(env.enclClass.sym));
+                         if (!TreeInfo.hasConstructorCall(tree, names._this)) {
+                             log.error(tree, Errors.NonCanonicalConstructorInvokeAnotherConstructor(env.enclClass.sym));
                          }
                      } else {
                          // but if it is the canonical:
  
                          /* if user generated, then it shouldn't:

@@ -1102,15 +1110,11 @@
                                                      Fragments.CanonicalMustNotHaveStrongerAccess(asFlagSet(env.enclClass.sym.flags() & AccessFlags))
                                              )
                                  );
                              }
  
-                             JCMethodInvocation app = TreeInfo.firstConstructorCall(tree);
-                             if (app != null &&
-                                     (TreeInfo.name(app.meth) == names._this ||
-                                             TreeInfo.name(app.meth) == names._super) &&
-                                     checkFirstConstructorStat(app, tree, false)) {
+                             if (TreeInfo.hasAnyConstructorCall(tree)) {
                                  log.error(tree, Errors.InvalidCanonicalConstructorInRecord(
                                          Fragments.Canonical, env.enclClass.sym.name,
                                          Fragments.CanonicalMustNotContainExplicitConstructorInvocation));
                              }
                          }

@@ -1184,20 +1188,22 @@
                      log.error(tree.pos(), Errors.NativeMethCantHaveBody);
                  }
                  // Add an implicit super() call unless an explicit call to
                  // super(...) or this(...) is given
                  // or we are compiling class java.lang.Object.
-                 if (tree.name == names.init && owner.type != syms.objectType) {
-                     JCBlock body = tree.body;
-                     if (body.stats.isEmpty() ||
-                             TreeInfo.getConstructorInvocationName(body.stats, names) == names.empty) {
-                         JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
+                 if (isConstructor && owner.type != syms.objectType) {
+                     if (!TreeInfo.hasAnyConstructorCall(tree)) {
+                         JCStatement supCall = make.at(tree.body.pos).Exec(make.Apply(List.nil(),
                                  make.Ident(names._super), make.Idents(List.nil())));
-                         body.stats = body.stats.prepend(supCall);
+                         if (owner.isValueClass()) {
+                             tree.body.stats = tree.body.stats.append(supCall);
+                         } else {
+                             tree.body.stats = tree.body.stats.prepend(supCall);
+                         }
                      } else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
                              (tree.mods.flags & GENERATEDCONSTR) == 0 &&
-                             TreeInfo.isSuperCall(body.stats.head)) {
+                             TreeInfo.hasConstructorCall(tree, names._super)) {
                          // enum constructors are not allowed to call super
                          // directly, so make sure there aren't any super calls
                          // in enum constructors, except in the compiler
                          // generated one.
                          log.error(tree.body.stats.head.pos(),

@@ -1223,19 +1229,23 @@
  
                  // Attribute all type annotations in the body
                  annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null);
                  annotate.flush();
  
+                 // Start of constructor prologue
+                 localEnv.info.ctorPrologue = isConstructor;
+ 
                  // Attribute method body.
                  attribStat(tree.body, localEnv);
              }
  
              localEnv.info.scope.leave();
              result = tree.type = m.type;
          } finally {
              chk.setLint(prevLint);
              chk.setMethod(prevMethod);
+             env.info.ctorPrologue = ctorProloguePrev;
          }
      }
  
      public void visitVarDef(JCVariableDecl tree) {
          // Local variables have not been entered yet, so we need to do it now:

@@ -1328,11 +1338,12 @@
          for (Symbol s : syms.objectType.tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
              if (s.type.getParameterTypes().isEmpty()) {
                  return true;
              }
          }
-         return false;
+         // isValueObject is not included in Object yet so we need a work around
+         return name == names.isValueObject;
      }
  
      Fragment canInferLocalVarType(JCVariableDecl tree) {
          LocalInitScanner lis = new LocalInitScanner();
          lis.scan(tree.init);

@@ -1907,11 +1918,11 @@
          }
          return null;
      }
  
      public void visitSynchronized(JCSynchronized tree) {
-         chk.checkRefType(tree.pos(), attribExpr(tree.lock, env));
+         chk.checkIdentityType(tree.pos(), attribExpr(tree.lock, env));
          if (env.info.lint.isEnabled(LintCategory.SYNCHRONIZATION) && isValueBased(tree.lock.type)) {
              log.warning(LintCategory.SYNCHRONIZATION, tree.pos(), Warnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
          }
          attribStat(tree.body, env);
          result = null;

@@ -2516,25 +2527,19 @@
          boolean isConstructorCall =
              methName == names._this || methName == names._super;
  
          ListBuffer<Type> argtypesBuf = new ListBuffer<>();
          if (isConstructorCall) {
-             // We are seeing a ...this(...) or ...super(...) call.
-             // Check that this is the first statement in a constructor.
-             checkFirstConstructorStat(tree, env.enclMethod, true);
- 
-             // Record the fact
-             // that this is a constructor call (using isSelfCall).
-             localEnv.info.isSelfCall = true;
  
              // Attribute arguments, yielding list of argument types.
-             localEnv.info.constructorArgs = true;
              KindSelector kind = attribArgs(KindSelector.MTH, tree.args, localEnv, argtypesBuf);
-             localEnv.info.constructorArgs = false;
              argtypes = argtypesBuf.toList();
              typeargtypes = attribTypes(tree.typeargs, localEnv);
  
+             // Done with this()/super() parameters. End of constructor prologue.
+             env.info.ctorPrologue = false;
+ 
              // Variable `site' points to the class in which the called
              // constructor is defined.
              Type site = env.enclClass.sym.type;
              if (methName == names._super) {
                  if (site == syms.objectType) {

@@ -2659,30 +2664,10 @@
              } else {
                  return restype;
              }
          }
  
-         /** Check that given application node appears as first statement
-          *  in a constructor call.
-          *  @param tree          The application node
-          *  @param enclMethod    The enclosing method of the application.
-          *  @param error         Should an error be issued?
-          */
-         boolean checkFirstConstructorStat(JCMethodInvocation tree, JCMethodDecl enclMethod, boolean error) {
-             if (enclMethod != null && enclMethod.name == names.init) {
-                 JCBlock body = enclMethod.body;
-                 if (body.stats.head.hasTag(EXEC) &&
-                     ((JCExpressionStatement) body.stats.head).expr == tree)
-                     return true;
-             }
-             if (error) {
-                 log.error(tree.pos(),
-                         Errors.CallMustBeFirstStmtInCtor(TreeInfo.name(tree.meth)));
-             }
-             return false;
-         }
- 
          /** Obtain a method type with given argument types.
           */
          Type newMethodTemplate(Type restype, List<Type> argtypes, List<Type> typeargtypes) {
              MethodType mt = new MethodType(argtypes, restype, List.nil(), syms.methodClass);
              return (typeargtypes == null) ? mt : (Type)new ForAll(typeargtypes, mt);

@@ -4351,20 +4336,10 @@
              // that the variable is assignable in the current environment.
              if (KindSelector.ASG.subset(pkind()))
                  checkAssignable(tree.pos(), v, null, env);
          }
  
-         // In a constructor body,
-         // if symbol is a field or instance method, check that it is
-         // not accessed before the supertype constructor is called.
-         if (symEnv.info.isSelfCall &&
-             sym.kind.matches(KindSelector.VAL_MTH) &&
-             sym.owner.kind == TYP &&
-             (sym.flags() & STATIC) == 0) {
-             chk.earlyRefError(tree.pos(), sym.kind == VAR ?
-                                           sym : thisSym(tree.pos(), env));
-         }
          Env<AttrContext> env1 = env;
          if (sym.kind != ERR && sym.kind != TYP &&
              sym.owner != null && sym.owner != env1.enclClass.sym) {
              // If the found symbol is inaccessible, then it is
              // accessed through an enclosing instance.  Locate this

@@ -4396,10 +4371,11 @@
                  skind = KindSelector.of(skind, KindSelector.VAL, KindSelector.TYP);
          }
  
          // Attribute the qualifier expression, and determine its symbol (if any).
          Type site = attribTree(tree.selected, env, new ResultInfo(skind, Type.noType));
+         Assert.check(site == tree.selected.type);
          if (!pkind().contains(KindSelector.TYP_PCK))
              site = capture(site); // Capture field access
  
          // don't allow T.class T[].class, etc
          if (skind == KindSelector.TYP) {

@@ -4472,22 +4448,11 @@
                                        KindSelector.VAL : sitesym.kind.toSelector(),
                                new ResultInfo(KindSelector.TYP_PCK, pt()));
          }
  
          if (isType(sitesym)) {
-             if (sym.name == names._this || sym.name == names._super) {
-                 // If `C' is the currently compiled class, check that
-                 // `C.this' does not appear in an explicit call to a constructor
-                 // also make sure that `super` is not used in constructor invocations
-                 if (env.info.isSelfCall &&
-                         ((sym.name == names._this &&
-                         site.tsym == env.enclClass.sym) ||
-                         sym.name == names._super && env.info.constructorArgs &&
-                         (sitesym.isInterface() || site.tsym == env.enclClass.sym))) {
-                     chk.earlyRefError(tree.pos(), sym);
-                 }
-             } else {
+             if (sym.name != names._this && sym.name != names._super) {
                  // Check if type-qualified fields or methods are static (JLS)
                  if ((sym.flags() & STATIC) == 0 &&
                      sym.name != names._super &&
                      (sym.kind == VAR || sym.kind == MTH)) {
                      rs.accessBase(rs.new StaticError(sym),

@@ -5506,11 +5471,11 @@
  
                          if (!hasErrorSuper) {
                              log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
                          }
                      }
-                 } else {
+                 } else if ((c.flags_field & Flags.COMPOUND) == 0) {
                      if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) {
                          log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local));
                      }
  
                      if (!c.type.isCompound()) {

@@ -5544,10 +5509,15 @@
  
                  if (rs.isSerializable(c.type)) {
                      env.info.isSerializable = true;
                  }
  
+                 if (c.isValueClass()) {
+                     Assert.check(env.tree.hasTag(CLASSDEF));
+                     chk.checkConstraintsOfValueClass((JCClassDecl) env.tree, c);
+                 }
+ 
                  attribClassBody(env, c);
  
                  chk.checkDeprecatedAnnotation(env.tree.pos(), c);
                  chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
                  chk.checkFunctionalInterface((JCClassDecl) env.tree, c);

@@ -5672,10 +5642,13 @@
                          sym.getConstValue() == null)
                      log.error(l.head.pos(), Errors.IclsCantHaveStaticDecl(c));
              }
          }
  
+         // Check for proper placement of super()/this() calls.
+         chk.checkSuperInitCalls(tree);
+ 
          // Check for cycles among non-initial constructors.
          chk.checkCyclicConstructors(tree);
  
          // Check for cycles among annotation elements.
          chk.checkNonCyclicElements(tree);
< prev index next >