changeset 1447:027ae5764025

Bug fixes: *) LambdaToInnerClass translator should not emit non-static anonymous inner class if lambda is inside self-constructor call (using this(...)). *) Routine for finding functional descriptor should return both the descriptor symbol (one of the method symbols in a given interface) and the instantiated descriptor type
author mcimadamore
date Tue, 07 Aug 2012 15:55:05 +0100
parents 18edb8e7d1ee
children ed0ff181ee27
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/DeferredAttr.java src/share/classes/com/sun/tools/javac/comp/GraphInfer.java src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java src/share/classes/com/sun/tools/javac/comp/Resolve.java test/tools/javac/lambda/LambdaConv24.java
diffstat 11 files changed, 154 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Types.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java	Tue Aug 07 15:55:05 2012 +0100
@@ -44,6 +44,7 @@
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.BoundKind.*;
 import static com.sun.tools.javac.util.ListBuffer.lb;
+import com.sun.xml.internal.messaging.saaj.packaging.mime.util.BEncoderStream;
 
 /**
  * Utility class containing various operations on types.
@@ -335,18 +336,34 @@
             return diagnostic;
         }
     }
+    
+    private class FunctionalDescriptorResult {
+        Symbol descSym;
+
+        FunctionalDescriptorResult(Symbol descSym) {
+            this.descSym = descSym;
+        }
+
+        public Symbol getSymbol() {
+            return descSym;
+        }
+
+        public Type getType(Type origin) {
+            return memberType(origin, descSym);
+        }
+    }
 
     class DescriptorCache {
 
         private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>();
 
         class Entry {
-            final MethodSymbol cachedDesc;
+            final FunctionalDescriptorResult cachedDescRes;
             final int prevMark;
 
-            public Entry(MethodSymbol cachedDesc,
+            public Entry(FunctionalDescriptorResult cachedDescRes,
                     int prevMark) {
-                this.cachedDesc = cachedDesc;
+                this.cachedDescRes = cachedDescRes;
                 this.prevMark = prevMark;
             }
 
@@ -355,17 +372,17 @@
             }
         }
 
-        MethodSymbol get(TypeSymbol origin) throws SAMConversionFailure {
+        FunctionalDescriptorResult get(TypeSymbol origin) throws SAMConversionFailure {
             Entry e = _map.get(origin);
             CompoundScope members = membersClosure(origin.type, false);
             if (e == null ||
                     !e.matches(members.getMark())) {
-                MethodSymbol desc = findDescriptorInternal(origin, members);
-                _map.put(origin, new Entry(desc, members.getMark()));
-                return desc;
+                FunctionalDescriptorResult descRes = findDescriptorInternal(origin, members);
+                _map.put(origin, new Entry(descRes, members.getMark()));
+                return descRes;
             }
             else {
-                return e.cachedDesc;
+                return e.cachedDescRes;
             }
         }
 
@@ -391,29 +408,27 @@
             }
         };
 
-        public MethodSymbol findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws SAMConversionFailure {
+        public FunctionalDescriptorResult findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws SAMConversionFailure {
             if (!origin.isInterface()) {
                 //t must be an abstract class or an interface
                 throw samConversionFailure.setMessage("target.for.lambda.conv.must.be.interface");
             }
 
-            ListBuffer<Symbol> abstracts = ListBuffer.lb();
-            int count = 0;
+            final ListBuffer<Symbol> abstracts = ListBuffer.lb();
             for (Symbol sym : membersCache.getElements(new DescriptorFilter(origin))) {
-                count++;
                 Type mtype = memberType(origin.type, sym);
                 if (abstracts.isEmpty() ||
                         (sym.name == abstracts.first().name &&
                         overrideEquivalent(mtype, memberType(origin.type, abstracts.first())))) {
                     abstracts.append(sym);
+                } else {
+                    //the target method(s) should be the only abstract members of t
+                    throw samConversionFailure.setMessage("incompatible.targets.for.lambda.conv", Kinds.kindName(origin), origin);
                 }
             }
             if (abstracts.isEmpty()) {
                 //t must define a suitable non-generic method
                 throw samConversionFailure.setMessage("no.target.method.for.lambda.conv", Kinds.kindName(origin), origin);
-            } else if (abstracts.size() != count) {
-                //the target method(s) should be the only abstract members of t
-                throw samConversionFailure.setMessage("incompatible.targets.for.lambda.conv", Kinds.kindName(origin), origin);
             } else if (abstracts.size() == 1) {
                 if (abstracts.first().type.tag == FORALL) {
                     throw samConversionFailure.setMessage("invalid.generic.target.for.lambda.conv",
@@ -421,7 +436,7 @@
                                                           Kinds.kindName(origin),
                                                           origin);
                 } else {
-                    return (MethodSymbol)abstracts.first();
+                    return new FunctionalDescriptorResult(abstracts.first());
                 }
             } else { // size > 1
                 for (Symbol msym : abstracts) {
@@ -432,12 +447,12 @@
                                                               origin);
                     }
                 }
-                MethodType mtype = mergeDescriptors(origin, abstracts.toList());
-                if (mtype == null) {
+                FunctionalDescriptorResult descRes = mergeDescriptors(origin, abstracts.toList());
+                if (descRes == null) {
                     //we can get here if the SAM class is ill-formed
                     throw samConversionFailure.setMessage("incompatible.targets.for.lambda.conv", Kinds.kindName(origin), origin);
                 }
-                return new MethodSymbol(abstracts.first().flags(), abstracts.first().name, mtype, origin);
+                return descRes;
             }
         }
 
@@ -447,7 +462,7 @@
          * type is a method type that is override-equivalent and return-type
          * substitutable with each method in the original list.
          */
