langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
changeset 29776 984a79b71cfe
parent 29293 1583c6dd6df7
child 29842 826ac2519523
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Sat Mar 28 10:18:27 2015 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Mar 30 17:09:14 2015 +0530
@@ -32,6 +32,8 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.jvm.*;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@@ -84,6 +86,7 @@
     private boolean suppressAbortOnBadClassFile;
     private boolean enableSunApiLintControl;
     private final JavaFileManager fileManager;
+    private final Source source;
     private final Profile profile;
     private final boolean warnOnAccessToSensitiveMembers;
 
@@ -122,11 +125,12 @@
         lint = Lint.instance(context);
         fileManager = context.get(JavaFileManager.class);
 
-        Source source = Source.instance(context);
+        source = Source.instance(context);
         allowSimplifiedVarargs = source.allowSimplifiedVarargs();
         allowDefaultMethods = source.allowDefaultMethods();
         allowStrictMethodClashCheck = source.allowStrictMethodClashCheck();
         allowPrivateSafeVarargs = source.allowPrivateSafeVarargs();
+        allowDiamondWithAnonymousClassCreation = source.allowDiamondWithAnonymousClassCreation();
         complexInference = options.isSet("complexinference");
         warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
         suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile");
@@ -169,6 +173,10 @@
      */
     boolean allowPrivateSafeVarargs;
 
+    /** Switch: can diamond inference be used in anonymous instance creation ?
+     */
+    boolean allowDiamondWithAnonymousClassCreation;
+
     /** Switch: -complexinference option set?
      */
     boolean complexInference;
@@ -773,10 +781,9 @@
         if (!TreeInfo.isDiamond(tree) ||
                 t.isErroneous()) {
             return checkClassType(tree.clazz.pos(), t, true);
-        } else if (tree.def != null) {
+        } else if (tree.def != null && !allowDiamondWithAnonymousClassCreation) {
             log.error(tree.clazz.pos(),
-                    "cant.apply.diamond.1",
-                    t, diags.fragment("diamond.and.anon.class", t));
+                    Errors.CantApplyDiamond1(t, Fragments.DiamondAndAnonClassNotSupportedInSource(source.name)));
             return types.createErrorType(t);
         } else if (t.tsym.type.getTypeArguments().isEmpty()) {
             log.error(tree.clazz.pos(),
@@ -794,6 +801,59 @@
         }
     }
 
+    /** Check that the type inferred using the diamond operator does not contain
+     *  non-denotable types such as captured types or intersection types.
+     *  @param t the type inferred using the diamond operator
+     *  @return  the (possibly empty) list of non-denotable types.
+     */
+    List<Type> checkDiamondDenotable(ClassType t) {
+        ListBuffer<Type> buf = new ListBuffer<>();
+        for (Type arg : t.getTypeArguments()) {
+            if (!diamondTypeChecker.visit(arg, null)) {
+                buf.append(arg);
+            }
+        }
+        return buf.toList();
+    }
+        // where
+
+        /** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
+         *  types. The visit methods return false as soon as a non-denotable type is encountered and true
+         *  otherwise.
+         */
+        private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
+            @Override
+            public Boolean visitType(Type t, Void s) {
+                return true;
+            }
+            @Override
+            public Boolean visitClassType(ClassType t, Void s) {
+                if (t.isCompound()) {
+                    return false;
+                }
+                for (Type targ : t.getTypeArguments()) {
+                    if (!visit(targ, s)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            @Override
+            public Boolean visitCapturedType(CapturedType t, Void s) {
+                return false;
+            }
+
+            @Override
+            public Boolean visitArrayType(ArrayType t, Void s) {
+                return visit(t.elemtype, s);
+            }
+
+            @Override
+            public Boolean visitWildcardType(WildcardType t, Void s) {
+                return visit(t.type, s);
+            }
+        };
+
     void checkVarargsMethodDecl(Env<AttrContext> env, JCMethodDecl tree) {
         MethodSymbol m = tree.sym;
         if (!allowSimplifiedVarargs) return;
@@ -1917,7 +1977,7 @@
      *                      for errors.
      *  @param m            The overriding method.
      */
-    void checkOverride(JCMethodDecl tree, MethodSymbol m) {
+    void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
         ClassSymbol origin = (ClassSymbol)m.owner;
         if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name))
             if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
@@ -1934,7 +1994,12 @@
             }
         }
 
-        if (m.attribute(syms.overrideType.tsym) != null && !isOverrider(m)) {
+        // Check if this method must override a super method due to being annotated with @Override
+        // or by virtue of being a member of a diamond inferred anonymous class. Latter case is to
+        // be treated "as if as they were annotated" with @Override.
+        boolean mustOverride = m.attribute(syms.overrideType.tsym) != null ||
+                (env.info.isAnonymousDiamond && !m.isConstructor() && !m.isPrivate());
+        if (mustOverride && !isOverrider(m)) {
             DiagnosticPosition pos = tree.pos();
             for (JCAnnotation a : tree.getModifiers().annotations) {
                 if (a.annotationType.type.tsym == syms.overrideType.tsym) {