8029721: javac crash for annotated parameter type of lambda in a field

Fri, 13 Dec 2013 14:13:03 +0000

author
vromero
date
Fri, 13 Dec 2013 14:13:03 +0000
changeset 2222
8832b6048e65
parent 2221
d80c3d6f4f05
child 2223
6d1f9d1fd585

8029721: javac crash for annotated parameter type of lambda in a field
Reviewed-by: rfield, jfranck

src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java file | annotate | diff | comparison | revisions
test/tools/javac/annotations/typeAnnotations/newlocations/Lambda.java file | annotate | diff | comparison | revisions
test/tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java file | annotate | diff | comparison | revisions
test/tools/javac/lambda/LambdaScope05.out file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Dec 12 19:19:07 2013 -0800
     1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Dec 13 14:13:03 2013 +0000
     1.3 @@ -2590,15 +2590,61 @@
     1.4              }
     1.5          }
     1.6  
     1.7 +        /* Map to hold 'fake' clinit methods. If a lambda is used to initialize a
     1.8 +         * static field and that lambda has type annotations, these annotations will
     1.9 +         * also be stored at these fake clinit methods.
    1.10 +         *
    1.11 +         * LambdaToMethod also use fake clinit methods so they can be reused.
    1.12 +         * Also as LTM is a phase subsequent to attribution, the methods from
    1.13 +         * clinits can be safely removed by LTM to save memory.
    1.14 +         */
    1.15 +        private Map<ClassSymbol, MethodSymbol> clinits = new HashMap<>();
    1.16 +
    1.17 +        public MethodSymbol removeClinit(ClassSymbol sym) {
    1.18 +            return clinits.remove(sym);
    1.19 +        }
    1.20 +
    1.21 +        /* This method returns an environment to be used to attribute a lambda
    1.22 +         * expression.
    1.23 +         *
    1.24 +         * The owner of this environment is a method symbol. If the current owner
    1.25 +         * is not a method, for example if the lambda is used to initialize
    1.26 +         * a field, then if the field is:
    1.27 +         *
    1.28 +         * - an instance field, we use the first constructor.
    1.29 +         * - a static field, we create a fake clinit method.
    1.30 +         */
    1.31          private Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) {
    1.32              Env<AttrContext> lambdaEnv;
    1.33              Symbol owner = env.info.scope.owner;
    1.34              if (owner.kind == VAR && owner.owner.kind == TYP) {
    1.35                  //field initializer
    1.36                  lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dupUnshared()));
    1.37 -                lambdaEnv.info.scope.owner =
    1.38 -                    new MethodSymbol((owner.flags() & STATIC) | BLOCK, names.empty, null,
    1.39 -                                     env.info.scope.owner);
    1.40 +                ClassSymbol enclClass = owner.enclClass();
    1.41 +                /* if the field isn't static, then we can get the first constructor
    1.42 +                 * and use it as the owner of the environment. This is what
    1.43 +                 * LTM code is doing to look for type annotations so we are fine.
    1.44 +                 */
    1.45 +                if ((owner.flags() & STATIC) == 0) {
    1.46 +                    for (Symbol s : enclClass.members_field.getElementsByName(names.init)) {
    1.47 +                        lambdaEnv.info.scope.owner = s;
    1.48 +                        break;
    1.49 +                    }
    1.50 +                } else {
    1.51 +                    /* if the field is static then we need to create a fake clinit
    1.52 +                     * method, this method can later be reused by LTM.
    1.53 +                     */
    1.54 +                    MethodSymbol clinit = clinits.get(enclClass);
    1.55 +                    if (clinit == null) {
    1.56 +                        Type clinitType = new MethodType(List.<Type>nil(),
    1.57 +                                syms.voidType, List.<Type>nil(), syms.methodClass);
    1.58 +                        clinit = new MethodSymbol(STATIC | SYNTHETIC | PRIVATE,
    1.59 +                                names.clinit, clinitType, enclClass);
    1.60 +                        clinit.params = List.<VarSymbol>nil();
    1.61 +                        clinits.put(enclClass, clinit);
    1.62 +                    }
    1.63 +                    lambdaEnv.info.scope.owner = clinit;
    1.64 +                }
    1.65              } else {
    1.66                  lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
    1.67              }
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Dec 12 19:19:07 2013 -0800
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Dec 13 14:13:03 2013 +0000
     2.3 @@ -1474,12 +1474,27 @@
     2.4          private Symbol initSym(ClassSymbol csym, long flags) {
     2.5              boolean isStatic = (flags & STATIC) != 0;
     2.6              if (isStatic) {
     2.7 -                //static clinits are generated in Gen - so we need to fake them
     2.8 -                Symbol clinit = clinits.get(csym);
     2.9 +                /* static clinits are generated in Gen, so we need to use a fake
    2.10 +                 * one. Attr creates a fake clinit method while attributing
    2.11 +                 * lambda expressions used as initializers of static fields, so
    2.12 +                 * let's use that one.
    2.13 +                 */
    2.14 +                MethodSymbol clinit = attr.removeClinit(csym);
    2.15 +                if (clinit != null) {
    2.16 +                    clinits.put(csym, clinit);
    2.17 +                    return clinit;
    2.18 +                }
    2.19 +
    2.20 +                /* if no clinit is found at Attr, then let's try at clinits.
    2.21 +                 */
    2.22 +                clinit = (MethodSymbol)clinits.get(csym);
    2.23                  if (clinit == null) {
    2.24 +                    /* no luck, let's create a new one
    2.25 +                     */
    2.26                      clinit = makePrivateSyntheticMethod(STATIC,
    2.27                              names.clinit,
    2.28 -                            new MethodType(List.<Type>nil(), syms.voidType, List.<Type>nil(), syms.methodClass),
    2.29 +                            new MethodType(List.<Type>nil(), syms.voidType,
    2.30 +                                List.<Type>nil(), syms.methodClass),
    2.31                              csym);
    2.32                      clinits.put(csym, clinit);
    2.33                  }
     3.1 --- a/test/tools/javac/annotations/typeAnnotations/newlocations/Lambda.java	Thu Dec 12 19:19:07 2013 -0800
     3.2 +++ b/test/tools/javac/annotations/typeAnnotations/newlocations/Lambda.java	Fri Dec 13 14:13:03 2013 +0000
     3.3 @@ -23,8 +23,9 @@
     3.4  
     3.5  /*
     3.6   * @test
     3.7 - * @bug 8008077
     3.8 + * @bug 8008077 8029721
     3.9   * @summary new type annotation location: lambda expressions
    3.10 + * javac crash for annotated parameter type of lambda in a field
    3.11   * @compile Lambda.java
    3.12   * @author Werner Dietl
    3.13   */
    3.14 @@ -57,6 +58,14 @@
    3.15      LambdaInt2 getLambda() {
    3.16          return (@TA Object x, @TB Object y) -> { @TA Object l = null; System.out.println("We have: " + (@TB Object) x); };
    3.17      }
    3.18 +
    3.19 +    java.util.function.IntUnaryOperator x = (@TA int y) -> 1;
    3.20 +
    3.21 +    static java.util.function.IntUnaryOperator xx = (@TA int y) -> 1;
    3.22 +
    3.23 +    java.util.function.IntUnaryOperator foo() {
    3.24 +        return (@TA int y) -> 2;
    3.25 +    }
    3.26  }
    3.27  
    3.28  @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
     4.1 --- a/test/tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java	Thu Dec 12 19:19:07 2013 -0800
     4.2 +++ b/test/tools/javac/annotations/typeAnnotations/referenceinfos/Lambda.java	Fri Dec 13 14:13:03 2013 +0000
     4.3 @@ -23,8 +23,9 @@
     4.4  
     4.5  /*
     4.6   * @test
     4.7 - * @bug 8008077
     4.8 + * @bug 8008077 8029721
     4.9   * @summary Test population of reference info for lambda expressions
    4.10 + * javac crash for annotated parameter type of lambda in a field
    4.11   * @compile -g Driver.java ReferenceInfoUtil.java Lambda.java
    4.12   * @run main Driver Lambda
    4.13   * @author Werner Dietl
    4.14 @@ -285,4 +286,24 @@
    4.15                  "  }" +
    4.16                  "}";
    4.17      }
    4.18 +
    4.19 +    @TADescriptions({
    4.20 +        @TADescription(annotation = "TA", type = METHOD_FORMAL_PARAMETER,
    4.21 +            paramIndex = 0)})
    4.22 +    public String lambdaField1() {
    4.23 +        return
    4.24 +            "class Test {" +
    4.25 +                " java.util.function.IntUnaryOperator field = (@TA int y) -> 1;" +
    4.26 +            "}";
    4.27 +    }
    4.28 +
    4.29 +    @TADescriptions({
    4.30 +        @TADescription(annotation = "TA", type = METHOD_FORMAL_PARAMETER,
    4.31 +            paramIndex = 0)})
    4.32 +    public String lambdaField2() {
    4.33 +        return
    4.34 +            "class Test {" +
    4.35 +                " static java.util.function.IntUnaryOperator field = (@TA int y) -> 1;" +
    4.36 +            "}";
    4.37 +    }
    4.38  }
     5.1 --- a/test/tools/javac/lambda/LambdaScope05.out	Thu Dec 12 19:19:07 2013 -0800
     5.2 +++ b/test/tools/javac/lambda/LambdaScope05.out	Fri Dec 13 14:13:03 2013 +0000
     5.3 @@ -1,5 +1,5 @@
     5.4  LambdaScope05.java:13:47: compiler.err.already.defined.in.clinit: kindname.variable, p, kindname.static.init, kindname.class, LambdaScope05
     5.5 -LambdaScope05.java:14:40: compiler.err.already.defined.in.clinit: kindname.variable, p, kindname.instance.init, kindname.class, LambdaScope05
     5.6 +LambdaScope05.java:14:40: compiler.err.already.defined: kindname.variable, p, kindname.constructor, LambdaScope05()
     5.7  LambdaScope05.java:17:43: compiler.err.already.defined.in.clinit: kindname.variable, p, kindname.static.init, kindname.class, LambdaScope05
     5.8  LambdaScope05.java:21:43: compiler.err.already.defined.in.clinit: kindname.variable, p, kindname.instance.init, kindname.class, LambdaScope05
     5.9  LambdaScope05.java:25:43: compiler.err.already.defined: kindname.variable, p, kindname.method, m_static()

mercurial