changeset 2245:00274133b7d2

8016177: structural most specific and stuckness 8016178: Order of unsticking functional expressions Refined rules for structural most specific for lambda/method references after recent changes.
author mcimadamore
date Fri, 26 Jul 2013 12:46:37 +0100
parents d34073d069c8
children 93e9a9aa6e18
files src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java src/share/classes/com/sun/tools/javac/comp/Resolve.java src/share/classes/com/sun/tools/javac/tree/JCTree.java test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java test/tools/javac/lambda/8016177/T8016177c.java test/tools/javac/lambda/8016177/T8016177c.out test/tools/javac/lambda/methodReference/SamConversionComboTest.java
diffstat 7 files changed, 104 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Thu Jul 25 16:29:24 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Fri Jul 26 12:46:37 2013 +0100
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.comp;
 
+import com.sun.source.tree.MemberReferenceTree;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
@@ -553,10 +554,12 @@
 
             ResultInfo resultInfo;
             InferenceContext inferenceContext;
+            Env<AttrContext> env;
 
             public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) {
                 this.resultInfo = resultInfo;
                 this.inferenceContext = deferredAttrContext.inferenceContext;                
+                this.env = dt.env;
                 dt.tree.accept(this);
                 dt.speculativeCache.put(stuckTree, resultInfo);
                 return Type.noType;
@@ -605,7 +608,19 @@
                     } catch (Types.FunctionDescriptorLookupError ex) {
                         checkContext.report(null, ex.getDiagnostic());
                     }
-                    switch (tree.sym.kind) {
+                    Env<AttrContext> localEnv = env.dup(tree);
+                    JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
+                            attr.memberReferenceQualifierResult(tree));
+                    ListBuffer<Type> argtypes = ListBuffer.lb();
+                    for (Type t : types.findDescriptorType(pt).getParameterTypes()) {
+                        argtypes.append(Type.noType);
+                    }
+                    JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
+                    mref2.expr = exprTree;
+                    Pair<Symbol, ?> lookupRes =
+                            rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
+                                tree.name, argtypes.toList(), null, true, rs.arityMethodCheck, inferenceContext);
+                    switch (lookupRes.fst.kind) {
                         //note: as argtypes are erroneous types, type-errors must
                         //have been caused by arity mismatch
                         case Kinds.ABSENT_MTH:
@@ -847,30 +862,10 @@
 
             Type descType = types.findDescriptorType(pt);
             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
-            Env<AttrContext> localEnv = env.dup(tree, env.info.dup());
-            if (freeArgVars.nonEmpty()) {
-                //perform arity-based check
-                JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
-                        attr.memberReferenceQualifierResult(tree));
-                ListBuffer<Type> argtypes = ListBuffer.lb();
-                for (Type t : descType.getParameterTypes()) {
-                    argtypes.append(Type.noType);
-                }
-                JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
-                mref2.expr = exprTree;
-                Pair<Symbol, ReferenceLookupHelper> lookupRes =
-                        rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
-                            tree.name, argtypes.toList(), null, true, rs.arityMethodCheck,
-                            inferenceContext);
-                Symbol res = tree.sym = lookupRes.fst;
-                if (res.kind >= Kinds.ERRONEOUS ||
-                        res.type.hasTag(FORALL) ||
-                        (res.flags() & Flags.VARARGS) != 0 ||
-                        (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
-                        exprTree.type.isRaw())) {
-                    stuckVars.addAll(freeArgVars);
-                    depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
-                }
+            if (freeArgVars.nonEmpty() &&
+                    tree.overloadKind == JCMemberReference.OverloadKind.OVERLOADED) {
+                stuckVars.addAll(freeArgVars);
+                depVars.addAll(inferenceContext.freeVarsIn(descType.getReturnType()));
             }
         }
 
@@ -978,6 +973,26 @@
 
         @Override
         public void visitReference(JCMemberReference tree) {
+            //perform arity-based check
+            Env<AttrContext> localEnv = env.dup(tree);
+            JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), localEnv,
+                    attr.memberReferenceQualifierResult(tree));
+            JCMemberReference mref2 = new TreeCopier<Void>(make).copy(tree);
+            mref2.expr = exprTree;
+            Pair<Symbol, ReferenceLookupHelper> lookupRes =
+                    rs.resolveMemberReference(tree, localEnv, mref2, exprTree.type,
+                        tree.name, List.<Type>nil(), null, true, rs.nilMethodCheck,
+                        infer.emptyContext);
+            Symbol res = tree.sym = lookupRes.fst;
+            if (res.kind >= Kinds.ERRONEOUS ||
+                    res.type.hasTag(FORALL) ||
+                    (res.flags() & Flags.VARARGS) != 0 ||
+                    (TreeInfo.isStaticSelector(exprTree, tree.name.table.names) &&
+                    exprTree.type.isRaw())) {
+                tree.overloadKind = JCMemberReference.OverloadKind.OVERLOADED;
+            } else {
+                tree.overloadKind = JCMemberReference.OverloadKind.UNOVERLOADED;
+            }
             //a method reference is always a poly expression
             result = ArgumentExpressionKind.POLY;
         }
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Jul 25 16:29:24 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Jul 26 12:46:37 2013 +0100
@@ -1064,7 +1064,7 @@
                             return (e1 == null || e2 == null ||
                                     e1.speculativeTree == deferredAttr.stuckTree ||
                                     e2.speculativeTree == deferredAttr.stuckTree) ?
