Merge
authorlana
Tue, 06 Dec 2011 20:26:09 -0800
changeset 11145 893729a0ff19
parent 11078 736a63b854f3 (current diff)
parent 11144 8a4ae514eedf (diff)
child 11150 27c6c6c32d01
Merge
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/source/tree/LambdaExpressionTree.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+/**
+ * A tree node for a lambda expression.
+ *
+ * For example:
+ * <pre>
+ *   ()->{}
+ *   (List<String> ls)->ls.size()
+ *   (x,y)-> { return x + y; }
+ * </pre>
+ */
+public interface LambdaExpressionTree extends ExpressionTree {
+
+    /**
+     * Lambda expressions come in two forms: (i) expression lambdas, whose body
+     * is an expression, and (ii) statement lambdas, whose body is a block
+     */
+    public enum BodyKind {
+        /** enum constant for expression lambdas */
+        EXPRESSION,
+        /** enum constant for statement lambdas */
+        STATEMENT;
+    }
+
+    List<? extends VariableTree> getParameters();
+    Tree getBody();
+    BodyKind getBodyKind();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/source/tree/MemberReferenceTree.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.source.tree;
+
+import java.util.List;
+
+import javax.lang.model.element.Name;
+
+/**
+ * A tree node for a member reference expression.
+ *
+ * For example:
+ * <pre>
+ *   <em>expression</em> # <em>[ identifier | new ]</em>
+ * </pre>
+ *
+ * @see JSR 292
+ */
+public interface MemberReferenceTree extends ExpressionTree {
+
+    /**
+     * There are two kinds of member references: (i) method references and
+     * (ii) constructor references
+     */
+    public enum ReferenceMode {
+        /** enum constant for method references */
+        INVOKE,
+        /** enum constant for constructor references */
+        NEW
+    }
+    ReferenceMode getMode();
+    ExpressionTree getQualifierExpression();
+    Name getName();
+    List<? extends ExpressionTree> getTypeArguments();
+}
--- a/langtools/src/share/classes/com/sun/source/tree/Tree.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/tree/Tree.java	Tue Dec 06 20:26:09 2011 -0800
@@ -132,6 +132,11 @@
         MEMBER_SELECT(MemberSelectTree.class),
 
         /**
+         * Used for instances of {@link MemberReferenceTree}.
+         */
+        MEMBER_REFERENCE(MemberReferenceTree.class),
+
+        /**
          * Used for instances of {@link ForLoopTree}.
          */
         FOR_LOOP(ForLoopTree.class),
@@ -187,6 +192,11 @@
         NEW_CLASS(NewClassTree.class),
 
         /**
+         * Used for instances of {@link LambdaExpressionTree}.
+         */
+        LAMBDA_EXPRESSION(LambdaExpressionTree.class),
+
+        /**
          * Used for instances of {@link ParenthesizedTree}.
          */
         PARENTHESIZED(ParenthesizedTree.class),
--- a/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/tree/TreeVisitor.java	Tue Dec 06 20:26:09 2011 -0800
@@ -85,9 +85,11 @@
     R visitModifiers(ModifiersTree node, P p);
     R visitNewArray(NewArrayTree node, P p);
     R visitNewClass(NewClassTree node, P p);
+    R visitLambdaExpression(LambdaExpressionTree node, P p);
     R visitParenthesized(ParenthesizedTree node, P p);
     R visitReturn(ReturnTree node, P p);
     R visitMemberSelect(MemberSelectTree node, P p);
+    R visitMemberReference(MemberReferenceTree node, P p);
     R visitEmptyStatement(EmptyStatementTree node, P p);
     R visitSwitch(SwitchTree node, P p);
     R visitSynchronized(SynchronizedTree node, P p);
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Tue Dec 06 20:26:09 2011 -0800
@@ -172,6 +172,10 @@
         return defaultAction(node, p);
     }
 
+    public R visitLambdaExpression(LambdaExpressionTree node, P p) {
+        return defaultAction(node, p);
+    }
+
     public R visitParenthesized(ParenthesizedTree node, P p) {
         return defaultAction(node, p);
     }
@@ -208,6 +212,10 @@
         return defaultAction(node, p);
     }
 
+    public R visitMemberReference(MemberReferenceTree node, P p) {
+        return defaultAction(node, p);
+    }
+
     public R visitIdentifier(IdentifierTree node, P p) {
         return defaultAction(node, p);
     }
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java	Tue Dec 06 20:26:09 2011 -0800
@@ -285,6 +285,12 @@
         return r;
     }
 
+    public R visitLambdaExpression(LambdaExpressionTree node, P p) {
+        R r = scan(node.getParameters(), p);
+        r = scanAndReduce(node.getBody(), p, r);
+        return r;
+    }
+
     public R visitParenthesized(ParenthesizedTree node, P p) {
         return scan(node.getExpression(), p);
     }
@@ -333,6 +339,12 @@
         return scan(node.getExpression(), p);
     }
 
+    public R visitMemberReference(MemberReferenceTree node, P p) {
+        R r = scan(node.getQualifierExpression(), p);
+        r = scanAndReduce(node.getTypeArguments(), p, r);
+        return r;
+    }
+
     public R visitIdentifier(IdentifierTree node, P p) {
         return null;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Tue Dec 06 20:26:09 2011 -0800
@@ -194,6 +194,12 @@
     public boolean allowObjectToPrimitiveCast() {
         return compareTo(JDK1_7) >= 0;
     }
+    public boolean allowLambda() {
+        return compareTo(JDK1_8) >= 0;
+    }
+    public boolean allowMethodReferences() {
+        return compareTo(JDK1_8) >= 0;
+    }
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Dec 06 20:26:09 2011 -0800
@@ -1975,6 +1975,16 @@
         result = check(tree, owntype, VAL, pkind, pt);
     }
 
+    @Override
+    public void visitLambda(JCLambda that) {
+        throw new UnsupportedOperationException("Lambda expression not supported yet");
+    }
+
+    @Override
+    public void visitReference(JCMemberReference that) {
+        throw new UnsupportedOperationException("Member references not supported yet");
+    }
+
     public void visitParens(JCParens tree) {
         Type owntype = attribTree(tree.expr, env, pkind, pt);
         result = check(tree, owntype, pkind, pkind, pt);
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java	Tue Dec 06 20:26:09 2011 -0800
@@ -637,6 +637,10 @@
                         lexError(pos, "unclosed.str.lit");
                     }
                     break loop;
