8005854: Add support for array constructor references
authormcimadamore
Wed, 16 Jan 2013 16:27:01 +0000
changeset 15360 450af2a9e3c9
parent 15359 a73dcb8dcbae
child 15361 01f1828683e6
8005854: Add support for array constructor references Summary: Support constructor references of the kind int[]::new Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java
langtools/test/tools/javac/lambda/MethodReference59.java
langtools/test/tools/javac/lambda/MethodReference60.java
langtools/test/tools/javac/lambda/MethodReference60.out
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Jan 15 13:03:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Jan 16 16:27:01 2013 +0000
@@ -634,25 +634,40 @@
         }
     }
 
+    Type checkClassOrArrayType(DiagnosticPosition pos, Type t) {
+        if (!t.hasTag(CLASS) && !t.hasTag(ARRAY) && !t.hasTag(ERROR)) {
+            return typeTagError(pos,
+                                diags.fragment("type.req.class.array"),
+                                asTypeParam(t));
+        } else {
+            return t;
+        }
+    }
+
     /** Check that type is a class or interface type.
      *  @param pos           Position to be used for error reporting.
      *  @param t             The type to be checked.
      */
     Type checkClassType(DiagnosticPosition pos, Type t) {
-        if (!t.hasTag(CLASS) && !t.hasTag(ERROR))
+        if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
             return typeTagError(pos,
                                 diags.fragment("type.req.class"),
-                                (t.hasTag(TYPEVAR))
-                                ? diags.fragment("type.parameter", t)
-                                : t);
-        else
+                                asTypeParam(t));
+        } else {
             return t;
+        }
     }
+    //where
+        private Object asTypeParam(Type t) {
+            return (t.hasTag(TYPEVAR))
+                                    ? diags.fragment("type.parameter", t)
+                                    : t;
+        }
 
     /** Check that type is a valid qualifier for a constructor reference expression
      */
     Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
