< prev index next >

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

Print this page
*** 43,10 ***
--- 43,11 ---
  import com.sun.tools.javac.code.Lint.LintCategory;
  import com.sun.tools.javac.code.Scope.WriteableScope;
  import com.sun.tools.javac.code.Source.Feature;
  import com.sun.tools.javac.code.Symbol.*;
  import com.sun.tools.javac.code.Type.*;
+ import com.sun.tools.javac.code.Type.ClassType.Flavor;
  import com.sun.tools.javac.code.TypeMetadata.Annotations;
  import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
  import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
  import com.sun.tools.javac.comp.Check.CheckContext;
  import com.sun.tools.javac.comp.DeferredAttr.AttrMode;

*** 164,10 ***
--- 165,11 ---
          attrRecover = AttrRecover.instance(context);
  
          Options options = Options.instance(context);
  
          Source source = Source.instance(context);
+         allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
          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 = (preview.isEnabled() || !preview.isPreview(Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF)) &&

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

*** 270,11 ***
             // owner refers to the innermost variable, method or
             // initializer block declaration at this point.
          boolean isAssignable =
              v.owner == owner
              ||
!             ((owner.name == names.init ||    // i.e. we are in a constructor
                owner.kind == VAR ||           // i.e. we are in a variable initializer
                (owner.flags() & BLOCK) != 0)  // i.e. we are in an initializer block
               &&
               v.owner == owner.owner
               &&
--- 276,11 ---
             // owner refers to the innermost variable, method or
             // initializer block declaration at this point.
          boolean isAssignable =
              v.owner == owner
              ||
!             ((names.isInitOrVNew(owner.name) ||    // i.e. we are in a constructor
                owner.kind == VAR ||           // i.e. we are in a variable initializer
                (owner.flags() & BLOCK) != 0)  // i.e. we are in an initializer block
               &&
               v.owner == owner.owner
               &&

*** 797,13 ***
          for (JCTypeParameter tvar : typarams) {
              TypeVar a = (TypeVar)tvar.type;
              a.tsym.flags_field |= UNATTRIBUTED;
              a.setUpperBound(Type.noType);
              if (!tvar.bounds.isEmpty()) {
!                 List<Type> bounds = List.of(attribType(tvar.bounds.head, env));
                  for (JCExpression bound : tvar.bounds.tail)
!                     bounds = bounds.prepend(attribType(bound, env));
                  types.setBounds(a, bounds.reverse());
              } else {
                  // if no bounds are given, assume a single bound of
                  // java.lang.Object.
                  types.setBounds(a, List.of(syms.objectType));
--- 803,13 ---
          for (JCTypeParameter tvar : typarams) {
              TypeVar a = (TypeVar)tvar.type;
              a.tsym.flags_field |= UNATTRIBUTED;
              a.setUpperBound(Type.noType);
              if (!tvar.bounds.isEmpty()) {
!                 List<Type> bounds = List.of(chk.checkRefType(tvar.bounds.head, attribType(tvar.bounds.head, env), false));
                  for (JCExpression bound : tvar.bounds.tail)
!                     bounds = bounds.prepend(chk.checkRefType(bound, attribType(bound, env), false));
                  types.setBounds(a, bounds.reverse());
              } else {
                  // if no bounds are given, assume a single bound of
                  // java.lang.Object.
                  types.setBounds(a, List.of(syms.objectType));

*** 1069,11 ***
                          log.error(tree,
                                  Errors.InvalidAccessorMethodInRecord(env.enclClass.sym, Fragments.AccessorMethodMustNotBeStatic));
                      }
                  }
  
!                 if (tree.name == names.init) {
                      // 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 ||
--- 1075,11 ---
                          log.error(tree,
                                  Errors.InvalidAccessorMethodInRecord(env.enclClass.sym, Fragments.AccessorMethodMustNotBeStatic));
                      }
                  }
  
!                 if (names.isInitOrVNew(tree.name)) {
                      // 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 ||

*** 1184,14 ***
                      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(),
                                  make.Ident(names._super), make.Idents(List.nil())));
                          body.stats = body.stats.prepend(supCall);
                      } else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
                              (tree.mods.flags & GENERATEDCONSTR) == 0 &&
--- 1190,14 ---
                      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 (names.isInitOrVNew(tree.name) && owner.type != syms.objectType) {
                      JCBlock body = tree.body;
                      if (body.stats.isEmpty() ||
!                             TreeInfo.getConstructorInvocationName(body.stats, names, true) == names.empty) {
                          JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
                                  make.Ident(names._super), make.Idents(List.nil())));
                          body.stats = body.stats.prepend(supCall);
                      } else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
                              (tree.mods.flags & GENERATEDCONSTR) == 0 &&