+                case '#':
+                    reader.scanChar();
+                    tk = TokenKind.HASH;
+                    break loop;
                 default:
                     if (isSpecial(reader.ch)) {
                         scanOperator();
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Dec 06 20:26:09 2011 -0800
@@ -27,6 +27,8 @@
 
 import java.util.*;
 
+import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
+
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.parser.Tokens.*;
 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
@@ -110,6 +112,10 @@
         this.allowDiamond = source.allowDiamond();
         this.allowMulticatch = source.allowMulticatch();
         this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
+        this.allowLambda = source.allowLambda() &&
+                fac.options.isSet("allowLambda");
+        this.allowMethodReferences = source.allowMethodReferences() &&
+                fac.options.isSet("allowMethodReferences");
         this.keepDocComments = keepDocComments;
         docComments = keepDocComments ? new HashMap<JCTree,String>() : null;
         this.keepLineMap = keepLineMap;
@@ -166,6 +172,14 @@
      */
     boolean allowStringFolding;
 
+    /** Switch: should we recognize lambda expressions?
+     */
+    boolean allowLambda;
+
+    /** Switch: should we allow method/constructor references?
+     */
+    boolean allowMethodReferences;
+
     /** Switch: should we keep docComments?
      */
     boolean keepDocComments;
@@ -203,6 +217,30 @@
         token = S.token();
     }
 
+    protected boolean peekToken(TokenKind tk) {
+        return S.token(1).kind == tk;
+    }
+
+    protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
+        return S.token(1).kind == tk1 &&
+                S.token(2).kind == tk2;
+    }
+
+    protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
+        return S.token(1).kind == tk1 &&
+                S.token(2).kind == tk2 &&
+                S.token(3).kind == tk3;
+    }
+
+    protected boolean peekToken(TokenKind... kinds) {
+        for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
+            if (S.token(lookahead + 1).kind != kinds[lookahead]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /* ---------- error recovery -------------- */
 
     private JCErroneous errorTree;
@@ -749,7 +787,7 @@
             top++;
             topOp = token;
             nextToken();
-            odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3();
+            odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3NoParams();
             while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
                 odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1],
                                         odStack[top]);
@@ -849,7 +887,10 @@
      *                 | [TypeArguments] THIS [Arguments]
      *                 | [TypeArguments] SUPER SuperSuffix
      *                 | NEW [TypeArguments] Creator
+     *                 | "(" Arguments ")" "->" ( Expression | Block )
+     *                 | Ident "->" ( Expression | Block )
      *                 | Ident { "." Ident }
