8011591: BootstrapMethodError when capturing constructor ref to local classes

Wed, 01 May 2013 08:46:04 -0700

author
rfield
date
Wed, 01 May 2013 08:46:04 -0700
changeset 1717
8e27e84de2e9
parent 1716
260013a710ef
child 1718
ec434cfd2752
child 1721
abd153854f16

8011591: BootstrapMethodError when capturing constructor ref to local classes
Reviewed-by: mcimadamore

src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestNewInnerImplicitArgs.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Apr 30 17:53:30 2013 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed May 01 08:46:04 2013 -0700
     1.3 @@ -40,10 +40,9 @@
     1.4  import com.sun.tools.javac.code.Symbol.VarSymbol;
     1.5  import com.sun.tools.javac.code.Symtab;
     1.6  import com.sun.tools.javac.code.Type;
     1.7 -import com.sun.tools.javac.code.Type.ClassType;
     1.8  import com.sun.tools.javac.code.Type.MethodType;
     1.9  import com.sun.tools.javac.code.Types;
    1.10 -import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzer.*;
    1.11 +import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
    1.12  import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
    1.13  import com.sun.tools.javac.jvm.*;
    1.14  import com.sun.tools.javac.util.*;
    1.15 @@ -81,7 +80,7 @@
    1.16      private Env<AttrContext> attrEnv;
    1.17  
    1.18      /** the analyzer scanner */
    1.19 -    private LambdaAnalyzer analyzer;
    1.20 +    private LambdaAnalyzerPreprocessor analyzer;
    1.21  
    1.22      /** map from lambda trees to translation contexts */
    1.23      private Map<JCTree, TranslationContext<?>> contextMap;
    1.24 @@ -156,7 +155,7 @@
    1.25          make = TreeMaker.instance(context);
    1.26          types = Types.instance(context);
    1.27          transTypes = TransTypes.instance(context);
    1.28 -        analyzer = new LambdaAnalyzer();
    1.29 +        analyzer = new LambdaAnalyzerPreprocessor();
    1.30      }
    1.31      // </editor-fold>
    1.32  
    1.33 @@ -206,7 +205,7 @@
    1.34      public void visitClassDef(JCClassDecl tree) {
    1.35          if (tree.sym.owner.kind == PCK) {
    1.36              //analyze class
    1.37 -            analyzer.analyzeClass(tree);
    1.38 +            tree = analyzer.analyzeAndPreprocessClass(tree);
    1.39          }
    1.40          KlassInfo prevKlassInfo = kInfo;
    1.41          try {
    1.42 @@ -531,16 +530,25 @@
    1.43      /** Make an attributed class instance creation expression.
    1.44       *  @param ctype    The class type.
    1.45       *  @param args     The constructor arguments.
    1.46 +     *  @param cons     The constructor symbol
    1.47       */
    1.48 -    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
    1.49 +    JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
    1.50          JCNewClass tree = make.NewClass(null,
    1.51              null, make.QualIdent(ctype.tsym), args, null);
    1.52 -        tree.constructor = rs.resolveConstructor(
    1.53 -            null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil());
    1.54 +        tree.constructor = cons;
    1.55          tree.type = ctype;
    1.56          return tree;
    1.57      }
    1.58  
    1.59 +    /** Make an attributed class instance creation expression.
    1.60 +     *  @param ctype    The class type.
    1.61 +     *  @param args     The constructor arguments.
    1.62 +     */
    1.63 +    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
    1.64 +        return makeNewClass(ctype, args,
    1.65 +                rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
    1.66 +     }
    1.67 +
    1.68      private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
    1.69              DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
    1.70          String functionalInterfaceClass = classSig(targetType);
    1.71 @@ -1019,8 +1027,9 @@
    1.72       * This visitor collects information about translation of a lambda expression.
    1.73       * More specifically, it keeps track of the enclosing contexts and captured locals
    1.74       * accessed by the lambda being translated (as well as other useful info).
    1.75 +     * It also translates away problems for LambdaToMethod.
    1.76       */
    1.77 -    class LambdaAnalyzer extends TreeScanner {
    1.78 +    class LambdaAnalyzerPreprocessor extends TreeTranslator {
    1.79  
    1.80          /** the frame stack - used to reconstruct translation info about enclosing scopes */
    1.81          private List<Frame> frameStack;
    1.82 @@ -1047,10 +1056,10 @@
    1.83          private Map<ClassSymbol, Symbol> clinits =
    1.84                  new HashMap<ClassSymbol, Symbol>();
    1.85  
    1.86 -        private void analyzeClass(JCClassDecl tree) {
    1.87 +        private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
    1.88              frameStack = List.nil();
    1.89              localClassDefs = new HashMap<Symbol, JCClassDecl>();
    1.90 -            scan(tree);
    1.91 +            return translate(tree);
    1.92          }
    1.93  
    1.94          @Override
    1.95 @@ -1154,7 +1163,7 @@
    1.96                      frameStack.head.addLocal(param.sym);
    1.97                  }
    1.98                  contextMap.put(tree, context);
    1.99 -                scan(tree.body);
   1.100 +                super.visitLambda(tree);
   1.101                  context.complete();
   1.102              }
   1.103              finally {
   1.104 @@ -1220,12 +1229,47 @@
   1.105                      };
   1.106                      fvc.scan(localCDef);
   1.107                  }
   1.108 -            }
   1.109 +        }
   1.110  
   1.111 +        /**
   1.112 +         * Method references to local class constructors, may, if the local
   1.113 +         * class references local variables, have implicit constructor
   1.114 +         * parameters added in Lower; As a result, the invokedynamic bootstrap
   1.115 +         * information added in the LambdaToMethod pass will have the wrong
   1.116 +         * signature. Hooks between Lower and LambdaToMethod have been added to
   1.117 +         * handle normal "new" in this case. This visitor converts potentially
   1.118 +         * effected method references into a lambda containing a normal "new" of
   1.119 +         * the class.
   1.120 +         *
   1.121 +         * @param tree
   1.122 +         */
   1.123          @Override
   1.124          public void visitReference(JCMemberReference tree) {
   1.125 -            scan(tree.getQualifierExpression());
   1.126 -            contextMap.put(tree, makeReferenceContext(tree));
   1.127 +            if (tree.getMode() == ReferenceMode.NEW
   1.128 +                    && tree.kind != ReferenceKind.ARRAY_CTOR
   1.129 +                    && tree.sym.owner.isLocal()) {
   1.130 +                MethodSymbol consSym = (MethodSymbol) tree.sym;
   1.131 +                List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
   1.132 +                Type classType = consSym.owner.type;
   1.133 +
   1.134 +                // Make new-class call
   1.135 +                List<JCVariableDecl> params = make.Params(ptypes, owner());
   1.136 +                JCNewClass nc = makeNewClass(classType, make.Idents(params));
   1.137 +                nc.pos = tree.pos;
   1.138 +
   1.139 +                // Make lambda holding the new-class call
   1.140 +                JCLambda slam = make.Lambda(params, nc);
   1.141 +                slam.descriptorType = tree.descriptorType;
   1.142 +                slam.targets = tree.targets;
   1.143 +                slam.type = tree.type;
   1.144 +                slam.pos = tree.pos;
   1.145 +
   1.146 +                // Now it is a lambda, process as such
   1.147 +                visitLambda(slam);
   1.148 +            } else {
   1.149 +                super.visitReference(tree);
   1.150 +                contextMap.put(tree, makeReferenceContext(tree));
   1.151 +            }
   1.152          }
   1.153  
   1.154          @Override
   1.155 @@ -1240,10 +1284,8 @@
   1.156                      }
   1.157                      localContext = localContext.prev;
   1.158                  }
   1.159 -                scan(tree.selected);
   1.160 -            } else {
   1.161 -                super.visitSelect(tree);
   1.162              }
   1.163 +            super.visitSelect(tree);
   1.164          }
   1.165  
   1.166          @Override
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestNewInnerImplicitArgs.java	Wed May 01 08:46:04 2013 -0700
     2.3 @@ -0,0 +1,82 @@
     2.4 +/*
     2.5 + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.  Oracle designates this
    2.11 + * particular file as subject to the "Classpath" exception as provided
    2.12 + * by Oracle in the LICENSE file that accompanied this code.
    2.13 + *
    2.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.17 + * version 2 for more details (a copy is included in the LICENSE file that
    2.18 + * accompanied this code).
    2.19 + *
    2.20 + * You should have received a copy of the GNU General Public License version
    2.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.23 + *
    2.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.25 + * or visit www.oracle.com if you need additional information or have any
    2.26 + * questions.
    2.27 + */
    2.28 +
    2.29 +/**
    2.30 + * @test
    2.31 + * @bug 8011591
    2.32 + * @summary BootstrapMethodError when capturing constructor ref to local classes
    2.33 + * @run testng MethodReferenceTestNewInnerImplicitArgs
    2.34 + */
    2.35 +
    2.36 +import org.testng.annotations.Test;
    2.37 +
    2.38 +import static org.testng.Assert.assertEquals;
    2.39 +
    2.40 +/**
    2.41 + * Test the case that a constructor has implicit parameters added to
    2.42 + * access local variables and that this constructor is used in a
    2.43 + * method reference.
    2.44 + * @author Robert Field
    2.45 + */
    2.46 +
    2.47 +@Test
    2.48 +public class MethodReferenceTestNewInnerImplicitArgs {
    2.49 +
    2.50 +
    2.51 +    static class S {
    2.52 +        String b;
    2.53 +        S(String s, String s2) { b = s + s2; }
    2.54 +    }
    2.55 +
    2.56 +    interface I {
    2.57 +        S m();
    2.58 +    }
    2.59 +
    2.60 +    interface I2 {
    2.61 +        S m(int i, int j);
    2.62 +    }
    2.63 +
    2.64 +    public static void testConstructorReferenceImplicitParameters() {
    2.65 +        String title = "Hey";
    2.66 +        String a2 = "!!!";
    2.67 +        class MS extends S {
    2.68 +            MS() {
    2.69 +                super(title, a2);
    2.70 +            }
    2.71 +        }
    2.72 +
    2.73 +        I result = MS::new;
    2.74 +        assertEquals(result.m().b, "Hey!!!");
    2.75 +
    2.76 +        class MS2 extends S {
    2.77 +            MS2(int x, int y) {
    2.78 +                super(title+x, a2+y);
    2.79 +            }
    2.80 +        }
    2.81 +
    2.82 +        I2 result2 = MS2::new;
    2.83 +        assertEquals(result2.m(8, 4).b, "Hey8!!!4");
    2.84 +    }
    2.85 +}

mercurial