changeset 746:76f6f9e8b0ec

Misc bug fixes: *) SAM conversion where target type is erroneous lead to spurious diagnostic *) Issues with SAM conversion and generic class hierarchies *) Overhaul of extension method resolution algorithm
author mcimadamore
date Thu, 28 Oct 2010 13:04:00 +0100
parents 4506d2ab97a0
children fa6868eac2c4
files src/share/classes/com/sun/tools/javac/code/Types.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/comp/Resolve.java test/tools/javac/defender/Neg02.java test/tools/javac/defender/Neg02.out test/tools/javac/defender/Pos05.java test/tools/javac/defender/Pos06.java test/tools/javac/lambda/LambdaConv11.java
diffstat 9 files changed, 263 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Oct 26 17:50:10 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Thu Oct 28 13:04:00 2010 +0100
@@ -437,7 +437,7 @@
         }
         
         ListBuffer<Symbol> abstracts = ListBuffer.lb();
-        int count = findSAM(t, abstracts, t.isInterface());
+        int count = findSAM(t, t, abstracts);
         if (abstracts.size() == 0) {
             //t must define a suitable non-generic method
             return new SAMResult(site, t, "no.target.method.for.lambda.conv");
@@ -449,7 +449,7 @@
         }
     }    
     //where
-    private int findSAM(Type t, ListBuffer<Symbol> buf, boolean isInterface) {
+    private int findSAM(Type site, Type t, ListBuffer<Symbol> buf) {
         int count = 0;
         if (t == Type.noType) return count;
         for (Scope.Entry e = t.tsym.members().elems ; e != null ; e = e.sibling) {
@@ -457,18 +457,20 @@
                     e.sym.kind == Kinds.MTH &&
                     (e.sym.flags() & ABSTRACT) != 0 &&
                     (e.sym.flags() & DEFENDER) == 0 &&
-                    (!isInterface || !overridesObjectMethod(e.sym, t.tsym))) {
+                    (!t.isInterface() || !overridesObjectMethod(e.sym, t.tsym))) {
+                MethodSymbol msym = (MethodSymbol)e.sym;
                 if (buf.isEmpty() ||
-                        (e.sym.name == buf.first().name &&
-                        overrideEquivalent(e.sym.type, buf.first().type))) {
+                        (msym.name == buf.first().name &&
+                        msym.implementation(site.tsym, this, false) != null &&
+                        overrideEquivalent(msym.implementation(site.tsym, this, false).type, buf.first().type))) {
                     buf.append(e.sym);
                 }
                 count++;
             }
         }
-        count += findSAM(supertype(t), buf, isInterface);
+        count += findSAM(site, supertype(t), buf);
         for (Type i : interfaces(t)) {
-            count += findSAM(i, buf, isInterface);
+            count += findSAM(site, i, buf);
         }
         return count;
     }