*** 1200,10 ***
--- 1206,16 ---
                          // 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(),
                                    Errors.CallToSuperNotAllowedInEnumCtor(env.enclClass.sym));
+                     } else if ((env.enclClass.sym.flags() & VALUE_CLASS) != 0 &&
+                         (tree.mods.flags & GENERATEDCONSTR) == 0 &&
+                         TreeInfo.isSuperCall(body.stats.head)) {
+                         // value constructors are not allowed to call super directly,
+                         // but tolerate compiler generated ones, these are ignored during code generation
+                         log.error(tree.body.stats.head.pos(), Errors.CallToSuperNotAllowedInValueCtor);
                      }
                      if (env.enclClass.sym.isRecord() && (tree.sym.flags_field & RECORD) != 0) { // we are seeing the canonical constructor
                          List<Name> recordComponentNames = TreeInfo.recordFields(env.enclClass).map(vd -> vd.sym.name);
                          List<Name> initParamNames = tree.sym.params.map(p -> p.name);
                          if (!initParamNames.equals(recordComponentNames)) {

*** 1287,12 ***
          try {
              v.getConstValue(); // ensure compile-time constant initializer is evaluated
              deferredLintHandler.flush(tree.pos());
              chk.checkDeprecatedAnnotation(tree.pos(), v);
  
              if (tree.init != null) {
!                 if ((v.flags_field & FINAL) == 0 ||
                      !memberEnter.needsLazyConstValue(tree.init)) {
                      // Not a compile-time constant
                      // Attribute initializer in a new environment
                      // with the declared variable as owner.
                      // Check that initializer conforms to variable's declared type.
--- 1299,15 ---
          try {
              v.getConstValue(); // ensure compile-time constant initializer is evaluated
              deferredLintHandler.flush(tree.pos());
              chk.checkDeprecatedAnnotation(tree.pos(), v);
  
+             /* Don't want constant propagation/folding for instance fields of primitive classes,
+                as these can undergo updates via copy on write.
+             */
              if (tree.init != null) {
!                 if ((v.flags_field & FINAL) == 0 || ((v.flags_field & STATIC) == 0 && v.owner.isValueClass()) ||
                      !memberEnter.needsLazyConstValue(tree.init)) {
                      // Not a compile-time constant
                      // Attribute initializer in a new environment
                      // with the declared variable as owner.
                      // Check that initializer conforms to variable's declared type.

*** 1328,11 ***
          for (Symbol s : syms.objectType.tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
              if (s.type.getParameterTypes().isEmpty()) {
                  return true;
              }
          }
!         return false;
      }
  
      Fragment canInferLocalVarType(JCVariableDecl tree) {
          LocalInitScanner lis = new LocalInitScanner();
          lis.scan(tree.init);
--- 1343,12 ---
          for (Symbol s : syms.objectType.tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
              if (s.type.getParameterTypes().isEmpty()) {
                  return true;
              }
          }
!         // 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);

*** 1520,11 ***
              Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
              chk.checkNonVoid(tree.pos(), exprType);
              Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
              if (elemtype == null) {
                  // or perhaps expr implements Iterable<T>?
!                 Type base = types.asSuper(exprType, syms.iterableType.tsym);
                  if (base == null) {
                      log.error(tree.expr.pos(),
                                Errors.ForeachNotApplicableToType(exprType,
                                                                  Fragments.TypeReqArrayOrIterable));
                      elemtype = types.createErrorType(exprType);
--- 1536,11 ---
              Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
              chk.checkNonVoid(tree.pos(), exprType);
              Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
              if (elemtype == null) {
                  // or perhaps expr implements Iterable<T>?
!                 Type base = types.asSuper(exprType.referenceProjectionOrSelf(), syms.iterableType.tsym);
                  if (base == null) {
                      log.error(tree.expr.pos(),
                                Errors.ForeachNotApplicableToType(exprType,
                                                                  Fragments.TypeReqArrayOrIterable));
                      elemtype = types.createErrorType(exprType);

*** 1536,11 ***
  
                      // Check the return type of the method iterator().
                      // This is the bare minimum we need to verify to make sure code generation doesn't crash.
                      Symbol iterSymbol = rs.resolveInternalMethod(tree.pos(),
                              loopEnv, types.skipTypeVars(exprType, false), names.iterator, List.nil(), List.nil());
!                     if (types.asSuper(iterSymbol.type.getReturnType(), syms.iteratorType.tsym) == null) {
                          log.error(tree.pos(),
                                  Errors.ForeachNotApplicableToType(exprType, Fragments.TypeReqArrayOrIterable));
                      }
                  }
              }
--- 1552,11 ---
  
                      // Check the return type of the method iterator().
                      // This is the bare minimum we need to verify to make sure code generation doesn't crash.
                      Symbol iterSymbol = rs.resolveInternalMethod(tree.pos(),
                              loopEnv, types.skipTypeVars(exprType, false), names.iterator, List.nil(), List.nil());
!                     if (types.asSuper(iterSymbol.type.getReturnType().referenceProjectionOrSelf(), syms.iteratorType.tsym) == null) {
                          log.error(tree.pos(),
                                  Errors.ForeachNotApplicableToType(exprType, Fragments.TypeReqArrayOrIterable));
                      }
                  }
              }

*** 1855,11 ***
          }
          return null;
      }
  
      public void visitSynchronized(JCSynchronized tree) {
!         chk.checkRefType(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;
--- 1871,11 ---
          }
          return null;
      }
  
      public void visitSynchronized(JCSynchronized tree) {
!         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;

*** 1946,11 ***
          }
      }
  
      void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
          if (!resource.isErroneous() &&
!             types.asSuper(resource, syms.autoCloseableType.tsym) != null &&
              !types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
              Symbol close = syms.noSymbol;
              Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log);
              try {
                  close = rs.resolveQualifiedMethod(pos,
--- 1962,11 ---
          }
      }
  
      void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
          if (!resource.isErroneous() &&
!             types.asSuper(resource.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null &&
              !types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
              Symbol close = syms.noSymbol;
              Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log);
              try {
                  close = rs.resolveQualifiedMethod(pos,

*** 2135,27 ***
                          return candidate;
                      }
                  }
              }
  
!             // Those were all the cases that could result in a primitive
              condTypes = condTypes.stream()
!                                  .map(t -> t.isPrimitive() ? types.boxedClass(t).type : t)
                                   .collect(List.collector());
  
              for (Type type : condTypes) {
                  if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
                      return type.baseType();
              }
  
              Iterator<DiagnosticPosition> posIt = positions.iterator();
  
              condTypes = condTypes.stream()
!                                  .map(t -> chk.checkNonVoid(posIt.next(), t))
                                   .collect(List.collector());
  
!             // both are known to be reference types.  The result is
              // lub(thentype,elsetype). This cannot fail, as it will
              // always be possible to infer "Object" if nothing better.
              return types.lub(condTypes.stream()
                          .map(t -> t.baseType())
                          .filter(t -> !t.hasTag(BOT))
--- 2151,29 ---
                          return candidate;
                      }
                  }
              }
  
!             // Those were all the cases that could result in a primitive. See if primitive boxing and primitive
+             // value conversions bring about a convergence.
              condTypes = condTypes.stream()
!                                  .map(t -> t.isPrimitive() ? types.boxedClass(t).type
+                                          : t.isReferenceProjection() ? t.valueProjection() : t)
                                   .collect(List.collector());
  
              for (Type type : condTypes) {
                  if (condTypes.stream().filter(t -> t != type).allMatch(t -> types.isAssignable(t, type)))
                      return type.baseType();
              }
  
              Iterator<DiagnosticPosition> posIt = positions.iterator();
  
              condTypes = condTypes.stream()
!                                  .map(t -> chk.checkNonVoid(posIt.next(), allowPrimitiveClasses && t.isPrimitiveClass() ? t.referenceProjection() : t))
                                   .collect(List.collector());
  
!             // both are known to be reference types (or projections).  The result is
              // lub(thentype,elsetype). This cannot fail, as it will
              // always be possible to infer "Object" if nothing better.
              return types.lub(condTypes.stream()
                          .map(t -> t.baseType())
                          .filter(t -> !t.hasTag(BOT))

*** 2590,16 ***
              if (msym != null &&
                      (msym.owner == syms.objectType.tsym || msym.owner.isInterface()) &&
                      methodName == names.getClass &&
                      argtypes.isEmpty()) {
                  // as a special case, x.getClass() has type Class<? extends |X|>
                  return new ClassType(restype.getEnclosingType(),
!                         List.of(new WildcardType(types.erasure(qualifierType.baseType()),
                                  BoundKind.EXTENDS,
                                  syms.boundClass)),
                          restype.tsym,
!                         restype.getMetadata());
              } else if (msym != null &&
                      msym.owner == syms.arrayClass &&
                      methodName == names.clone &&
                      types.isArray(qualifierType)) {
                  // as a special case, array.clone() has a result that is
--- 2608,21 ---
              if (msym != null &&
                      (msym.owner == syms.objectType.tsym || msym.owner.isInterface()) &&
                      methodName == names.getClass &&
                      argtypes.isEmpty()) {
                  // as a special case, x.getClass() has type Class<? extends |X|>
+                 // Special treatment for primitive classes: Given an expression v of type V where
+                 // V is a primitive class, v.getClass() is typed to be Class<? extends |V.ref|>
+                 Type wcb = types.erasure(allowPrimitiveClasses && qualifierType.isPrimitiveClass() ?
+                                          qualifierType.referenceProjection() : qualifierType.baseType());
                  return new ClassType(restype.getEnclosingType(),
!                         List.of(new WildcardType(wcb,
                                  BoundKind.EXTENDS,
                                  syms.boundClass)),
                          restype.tsym,
!                         restype.getMetadata(),
+                         restype.getFlavor());
              } else if (msym != null &&
                      msym.owner == syms.arrayClass &&
                      methodName == names.clone &&
                      types.isArray(qualifierType)) {
                  // as a special case, array.clone() has a result that is

*** 2615,11 ***
           *  @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;
              }
--- 2638,11 ---
           *  @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 && names.isInitOrVNew(enclMethod.name)) {
                  JCBlock body = enclMethod.body;
                  if (body.stats.head.hasTag(EXEC) &&
                      ((JCExpressionStatement) body.stats.head).expr == tree)
                      return true;
              }

*** 2764,10 ***
--- 2787,20 ---
                  log.error(tree.pos(), Errors.EnumCantBeInstantiated);
  
              boolean isSpeculativeDiamondInferenceRound = TreeInfo.isDiamond(tree) &&
                      resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
              boolean skipNonDiamondPath = false;
+             // Check that it is an instantiation of a class and not a projection type
+             if (allowPrimitiveClasses) {
+                 if (clazz.hasTag(SELECT)) {
+                     JCFieldAccess fieldAccess = (JCFieldAccess) clazz;
+                     if (fieldAccess.selected.type.isPrimitiveClass() &&
+                             (fieldAccess.name == names.ref || fieldAccess.name == names.val)) {
+                         log.error(tree.pos(), Errors.ProjectionCantBeInstantiated);
+                     }
+                 }
+             }
              // Check that class is not abstract
              if (cdef == null && !isSpeculativeDiamondInferenceRound && // class body may be nulled out in speculative tree copy
                  (clazztype.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
                  log.error(tree.pos(),
                            Errors.AbstractCantBeInstantiated(clazztype.tsym));

*** 2788,11 ***
              }
              if (TreeInfo.isDiamond(tree)) {
                  ClassType site = new ClassType(clazztype.getEnclosingType(),
                              clazztype.tsym.type.getTypeArguments(),
                                                 clazztype.tsym,
!                                                clazztype.getMetadata());
  
                  Env<AttrContext> diamondEnv = localEnv.dup(tree);
                  diamondEnv.info.selectSuper = cdef != null || tree.classDeclRemoved();
                  diamondEnv.info.pendingResolutionPhase = null;
  
--- 2821,12 ---
              }
              if (TreeInfo.isDiamond(tree)) {
                  ClassType site = new ClassType(clazztype.getEnclosingType(),
                              clazztype.tsym.type.getTypeArguments(),
                                                 clazztype.tsym,
!                                                clazztype.getMetadata(),
+                                                clazztype.getFlavor());
  
                  Env<AttrContext> diamondEnv = localEnv.dup(tree);
                  diamondEnv.info.selectSuper = cdef != null || tree.classDeclRemoved();
                  diamondEnv.info.pendingResolutionPhase = null;
  

*** 2942,10 ***
--- 2976,13 ---
                      }
                      // For <>(){}, inferred types must also be accessible.
                      for (Type t : clazztype.getTypeArguments()) {
                          rs.checkAccessibleType(env, t);
                      }
+                     if (allowPrimitiveClasses) {
+                         chk.checkParameterizationByPrimitiveClass(tree, clazztype);
+                     }
                  }
  
                  // If we already errored, be careful to avoid a further avalanche. ErrorType answers
                  // false for isInterface call even when the original type is an interface.
                  boolean implementing = clazztype.tsym.isInterface() ||

*** 3014,10 ***
--- 3051,13 ---
       */
      public JCExpression makeNullCheck(JCExpression arg) {
          // optimization: new Outer() can never be null; skip null check
          if (arg.getTag() == NEWCLASS)
              return arg;
+         // Likewise arg can't be null if it is a primitive class instance.
+         if (allowPrimitiveClasses && arg.type.isPrimitiveClass())
+             return arg;
          // optimization: X.this is never null; skip null check
          Name name = TreeInfo.name(arg);
          if (name == names._this || name == names._super) return arg;
  
          JCTree.Tag optag = NULLCHK;

*** 3503,11 ***
                  /* if the field isn't static, then we can get the first constructor
                   * and use it as the owner of the environment. This is what
                   * LTM code is doing to look for type annotations so we are fine.
                   */
                  if ((owner.flags() & STATIC) == 0) {
!                     for (Symbol s : enclClass.members_field.getSymbolsByName(names.init)) {
                          newScopeOwner = s;
                          break;
                      }
                  } else {
                      /* if the field is static then we need to create a fake clinit
--- 3543,12 ---
                  /* if the field isn't static, then we can get the first constructor
                   * and use it as the owner of the environment. This is what
                   * LTM code is doing to look for type annotations so we are fine.
                   */
                  if ((owner.flags() & STATIC) == 0) {
!                     Name constructorName = owner.isConcreteValueClass() ? names.vnew : names.init;
+                     for (Symbol s : enclClass.members_field.getSymbolsByName(constructorName)) {
                          newScopeOwner = s;
                          break;
                      }
                  } else {
                      /* if the field is static then we need to create a fake clinit

*** 3566,17 ***
                  //give up attribution of method reference
                  result = that.type = exprType;
                  return;
              }
  
              if (TreeInfo.isStaticSelector(that.expr, names)) {
                  //if the qualifier is a type, validate it; raw warning check is
                  //omitted as we don't know at this stage as to whether this is a
                  //raw selector (because of inference)
                  chk.validate(that.expr, env, false);
              } else {
-                 Symbol lhsSym = TreeInfo.symbol(that.expr);
                  localEnv.info.selectSuper = lhsSym != null && lhsSym.name == names._super;
              }
              //attrib type-arguments
              List<Type> typeargtypes = List.nil();
              if (that.typeargs != null) {
--- 3607,21 ---
                  //give up attribution of method reference
                  result = that.type = exprType;
                  return;
              }
  
+             Symbol lhsSym = TreeInfo.symbol(that.expr);
              if (TreeInfo.isStaticSelector(that.expr, names)) {
+                 // TODO - a bit hacky but...
+                 if (lhsSym != null && lhsSym.isConcreteValueClass() && that.name == names.init) {
+                     that.name = names.vnew;
+                 }
                  //if the qualifier is a type, validate it; raw warning check is
                  //omitted as we don't know at this stage as to whether this is a
                  //raw selector (because of inference)
                  chk.validate(that.expr, env, false);
              } else {
                  localEnv.info.selectSuper = lhsSym != null && lhsSym.name == names._super;
              }
              //attrib type-arguments
              List<Type> typeargtypes = List.nil();
              if (that.typeargs != null) {

*** 3656,11 ***
                      result = that.type = types.createErrorType(currentTarget);
                      return;
                  }
              }
  
!             that.sym = refSym.isConstructor() ? refSym.baseSymbol() : refSym;
              that.kind = lookupHelper.referenceKind(that.sym);
              that.ownerAccessible = rs.isAccessible(localEnv, that.sym.enclClass());
  
              if (desc.getReturnType() == Type.recoveryType) {
                  // stop here
--- 3701,11 ---
                      result = that.type = types.createErrorType(currentTarget);
                      return;
                  }
              }
  
!             that.sym = refSym.isInitOrVNew() ? refSym.baseSymbol() : refSym;
              that.kind = lookupHelper.referenceKind(that.sym);
              that.ownerAccessible = rs.isAccessible(localEnv, that.sym.enclClass());
  
              if (desc.getReturnType() == Type.recoveryType) {
                  // stop here

*** 4340,10 ***
--- 4385,20 ---
                  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 (allowPrimitiveClasses && tree.name == names._class && site.isPrimitiveClass()) {
+             /* 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
+              */
+              if (!tree.selected.hasTag(SELECT) || ((JCFieldAccess) tree.selected).name != names.val) {
+                  tree.selected.setType(site = site.referenceProjection());
+              }
+         }
          if (!pkind().contains(KindSelector.TYP_PCK))
              site = capture(site); // Capture field access
  
          // don't allow T.class T[].class, etc
          if (skind == KindSelector.TYP) {

*** 4352,11 ***
                  elt = ((ArrayType)elt).elemtype;
              if (elt.hasTag(TYPEVAR)) {
                  log.error(tree.pos(), Errors.TypeVarCantBeDeref);
                  result = tree.type = types.createErrorType(tree.name, site.tsym, site);
                  tree.sym = tree.type.tsym;
!                 return ;
              }
          }
  
          // If qualifier symbol is a type or `super', assert `selectSuper'
          // for the selection. This is relevant for determining whether
--- 4407,11 ---
                  elt = ((ArrayType)elt).elemtype;
              if (elt.hasTag(TYPEVAR)) {
                  log.error(tree.pos(), Errors.TypeVarCantBeDeref);
                  result = tree.type = types.createErrorType(tree.name, site.tsym, site);
                  tree.sym = tree.type.tsym;
!                 return;
              }
          }
  
          // If qualifier symbol is a type or `super', assert `selectSuper'
          // for the selection. This is relevant for determining whether

*** 4456,11 ***
              // Check that super-qualified symbols are not abstract (JLS)
              rs.checkNonAbstract(tree.pos(), sym);
  
              if (site.isRaw()) {
                  // Determine argument types for site.
!                 Type site1 = types.asSuper(env.enclClass.sym.type, site.tsym);
                  if (site1 != null) site = site1;
              }
          }
  
          if (env.info.isSerializable) {
--- 4511,11 ---
              // Check that super-qualified symbols are not abstract (JLS)
              rs.checkNonAbstract(tree.pos(), sym);
  
              if (site.isRaw()) {
                  // Determine argument types for site.
!                 Type site1 = types.asSuper(env.enclClass.sym.type.referenceProjectionOrSelf(), site.tsym);
                  if (site1 != null) site = site1;
              }
          }
  
          if (env.info.isSerializable) {

*** 4499,10 ***
--- 4554,12 ---
                      return rs.resolveSelf(pos, env, site.tsym, name);
                  } else if (name == names._class) {
                      // In this case, we have already made sure in
                      // visitSelect that qualifier expression is a type.
                      return syms.getClassField(site, types);
+                 } else if (allowPrimitiveClasses && site.isPrimitiveClass() && isType(location) && resultInfo.pkind.contains(KindSelector.TYP) && (name == names.ref || name == names.val)) {
+                     return site.tsym;
                  } else {
                      // We are seeing a plain identifier as selector.
                      Symbol sym = rs.findIdentInType(pos, env, site, name, resultInfo.pkind);
                          sym = rs.accessBase(sym, pos, location, site, name, true);
                      return sym;

*** 4602,24 ***
              }
              Type owntype; // The computed type of this identifier occurrence.
              switch (sym.kind) {
              case TYP:
                  // For types, the computed type equals the symbol's type,
!                 // except for two situations:
                  owntype = sym.type;
                  if (owntype.hasTag(CLASS)) {
                      chk.checkForBadAuxiliaryClassAccess(tree.pos(), env, (ClassSymbol)sym);
                      Type ownOuter = owntype.getEnclosingType();
  
!                     // (a) If the symbol's type is parameterized, erase it
                      // because no type parameters were given.
                      // We recover generic outer type later in visitTypeApply.
                      if (owntype.tsym.type.getTypeArguments().nonEmpty()) {
                          owntype = types.erasure(owntype);
                      }
  
!                     // (b) If the symbol's type is an inner class, then
                      // we have to interpret its outer type as a superclass
                      // of the site type. Example:
                      //
                      // class Tree<A> { class Visitor { ... } }
                      // class PointTree extends Tree<Point> { ... }
--- 4659,34 ---
              }
              Type owntype; // The computed type of this identifier occurrence.
              switch (sym.kind) {
              case TYP:
                  // For types, the computed type equals the symbol's type,
!                 // except for three situations:
                  owntype = sym.type;
                  if (owntype.hasTag(CLASS)) {
+                     if (allowPrimitiveClasses) {
+                         Assert.check(owntype.getFlavor() != Flavor.X_Typeof_X);
+                     }
                      chk.checkForBadAuxiliaryClassAccess(tree.pos(), env, (ClassSymbol)sym);
                      Type ownOuter = owntype.getEnclosingType();
  
!                     // (a) If symbol is a primitive class and its reference projection
+                     // is requested via the .ref notation, then adjust the computed type to
+                     // reflect this.
+                     if (allowPrimitiveClasses && owntype.isPrimitiveClass() && tree.hasTag(SELECT) && ((JCFieldAccess) tree).name == names.ref) {
+                         owntype = new ClassType(owntype.getEnclosingType(), owntype.getTypeArguments(), (TypeSymbol)sym, owntype.getMetadata(), Flavor.L_TypeOf_Q);
+                     }
+ 
+                     // (b) If the symbol's type is parameterized, erase it
                      // because no type parameters were given.
                      // We recover generic outer type later in visitTypeApply.
                      if (owntype.tsym.type.getTypeArguments().nonEmpty()) {
                          owntype = types.erasure(owntype);
                      }
  
!                     // (c) If the symbol's type is an inner class, then
                      // we have to interpret its outer type as a superclass
                      // of the site type. Example:
                      //
                      // class Tree<A> { class Visitor { ... } }
                      // class PointTree extends Tree<Point> { ... }

*** 4635,11 ***
                          if (normOuter == null) // perhaps from an import
                              normOuter = types.erasure(ownOuter);
                          if (normOuter != ownOuter)
                              owntype = new ClassType(
                                  normOuter, List.nil(), owntype.tsym,
!                                 owntype.getMetadata());
                      }
                  }
                  break;
              case VAR:
                  VarSymbol v = (VarSymbol)sym;
--- 4702,11 ---
                          if (normOuter == null) // perhaps from an import
                              normOuter = types.erasure(ownOuter);
                          if (normOuter != ownOuter)
                              owntype = new ClassType(
                                  normOuter, List.nil(), owntype.tsym,
!                                 owntype.getMetadata(), owntype.getFlavor());
                      }
                  }
                  break;
              case VAR:
                  VarSymbol v = (VarSymbol)sym;

*** 4698,11 ***
  
              // Emit a `deprecation' warning if symbol is deprecated.
              // (for constructors (but not for constructor references), the error
              // was given when the constructor was resolved)
  
!             if (sym.name != names.init || tree.hasTag(REFERENCE)) {
                  chk.checkDeprecated(tree.pos(), env.info.scope.owner, sym);
                  chk.checkSunAPI(tree.pos(), sym);
                  chk.checkProfile(tree.pos(), sym);
                  chk.checkPreview(tree.pos(), env.info.scope.owner, sym);
              }
--- 4765,11 ---
  
              // Emit a `deprecation' warning if symbol is deprecated.
              // (for constructors (but not for constructor references), the error
              // was given when the constructor was resolved)
  
!             if (!names.isInitOrVNew(sym.name) || tree.hasTag(REFERENCE)) {
                  chk.checkDeprecated(tree.pos(), env.info.scope.owner, sym);
                  chk.checkSunAPI(tree.pos(), sym);
                  chk.checkProfile(tree.pos(), sym);
                  chk.checkPreview(tree.pos(), env.info.scope.owner, sym);
              }

*** 4952,10 ***
--- 5019,41 ---
              log.report(errDiag);
              return types.createErrorType(site);
          }
      }
  
+     public void visitDefaultValue(JCDefaultValue tree) {
+         if (!allowPrimitiveClasses) {
+             log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(),
+                     Feature.PRIMITIVE_CLASSES.error(sourceName));
+         }
+ 
+         // Attribute the qualifier expression, and determine its symbol (if any).
+         Type site = attribTree(tree.clazz, env, new ResultInfo(KindSelector.TYP_PCK, Type.noType));
+         if (!pkind().contains(KindSelector.TYP_PCK))
+             site = capture(site); // Capture field access
+         if (!allowPrimitiveClasses) {
+             result = types.createErrorType(names._default, site.tsym, site);
+         } else {
+             Symbol sym = switch (site.getTag()) {
+                 case WILDCARD -> throw new AssertionError(tree);
+                 case PACKAGE -> {
+                     log.error(tree.pos, Errors.CantResolveLocation(Kinds.KindName.CLASS, site.tsym.getQualifiedName(), null, null,
+                             Fragments.Location(Kinds.typeKindName(env.enclClass.type), env.enclClass.type, null)));
+                     yield syms.errSymbol;
+                 }
+                 case ERROR -> types.createErrorType(names._default, site.tsym, site).tsym;
+                 default -> new VarSymbol(STATIC, names._default, site, site.tsym);
+             };
+ 
+             if (site.hasTag(TYPEVAR) && sym.kind != ERR) {
+                 site = types.skipTypeVars(site, true);
+             }
+             result = checkId(tree, site, sym, env, resultInfo);
+         }
+     }
+ 
      public void visitLiteral(JCLiteral tree) {
          result = check(tree, litType(tree.typetag).constType(tree.value),
                  KindSelector.VAL, resultInfo);
      }
      //where