+     *                 | Expression3 MemberReferenceSuffix
      *                   [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
      *                   | Arguments
      *                   | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
@@ -890,60 +931,87 @@
                     mode = EXPR;
                     t = literal(names.hyphen, pos);
                 } else {
-                    t = term3();
+                    t = term3NoParams();
                     return F.at(pos).Unary(unoptag(tk), t);
                 }
             } else return illegal();
             break;
         case LPAREN:
             if (typeArgs == null && (mode & EXPR) != 0) {
-                nextToken();
-                mode = EXPR | TYPE | NOPARAMS;
-                t = term3();
-                if ((mode & TYPE) != 0 && token.kind == LT) {
-                    // Could be a cast to a parameterized type
-                    JCTree.Tag op = JCTree.Tag.LT;
-                    int pos1 = token.pos;
+                if (peekToken(FINAL) ||
+                        peekToken(RPAREN) ||
+                        peekToken(IDENTIFIER, COMMA) ||
+                        peekToken(IDENTIFIER, RPAREN, ARROW)) {
+                    //implicit n-ary lambda
+                    t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
+                    break;
+                } else {
                     nextToken();
-                    mode &= (EXPR | TYPE);
-                    mode |= TYPEARG;
-                    JCExpression t1 = term3();
-                    if ((mode & TYPE) != 0 &&
-                        (token.kind == COMMA || token.kind == GT)) {
-                        mode = TYPE;
-                        ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
-                        args.append(t1);
-                        while (token.kind == COMMA) {
+                    mode = EXPR | TYPE;
+                    t = term3NoParams();
+                    if ((mode & TYPE) != 0 && token.kind == LT) {
+                        // Could be a cast to a parameterized type
+                        JCTree.Tag op = JCTree.Tag.LT;
+                        int pos1 = token.pos;
+                        nextToken();
+                        mode &= (EXPR | TYPE);
+                        mode |= TYPEARG;
+                        JCExpression t1 = term3();
+                        if ((mode & TYPE) != 0 &&
+                            (token.kind == COMMA || token.kind == GT)) {
+                            mode = TYPE;
+                            ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
+                            args.append(t1);
+                            while (token.kind == COMMA) {
+                                nextToken();
+                                args.append(typeArgument());
+                            }
+                            accept(GT);
+                            t = toP(F.at(pos1).TypeApply(t, args.toList()));
+                            checkGenerics();
+                            mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
+                            t = term3Rest(t, typeArgs);
+                            if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
+                                //explicit lambda (w/ generic type)
+                                mode = EXPR;
+                                JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
+                                if (token.kind == ELLIPSIS) {
+                                    mods.flags = Flags.VARARGS;
+                                    t = to(F.at(token.pos).TypeArray(t));
+                                    nextToken();
+                                }
+                                t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
+                                break;
+                            }
+                        } else {
+                            Assert.check((mode & EXPR) != 0);
+                            mode = EXPR;
+                            JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
+                            t = F.at(pos1).Binary(op, t, e);
+                            t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
+                        }
+                    } else if ((mode & TYPE) != 0 &&
+                            (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
+                        //explicit lambda (w/ non-generic type)
+                        mode = EXPR;
+                        JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
+                        if (token.kind == ELLIPSIS) {
+                            mods.flags = Flags.VARARGS;
+                            t = to(F.at(token.pos).TypeArray(t));
                             nextToken();
-                            args.append(typeArgument());
                         }
-                        accept(GT);
-                        t = toP(F.at(pos1).TypeApply(t, args.toList()));
-                        checkGenerics();
-                        while (token.kind == DOT) {
-                            nextToken();
-                            mode = TYPE;
-                            t = toP(F.at(token.pos).Select(t, ident()));
-                            t = typeArgumentsOpt(t);
-                        }
-                        t = bracketsOpt(toP(t));
-                    } else if ((mode & EXPR) != 0) {
-                        mode = EXPR;
-                        JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
-                        t = F.at(pos1).Binary(op, t, e);
+                        t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
+                        break;
+                    } else {
                         t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
-                    } else {
-                        accept(GT);
                     }
                 }
-                else {
-                    t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
-                }
+
                 accept(RPAREN);
                 lastmode = mode;
                 mode = EXPR;
                 if ((lastmode & EXPR) == 0) {
-                    JCExpression t1 = term3();
+                    JCExpression t1 = term3NoParams();
                     return F.at(pos).TypeCast(t, t1);
                 } else if ((lastmode & TYPE) != 0) {
                     switch (token.kind) {
@@ -953,14 +1021,16 @@
                     case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
                     case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
                     case TRUE: case FALSE: case NULL:
-                    case NEW: case IDENTIFIER: case ASSERT: case ENUM:
+                        case NEW: case IDENTIFIER: case ASSERT: case ENUM:
                     case BYTE: case SHORT: case CHAR: case INT:
                     case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
-                        JCExpression t1 = term3();
+                        JCExpression t1 = term3NoParams();
                         return F.at(pos).TypeCast(t, t1);
                     }
                 }
-            } else return illegal();
+            } else {
+                return illegal();
+            }
             t = toP(F.at(pos).Parens(t));
             break;
         case THIS:
@@ -1003,75 +1073,122 @@
             break;
         case IDENTIFIER: case ASSERT: case ENUM:
             if (typeArgs != null) return illegal();
-            t = toP(F.at(token.pos).Ident(ident()));
-            loop: while (true) {
-                pos = token.pos;
-                switch (token.kind) {
-                case LBRACKET:
-                    nextToken();
-                    if (token.kind == RBRACKET) {
+            if ((mode & EXPR) != 0 && peekToken(ARROW)) {
+                t = lambdaExpressionOrStatement(false, false, pos);
+            } else {
+                t = toP(F.at(token.pos).Ident(ident()));
+                loop: while (true) {
+                    pos = token.pos;
+                    switch (token.kind) {
+                    case LBRACKET:
                         nextToken();
-                        t = bracketsOpt(t);
-                        t = toP(F.at(pos).TypeArray(t));
-                        t = bracketsSuffix(t);
-                    } else {
+                        if (token.kind == RBRACKET) {
+                            nextToken();
+                            t = bracketsOpt(t);
+                            t = toP(F.at(pos).TypeArray(t));
+                            t = bracketsSuffix(t);
+                        } else {
+                            if ((mode & EXPR) != 0) {
+                                mode = EXPR;
+                                JCExpression t1 = term();
+                                t = to(F.at(pos).Indexed(t, t1));
+                            }
+                            accept(RBRACKET);
+                        }
+                        break loop;
+                    case LPAREN:
                         if ((mode & EXPR) != 0) {
                             mode = EXPR;
-                            JCExpression t1 = term();
-                            t = to(F.at(pos).Indexed(t, t1));
+                            t = arguments(typeArgs, t);
+                            typeArgs = null;
                         }
-                        accept(RBRACKET);
-                    }
-                    break loop;
-                case LPAREN:
-                    if ((mode & EXPR) != 0) {
-                        mode = EXPR;
-                        t = arguments(typeArgs, t);
-                        typeArgs = null;
-                    }
-                    break loop;
-                case DOT:
-                    nextToken();
-                    int oldmode = mode;
-                    mode &= ~NOPARAMS;
-                    typeArgs = typeArgumentsOpt(EXPR);
-                    mode = oldmode;
-                    if ((mode & EXPR) != 0) {
-                        switch (token.kind) {
-                        case CLASS:
-                            if (typeArgs != null) return illegal();
-                            mode = EXPR;
-                            t = to(F.at(pos).Select(t, names._class));
-                            nextToken();
-                            break loop;
-                        case THIS:
-                            if (typeArgs != null) return illegal();
-                            mode = EXPR;
-                            t = to(F.at(pos).Select(t, names._this));
-                            nextToken();
-                            break loop;
-                        case SUPER:
-                            mode = EXPR;
-                            t = to(F.at(pos).Select(t, names._super));
-                            t = superSuffix(typeArgs, t);
-                            typeArgs = null;
-                            break loop;
-                        case NEW:
-                            if (typeArgs != null) return illegal();
-                            mode = EXPR;
+                        break loop;
+                    case DOT:
+                        nextToken();
+                        int oldmode = mode;
+                        mode &= ~NOPARAMS;
+                        typeArgs = typeArgumentsOpt(EXPR);
+                        mode = oldmode;
+                        if ((mode & EXPR) != 0) {
+                            switch (token.kind) {
+                            case CLASS:
+                                if (typeArgs != null) return illegal();
+                                mode = EXPR;
+                                t = to(F.at(pos).Select(t, names._class));
+                                nextToken();
+                                break loop;
+                            case THIS:
+                                if (typeArgs != null) return illegal();
+                                mode = EXPR;
+                                t = to(F.at(pos).Select(t, names._this));
+                                nextToken();
+                                break loop;
+                            case SUPER:
+                                mode = EXPR;
+                                t = to(F.at(pos).Select(t, names._super));
+                                t = superSuffix(typeArgs, t);
+                                typeArgs = null;
+                                break loop;
+                            case NEW:
+                                if (typeArgs != null) return illegal();
+                                mode = EXPR;
+                                int pos1 = token.pos;
+                                nextToken();
+                                if (token.kind == LT) typeArgs = typeArguments(false);
+                                t = innerCreator(pos1, typeArgs, t);
+                                typeArgs = null;
+                                break loop;
+                            }
+                        }
+                        // typeArgs saved for next loop iteration.
+                        t = toP(F.at(pos).Select(t, ident()));
+                        break;
+                    case LT:
+                        if ((mode & (TYPE | NOPARAMS)) == 0) {
+                            //could be an unbound method reference whose qualifier
+                            //is a generic type i.e. A<S>#m
+                            mode = EXPR | TYPE;
+                            JCTree.Tag op = JCTree.Tag.LT;
                             int pos1 = token.pos;
                             nextToken();
-                            if (token.kind == LT) typeArgs = typeArguments(false);
-                            t = innerCreator(pos1, typeArgs, t);
-                            typeArgs = null;
-                            break loop;
+                            mode |= EXPR | TYPE | TYPEARG;
+                            JCExpression t1 = term3();
+                            if ((mode & TYPE) != 0 &&
+                                (token.kind == COMMA || token.kind == GT)) {
+                                mode = TYPE;
+                                ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
+                                args.append(t1);
+                                while (token.kind == COMMA) {
+                                    nextToken();
+                                    args.append(typeArgument());
+                                }
+                                accept(GT);
+                                t = toP(F.at(pos1).TypeApply(t, args.toList()));
+                                checkGenerics();
+                                while (token.kind == DOT) {
+                                    nextToken();
+                                    mode = TYPE;
+                                    t = toP(F.at(token.pos).Select(t, ident()));
+                                    t = typeArgumentsOpt(t);
+                                }
+                                if (token.kind != HASH) {
+                                    //method reference expected here
+                                    t = illegal();
+                                }
+                                mode = EXPR;
+                                break;
+                            } else if ((mode & EXPR) != 0) {
+                                //rollback - it was a binary expression
+                                mode = EXPR;
+                                JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
+                                t = F.at(pos1).Binary(op, t, e);
+                                t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
+                            }
                         }
+                        break loop;
+                    default:
+                        break loop;
                     }
-                    // typeArgs saved for next loop iteration.
-                    t = toP(F.at(pos).Select(t, ident()));
-                    break;
-                default:
-                    break loop;
                 }
             }
             if (typeArgs != null) illegal();
@@ -1105,6 +1222,19 @@
         default:
             return illegal();
         }
+        return term3Rest(t, typeArgs);
+    }
+
+    JCExpression term3NoParams() {
+        try {
+            mode |= NOPARAMS;
+            return term3();
+        } finally {
+            mode &= ~NOPARAMS;
+        }
+    }
+
+    JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
         if (typeArgs != null) illegal();
         while (true) {
             int pos1 = token.pos;
@@ -1149,6 +1279,11 @@
                     t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
                     typeArgs = null;
                 }
+            } else if ((mode & EXPR) != 0 && token.kind == HASH) {
+                mode = EXPR;
+                if (typeArgs != null) return illegal();
+                accept(HASH);
+                t = memberReferenceSuffix(pos1, t);
             } else {
                 break;
             }
@@ -1162,12 +1297,59 @@
         return toP(t);
     }
 
+    JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
+        ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
+        params.append(firstParam);
+        JCVariableDecl lastParam = firstParam;
+        while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
+            nextToken();
+            params.append(lastParam = formalParameter());
+        }
+        accept(RPAREN);
+        return lambdaExpressionOrStatementRest(params.toList(), pos);
+    }
+
+    JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
+        List<JCVariableDecl> params = explicitParams ?
+                formalParameters() :
+                implicitParameters(hasParens);
+
+        return lambdaExpressionOrStatementRest(params, pos);
+    }
+
+    JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
+        if (token.kind != ARROW) {
+            //better error recovery
+            return F.at(pos).Erroneous(args);
+        }
+
+        checkLambda();
+        accept(ARROW);
+
+        return token.kind == LBRACE ?
+            lambdaStatement(args, pos, pos) :
+            lambdaExpression(args, pos);
+    }
+
+    JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
+        JCBlock block = block(pos2, 0);
+        return toP(F.at(pos).Lambda(args, block));
+    }
+
+    JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
+        JCTree expr = parseExpression();
+        return toP(F.at(pos).Lambda(args, expr));
+    }
+
     /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
      */
     JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
         nextToken();
         if (token.kind == LPAREN || typeArgs != null) {
             t = arguments(typeArgs, t);
+        } else if (token.kind == HASH) {
+            if (typeArgs != null) return illegal();
+            t = memberReferenceSuffix(t);
         } else {
             int pos = token.pos;
             accept(DOT);
@@ -1377,6 +1559,36 @@
         return t;
     }
 