-        t = checkClassType(pos, t);
+        t = checkClassOrArrayType(pos, t);
         if (t.hasTag(CLASS)) {
             if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
                 log.error(pos, "abstract.cant.be.instantiated");
@@ -690,11 +705,8 @@
      *  @param t             The type to be checked.
      */
     Type checkReifiableReferenceType(DiagnosticPosition pos, Type t) {
-        if (!t.hasTag(CLASS) && !t.hasTag(ARRAY) && !t.hasTag(ERROR)) {
-            return typeTagError(pos,
-                                diags.fragment("type.req.class.array"),
-                                t);
-        } else if (!types.isReifiable(t)) {
+        t = checkClassOrArrayType(pos, t);
+        if (!t.isErroneous() && !types.isReifiable(t)) {
             log.error(pos, "illegal.generic.type.for.instof");
             return types.createErrorType(t);
         } else {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Jan 15 13:03:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed Jan 16 16:27:01 2013 +0000
@@ -302,6 +302,7 @@
             case UNBOUND:           /** Type :: instMethod */
             case STATIC:            /** Type :: staticMethod */
             case TOPLEVEL:          /** Top level :: new */
+            case ARRAY_CTOR:        /** ArrayType :: new */
                 init = null;
                 break;
 
@@ -645,24 +646,33 @@
          * to the first bridge synthetic parameter
          */
         private JCExpression bridgeExpressionNew() {
-            JCExpression encl = null;
-            switch (tree.kind) {
-                case UNBOUND:
-                case IMPLICIT_INNER:
-                    encl = make.Ident(params.first());
-            }
+            if (tree.kind == ReferenceKind.ARRAY_CTOR) {
+                //create the array creation expression
+                JCNewArray newArr = make.NewArray(make.Type(types.elemtype(tree.getQualifierExpression().type)),
+                        List.of(make.Ident(params.first())),
+                        null);
+                newArr.type = tree.getQualifierExpression().type;
+                return newArr;
+            } else {
+                JCExpression encl = null;
+                switch (tree.kind) {
+                    case UNBOUND:
+                    case IMPLICIT_INNER:
+                        encl = make.Ident(params.first());
+                }
 
-            //create the instance creation expression
-            JCNewClass newClass = make.NewClass(encl,
-                    List.<JCExpression>nil(),
-                    make.Type(tree.getQualifierExpression().type),
-                    convertArgs(tree.sym, args.toList(), tree.varargsElement),
-                    null);
-            newClass.constructor = tree.sym;
-            newClass.constructorType = tree.sym.erasure(types);
-            newClass.type = tree.getQualifierExpression().type;
-            setVarargsIfNeeded(newClass, tree.varargsElement);
-            return newClass;
+                //create the instance creation expression
+                JCNewClass newClass = make.NewClass(encl,
+                        List.<JCExpression>nil(),
+                        make.Type(tree.getQualifierExpression().type),
+                        convertArgs(tree.sym, args.toList(), tree.varargsElement),
+                        null);
+                newClass.constructor = tree.sym;
+                newClass.constructorType = tree.sym.erasure(types);
+                newClass.type = tree.getQualifierExpression().type;
+                setVarargsIfNeeded(newClass, tree.varargsElement);
+                return newClass;
+            }
         }
 
         private VarSymbol addParameter(String name, Type p, boolean genArg) {
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Jan 15 13:03:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jan 16 16:27:01 2013 +0000
@@ -2386,10 +2386,23 @@
                                   List<Type> typeargtypes,
                                   boolean boxingAllowed) {
         MethodResolutionPhase maxPhase = boxingAllowed ? VARARITY : BASIC;
+
+        ReferenceLookupHelper boundLookupHelper;
+        if (!name.equals(names.init)) {
+            //method reference
+            boundLookupHelper =
+                    new MethodReferenceLookupHelper(referenceTree, name, site, argtypes, typeargtypes, maxPhase);
+        } else if (site.hasTag(ARRAY)) {
+            //array constructor reference
+            boundLookupHelper =
+                    new ArrayConstructorReferenceLookupHelper(referenceTree, site, argtypes, typeargtypes, maxPhase);
+        } else {
+            //class constructor reference
+            boundLookupHelper =
+                    new ConstructorReferenceLookupHelper(referenceTree, site, argtypes, typeargtypes, maxPhase);
+        }
+
         //step 1 - bound lookup
-        ReferenceLookupHelper boundLookupHelper = name.equals(names.init) ?
-                new ConstructorReferenceLookupHelper(referenceTree, site, argtypes, typeargtypes, maxPhase) :
-                new MethodReferenceLookupHelper(referenceTree, name, site, argtypes, typeargtypes, maxPhase);
         Env<AttrContext> boundEnv = env.dup(env.tree, env.info.dup());
         Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(), site.tsym, boundLookupHelper);
 
@@ -2627,6 +2640,33 @@
     }
 
     /**
+     * Helper class for array constructor lookup; an array constructor lookup
+     * is simulated by looking up a method that returns the array type specified
+     * as qualifier, and that accepts a single int parameter (size of the array).
+     */
+    class ArrayConstructorReferenceLookupHelper extends ReferenceLookupHelper {
+
+        ArrayConstructorReferenceLookupHelper(JCMemberReference referenceTree, Type site, List<Type> argtypes,
+                List<Type> typeargtypes, MethodResolutionPhase maxPhase) {
+            super(referenceTree, names.init, site, argtypes, typeargtypes, maxPhase);
+        }
+
+        @Override
+        protected Symbol lookup(Env<AttrContext> env, MethodResolutionPhase phase) {
+            Scope sc = new Scope(syms.arrayClass);
+            MethodSymbol arrayConstr = new MethodSymbol(PUBLIC, name, null, site.tsym);
+            arrayConstr.type = new MethodType(List.of(syms.intType), site, List.<Type>nil(), syms.methodClass);
+            sc.enter(arrayConstr);
+            return findMethodInScope(env, site, name, argtypes, typeargtypes, sc, methodNotFound, phase.isBoxingRequired(), phase.isVarargsRequired(), false, false);
+        }
+
+        @Override
+        ReferenceKind referenceKind(Symbol sym) {
+            return ReferenceKind.ARRAY_CTOR;
+        }
+    }
+
+    /**
      * Helper class for constructor reference lookup. The lookup logic is based
      * upon either Resolve.findMethod or Resolve.findDiamond - depending on
      * whether the constructor reference needs diamond inference (this is the case
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Jan 15 13:03:11 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Jan 16 16:27:01 2013 +0000
@@ -1838,7 +1838,9 @@
             /** Inner # new */
             IMPLICIT_INNER(ReferenceMode.NEW, false),
             /** Toplevel # new */
-            TOPLEVEL(ReferenceMode.NEW, false);
+            TOPLEVEL(ReferenceMode.NEW, false),
+            /** ArrayType # new */
+            ARRAY_CTOR(ReferenceMode.NEW, false);
 
             final ReferenceMode mode;
             final boolean unbound;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference59.java	Wed Jan 16 16:27:01 2013 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004102
+ * @summary Add support for array constructor references
+ */
+public class MethodReference59 {
+
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    interface ArrayFactory<X> {
+        X make(int size);
+    }
+
+    public static void main(String[] args) {
+        ArrayFactory<int[]> factory1 = int[]::new;
+        int[] i1 = factory1.make(5);
+        assertTrue(i1.length == 5);
+        ArrayFactory<int[][]> factory2 = int[][]::new;
+        int[][] i2 = factory2.make(5);
+        assertTrue(i2.length == 5);
+        assertTrue(assertionCount == 2);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference60.java	Wed Jan 16 16:27:01 2013 +0000
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004102
+ * @summary Add support for array constructor references
+ * @compile/fail/ref=MethodReference60.out -XDrawDiagnostics MethodReference60.java
+ */
+public class MethodReference60 {
+
+    interface ArrayFactory<X> {
+        X make(int size);
+    }
+
+    interface BadArrayFactory1<X> {
+        X make();
+    }
+
+    interface BadArrayFactory2<X> {
+        X make(int i1, int i2);
+    }
+
+    interface BadArrayFactory3<X> {
+        X make(String s);
+    }
+
+    public static void main(String[] args) {
+        BadArrayFactory1<int[]> factory1 = int[]::new; //param mismatch
+        BadArrayFactory2<int[]> factory2 = int[]::new; //param mismatch
+        BadArrayFactory3<int[]> factory3 = int[]::new; //param mismatch
+        ArrayFactory<Integer> factory4 = int[]::new; //return type mismatch
+        ArrayFactory<Integer[]> factory5 = int[]::new; //return type mismatch
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReference60.out	Wed Jan 16 16:27:01 2013 +0000
@@ -0,0 +1,6 @@
+MethodReference60.java:49:44: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Array, int, compiler.misc.no.args, kindname.class, Array, (compiler.misc.arg.length.mismatch)))
+MethodReference60.java:50:44: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Array, int, int,int, kindname.class, Array, (compiler.misc.arg.length.mismatch)))
+MethodReference60.java:51:44: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Array, int, java.lang.String, kindname.class, Array, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.String, int))))
+MethodReference60.java:52:42: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.mref: (compiler.misc.inconvertible.types: int[], java.lang.Integer))
+MethodReference60.java:53:44: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.mref: (compiler.misc.inconvertible.types: int[], java.lang.Integer[]))
+5 errors