-                                            super.compatible(found, req, warn) :
+                                            false :
                                             mostSpecific(e2.resultInfo.pt, patchPt(e1), e1.speculativeTree, warn);
                         default:
                             return standaloneMostSpecific(found, req, actual, warn);
@@ -1151,13 +1151,15 @@
                 @Override
                 public void visitReference(JCMemberReference tree) {
                     if (types.isFunctionalInterface(t.tsym) &&
-                            types.isFunctionalInterface(s.tsym) &&
-                            types.asSuper(t, s.tsym) == null &&
-                            types.asSuper(s, t.tsym) == null) {
+                            types.isFunctionalInterface(s.tsym)) {
                         Type desc_t = types.findDescriptorType(t);
                         Type desc_s = types.findDescriptorType(s);
-                        if (types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) {
-                            if (!desc_s.getReturnType().hasTag(VOID)) {
+                        if (types.isSameTypes(desc_t.getParameterTypes(),
+                                inferenceContext().asFree(desc_s.getParameterTypes()))) {
+                            if (types.asSuper(t, s.tsym) != null ||
+                                types.asSuper(s, t.tsym) != null) {
+                                result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+                            } else if (!desc_s.getReturnType().hasTag(VOID)) {
                                 //perform structural comparison
                                 Type ret_t = desc_t.getReturnType();
                                 Type ret_s = desc_s.getReturnType();
@@ -1167,25 +1169,24 @@
                             } else {
                                 return;
                             }
-                        } else {
-                            result &= false;
                         }
                     } else {
-                        result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+                        result &= false;
                     }
                 }
 
                 @Override
                 public void visitLambda(JCLambda tree) {
                     if (types.isFunctionalInterface(t.tsym) &&
-                            types.isFunctionalInterface(s.tsym) &&
-                            types.asSuper(t, s.tsym) == null &&
-                            types.asSuper(s, t.tsym) == null) {
+                            types.isFunctionalInterface(s.tsym)) {
                         Type desc_t = types.findDescriptorType(t);
                         Type desc_s = types.findDescriptorType(s);
-                        if (tree.paramKind == JCLambda.ParameterKind.EXPLICIT
-                                || types.isSameTypes(desc_t.getParameterTypes(), desc_s.getParameterTypes())) {
-                            if (!desc_s.getReturnType().hasTag(VOID)) {
+                        if (types.isSameTypes(desc_t.getParameterTypes(),
+                                inferenceContext().asFree(desc_s.getParameterTypes()))) {
+                            if (types.asSuper(t, s.tsym) != null ||
+                                types.asSuper(s, t.tsym) != null) {
+                                result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+                            } else if (!desc_s.getReturnType().hasTag(VOID)) {
                                 //perform structural comparison
                                 Type ret_t = desc_t.getReturnType();
                                 Type ret_s = desc_s.getReturnType();
@@ -1193,11 +1194,9 @@
                             } else {
                                 return;
                             }
-                        } else {
-                            result &= false;
                         }
                     } else {
-                        result &= MostSpecificCheckContext.super.compatible(t, s, warn);
+                        result &= false;
                     }
                 }
                 //where
--- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Thu Jul 25 16:29:24 2013 +0100
+++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Jul 26 12:46:37 2013 +0100
@@ -1898,6 +1898,7 @@
      * Selects a member expression.
      */
     public static class JCMemberReference extends JCFunctionalExpression implements MemberReferenceTree {
+        
         public ReferenceMode mode;
         public ReferenceKind kind;
         public Name name;
@@ -1907,6 +1908,12 @@
         public Type varargsElement;
         public PolyKind refPolyKind;
         public boolean ownerAccessible;
+        public OverloadKind overloadKind;
+        
+        public enum OverloadKind {
+            OVERLOADED,
+            UNOVERLOADED;
+        }
 
         /**
          * Javac-dependent classification for member references, based
--- a/test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java	Thu Jul 25 16:29:24 2013 +0100
+++ b/test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java	Fri Jul 26 12:46:37 2013 +0100
@@ -31,6 +31,7 @@
     }
 
     void g(String s, Integer i) { }
+    void g(Integer i, String s) { }
 
     <Z> void m(SAM<Z> s) { }
 
--- a/test/tools/javac/lambda/8016177/T8016177c.java	Thu Jul 25 16:29:24 2013 +0100
+++ b/test/tools/javac/lambda/8016177/T8016177c.java	Fri Jul 26 12:46:37 2013 +0100
@@ -1,31 +1,8 @@
 /*
- * Copyright (c) 2013, 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
+ * @test /nodynamiccopyright/
  * @bug 8016081 8016178
  * @summary structural most specific and stuckness
- * @compile T8016177c.java
+ * @compile/fail/ref=T8016177c.out -XDrawDiagnostics T8016177c.java
  */
 
 class T8016177c {
@@ -36,8 +13,35 @@
 
     interface ExtFunction<X, Y> extends Function<X, Y> { }
 
-    <U, V> U m(Function<U, V> f) { return null; } 
-    <U, V> U m(ExtFunction<U, V> f) { return null; }
+    <U, V> U m1(Function<U, V> f) { return null; } 
+    <U, V> U m1(ExtFunction<U, V> f) { return null; }
+    
+    void m2(Function<Integer, Integer> f) { } 
+    void m2(ExtFunction<Integer, Integer> f) { }
+    
+    void m3(Function<Integer, Integer> f) { } 
+    void m3(ExtFunction<Object, Integer> f) { }
+    
+    int g1(Object s) { return 1; }
+    
+    int g2(Number s) { return 1; }
+    int g2(Object s) { return 1; }
     
-    void test() { m(x->1); }
+    void test() {
+        m1((Integer x)->x); //ok - explicit lambda - subtyping picks most specific
+        m2((Integer x)->x); //ok - explicit lambda - subtyping picks most specific
+        m3((Integer x)->x); //ok - explicit lambda (only one applicable)
+        
+        m1(x->1); //ambiguous - stuck lambda
+        m2(x->1); //ok - subtyping picks most specific
+        m3(x->1); //ambiguous - implicit lambda & different params
+
+        m1(this::g1); //ok - unambiguous ref - subtyping picks most specific
+        m2(this::g1); //ok - unambiguous ref - subtyping picks most specific
+        m3(this::g1); //ambiguous - both applicable, neither most specific
+        
+        m1(this::g2); //ambiguous - stuck mref
+        m2(this::g2); //ok - subtyping picks most specific
+        m3(this::g2); //ambiguous - different params
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/8016177/T8016177c.out	Fri Jul 26 12:46:37 2013 +0100
@@ -0,0 +1,6 @@
+T8016177c.java:35:9: compiler.err.ref.ambiguous: m1, kindname.method, <U,V>m1(T8016177c.Function<U,V>), T8016177c, kindname.method, <U,V>m1(T8016177c.ExtFunction<U,V>), T8016177c
+T8016177c.java:37:9: compiler.err.ref.ambiguous: m3, kindname.method, m3(T8016177c.Function<java.lang.Integer,java.lang.Integer>), T8016177c, kindname.method, m3(T8016177c.ExtFunction<java.lang.Object,java.lang.Integer>), T8016177c
+T8016177c.java:41:9: compiler.err.ref.ambiguous: m3, kindname.method, m3(T8016177c.Function<java.lang.Integer,java.lang.Integer>), T8016177c, kindname.method, m3(T8016177c.ExtFunction<java.lang.Object,java.lang.Integer>), T8016177c
+T8016177c.java:43:9: compiler.err.ref.ambiguous: m1, kindname.method, <U,V>m1(T8016177c.Function<U,V>), T8016177c, kindname.method, <U,V>m1(T8016177c.ExtFunction<U,V>), T8016177c
+T8016177c.java:45:9: compiler.err.ref.ambiguous: m3, kindname.method, m3(T8016177c.Function<java.lang.Integer,java.lang.Integer>), T8016177c, kindname.method, m3(T8016177c.ExtFunction<java.lang.Object,java.lang.Integer>), T8016177c
+5 errors
--- a/test/tools/javac/lambda/methodReference/SamConversionComboTest.java	Thu Jul 25 16:29:24 2013 +0100
+++ b/test/tools/javac/lambda/methodReference/SamConversionComboTest.java	Fri Jul 26 12:46:37 2013 +0100
@@ -7,7 +7,7 @@
  * 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
+ * ANY WARRANTY; without even the implied warranty of MERzCHANTABILITY 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).