*** 5018,11 ***
                              site = types.erasure(clazzOuter);
                          clazzOuter = site;
                      }
                  }
                  owntype = new ClassType(clazzOuter, actuals, clazztype.tsym,
!                                         clazztype.getMetadata());
              } else {
                  if (formals.length() != 0) {
                      log.error(tree.pos(),
                                Errors.WrongNumberTypeArgs(Integer.toString(formals.length())));
                  } else {
--- 5116,11 ---
                              site = types.erasure(clazzOuter);
                          clazzOuter = site;
                      }
                  }
                  owntype = new ClassType(clazzOuter, actuals, clazztype.tsym,
!                                         clazztype.getMetadata(), clazztype.getFlavor());
              } else {
                  if (formals.length() != 0) {
                      log.error(tree.pos(),
                                Errors.WrongNumberTypeArgs(Integer.toString(formals.length())));
                  } else {

*** 5145,11 ***
              } else {
                  extending = null;
                  implementing = bounds;
              }
              JCClassDecl cd = make.at(tree).ClassDef(
!                 make.Modifiers(PUBLIC | ABSTRACT),
                  names.empty, List.nil(),
                  extending, implementing, List.nil());
  
              ClassSymbol c = (ClassSymbol)owntype.tsym;
              Assert.check((c.flags() & COMPOUND) != 0);
--- 5243,11 ---
              } else {
                  extending = null;
                  implementing = bounds;
              }
              JCClassDecl cd = make.at(tree).ClassDef(
!                 make.Modifiers(PUBLIC | ABSTRACT | (extending != null && TreeInfo.symbol(extending).isPrimitiveClass() ? PRIMITIVE_CLASS : 0)),
                  names.empty, List.nil(),
                  extending, implementing, List.nil());
  
              ClassSymbol c = (ClassSymbol)owntype.tsym;
              Assert.check((c.flags() & COMPOUND) != 0);