-        private MethodType mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) {
+        private FunctionalDescriptorResult mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) {
             //merge argument types - simply take the signature that is a
             //subsigature of all other signatures in the list (as per JLS 8.4.2)
             List<Symbol> mostSpecific = List.nil();
@@ -501,9 +516,15 @@
                     mt1.getThrownTypes() :
                     chk.intersect(mt1.getThrownTypes(), thrown);
             }
-
-            Type mt = memberType(origin.type, bestSoFar);
-            return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown, syms.methodClass);
+            
+            final List<Type> thrown1 = thrown;
+            return new FunctionalDescriptorResult(bestSoFar) {
+                @Override
+                public Type getType(Type origin) {
+                    Type mt = memberType(origin, getSymbol());
+                    return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown1, syms.methodClass);
+                }
+            };
         }
 
         boolean isSubtypeInternal(Type s, Type t) {
@@ -518,26 +539,22 @@
     /**
      * Find the method descriptor associated to this class symbol - if the
      * symbol 'origin' is not a functional interface, an exception is thrown.
-     * The returned descriptor is a method symbol whose owner is 'origin'.
      */
-    public MethodSymbol findDescriptor(TypeSymbol origin) throws SAMConversionFailure {
-        return descCache.get(origin);
+    public Symbol findDescriptorSymbol(TypeSymbol origin) throws SAMConversionFailure {
+        return descCache.get(origin).getSymbol();
     }
-
+    
     /**
-     * Find the method descriptor associated to this class type - if the
-     * type 'site' is not a functional interface, an exception is thrown.
-     * The returned descriptor is a method type (an instantiated signature of
-     * the method descriptor symbol seen as a member of 'site').
+     * Find the type of the method descriptor associated to this class symbol -
+     * if the symbol 'origin' is not a functional interface, an exception is thrown.
      */
-    public MethodType findDescriptor(Type site) throws SAMConversionFailure {
-        MethodSymbol msym = findDescriptor(site.tsym);
-        return (MethodType)memberType(site, msym);
+    public Type findDescriptorType(Type origin) throws SAMConversionFailure {
+        return descCache.get(origin.tsym).getType(origin);
     }
 
     public boolean isSam(TypeSymbol tsym) {
         try {
-            findDescriptor(tsym);
+            findDescriptorSymbol(tsym);
             return true;
         } catch (SAMConversionFailure ex) {
             return false;
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Aug 07 15:55:05 2012 +0100
@@ -2159,7 +2159,7 @@
                     clazztype.tag == CLASS &&
                     lambdaOrReferenceAllowed(tree) &&
                     types.isSam(clazztype.tsym)) {
-                MethodSymbol samDescriptor = types.findDescriptor(clazztype.tsym);
+                Symbol samDescriptor = types.findDescriptorSymbol(clazztype.tsym);
                 int count = 0;
                 boolean found = false;
                 for (Symbol sym : csym.members().getElements()) {
@@ -2254,7 +2254,7 @@
             }
             
             Type target = infer.inferSAM(that, pt(), explicitParamTypes, resultInfo.checkContext);
-            Type lambdaType = types.findDescriptor(target);            
+            Type lambdaType = types.findDescriptorType(target);
 
             if (!TreeInfo.isExplicitLambda(that)) {
                 //add param type info in the AST
@@ -2675,7 +2675,7 @@
             }
             
             Type target = infer.inferSAM(that, pt(), null, resultInfo.checkContext);
-            Type desc = types.findDescriptor(target);
+            Type desc = types.findDescriptorType(target);
 
             //attrib type-arguments and receiver expr
             List<Type> typeargtypes = List.nil();
@@ -2794,7 +2794,7 @@
      * SAM descriptor.
      */
     void checkLambdaCompatible(JCLambda tree, Type target, CheckContext checkContext, boolean speculativeAttr) {
-        Type descriptor = types.findDescriptor(target);
+        Type descriptor = types.findDescriptorType(target);
         Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
 
         //return values have already been checked - but if lambda has no return
@@ -2821,7 +2821,7 @@
     }
     
     void checkReferenceCompatible(JCMemberReference tree, Type target, Type refType, CheckContext checkContext, boolean speculativeAttr) {
-        Type descriptor = types.findDescriptor(target);
+        Type descriptor = types.findDescriptorType(target);
         Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
         
         Type resType = tree.getMode() == ReferenceMode.INVOKE ?
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Aug 07 15:55:05 2012 +0100
@@ -943,7 +943,7 @@
         }
 
         void checkAccessibleSAM(DiagnosticPosition pos, Env<AttrContext> env, Type sam) {
-            Type desc = types.findDescriptor(sam);
+            Type desc = types.findDescriptorType(sam);
             SamAccessibilityChecker samAccessibilityChecker =
                     new SamAccessibilityChecker(env);
             //check args accessibility (only if implicit parameter types)
--- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Tue Aug 07 15:55:05 2012 +0100
@@ -329,7 +329,7 @@
                 if (!types.isSam(pt.tsym)) {
                     return;
                 }
-                Type descType = types.findDescriptor(pt);
+                Type descType = types.findDescriptorType(pt);
                 List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
                 if (!TreeInfo.isExplicitLambda(tree) &&
                         freeArgVars.nonEmpty()) {
@@ -358,7 +358,7 @@
             if (!types.isSam(pt.tsym)) {
                 return;
             }
-            Type descType = types.findDescriptor(pt);
+            Type descType = types.findDescriptorType(pt);
             List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
             stuckVars.addAll(freeArgVars);
         }
--- a/src/share/classes/com/sun/tools/javac/comp/GraphInfer.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/GraphInfer.java	Tue Aug 07 15:55:05 2012 +0100
@@ -283,7 +283,7 @@
                 //get constraints from explicit params (this is done by
                 //checking that explicit param types are equal to the ones
                 //in the SAM descriptors)
-                List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes();
+                List<Type> descParameterTypes = types.findDescriptorType(formalSam).getParameterTypes();
                 if (descParameterTypes.size() != paramTypes.size()) {
                     checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
                     return types.createErrorType(samType);
@@ -319,7 +319,7 @@
                 if (paramTypes == null) {
                     try {
                         //we need to fix synthetic inference variables in argument position
-                        samInferenceContext.solve(samInferenceContext.freeVarsIn(types.findDescriptor(formalSam).getParameterTypes()));
+                        samInferenceContext.solve(samInferenceContext.freeVarsIn(types.findDescriptorType(formalSam).getParameterTypes()));
                     } catch (InferenceException ex) {
                         checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
                         return types.createErrorType(samType);
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToInnerClass.java	Tue Aug 07 15:55:05 2012 +0100
@@ -549,7 +549,8 @@
                 super(tree);
                 SuperCallAnalyzer sca = new SuperCallAnalyzer();
                 sca.scan(tree.body);
-                long flags = sca.captureSuper ? 0 : owner.flags() & STATIC;
+                long flags = isSelfCall ? STATIC :
+                        (sca.captureSuper ? 0 : owner.flags() & STATIC);
                 this.lambdaClassSym = makeFunctionalClassSym(flags, tree.targetType, owner);
                 this.translatedSym = makeFunctionalDescriptorSym(tree.targetType, lambdaClassSym);
             }
@@ -643,7 +644,8 @@
 
             ReferenceToInnerTranslationContext(JCMemberReference tree) {
                 super(tree);
-                this.referenceClassSym = makeFunctionalClassSym(owner.flags() & STATIC, tree.targetType, owner);
+                long flags = isSelfCall ? STATIC : (owner.flags() & STATIC);
+                this.referenceClassSym = makeFunctionalClassSym(flags, tree.targetType, owner);
                 this.translatedSym = makeFunctionalDescriptorSym(tree.targetType, referenceClassSym);
                 if (tree.hasKind(ReferenceKind.SUPER)) {
                     this.bridgeSym = makeSyntheticMethod(0, "$bridge$" + tree.pos, types.erasure(translatedSym.type), instance());
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Aug 07 15:55:05 2012 +0100
@@ -510,7 +510,7 @@
         //determine the static bsm args
         Type mtype = makeFunctionalDescriptorType(targetType, true);
         List<Object> staticArgs = List.<Object>of(
-                new Pool.MemberReference(ClassFile.REF_invokeInterface, types.findDescriptor(targetType.tsym)),
+                new Pool.MemberReference(ClassFile.REF_invokeInterface, types.findDescriptorSymbol(targetType.tsym)),
                 new Pool.MemberReference(refKind, refSym),
                 new MethodType(mtype.getParameterTypes(),
                         mtype.getReturnType(),
@@ -722,7 +722,7 @@
             }
 
             protected Type generatedLambdaSig() {
-                return types.erasure(types.findDescriptor(tree.targetType));
+                return types.erasure(types.findDescriptorType(tree.targetType));
             }
         }
 
@@ -770,7 +770,7 @@
             }
 
             protected Type bridgedRefSig() {
-                return types.erasure(types.findDescriptor(tree.targetType.tsym).type);
+                return types.erasure(types.findDescriptorSymbol(tree.targetType.tsym).type);
             }
         }
     }
--- a/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/LambdaTranslator.java	Tue Aug 07 15:55:05 2012 +0100
@@ -303,7 +303,7 @@
     // </editor-fold>
 
     private MethodSymbol makeSamDescriptor(Type targetType) {
-        return types.findDescriptor(targetType.tsym);
+        return (MethodSymbol)types.findDescriptorSymbol(targetType.tsym);
     }
 
     private Type makeFunctionalDescriptorType(Type targetType, MethodSymbol samDescriptor, boolean erased) {
@@ -374,6 +374,9 @@
 
         /** the frame stack - used to reconstruct translation info about enclosing scopes */
         List<Frame> frameStack;
+        
+        /** are we inside a constructor call (i.e. 'this(xyz)') */
+        protected boolean isSelfCall = false;
     
         abstract TranslationContext makeLambdaContext(JCLambda tree);
         
@@ -648,6 +651,20 @@
                 frameStack = prevStack;
             }
         }
+
+        @Override
+        public void visitApply(JCMethodInvocation tree) {
+            boolean prevSelfCall = false;
+            try {
+                if (tree.meth.hasTag(IDENT) &&
+                        ((JCIdent)tree.meth).name == names._this) {
+                    isSelfCall = true;
+                }
+                super.visitApply(tree);
+            } finally {
+                isSelfCall = prevSelfCall;
+            }
+        }
         
         /**
          *  This is used to filter out those identifiers that needs to be adjusted
--- a/src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java	Tue Aug 07 15:55:05 2012 +0100
@@ -251,7 +251,7 @@
                 //get constraints from explicit params (this is done by
                 //checking that explicit param types are equal to the ones
                 //in the SAM descriptors)
-                List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes();
+                List<Type> descParameterTypes = types.findDescriptorType(formalSam).getParameterTypes();
                 if (descParameterTypes.size() != paramTypes.size()) {
                     checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType));
                     return types.createErrorType(samType);
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon Aug 06 12:11:27 2012 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Aug 07 15:55:05 2012 +0100
@@ -1327,16 +1327,16 @@
             //this is unexpectedas the method was deemed applicable
             Assert.error();
         }
-        Type ret_s = types.findDescriptor(s).getReturnType();
-        Type ret_t = types.findDescriptor(t).getReturnType();
+        Type ret_s = types.findDescriptorType(s).getReturnType();
+        Type ret_t = types.findDescriptorType(t).getReturnType();
         
         //covariant most specific check for functional descriptor return type
         if (!types.isSubtype(ret_s, ret_t)) {
             return false;
         }
         
-        List<Type> args_s = types.findDescriptor(s).getParameterTypes();
-        List<Type> args_t = types.findDescriptor(t).getParameterTypes();
+        List<Type> args_s = types.findDescriptorType(s).getParameterTypes();
+        List<Type> args_t = types.findDescriptorType(t).getParameterTypes();
         
         //arity must be identical
         if (args_s.length() != args_t.length()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv24.java	Tue Aug 07 15:55:05 2012 +0100
@@ -0,0 +1,62 @@
+/*
+ * 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
+ * @summary check that lambda inside 'this' call is handled properly
+ * @run main LambdaConv24
+ */
+public class LambdaConv24 {
+    
+    static int assertionCount = 0;
+
+    static void assertTrue(boolean cond) {
+        assertionCount++;
+        if (!cond)
+            throw new AssertionError();
+    }
+
+    interface SAM<X> {
+        boolean m(X x);
+    }
+
+    LambdaConv24(SAM<String> p) {
+        assertTrue(p.m("42"));
+    }
+    
+    LambdaConv24(int i) {
+        this(s->true);
+    }
+    
+    LambdaConv24(int i1, int i2) {
+        this(LambdaConv24::m);
+    }
+    
+    static boolean m(String s) { return true; }
+    
+    public static void main(String[] args) {
+        new LambdaConv24(1);
+        new LambdaConv24(1,2);
+        assertTrue(assertionCount == 2);
+    }
+}