+    /**
+     * MemberReferenceSuffix = "#" [TypeArguments] Ident
+     *                       | "#" [TypeArguments] "new"
+     */
+    JCExpression memberReferenceSuffix(JCExpression t) {
+        int pos1 = token.pos;
+        accept(HASH);
+        return memberReferenceSuffix(pos1, t);
+    }
+
+    JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
+        checkMethodReferences();
+        mode = EXPR;
+        List<JCExpression> typeArgs = null;
+        if (token.kind == LT) {
+            typeArgs = typeArguments(false);
+        }
+        Name refName = null;
+        ReferenceMode refMode = null;
+        if (token.kind == NEW) {
+            refMode = ReferenceMode.NEW;
+            refName = names.init;
+            nextToken();
+        } else {
+            refMode = ReferenceMode.INVOKE;
+            refName = ident();
+        }
+        return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
+    }
+
     /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
      */
     JCExpression creator(int newpos, List<JCExpression> typeArgs) {
@@ -2779,6 +2991,24 @@
         return params.toList();
     }
 
+    List<JCVariableDecl> implicitParameters(boolean hasParens) {
+        if (hasParens) {
+            accept(LPAREN);
+        }
+        ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
+        if (token.kind != RPAREN && token.kind != ARROW) {
+            params.append(implicitParameter());
+            while (token.kind == COMMA) {
+                nextToken();
+                params.append(implicitParameter());
+            }
+        }
+        if (hasParens) {
+            accept(RPAREN);
+        }
+        return params.toList();
+    }
+
     JCModifiers optFinal(long flags) {
         JCModifiers mods = modifiersOpt();
         checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
@@ -2801,6 +3031,11 @@
         return variableDeclaratorId(mods, type);
     }
 
+    protected JCVariableDecl implicitParameter() {
+        JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
+        return variableDeclaratorId(mods, null);
+    }
+
 /* ---------- auxiliary methods -------------- */
 
     void error(int pos, String key, Object ... args) {
@@ -3024,6 +3259,18 @@
             allowTWR = true;
         }
     }
+    void checkLambda() {
+        if (!allowLambda) {
+            log.error(token.pos, "lambda.not.supported.in.source", source.name);
+            allowLambda = true;
+        }
+    }
+    void checkMethodReferences() {
+        if (!allowMethodReferences) {
+            log.error(token.pos, "method.references.not.supported.in.source", source.name);
+            allowMethodReferences = true;
+        }
+    }
 
     /*
      * a functional source tree and end position mappings
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/Lexer.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Lexer.java	Tue Dec 06 20:26:09 2011 -0800
@@ -50,6 +50,11 @@
     Token token();
 
     /**
+     * Return token with given lookahead.
+     */
+    Token token(int lookahead);
+
+    /**
      * Return the last character position of the previous token.
      */
     Token prevToken();
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Tue Dec 06 20:26:09 2011 -0800
@@ -26,8 +26,9 @@
 package com.sun.tools.javac.parser;
 
 import java.nio.*;
+import java.util.List;
+import java.util.ArrayList;
 
-import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.Position.LineMap;
 import com.sun.tools.javac.parser.JavaTokenizer.*;
 
@@ -53,6 +54,10 @@
      */
     private Token prevToken;
 