@@ -630,8 +632,9 @@
         }
 
         public JCDiagnostic getDiagnostic(JCDiagnostic.Factory diags) {
-            return diags.fragment(errKey,
-                        args);
+            return errKey != null ?
+                diags.fragment(errKey, args) :
+                null;
         }
 
         /**
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Oct 26 17:50:10 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Oct 28 13:04:00 2010 +0100
@@ -2371,11 +2371,6 @@
         //'normalize' the target type (i.e. strip toplevel wildcards, where possible)
         Type superType = types.normalize(samOrFunctionType);
 
-//        Type samType = chk.checkSAM(that, superType, env);
-//        if (samType.isErroneous()) {
-//            return that.type = samType;
-//        }
-
         //create an environment for attribution of the lambda expression
         final Env<AttrContext> localEnv = lambdaEnvironment(that, superType);
 
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Oct 26 17:50:10 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Oct 28 13:04:00 2010 +0100
@@ -794,10 +794,9 @@
             //if the target type is neither a SAM type nor a function type, reports an error
             Types.SAMResult res = types.findSAM(t, env);
             String key = "invalid.target.type.for.lambda.conv";
-            JCDiagnostic explanation = null;
-            if (res.isErroneous()) {
+            JCDiagnostic explanation = res.getDiagnostic(diags);
+            if (res.isErroneous() && explanation != null) {
                 key = "invalid.target.type.for.lambda.conv.1";
-                explanation = res.getDiagnostic(diags);
             }
             log.error(pos, key, t, explanation);
             return types.createErrorType(t);
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Oct 26 17:50:10 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Oct 28 13:04:00 2010 +0100
@@ -72,6 +72,7 @@
     public final boolean allowMethodHandles;
     public final boolean allowInvokeDynamic;
     public final boolean allowTransitionalJSR292;
+    public final boolean allowDefenderMethods;
     private final boolean debugResolve;
 
     Scope polymorphicSignatureScope;
@@ -118,6 +119,7 @@
         allowInvokeDynamic = (allowTransitionalJSR292 ||
                 target.hasInvokedynamic()) &&
                 options.isSet("invokedynamic");
+        allowDefenderMethods = source.allowDefenderMethods();
         polymorphicSignatureScope = new Scope(syms.noSymbol);
 
         inapplicableMethodException = new InapplicableMethodException(diags);
@@ -900,26 +902,69 @@
             if (name == names.init)
                 break;
             //- System.out.println(" - " + bestSoFar);
-            Symbol concrete = methodNotFound;
-            if ((bestSoFar.flags() & ABSTRACT) == 0)
-                concrete = bestSoFar;
+            if (abstractok) {
+                Symbol concrete = methodNotFound;
+                if ((bestSoFar.flags() & ABSTRACT) == 0)
+                    concrete = bestSoFar;
+                for (List<Type> l = types.interfaces(c.type);
+                     l.nonEmpty();
+                     l = l.tail) {
+                    bestSoFar = findMethod(env, site, name, argtypes,
+                                           typeargtypes,
+                                           l.head, abstractok, bestSoFar,
+                                           allowBoxing, useVarargs, operator);
+                }
+                if (concrete != bestSoFar &&
+                    concrete.kind < ERR  && bestSoFar.kind < ERR &&
+                    types.isSubSignature(concrete.type, bestSoFar.type))
+                    bestSoFar = concrete;
+            }
+        }
+        if (bestSoFar.kind >= AMBIGUOUS && allowDefenderMethods) {
+            bestSoFar = findDefenderMethod(env, site, name, argtypes, typeargtypes,
+                    intype, abstractok, bestSoFar, allowBoxing, useVarargs, operator);
+        }
+        return bestSoFar;
+    }
+    //where
+    private Symbol findDefenderMethod(Env<AttrContext> env,
+                              Type site,
+                              Name name,
+                              List<Type> argtypes,
+                              List<Type> typeargtypes,
+                              Type intype,
+                              boolean abstractok,
+                              Symbol bestSoFar,
+                              boolean allowBoxing,
+                              boolean useVarargs,
+                              boolean operator) {
+        for (Type ct = intype; ct.tag == CLASS || ct.tag == TYPEVAR; ct = types.supertype(ct)) {
+            while (ct.tag == TYPEVAR)
+                ct = ct.getUpperBound();
+            ClassSymbol c = (ClassSymbol)ct.tsym;
+            if (c.isInterface() && (c.flags() & DEFENDER) != 0) {
+                for (Scope.Entry e = c.members().lookup(name);
+                        e.scope != null;
+                        e = e.next()) {
+                    //- System.out.println(" e " + e.sym);
+                    if (e.sym.kind == MTH &&
+                            (e.sym.flags_field & DEFENDER) != 0) {
+                        bestSoFar = selectBest(env, site, argtypes, typeargtypes,
+                                           e.sym, bestSoFar,
+                                           allowBoxing,
+                                           useVarargs,
+                                           operator);
+                    }
+                }
+            }
             for (List<Type> l = types.interfaces(c.type);
-                 l.nonEmpty();
-                 l = l.tail) {
-                boolean abstractok2 = abstractok || (l.head.tsym.flags() & DEFENDER) != 0;
-                Symbol s2 = findMethod(env, site, name, argtypes,
-                                       typeargtypes,
-                                       l.head, abstractok2, bestSoFar,
-                                       allowBoxing, useVarargs, operator);
-                bestSoFar = s2.kind <= AMBIGUOUS && abstractok2 ?
-                    s2 :
-                    bestSoFar;
+                     l.nonEmpty();
+                     l = l.tail) {
+                bestSoFar = findDefenderMethod(env, site, name, argtypes,
+                        typeargtypes,
+                        l.head, abstractok, bestSoFar,
+                        allowBoxing, useVarargs, operator);
             }
-            if (concrete != bestSoFar &&
-                concrete.kind < ERR  && bestSoFar.kind < ERR &&
-                types.isSubSignature(concrete.type, bestSoFar.type))
-                bestSoFar = concrete;
-            
         }
         return bestSoFar;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Neg02.java	Thu Oct 28 13:04:00 2010 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, 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
+ * @summary check that ill-formed MI hierarchies do not compile
+ * @author  Maurizio Cimadamore
+ * @compile/fail/ref=Neg02.out -XDrawDiagnostics Neg02.java
+ */
+
+class Neg02 {
+     interface A {
+         extension void m() default Neg02.impl;
+     }
+
+     interface B {
+         extension void m() default Neg02.impl;
+     }
+
+     static class X implements A, B { }
+
+     void test(X x) {
+         x.m();
+         ((A)x).m();
+         ((B)x).m();
+     }
+
+     static void impl(A a) { }
+     static void impl(B b) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Neg02.out	Thu Oct 28 13:04:00 2010 +0100
@@ -0,0 +1,2 @@
+Neg02.java:40:13: compiler.err.types.incompatible.diff.default: Neg02.B, Neg02.A, m()
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos05.java	Thu Oct 28 13:04:00 2010 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010, 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
+ * @summary check that indirectly inherithed extension methods are discovered during resolution
+ * @author  Maurizio Cimadamore
+ * @compile Pos05.java
+ */
+
+class Pos05  {
+     interface A {
+         extension void m() default Pos05.impl;
+     }
+
+     interface B extends A { }
+
+     static class E implements B { }
+
+     void test(E e) {
+         e.m();
+     }
+
+     static void impl(A a) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/defender/Pos06.java	Thu Oct 28 13:04:00 2010 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 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
+ * @summary check that well-formed MI hierarchies behaves well w.r.t. method resolution (i.e. no ambiguities)
+ * @author  Maurizio Cimadamore
+ * @compile Pos06.java
+ */
+
+class Pos06 {
+     interface A {
+         extension void m() default Pos06.impl;
+     }
+
+     interface B {
+         extension void m() default Pos06.impl;
+     }
+
+     static class X implements A, B { }
+
+     void test(X x) {
+         x.m();
+         ((A)x).m();
+         ((B)x).m();
+     }
+
+     static void impl(Object a) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv11.java	Thu Oct 28 13:04:00 2010 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 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
+ * @summary issues with lambda conversion involving generic class hierarchies
+ * @author  Maurizio Cimadamore
+ * @compile LambdaConv11.java
+ */
+
+import java.util.Comparator;
+
+class LambdaConv11<T> {
+
+    static abstract class SAM<X> implements Comparator<X> {
+        public abstract int compare(X left, X right);
+    }
+
+    SAM<T> y = #{l, r -> 0 };
+}