*** 5168,11 ***
      public void visitWildcard(JCWildcard tree) {
          //- System.err.println("visitWildcard("+tree+");");//DEBUG
          Type type = (tree.kind.kind == BoundKind.UNBOUND)
              ? syms.objectType
              : attribType(tree.inner, env);
!         result = check(tree, new WildcardType(chk.checkRefType(tree.pos(), type),
                                                tree.kind.kind,
                                                syms.boundClass),
                  KindSelector.TYP, resultInfo);
      }
  
--- 5266,11 ---
      public void visitWildcard(JCWildcard tree) {
          //- System.err.println("visitWildcard("+tree+");");//DEBUG
          Type type = (tree.kind.kind == BoundKind.UNBOUND)
              ? syms.objectType
              : attribType(tree.inner, env);
!         result = check(tree, new WildcardType(chk.checkRefType(tree.pos(), type, false),
                                                tree.kind.kind,
                                                syms.boundClass),
                  KindSelector.TYP, resultInfo);
      }
  

*** 5286,10 ***
--- 5384,15 ---
       */
      public void attribClass(DiagnosticPosition pos, ClassSymbol c) {
          try {
              annotate.flush();
              attribClass(c);
+             if (allowPrimitiveClasses && c.type.isPrimitiveClass()) {
+                 final Env<AttrContext> env = typeEnvs.get(c);
+                 if (env != null && env.tree != null && env.tree.hasTag(CLASSDEF))
+                     chk.checkNonCyclicMembership((JCClassDecl)env.tree);
+             }
          } catch (CompletionFailure ex) {
              chk.completionError(pos, ex);
          }
      }
  

*** 5406,11 ***
  
                      if (!hasErrorSuper) {
                          log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
                      }
                  }
!             } else {
                  if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) {
                      log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local));
                  }
  
                  if (!c.type.isCompound()) {
--- 5509,11 ---
  
                      if (!hasErrorSuper) {
                          log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
                      }
                  }
!             } 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()) {

*** 5461,10 ***
--- 5564,15 ---
  
                  if (rs.isSerializable(c.type)) {
                      env.info.isSerializable = true;
                  }
  
+                 if (c.isValueClass()) {
+                     Assert.check(env.tree.hasTag(CLASSDEF));
+                     chk.checkConstraintsOfValueClass(env.tree.pos(), c);
+                 }
+ 
                  attribClassBody(env, c);
  
                  chk.checkDeprecatedAnnotation(env.tree.pos(), c);
                  chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
                  chk.checkFunctionalInterface((JCClassDecl) env.tree, c);
< prev index next >