+    /** Buffer of saved tokens (used during lookahead)
+     */
+    private List<Token> savedTokens = new ArrayList<Token>();
+
     private JavaTokenizer tokenizer;
     /**
      * Create a scanner from the input array.  This method might
@@ -80,16 +85,35 @@
     }
 
     public Token token() {
-        return token;
+        return token(0);
     }
 
+    public Token token(int lookahead) {
+        if (lookahead == 0) {
+            return token;
+        } else {
+            ensureLookahead(lookahead);
+            return savedTokens.get(lookahead - 1);
+        }
+    }
+    //where
+        private void ensureLookahead(int lookahead) {
+            for (int i = savedTokens.size() ; i < lookahead ; i ++) {
+                savedTokens.add(tokenizer.readToken());
+            }
+        }
+
     public Token prevToken() {
         return prevToken;
     }
 
     public void nextToken() {
         prevToken = token;
-        token = tokenizer.readToken();
+        if (!savedTokens.isEmpty()) {
+            token = savedTokens.remove(0);
+        } else {
+            token = tokenizer.readToken();
+        }
     }
 
     public Token split() {
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java	Tue Dec 06 20:26:09 2011 -0800
@@ -176,6 +176,8 @@
         TRUE("true", Tag.NAMED),
         FALSE("false", Tag.NAMED),
         NULL("null", Tag.NAMED),
+        ARROW("->"),
+        HASH("#"),
         LPAREN("("),
         RPAREN(")"),
         LBRACE("{"),
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Dec 06 20:26:09 2011 -0800
@@ -1945,6 +1945,16 @@
     strings in switch are not supported in -source {0}\n\
     (use -source 7 or higher to enable strings in switch)
 
+# 0: string
+compiler.err.lambda.not.supported.in.source=\
+    lambda expressions are not supported in -source {0}\n\
+    (use -source 8 or higher to enable lambda expressions)
+
+# 0: string
+compiler.err.method.references.not.supported.in.source=\
+    method references are not supported in -source {0}\n\
+    (use -source 8 or higher to enable method references)
+
 ########################################
 # Diagnostics for verbose resolution
 # used by Resolve (debug only)
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Dec 06 20:26:09 2011 -0800
@@ -41,6 +41,8 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.parser.EndPosTable;
 import com.sun.source.tree.*;
+import com.sun.source.tree.LambdaExpressionTree.BodyKind;
+import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 
 import static com.sun.tools.javac.code.BoundKind.*;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
@@ -198,6 +200,10 @@
          */
         NEWARRAY,
 
+        /** Lambda expression, of type Lambda.
+         */
+        LAMBDA,
+
         /** Parenthesized subexpressions, of type Parens.
          */
         PARENS,
@@ -222,6 +228,10 @@
          */
         SELECT,
 
+        /** Member references, of type Reference.
+         */
+        REFERENCE,
+
         /** Simple identifiers, of type Ident.
          */
         IDENT,
@@ -1487,6 +1497,56 @@
     }
 
     /**
+     * A lambda expression.
+     */
+    public static class JCLambda extends JCExpression implements LambdaExpressionTree {
+
+        public List<JCVariableDecl> params;
+        public JCTree body;
+        public Type targetType;
+        public boolean canCompleteNormally = true;
+        public List<Type> inferredThrownTypes;
+
+        public JCLambda(List<JCVariableDecl> params,
+                        JCTree body) {
+            this.params = params;
+            this.body = body;
+        }
+        @Override
+        public Tag getTag() {
+            return LAMBDA;
+        }
+        @Override
+        public void accept(Visitor v) {
+            v.visitLambda(this);
+        }
+        @Override
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitLambdaExpression(this, d);
+        }
+        public Kind getKind() {
+            return Kind.LAMBDA_EXPRESSION;
+        }
+        public JCTree getBody() {
+            return body;
+        }
+        public java.util.List<? extends VariableTree> getParameters() {
+            return params;
+        }
+        @Override
+        public JCLambda setType(Type type) {
+            super.setType(type);
+            return this;
+        }
+        @Override
+        public BodyKind getBodyKind() {
+            return body.hasTag(BLOCK) ?
+                    BodyKind.STATEMENT :
+                    BodyKind.EXPRESSION;
+        }
+    }
+
+    /**
      * A parenthesized subexpression ( ... )
      */
     public static class JCParens extends JCExpression implements ParenthesizedTree {
@@ -1747,6 +1807,46 @@
     }
 
     /**
+     * Selects a member expression.
+     */
+    public static class JCMemberReference extends JCExpression implements MemberReferenceTree {
+        public ReferenceMode mode;
+        public Name name;
+        public JCExpression expr;
+        public List<JCExpression> typeargs;
+        public Type targetType;
+        public Symbol sym;
+
+        protected JCMemberReference(ReferenceMode mode, Name name, JCExpression expr, List<JCExpression> typeargs) {
+            this.mode = mode;
+            this.name = name;
+            this.expr = expr;
+            this.typeargs = typeargs;
+        }
+        @Override
+        public void accept(Visitor v) { v.visitReference(this); }
+
+        public Kind getKind() { return Kind.MEMBER_REFERENCE; }
+        @Override
+        public ReferenceMode getMode() { return mode; }
+        @Override
+        public JCExpression getQualifierExpression() { return expr; }
+        @Override
+        public Name getName() { return name; }
+        @Override
+        public List<JCExpression> getTypeArguments() { return typeargs; }
+
+        @Override
+        public <R,D> R accept(TreeVisitor<R,D> v, D d) {
+            return v.visitMemberReference(this, d);
+        }
+        @Override
+        public Tag getTag() {
+            return REFERENCE;
+        }
+    }
+
+    /**
      * An identifier
      * @param idname the name
      * @param sym the symbol
@@ -2271,6 +2371,7 @@
         public void visitApply(JCMethodInvocation that)      { visitTree(that); }
         public void visitNewClass(JCNewClass that)           { visitTree(that); }
         public void visitNewArray(JCNewArray that)           { visitTree(that); }
+        public void visitLambda(JCLambda that)               { visitTree(that); }
         public void visitParens(JCParens that)               { visitTree(that); }
         public void visitAssign(JCAssign that)               { visitTree(that); }
         public void visitAssignop(JCAssignOp that)           { visitTree(that); }
@@ -2280,6 +2381,7 @@
         public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
         public void visitIndexed(JCArrayAccess that)         { visitTree(that); }
         public void visitSelect(JCFieldAccess that)          { visitTree(that); }
+        public void visitReference(JCMemberReference that)   { visitTree(that); }
         public void visitIdent(JCIdent that)                 { visitTree(that); }
         public void visitLiteral(JCLiteral that)             { visitTree(that); }
         public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); }
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java	Tue Dec 06 20:26:09 2011 -0800
@@ -28,6 +28,8 @@
 import java.io.*;
 import java.util.*;
 
+import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
+
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.code.*;
@@ -907,6 +909,17 @@
         }
     }
 
+    public void visitLambda(JCLambda tree) {
+        try {
+            print("(");
+            printExprs(tree.params);
+            print(")->");
+            printExpr(tree.body);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitParens(JCParens tree) {
         try {
             print("(");
@@ -1052,6 +1065,21 @@
         }
     }
 
+    public void visitReference(JCMemberReference tree) {
+        try {
+            printExpr(tree.expr);
+            print("#");
+            if (tree.typeargs != null) {
+                print("<");
+                printExprs(tree.typeargs);
+                print(">");
+            }
+            print(tree.getMode() == ReferenceMode.INVOKE ? tree.name : "new");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     public void visitIdent(JCIdent tree) {
         try {
             print(tree.name);
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Tue Dec 06 20:26:09 2011 -0800
@@ -271,6 +271,13 @@
         return M.at(t.pos).NewClass(encl, typeargs, clazz, args, def);
     }
 
+    public JCTree visitLambdaExpression(LambdaExpressionTree node, P p) {
+        JCLambda t = (JCLambda) node;
+        List<JCVariableDecl> params = copy(t.params, p);
+        JCTree body = copy(t.body, p);
+        return M.at(t.pos).Lambda(params, body);
+    }
+
     public JCTree visitParenthesized(ParenthesizedTree node, P p) {
         JCParens t = (JCParens) node;
         JCExpression expr = copy(t.expr, p);
@@ -289,6 +296,13 @@
         return M.at(t.pos).Select(selected, t.name);
     }
 
+    public JCTree visitMemberReference(MemberReferenceTree node, P p) {
+        JCMemberReference t = (JCMemberReference) node;
+        JCExpression expr = copy(t.expr, p);
+        List<JCExpression> typeargs = copy(t.typeargs, p);
+        return M.at(t.pos).Reference(t.mode, t.name, expr, typeargs);
+    }
+
     public JCTree visitEmptyStatement(EmptyStatementTree node, P p) {
         JCSkip t = (JCSkip) node;
         return M.at(t.pos).Skip();
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Tue Dec 06 20:26:09 2011 -0800
@@ -227,6 +227,34 @@
         }
     }
 
+    /**
+     * Return true if the AST corresponds to a static select of the kind A.B
+     */
+    public static boolean isStaticSelector(JCTree base, Names names) {
+        if (base == null)
+            return false;
+        switch (base.getTag()) {
+            case IDENT:
+                JCIdent id = (JCIdent)base;
+                return id.name != names._this &&
+                        id.name != names._super &&
+                        isStaticSym(base);
+            case SELECT:
+                return isStaticSym(base) &&
+                    isStaticSelector(((JCFieldAccess)base).selected, names);
+            case TYPEAPPLY:
+                return true;
+            default:
+                return false;
+        }
+    }
+    //where
+        private static boolean isStaticSym(JCTree tree) {
+            Symbol sym = symbol(tree);
+            return (sym.kind == Kinds.TYP ||
+                    sym.kind == Kinds.PCK);
+        }
+
     /** Return true if a tree represents the null literal. */
     public static boolean isNull(JCTree tree) {
         if (!tree.hasTag(LITERAL))
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Tue Dec 06 20:26:09 2011 -0800
@@ -351,6 +351,14 @@
         return tree;
     }
 
+    public JCLambda Lambda(List<JCVariableDecl> params,
+                           JCTree body)
+    {
+        JCLambda tree = new JCLambda(params, body);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCParens Parens(JCExpression expr) {
         JCParens tree = new JCParens(expr);
         tree.pos = pos;
@@ -405,6 +413,13 @@
         return tree;
     }
 
+    public JCMemberReference Reference(JCMemberReference.ReferenceMode mode, Name name,
+            JCExpression expr, List<JCExpression> typeargs) {
+        JCMemberReference tree = new JCMemberReference(mode, name, expr, typeargs);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCIdent Ident(Name name) {
         JCIdent tree = new JCIdent(name, null);
         tree.pos = pos;
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Tue Dec 06 20:26:09 2011 -0800
@@ -212,6 +212,11 @@
         scan(tree.elems);
     }
 
+    public void visitLambda(JCLambda tree) {
+        scan(tree.body);
+        scan(tree.params);
+    }
+
     public void visitParens(JCParens tree) {
         scan(tree.expr);
     }
@@ -254,6 +259,11 @@
         scan(tree.selected);
     }
 
+    public void visitReference(JCMemberReference tree) {
+        scan(tree.expr);
+        scan(tree.typeargs);
+    }
+
     public void visitIdent(JCIdent tree) {
     }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Tue Dec 06 20:26:09 2011 -0800
@@ -282,6 +282,12 @@
         result = tree;
     }
 
+    public void visitLambda(JCLambda tree) {
+        tree.params = translate(tree.params);
+        tree.body = translate(tree.body);
+        result = tree;
+    }
+
     public void visitNewArray(JCNewArray tree) {
         tree.elemtype = translate(tree.elemtype);
         tree.dims = translate(tree.dims);
@@ -340,6 +346,11 @@
         result = tree;
     }
 
+    public void visitReference(JCMemberReference tree) {
+        tree.expr = translate(tree.expr);
+        result = tree;
+    }
+
     public void visitIdent(JCIdent tree) {
         result = tree;
     }
--- a/langtools/test/tools/javac/diags/examples/CatchWithoutTry.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/CatchWithoutTry.java	Tue Dec 06 20:26:09 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2011, 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
@@ -23,7 +23,6 @@
 
 // key: compiler.err.catch.without.try
 // key: compiler.err.expected
-// key: compiler.err.not.stmt
 
 class CatchWithoutTry {
     void m() {
--- a/langtools/test/tools/javac/diags/examples/IllegalChar.java	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/test/tools/javac/diags/examples/IllegalChar.java	Tue Dec 06 20:26:09 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2011, 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
@@ -24,5 +24,5 @@
 // key: compiler.err.illegal.char
 
 class IllegalChar {
-    int i = #;
+    int i = `;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/LambdaNotSupported.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+// key: compiler.err.lambda.not.supported.in.source
+// options: -source 7 -Xlint:-options
+
+class LambdaNotSupported {
+    S s = ()->{};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/MethodReferencesNotSupported.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+// key: compiler.err.method.references.not.supported.in.source
+// options: -source 7 -Xlint:-options
+
+class MethodReferencesNotSupported {
+    S s = A#foo;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/NotAStatement.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// key: compiler.err.not.stmt
+
+class NotAStatement {
+    void m() {
+        x + 1;
+    }
+}
--- a/langtools/test/tools/javac/generics/rare/6665356/T6665356.out	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/test/tools/javac/generics/rare/6665356/T6665356.out	Tue Dec 06 20:26:09 2011 -0800
@@ -1,5 +1,5 @@
 T6665356.java:17:37: compiler.err.improperly.formed.type.param.missing
 T6665356.java:18:40: compiler.err.improperly.formed.type.inner.raw.param
-T6665356.java:26:23: compiler.err.improperly.formed.type.param.missing
+T6665356.java:26:22: compiler.err.improperly.formed.type.param.missing
 T6665356.java:27:25: compiler.err.improperly.formed.type.inner.raw.param
 4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/LambdaParserTest.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2011, 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
+ * @bug 7115050
+ * @summary Add parser support for lambda expressions
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class LambdaParserTest {
+
+    static int checkCount = 0;
+
+    enum LambdaKind {
+        NILARY_EXPR("()->x"),
+        NILARY_STMT("()->{ return x; }"),
+        ONEARY_SHORT_EXPR("x->x"),
+        ONEARY_SHORT_STMT("x->{ return x; }"),
+        ONEARY_EXPR("(#M1 #T1 x)->x"),
+        ONEARY_STMT("(#M1 #T1 x)->{ return x; }"),
+        TWOARY_EXPR("(#M1 #T1 x, #M2 #T2 y)->x"),
+        TWOARY_STMT("(#M1 #T1 x, #M2 #T2 y)->{ return x; }");
+
+        String lambdaTemplate;
+
+        LambdaKind(String lambdaTemplate) {
+            this.lambdaTemplate = lambdaTemplate;
+        }
+
+        String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
+                ModifierKind mk1, ModifierKind mk2) {
+            return lambdaTemplate.replaceAll("#M1", mk1.modifier)
+                    .replaceAll("#M2", mk2.modifier)
+                    .replaceAll("#T1", pk1.parameterType)
+                    .replaceAll("#T2", pk2.parameterType);
+        }
+
+        int arity() {
+            switch (this) {
+                case NILARY_EXPR:
+                case NILARY_STMT: return 0;
+                case ONEARY_SHORT_EXPR:
+                case ONEARY_SHORT_STMT:
+                case ONEARY_EXPR:
+                case ONEARY_STMT: return 1;
+                case TWOARY_EXPR:
+                case TWOARY_STMT: return 2;
+                default: throw new AssertionError("Invalid lambda kind " + this);
+            }
+        }
+
+        boolean isShort() {
+            return this == ONEARY_SHORT_EXPR ||
+                    this == ONEARY_SHORT_STMT;
+        }
+    }
+
+    enum LambdaParameterKind {
+        IMPLICIT(""),
+        EXPLIICT_SIMPLE("A"),
+        EXPLICIT_VARARGS("A..."),
+        EXPLICIT_GENERIC1("A<X>"),
+        EXPLICIT_GENERIC3("A<? extends X, ? super Y>");
+
+        String parameterType;
+
+        LambdaParameterKind(String parameterType) {
+            this.parameterType = parameterType;
+        }
+
+        boolean explicit() {
+            return this != IMPLICIT;
+        }
+    }
+
+    enum ModifierKind {
+        NONE(""),
+        FINAL("final"),
+        PUBLIC("public");
+
+        String modifier;
+
+        ModifierKind(String modifier) {
+            this.modifier = modifier;
+        }
+
+        boolean compatibleWith(LambdaParameterKind pk) {
+            switch (this) {
+                case PUBLIC: return false;
+                case FINAL: return pk != LambdaParameterKind.IMPLICIT;
+                case NONE: return true;
+                default: throw new AssertionError("Invalid modifier kind " + this);
+            }
+        }
+    }
+
+    enum ExprKind {
+        NONE("#L#S"),
+        SINGLE_PAREN1("(#L#S)"),
+        SINGLE_PAREN2("(#L)#S"),
+        DOUBLE_PAREN1("((#L#S))"),
+        DOUBLE_PAREN2("((#L)#S)"),
+        DOUBLE_PAREN3("((#L))#S");
+
+        String expressionTemplate;
+
+        ExprKind(String expressionTemplate) {
+            this.expressionTemplate = expressionTemplate;
+        }
+
+        String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
+                ModifierKind mk1, ModifierKind mk2, LambdaKind lk, SubExprKind sk) {
+            return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2))
+                    .replaceAll("#S", sk.subExpression);
+        }
+    }
+
+    enum SubExprKind {
+        NONE(""),
+        SELECT_FIELD(".f"),
+        SELECT_METHOD(".f()"),
+        SELECT_NEW(".new Foo()"),
+        POSTINC("++"),
+        POSTDEC("--");
+
+        String subExpression;
+
+        SubExprKind(String subExpression) {
+            this.subExpression = subExpression;
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+
+        //create default shared JavaCompiler - reused across multiple compilations
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+        for (LambdaKind lk : LambdaKind.values()) {
+            for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
+                if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT) continue;
+                for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
+                    if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT) continue;
+                    for (ModifierKind mk1 : ModifierKind.values()) {
+                        if (mk1 != ModifierKind.NONE && lk.isShort()) continue;
+                        if (lk.arity() < 1 && mk1 != ModifierKind.NONE) continue;
+                        for (ModifierKind mk2 : ModifierKind.values()) {
+                            if (lk.arity() < 2 && mk2 != ModifierKind.NONE) continue;
+                            for (SubExprKind sk : SubExprKind.values()) {
+                                for (ExprKind ek : ExprKind.values()) {
+                                    new LambdaParserTest(pk1, pk2, mk1, mk2, lk, sk, ek)
+                                            .run(comp, fm);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("Total check executed: " + checkCount);
+    }
+
+    LambdaParameterKind pk1;
+    LambdaParameterKind pk2;
+    ModifierKind mk1;
+    ModifierKind mk2;
+    LambdaKind lk;
+    SubExprKind sk;
+    ExprKind ek;
+    JavaSource source;
+    DiagnosticChecker diagChecker;
+
+    LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2, ModifierKind mk1,
+            ModifierKind mk2, LambdaKind lk, SubExprKind sk, ExprKind ek) {
+        this.pk1 = pk1;
+        this.pk2 = pk2;
+        this.mk1 = mk1;
+        this.mk2 = mk2;
+        this.lk = lk;
+        this.sk = sk;
+        this.ek = ek;
+        this.source = new JavaSource();
+        this.diagChecker = new DiagnosticChecker();
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        String template = "class Test {\n" +
+                          "   SAM s = #E;\n" +
+                          "}";
+
+        String source;
+
+        public JavaSource() {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            source = template.replaceAll("#E", ek.expressionString(pk1, pk2, mk1, mk2, lk, sk));
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+                Arrays.asList("-XDallowLambda"), null, Arrays.asList(source));
+        try {
+            ct.parse();
+        } catch (Throwable ex) {
+            throw new AssertionError("Error thron when parsing the following source:\n" + source.getCharContent(true));
+        }
+        check();
+    }
+
+    void check() {
+        checkCount++;
+
+        boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
+                (lk.arity() > 1 && !mk2.compatibleWith(pk2));
+
+        if (lk.arity() == 2 &&
+                (pk1.explicit() != pk2.explicit() ||
+                pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) {
+            errorExpected = true;
+        }
+
+        if (errorExpected != diagChecker.errorFound) {
+            throw new Error("invalid diagnostics for source:\n" +
+                source.getCharContent(true) +
+                "\nFound error: " + diagChecker.errorFound +
+                "\nExpected error: " + errorExpected);
+        }
+    }
+
+    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean errorFound;
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                errorFound = true;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/MethodReferenceParserTest.java	Tue Dec 06 20:26:09 2011 -0800
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2011, 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
+ * @bug 7115052
+ * @summary Add parser support for method references
+ */
+
+import com.sun.source.util.JavacTask;
+import java.net.URI;
+import java.util.Arrays;
+import javax.tools.Diagnostic;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+public class MethodReferenceParserTest {
+
+    static int checkCount = 0;
+
+    enum ReferenceKind {
+        METHOD_REF("#Q##Gm"),
+        CONSTRUCTOR_REF("#Q##Gnew"),
+        ERR_SUPER("#Q##Gsuper"),
+        ERR_METH0("#Q##Gm()"),
+        ERR_METH1("#Q##Gm(X)"),
+        ERR_CONSTR0("#Q##Gnew()"),
+        ERR_CONSTR1("#Q##Gnew(X)");
+
+        String referenceTemplate;
+
+        ReferenceKind(String referenceTemplate) {
+            this.referenceTemplate = referenceTemplate;
+        }
+
+        String getReferenceString(QualifierKind qk, GenericKind gk) {
+            return referenceTemplate
+                    .replaceAll("#Q", qk.qualifier)
+                    .replaceAll("#G", gk.typeParameters);
+        }
+
+        boolean erroneous() {
+            switch (this) {
+                case ERR_SUPER:
+                case ERR_METH0:
+                case ERR_METH1:
+                case ERR_CONSTR0:
+                case ERR_CONSTR1:
+                    return true;
+                default: return false;
+            }
+        }
+    }
+
+    enum GenericKind {
+        NONE(""),
+        ONE("<X>"),
+        TWO("<X,Y>");
+
+        String typeParameters;
+
+        GenericKind(String typeParameters) {
+            this.typeParameters = typeParameters;
+        }
+    }
+
+    enum QualifierKind {
+        THIS("this"),
+        SUPER("super"),
+        NEW("new Foo()"),
+        METHOD("m()"),
+        FIELD("a.f"),
+        UBOUND_SIMPLE("A"),
+        UNBOUND_GENERIC1("A<X>"),
+        UNBOUND_GENERIC2("A<X, Y>"),
+        UNBOUND_GENERIC3("A<? extends X, ? super Y>");
+
+        String qualifier;
+
+        QualifierKind(String qualifier) {
+            this.qualifier = qualifier;
+        }
+    }
+
+    enum ExprKind {
+        NONE("#R#S"),
+        SINGLE_PAREN1("(#R#S)"),
+        SINGLE_PAREN2("(#R)#S"),
+        DOUBLE_PAREN1("((#R#S))"),
+        DOUBLE_PAREN2("((#R)#S)"),
+        DOUBLE_PAREN3("((#R))#S");
+
+        String expressionTemplate;
+
+        ExprKind(String expressionTemplate) {
+            this.expressionTemplate = expressionTemplate;
+        }
+
+        String expressionString(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk) {
+            return expressionTemplate
+                    .replaceAll("#R", rk.getReferenceString(qk, gk))
+                    .replaceAll("#S", sk.subExpression);
+        }
+    }
+
+    enum SubExprKind {
+        NONE(""),
+        SELECT_FIELD(".f"),
+        SELECT_METHOD(".f()"),
+        SELECT_NEW(".new Foo()"),
+        POSTINC("++"),
+        POSTDEC("--");
+
+        String subExpression;
+
+        SubExprKind(String subExpression) {
+            this.subExpression = subExpression;
+        }
+    }
+
+    public static void main(String... args) throws Exception {
+
+        //create default shared JavaCompiler - reused across multiple compilations
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+
+        for (ReferenceKind rk : ReferenceKind.values()) {
+            for (QualifierKind qk : QualifierKind.values()) {
+                for (GenericKind gk : GenericKind.values()) {
+                    for (SubExprKind sk : SubExprKind.values()) {
+                        for (ExprKind ek : ExprKind.values()) {
+                            new MethodReferenceParserTest(rk, qk, gk, sk, ek).run(comp, fm);
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("Total check executed: " + checkCount);
+    }
+
+    ReferenceKind rk;
+    QualifierKind qk;
+    GenericKind gk;
+    SubExprKind sk;
+    ExprKind ek;
+    JavaSource source;
+    DiagnosticChecker diagChecker;
+
+    MethodReferenceParserTest(ReferenceKind rk, QualifierKind qk, GenericKind gk, SubExprKind sk, ExprKind ek) {
+        this.rk = rk;
+        this.qk = qk;
+        this.gk = gk;
+        this.sk = sk;
+        this.ek = ek;
+        this.source = new JavaSource();
+        this.diagChecker = new DiagnosticChecker();
+    }
+
+    class JavaSource extends SimpleJavaFileObject {
+
+        String template = "class Test {\n" +
+                          "   SAM s = #E;\n" +
+                          "}";
+
+        String source;
+
+        public JavaSource() {
+            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
+            source = template.replaceAll("#E", ek.expressionString(rk, qk, gk, sk));
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return source;
+        }
+    }
+
+    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
+        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
+                Arrays.asList("-XDallowMethodReferences"), null, Arrays.asList(source));
+        try {
+            ct.parse();
+        } catch (Throwable ex) {
+            throw new AssertionError("Error thrown when parsing the following source:\n" + source.getCharContent(true));
+        }
+        check();
+    }
+
+    void check() {
+        checkCount++;
+
+        if (diagChecker.errorFound != rk.erroneous()) {
+            throw new Error("invalid diagnostics for source:\n" +
+                source.getCharContent(true) +
+                "\nFound error: " + diagChecker.errorFound +
+                "\nExpected error: " + rk.erroneous());
+        }
+    }
+
+    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+        boolean errorFound;
+
+        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
+                errorFound = true;
+            }
+        }
+    }
+}
--- a/langtools/test/tools/javac/quid/T6999438.out	Wed Jul 05 17:56:44 2017 +0200
+++ b/langtools/test/tools/javac/quid/T6999438.out	Tue Dec 06 20:26:09 2011 -0800
@@ -1,4 +1,4 @@
-T6999438.java:8:9: compiler.err.illegal.char: 35
+T6999438.java:8:8: compiler.err.expected: token.identifier
 T6999438.java:8:10: compiler.err.illegal.start.of.type
 T6999438.java:8:25: compiler.err.expected: token.identifier
 T6999438.java:8:26: compiler.err.expected: ';'