changeset 58318:35114ceea341 lambda-leftovers

Automatic merge with default
author mcimadamore
date Tue, 15 Oct 2019 05:10:57 +0000
parents 9e3829305823 2d9a265926ac
children bfc5a6e98ffd
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java
diffstat 12 files changed, 573 insertions(+), 287 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Oct 15 05:10:57 2019 +0000
@@ -978,6 +978,10 @@
     }
 
     public void visitMethodDef(JCMethodDecl tree) {
+        boolean isLocal = env.info.scope.owner.kind == MTH;
+        if (isLocal) {
+            memberEnter.memberEnter(tree, env);
+        }
         MethodSymbol m = tree.sym;
         boolean isDefaultMethod = (m.flags() & DEFAULT) != 0;
 
@@ -991,22 +995,26 @@
 
             // Create a new environment with local scope
             // for attributing the method.
-            Env<AttrContext> localEnv = memberEnter.methodEnv(tree, env);
+            Env<AttrContext> localEnv = isLocal ?
+                    localMethodEnv(tree, env) :
+                    memberEnter.methodEnv(tree, env);
             localEnv.info.lint = lint;
 
             attribStats(tree.typarams, localEnv);
 
-            // If we override any other methods, check that we do so properly.
-            // JLS ???
-            if (m.isStatic()) {
-                chk.checkHideClashes(tree.pos(), env.enclClass.type, m);
-            } else {
-                chk.checkOverrideClashes(tree.pos(), env.enclClass.type, m);
-            }
-            chk.checkOverride(env, tree, m);
-
-            if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) {
-                log.error(tree, Errors.DefaultOverridesObjectMember(m.name, Kinds.kindName(m.location()), m.location()));
+            if (!isLocal) {
+                // If we override any other methods, check that we do so properly.
+                // JLS ???
+                if (m.isStatic()) {
+                    chk.checkHideClashes(tree.pos(), env.enclClass.type, m);
+                } else {
+                    chk.checkOverrideClashes(tree.pos(), env.enclClass.type, m);
+                }
+                chk.checkOverride(env, tree, m);
+
+                if (isDefaultMethod && types.overridesObjectMethod(m.enclClass(), m)) {
+                    log.error(tree, Errors.DefaultOverridesObjectMember(m.name, Kinds.kindName(m.location()), m.location()));
+                }
             }
 
             // Enter all type parameters into the local method scope.
@@ -3070,7 +3078,7 @@
          * - an instance field, we use the first constructor.
          * - a static field, we create a fake clinit method.
          */
-        public Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) {
+        public Env<AttrContext> lambdaEnv(JCTree that, Env<AttrContext> env) {
             Env<AttrContext> lambdaEnv;
             Symbol owner = env.info.scope.owner;
             ClassSymbol enclClass = owner.enclClass();
@@ -3120,6 +3128,16 @@
             return lambdaEnv;
         }
 
+        public Env<AttrContext> localMethodEnv(JCMethodDecl that, Env<AttrContext> env) {
+            Env<AttrContext> localMethodEnv = lambdaEnv(that, env);
+            if (that.sym.type != null) {
+            //when this is called in the enter stage, there's no type to be set
+                localMethodEnv.info.returnResult = new ResultInfo(KindSelector.VAL, that.sym.type.getReturnType());
+            }
+            return localMethodEnv;
+        }
+
+
     @Override
     public void visitReference(final JCMemberReference that) {
         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Tue Oct 15 05:10:57 2019 +0000
@@ -335,20 +335,34 @@
  * duplicate declaration checking
  *************************************************************************/
 
-    /** Check that variable does not hide variable with same name in
-     *  immediately enclosing local scope.
+    /** Check that variable (resp. local method) does not hide variable (resp. local method) with same
+     *  name in immediately enclosing local scope.
      *  @param pos           Position for error reporting.
-     *  @param v             The symbol.
+     *  @param byName        The symbol.
      *  @param s             The scope.
      */
-    void checkTransparentVar(DiagnosticPosition pos, VarSymbol v, Scope s) {
-        for (Symbol sym : s.getSymbolsByName(v.name)) {
-            if (sym.owner != v.owner) break;
-            if (sym.kind == VAR &&
-                sym.owner.kind.matches(KindSelector.VAL_MTH) &&
-                v.name != names.error) {
-                duplicateError(pos, sym);
-                return;
+    void checkTransparent(DiagnosticPosition pos, Symbol byName, Scope s) {
+        for (Symbol sym : s.getSymbolsByName(byName.name)) {
+            if (sym.owner != byName.owner) break;
+            checkDuplicateSymbol(pos, byName, sym);
+        }
+    }
+
+    private void checkDuplicateSymbol(DiagnosticPosition pos, Symbol s1, Symbol s2) {
+        if (s1 != s2 &&
+                (s2.flags() & CLASH) == 0 &&
+                s1.kind == s2.kind &&
+                s1.name != names.error &&
+                (s1.kind != MTH ||
+                        types.hasSameArgs(s1.type, s2.type) ||
+                        types.hasSameArgs(types.erasure(s1.type), types.erasure(s2.type)))) {
+            if (s1.kind == MTH && (s1.flags() & VARARGS) != (s2.flags() & VARARGS)) {
+                varargsDuplicateError(pos, s1, s2);
+            } else if (s1.kind == MTH && !types.hasSameArgs(s1.type, s2.type, false)) {
+                duplicateErasureError(pos, s1, s2);
+                s1.flags_field |= CLASH;
+            } else {
+                duplicateError(pos, s2);
             }
         }
     }
@@ -3435,26 +3449,7 @@
             return true;
         if (sym.owner.name == names.any) return false;
         for (Symbol byName : s.getSymbolsByName(sym.name, NON_RECURSIVE)) {
-            if (sym != byName &&
-                    (byName.flags() & CLASH) == 0 &&
-                    sym.kind == byName.kind &&
-                    sym.name != names.error &&
-                    (sym.kind != MTH ||
-                     types.hasSameArgs(sym.type, byName.type) ||
-                     types.hasSameArgs(types.erasure(sym.type), types.erasure(byName.type)))) {
-                if ((sym.flags() & VARARGS) != (byName.flags() & VARARGS)) {
-                    sym.flags_field |= CLASH;
-                    varargsDuplicateError(pos, sym, byName);
-                    return true;
-                } else if (sym.kind == MTH && !types.hasSameArgs(sym.type, byName.type, false)) {
-                    duplicateErasureError(pos, sym, byName);
-                    sym.flags_field |= CLASH;
-                    return true;
-                } else {
-                    duplicateError(pos, byName);
-                    return false;
-                }
-            }
+            checkDuplicateSymbol(pos, sym, byName);
         }
         return true;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Oct 15 05:10:57 2019 +0000
@@ -2712,6 +2712,7 @@
                             }
                             break;
                         }
+                    case METHODDEF:
                     case LAMBDA:
                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
                            reportEffectivelyFinalError(pos, sym);
@@ -2735,6 +2736,7 @@
                                 reportInnerClsNeedsFinalError(tree, sym);
                                 break;
                             }
+                        case METHODDEF:
                         case LAMBDA:
                             reportEffectivelyFinalError(tree, sym);
                     }
@@ -2743,8 +2745,14 @@
         }
 
         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
-            String subKey = currentTree.hasTag(LAMBDA) ?
-                  "lambda"  : "inner.cls";
+            String subKey;
+            switch (currentTree.getTag()) {
+                case LAMBDA: subKey = "lambda"; break;
+                case CLASSDEF: subKey = "inner.cls"; break;
+                case METHODDEF: subKey = "local.meth"; break;
+                default:
+                    throw new AssertionError();
+            }
             log.error(pos, Errors.CantRefNonEffectivelyFinalVar(sym, diags.fragment(subKey)));
         }
 
@@ -2781,6 +2789,22 @@
         }
 
         @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            if (tree.sym.owner.kind == MTH) {
+                //local method!
+                JCTree prevTree = currentTree;
+                try {
+                    currentTree = tree;
+                    super.visitMethodDef(tree);
+                } finally {
+                    currentTree = prevTree;
+                }
+            } else {
+                super.visitMethodDef(tree);
+            }
+        }
+
+        @Override
         public void visitIdent(JCIdent tree) {
             if (tree.sym.kind == VAR) {
                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Oct 15 05:10:57 2019 +0000
@@ -438,7 +438,7 @@
         List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
 
         //convert to an invokedynamic call
-        result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args);
+        result = makeMetafactoryIndyCall(localContext, sym.asHandle(), indy_args);
     }
 
     // where
@@ -464,6 +464,43 @@
             }
         }
 
+    @Override
+    public void visitMethodDef(JCMethodDecl tree) {
+        TranslationContext<?> localContext = context;
+        if (localContext != null && localContext.tree == tree) {
+            MethodSymbol sym = localContext.translatedSym;
+            MethodType localMethodType = (MethodType)sym.type;
+
+            //create a desugared (non-local) method
+            JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
+                    sym.name,
+                    make.QualIdent(localMethodType.getReturnType().tsym),
+                    List.nil(),
+                    localContext.syntheticParams,
+                    localMethodType.getThrownTypes() == null ?
+                            List.<JCExpression>nil() :
+                            make.Types(localMethodType.getThrownTypes()),
+                    null,
+                    null);
+            lambdaDecl.sym = sym;
+            lambdaDecl.type = localMethodType;
+
+            //As the local method body is translated, all references to parameters,
+            //captured variables, enclosing members are adjusted accordingly
+            //to refer to the static method parameters (rather than i.e. acessing to
+            //captured members directly).
+            lambdaDecl.body = translate(tree.body);
+
+            //Add the method to the list of methods to be added to this class.
+            kInfo.addMethod(lambdaDecl);
+
+            //omit this declaration from the enclosing body!
+            result = make.Skip();
+        } else {
+            super.visitMethodDef(tree);
+        }
+    }
+
     private JCIdent makeThis(Type type, Symbol owner) {
         VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
                 names._this,
@@ -520,6 +557,36 @@
         result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args);
     }
 
+    @Override
+    public void visitApply(JCMethodInvocation tree) {
+        Symbol m = TreeInfo.symbol(tree.meth);
+        Optional<TranslationContext<?>> optContext = contextMap.values().stream()
+                .filter(c -> c.tree.hasTag(METHODDEF) && ((JCMethodDecl)c.tree).sym == m)
+                .findFirst();
+        if (optContext.isPresent()) {
+            TranslationContext<?> localContext = optContext.get();
+            Symbol sym = localContext.translatedSym;
+            ListBuffer<JCExpression> syntheticInits = new ListBuffer<>();
+
+            //add captured locals
+            for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) {
+                JCTree captured_local = make.Ident(fv).setType(fv.type);
+                syntheticInits.append((JCExpression)captured_local);
+            }
+            // add captured outer this instances (used only when `this' capture itself is illegal)
+            for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
+                JCTree captured_local = make.QualThis(fv.type);
+                syntheticInits.append((JCExpression)captured_local);
+            }
+
+            //then, determine the arguments to the indy call
+            List<JCExpression> args = translate(tree.args.prependList(syntheticInits.toList()), localContext.prev);
+            result = make.Apply(List.nil(), make.Ident(sym), args).setType(tree.type);
+        } else {
+            super.visitApply(tree);
+        }
+    }
+
     /**
      * Translate identifiers within a lambda to the mapped identifier
      * @param tree
@@ -533,7 +600,7 @@
             try {
                 make.at(tree);
 
-                LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
+                TranslationContext<?> lambdaContext = context;
                 JCTree ltree = lambdaContext.translate(tree);
                 if (ltree != null) {
                     result = ltree;
@@ -561,7 +628,7 @@
             try {
                 make.at(tree);
 
-                LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
+                TranslationContext<?> lambdaContext = context;
                 JCTree ltree = lambdaContext.translate(tree);
                 if (ltree != null) {
                     result = ltree;
@@ -598,7 +665,7 @@
 
     @Override
     public void visitVarDef(JCVariableDecl tree) {
-        LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
+        TranslationContext<?> lambdaContext = context;
         if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) {
             tree.init = translate(tree.init);
             tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym);
@@ -1086,7 +1153,7 @@
     /**
      * Generate an indy method call to the meta factory
      */
-    private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context,
+    private JCExpression makeMetafactoryIndyCall(FunctionalTranslationContext<?> context,
             MethodHandleSymbol refSym, List<JCExpression> indy_args) {
         JCFunctionalExpression tree = context.tree;
         //determine the static bsm args
@@ -1322,8 +1389,7 @@
                             if (localContext.tree.hasTag(LAMBDA)) {
                                 JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol);
                                 if (block == null) break;
-                                ((LambdaTranslationContext)localContext)
-                                        .addSymbol(outerInstanceSymbol, CAPTURED_THIS);
+                                localContext.addSymbol(outerInstanceSymbol, CAPTURED_THIS);
                             }
                             localContext = localContext.prev;
                         }
@@ -1349,25 +1415,23 @@
                         tree.type.constValue() == null) {
                     TranslationContext<?> localContext = context();
                     while (localContext != null) {
-                        if (localContext.tree.getTag() == LAMBDA) {
+                        if (localContext.tree.getTag() == LAMBDA || localContext.tree.hasTag(METHODDEF)) {
                             JCTree block = capturedDecl(localContext.depth, tree.sym);
                             if (block == null) break;
-                            ((LambdaTranslationContext)localContext)
-                                    .addSymbol(tree.sym, CAPTURED_VAR);
+                            localContext.addSymbol(tree.sym, CAPTURED_VAR);
                         }
                         localContext = localContext.prev;
                     }
                 } else if (tree.sym.owner.kind == TYP) {
                     TranslationContext<?> localContext = context();
                     while (localContext != null  && !localContext.owner.isStatic()) {
-                        if (localContext.tree.hasTag(LAMBDA)) {
+                        if (localContext.tree.hasTag(LAMBDA) || localContext.tree.hasTag(METHODDEF)) {
                             JCTree block = capturedDecl(localContext.depth, tree.sym);
                             if (block == null) break;
                             switch (block.getTag()) {
                                 case CLASSDEF:
                                     JCClassDecl cdecl = (JCClassDecl)block;
-                                    ((LambdaTranslationContext)localContext)
-                                            .addSymbol(cdecl.sym, CAPTURED_THIS);
+                                    localContext.addSymbol(cdecl.sym, CAPTURED_THIS);
                                     break;
                                 default:
                                     Assert.error("bad block kind");
@@ -1420,8 +1484,21 @@
         public void visitMethodDef(JCMethodDecl tree) {
             List<Frame> prevStack = frameStack;
             try {
-                frameStack = frameStack.prepend(new Frame(tree));
-                super.visitMethodDef(tree);
+                if (tree.sym.owner.kind == MTH) {
+                    //local method
+                    LocalMethodTranslationContext context = new LocalMethodTranslationContext(tree);
+                    frameStack = frameStack.prepend(new Frame(tree));
+                    for (JCVariableDecl param : tree.params) {
+                        context.addSymbol(param.sym, PARAM);
+                        frameStack.head.addLocal(param.sym);
+                    }
+                    contextMap.put(tree, context);
+                    super.visitMethodDef(tree);
+                    context.complete();
+                } else {
+                    frameStack = frameStack.prepend(new Frame(tree));
+                    super.visitMethodDef(tree);
+                }
             }
             finally {
                 frameStack = prevStack;
@@ -1442,20 +1519,19 @@
                             JCTree block = capturedDecl(localContext.depth, outerInstanceSymbol);
                             if (block == null) break;
                         }
-                        ((LambdaTranslationContext)localContext)
-                                .addSymbol(outerInstanceSymbol, CAPTURED_THIS);
+                        localContext.addSymbol(outerInstanceSymbol, CAPTURED_THIS);
                     }
                     localContext = localContext.prev;
                 }
             }
             if (context() != null && !inReferencedClass && isLocal) {
-                LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context();
+                TranslationContext<?> lambdaContext = context();
                 captureLocalClassDefs(def, lambdaContext);
             }
             super.visitNewClass(tree);
         }
         //where
-            void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) {
+            void captureLocalClassDefs(Symbol csym, final TranslationContext<?> lambdaContext) {
                 JCClassDecl localCDef = localClassDefs.get(csym);
                 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) {
                     BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() {
@@ -1473,7 +1549,7 @@
                                     if (localContext.tree.getTag() == LAMBDA) {
                                         JCTree block = capturedDecl(localContext.depth, sym);
                                         if (block == null) break;
-                                        ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR);
+                                        localContext.addSymbol(sym, CAPTURED_VAR);
                                     }
                                     localContext = localContext.prev;
                                 }
@@ -1533,10 +1609,10 @@
                 // we much have an instance context
                 TranslationContext<?> localContext = context();
                 while (localContext != null  && !localContext.owner.isStatic()) {
-                    if (localContext.tree.hasTag(LAMBDA)) {
+                    if (localContext.tree.hasTag(LAMBDA) || localContext.tree.hasTag(METHODDEF)) {
                         JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym);
                         if (clazz == null) break;
-                        ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS);
+                        localContext.addSymbol(clazz.sym, CAPTURED_THIS);
                     }
                     localContext = localContext.prev;
                 }
@@ -1546,10 +1622,7 @@
 
         @Override
         public void visitVarDef(JCVariableDecl tree) {
-            TranslationContext<?> context = context();
-            LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)?
-                    (LambdaTranslationContext)context :
-                    null;
+            TranslationContext<?> ltc = context();
             if (ltc != null) {
                 if (frameStack.head.tree.hasTag(LAMBDA)) {
                     ltc.addSymbol(tree.sym, LOCAL_VAR);
@@ -1730,9 +1803,10 @@
             return null;
         }
 
-        private TranslationContext<?> context() {
+        @SuppressWarnings("unchecked")
+        private <T extends JCTree, Z extends TranslationContext<T>> Z context() {
             for (Frame frame : frameStack) {
-                TranslationContext<?> context = contextMap.get(frame.tree);
+                Z context = (Z)contextMap.get(frame.tree);
                 if (context != null) {
                     return context;
                 }
@@ -1756,14 +1830,11 @@
          *  set of nodes that select `this' (qualified this)
          */
         private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
-            LambdaTranslationContext lambdaContext =
-                    context instanceof LambdaTranslationContext ?
-                            (LambdaTranslationContext) context : null;
-            return lambdaContext != null
+            return context != null
                     && !fAccess.sym.isStatic()
                     && fAccess.name == names._this
                     && (fAccess.sym.owner.kind == TYP)
-                    && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
+                    && !context.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
         }
 
         /**
@@ -1806,10 +1877,10 @@
         }
 
         /**
-         * This class is used to store important information regarding translation of
-         * lambda expression/method references (see subclasses).
+         * This class is the common root for modelling the translation context associated with
+         * constructs handled by LambdaToMethod (lambdas, method references, local methods).
          */
-        abstract class TranslationContext<T extends JCFunctionalExpression> {
+        abstract class TranslationContext<T extends JCTree> {
 
             /** the underlying (untranslated) tree */
             final T tree;
@@ -1822,109 +1893,26 @@
 
             /** the enclosing translation context (set for nested lambdas/mref) */
             final TranslationContext<?> prev;
+            /**
+             * to prevent recursion, track local classes processed
+             */
+            final Set<Symbol> freeVarProcessedLocalClasses;
 
-            /** list of methods to be bridged by the meta-factory */
-            final List<Symbol> bridges;
+
+            Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
+            /** the synthetic symbol for the method hoisting the translated lambda */
+            MethodSymbol translatedSym;
+            List<JCVariableDecl> syntheticParams;
+
 
             TranslationContext(T tree) {
                 this.tree = tree;
                 this.owner = owner(true);
                 this.depth = frameStack.size() - 1;
                 this.prev = context();
-                ClassSymbol csym =
-                        types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
-                this.bridges = types.functionalInterfaceBridges(csym);
-            }
 
-            /** does this functional expression need to be created using alternate metafactory? */
-            boolean needsAltMetafactory() {
-                return tree.target.isIntersection() ||
-                        isSerializable() ||
-                        bridges.length() > 1;
-            }
-
-            /** does this functional expression require serialization support? */
-            boolean isSerializable() {
-                if (forceSerializable) {
-                    return true;
-                }
-                return types.asSuper(tree.target, syms.serializableType.tsym) != null;
-            }
-
-            /**
-             * @return Name of the enclosing method to be folded into synthetic
-             * method name
-             */
-            String enclosingMethodName() {
-                return syntheticMethodNameComponent(owner.name);
-            }
-
-            /**
-             * @return Method name in a form that can be folded into a
-             * component of a synthetic method name
-             */
-            String syntheticMethodNameComponent(Name name) {
-                if (name == null) {
-                    return "null";
-                }
-                String methodName = name.toString();
-                if (methodName.equals("<clinit>")) {
-                    methodName = "static";
-                } else if (methodName.equals("<init>")) {
-                    methodName = "new";
-                }
-                return methodName;
-            }
-        }
-
-        /**
-         * This class retains all the useful information about a lambda expression;
-         * the contents of this class are filled by the LambdaAnalyzer visitor,
-         * and the used by the main translation routines in order to adjust references
-         * to captured locals/members, etc.
-         */
-        class LambdaTranslationContext extends TranslationContext<JCLambda> {
-
-            /** variable in the enclosing context to which this lambda is assigned */
-            final Symbol self;
-
-            /** variable in the enclosing context to which this lambda is assigned */
-            final Symbol assignedTo;
-
-            Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;
-
-            /** the synthetic symbol for the method hoisting the translated lambda */
-            MethodSymbol translatedSym;
-
-            List<JCVariableDecl> syntheticParams;
-
-            /**
-             * to prevent recursion, track local classes processed
-             */
-            final Set<Symbol> freeVarProcessedLocalClasses;
-
-            /**
-             * For method references converted to lambdas.  The method
-             * reference receiver expression. Must be treated like a captured
-             * variable.
-             */
-            JCExpression methodReferenceReceiver;
-
-            LambdaTranslationContext(JCLambda tree) {
-                super(tree);
-                Frame frame = frameStack.head;
-                switch (frame.tree.getTag()) {
-                    case VARDEF:
-                        assignedTo = self = ((JCVariableDecl) frame.tree).sym;
-                        break;
-                    case ASSIGN:
-                        self = null;
-                        assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
-                        break;
-                    default:
-                        assignedTo = self = null;
-                        break;
-                 }
+                freeVarProcessedLocalClasses = new HashSet<>();
+                translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
 
                 // This symbol will be filled-in in complete
                 if (owner.kind == MTH) {
@@ -1938,93 +1926,12 @@
                 } else {
                     this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass());
                 }
-                translatedSymbols = new EnumMap<>(LambdaSymbolKind.class);
 
                 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
                 translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
-
-                freeVarProcessedLocalClasses = new HashSet<>();
-            }
-
-             /**
-             * For a serializable lambda, generate a disambiguating string
-             * which maximizes stability across deserialization.
-             *
-             * @return String to differentiate synthetic lambda method names
-             */
-            private String serializedLambdaDisambiguation() {
-                StringBuilder buf = new StringBuilder();
-                // Append the enclosing method signature to differentiate
-                // overloaded enclosing methods.  For lambdas enclosed in
-                // lambdas, the generated lambda method will not have type yet,
-                // but the enclosing method's name will have been generated
-                // with this same method, so it will be unique and never be
-                // overloaded.
-                Assert.check(
-                        owner.type != null ||
-                        directlyEnclosingLambda() != null);
-                if (owner.type != null) {
-                    buf.append(typeSig(owner.type, true));
-                    buf.append(":");
-                }
-
-                // Add target type info
-                buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
-                buf.append(" ");
-
-                // Add variable assigned to
-                if (assignedTo != null) {
-                    buf.append(assignedTo.flatName());
-                    buf.append("=");
-                }
-                //add captured locals info: type, name, order
-                for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
-                    if (fv != self) {
-                        buf.append(typeSig(fv.type, true));
-                        buf.append(" ");
-                        buf.append(fv.flatName());
-                        buf.append(",");
-                    }
-                }
-
-                return buf.toString();
-            }
-
-            /**
-             * For a non-serializable lambda, generate a simple method.
-             *
-             * @return Name to use for the synthetic lambda method name
-             */
-            private Name lambdaName() {
-                return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
-            }
-
-            /**
-             * For a serializable lambda, generate a method name which maximizes
-             * name stability across deserialization.
-             *
-             * @return Name to use for the synthetic lambda method name
-             */
-            private Name serializedLambdaName() {
-                StringBuilder buf = new StringBuilder();
-                buf.append(names.lambda);
-                // Append the name of the method enclosing the lambda.
-                buf.append(enclosingMethodName());
-                buf.append('$');
-                // Append a hash of the disambiguating string : enclosing method
-                // signature, etc.
-                String disam = serializedLambdaDisambiguation();
-                buf.append(Integer.toHexString(disam.hashCode()));
-                buf.append('$');
-                // The above appended name components may not be unique, append
-                // a count based on the above name components.
-                buf.append(syntheticMethodNameCounts.getIndex(buf));
-                String result = buf.toString();
-                //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
-                return names.fromString(result);
             }
 
             /**
@@ -2156,6 +2063,32 @@
             }
 
             /**
+             * @return Name of the enclosing method to be folded into synthetic
+             * method name
+             */
+            String enclosingMethodName() {
+                return syntheticMethodNameComponent(owner.name);
+            }
+
+            /**
+             * @return Method name in a form that can be folded into a
+             * component of a synthetic method name
+             */
+            String syntheticMethodNameComponent(Name name) {
+                if (name == null) {
+                    return "null";
+                }
+                String methodName = name.toString();
+                if (methodName.equals("<clinit>")) {
+                    methodName = "static";
+                } else if (methodName.equals("<init>")) {
+                    methodName = "new";
+                }
+                return methodName;
+            }
+
+
+            /**
              * The translatedSym is not complete/accurate until the analysis is
              * finished.  Once the analysis is finished, the translatedSym is
              * "completed" -- updated with type information, access modifiers,
@@ -2173,7 +2106,7 @@
                 // Lambda methods are private synthetic.
                 // Inherit ACC_STRICT from the enclosing method, or, for clinit,
                 // from the class.
-                translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD |
+                translatedSym.flags_field = SYNTHETIC | extraFlags() |
                         owner.flags_field & STRICTFP |
                         owner.owner.flags_field & STRICTFP |
                         PRIVATE |
@@ -2205,19 +2138,211 @@
                 translatedSym.params = parameterSymbols.toList();
 
                 // Compute and set the lambda name
-                translatedSym.name = isSerializable()
-                        ? serializedLambdaName()
-                        : lambdaName();
+                translatedSym.name = generatedName();
 
                 //prepend synthetic args to translated lambda method signature
                 translatedSym.type = types.createMethodTypeWithParameters(
-                        generatedLambdaSig(),
+                        generatedSig(),
                         TreeInfo.types(syntheticParams));
             }
 
-            Type generatedLambdaSig() {
+            abstract Type generatedSig();
+
+            abstract Name generatedName();
+
+            long extraFlags() { return 0; }
+        }
+
+        /**
+         * This class is used to store important information regarding translation of
+         * lambda expression/method references (see subclasses).
+         */
+        abstract class FunctionalTranslationContext<T extends JCFunctionalExpression> extends TranslationContext<T> {
+
+            /** list of methods to be bridged by the meta-factory */
+            final List<Symbol> bridges;
+
+            FunctionalTranslationContext(T tree) {
+                super(tree);
+                ClassSymbol csym =
+                        types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
+                this.bridges = types.functionalInterfaceBridges(csym);
+            }
+
+            /** does this functional expression need to be created using alternate metafactory? */
+            boolean needsAltMetafactory() {
+                return tree.target.isIntersection() ||
+                        isSerializable() ||
+                        bridges.length() > 1;
+            }
+
+            /** does this functional expression require serialization support? */
+            boolean isSerializable() {
+                if (forceSerializable) {
+                    return true;
+                }
+                return types.asSuper(tree.target, syms.serializableType.tsym) != null;
+            }
+
+            /**
+             * @return Name of the enclosing method to be folded into synthetic
+             * method name
+             */
+            String enclosingMethodName() {
+                return syntheticMethodNameComponent(owner.name);
+            }
+
+            /**
+             * @return Method name in a form that can be folded into a
+             * component of a synthetic method name
+             */
+            String syntheticMethodNameComponent(Name name) {
+                if (name == null) {
+                    return "null";
+                }
+                String methodName = name.toString();
+                if (methodName.equals("<clinit>")) {
+                    methodName = "static";
+                } else if (methodName.equals("<init>")) {
+                    methodName = "new";
+                }
+                return methodName;
+            }
+        }
+
+        /**
+         * This class retains all the useful information about a lambda expression;
+         * the contents of this class are filled by the LambdaAnalyzer visitor,
+         * and the used by the main translation routines in order to adjust references
+         * to captured locals/members, etc.
+         */
+        class LambdaTranslationContext extends FunctionalTranslationContext<JCLambda> {
+
+            /** variable in the enclosing context to which this lambda is assigned */
+            final Symbol self;
+
+            /** variable in the enclosing context to which this lambda is assigned */
+            final Symbol assignedTo;
+
+            /**
+             * For method references converted to lambdas.  The method
+             * reference receiver expression. Must be treated like a captured
+             * variable.
+             */
+            JCExpression methodReferenceReceiver;
+
+            LambdaTranslationContext(JCLambda tree) {
+                super(tree);
+                Frame frame = frameStack.head;
+                switch (frame.tree.getTag()) {
+                    case VARDEF:
+                        assignedTo = self = ((JCVariableDecl) frame.tree).sym;
+                        break;
+                    case ASSIGN:
+                        self = null;
+                        assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable());
+                        break;
+                    default:
+                        assignedTo = self = null;
+                        break;
+                }
+            }
+
+            /**
+             * For a serializable lambda, generate a disambiguating string
+             * which maximizes stability across deserialization.
+             *
+             * @return String to differentiate synthetic lambda method names
+             */
+            private String serializedLambdaDisambiguation() {
+                StringBuilder buf = new StringBuilder();
+                // Append the enclosing method signature to differentiate
+                // overloaded enclosing methods.  For lambdas enclosed in
+                // lambdas, the generated lambda method will not have type yet,
+                // but the enclosing method's name will have been generated
+                // with this same method, so it will be unique and never be
+                // overloaded.
+                Assert.check(
+                        owner.type != null ||
+                                directlyEnclosingLambda() != null);
+                if (owner.type != null) {
+                    buf.append(typeSig(owner.type));
+                    buf.append(":");
+                }
+
+                // Add target type info
+                buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName());
+                buf.append(" ");
+
+                // Add variable assigned to
+                if (assignedTo != null) {
+                    buf.append(assignedTo.flatName());
+                    buf.append("=");
+                }
+                //add captured locals info: type, name, order
+                for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) {
+                    if (fv != self) {
+                        buf.append(typeSig(fv.type));
+                        buf.append(" ");
+                        buf.append(fv.flatName());
+                        buf.append(",");
+                    }
+                }
+
+                return buf.toString();
+            }
+
+            /**
+             * For a non-serializable lambda, generate a simple method.
+             *
+             * @return Name to use for the synthetic lambda method name
+             */
+            private Name lambdaName() {
+                return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
+            }
+
+            /**
+             * For a serializable lambda, generate a method name which maximizes
+             * name stability across deserialization.
+             *
+             * @return Name to use for the synthetic lambda method name
+             */
+            private Name serializedLambdaName() {
+                StringBuilder buf = new StringBuilder();
+                buf.append(names.lambda);
+                // Append the name of the method enclosing the lambda.
+                buf.append(enclosingMethodName());
+                buf.append('$');
+                // Append a hash of the disambiguating string : enclosing method
+                // signature, etc.
+                String disam = serializedLambdaDisambiguation();
+                buf.append(Integer.toHexString(disam.hashCode()));
+                buf.append('$');
+                // The above appended name components may not be unique, append
+                // a count based on the above name components.
+                buf.append(syntheticMethodNameCounts.getIndex(buf));
+                String result = buf.toString();
+                //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam);
+                return names.fromString(result);
+            }
+
+            @Override
+            Name generatedName() {
+                return isSerializable() ?
+                        serializedLambdaName() :
+                        lambdaName();
+            }
+
+            @Override
+            Type generatedSig() {
                 return types.erasure(tree.getDescriptorType(types));
             }
+
+            @Override
+            long extraFlags() {
+                return LAMBDA_METHOD;
+            }
+
         }
 
         /**
@@ -2226,7 +2351,7 @@
          * and the used by the main translation routines in order to adjust method
          * references (i.e. in case a bridge is needed)
          */
-        final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> {
+        final class ReferenceTranslationContext extends FunctionalTranslationContext<JCMemberReference> {
 
             final boolean isSuper;
 
@@ -2320,7 +2445,43 @@
             Type bridgedRefSig() {
                 return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type);
             }
+
+
+            @Override
+            void complete() {
+                Assert.error();
+            }
+
+            @Override
+            Name generatedName() {
+                Assert.error();
+                return null;
+            }
+
+            @Override
+            Type generatedSig() {
+                Assert.error();
+                return null;
+            }
         }
+
+            class LocalMethodTranslationContext extends TranslationContext<JCMethodDecl> {
+
+                public LocalMethodTranslationContext(JCMethodDecl tree) {
+                    super(tree);
+                }
+
+                @Override
+                Name generatedName() {
+                    return names.local.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++));
+                }
+
+                @Override
+                Type generatedSig() {
+                    return tree.type;
+                }
+
+            }
     }
     // </editor-fold>
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Oct 15 05:10:57 2019 +0000
@@ -2532,7 +2532,7 @@
                     lambdaTranslationMap;
             try {
                 lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
-                        tree.sym.name.startsWith(names.lambda) ?
+                        (tree.sym.name.startsWith(names.lambda) || tree.sym.name.startsWith(names.local)) ?
                         makeTranslationMap(tree) : null;
                 super.visitMethodDef(tree);
             } finally {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue Oct 15 05:10:57 2019 +0000
@@ -176,7 +176,10 @@
     }
 
     public void visitMethodDef(JCMethodDecl tree) {
-        WriteableScope enclScope = enter.enterScope(env);
+        boolean isLocal = env.info.scope.owner.kind == MTH;
+        WriteableScope enclScope = isLocal ?
+                env.info.scope :
+                enter.enterScope(env);
         MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
         m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
         tree.sym = m;
@@ -186,7 +189,7 @@
             m.owner.flags_field |= DEFAULT;
         }
 
-        Env<AttrContext> localEnv = methodEnv(tree, env);
+        Env<AttrContext> localEnv = isLocal ? attr.localMethodEnv(tree, env) : methodEnv(tree, env);
         DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
         try {
             // Compute the method type
@@ -217,7 +220,10 @@
 
         localEnv.info.scope.leave();
         if (chk.checkUnique(tree.pos(), m, enclScope)) {
-        enclScope.enter(m);
+            if (isLocal) {
+                chk.checkTransparent(tree.pos(), m, enclScope);
+            }
+            enclScope.enter(m);
         }
 
         annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
@@ -297,7 +303,7 @@
             }
         }
         if (chk.checkUnique(tree.pos(), v, enclScope)) {
-            chk.checkTransparentVar(tree.pos(), v, enclScope);
+            chk.checkTransparent(tree.pos(), v, enclScope);
             enclScope.enter(v);
         } else if (v.owner.kind == MTH) {
             enclScope.enter(v);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Tue Oct 15 05:10:57 2019 +0000
@@ -1553,8 +1553,9 @@
                       Symbol bestSoFar,
                       boolean allowBoxing,
                       boolean useVarargs) {
+        boolean isLocalMethod = sym.owner.kind == MTH;
         if (sym.kind == ERR ||
-                (site.tsym != sym.owner && !sym.isInheritedIn(site.tsym, types)) ||
+                (site.tsym != sym.owner && (!isLocalMethod && !sym.isInheritedIn(site.tsym, types))) ||
                 !notOverriddenIn(site, sym)) {
             return bestSoFar;
         } else if (useVarargs && (sym.flags() & VARARGS) == 0) {
@@ -1579,7 +1580,7 @@
                     return bestSoFar;
             }
         }
-        if (!isAccessible(env, site, sym)) {
+        if (!isLocalMethod && !isAccessible(env, site, sym)) {
             return (bestSoFar.kind == ABSENT_MTH)
                 ? new AccessError(env, site, sym)
                 : bestSoFar;
@@ -1612,6 +1613,9 @@
             boolean m2SignatureMoreSpecific =
                     signatureMoreSpecific(argtypes, env, site, m2, m1, useVarargs);
             if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) {
+                if (m1.owner.kind == MTH || m2.owner.kind == MTH) {
+                    return ambiguityError(m1, m2);
+                }
                 Type mt1 = types.memberType(site, m1);
                 Type mt2 = types.memberType(site, m2);
                 if (!types.overrideEquivalent(mt1, mt2))
@@ -1935,8 +1939,13 @@
             Assert.check(env1.info.preferredTreeForDiagnostics == null);
             env1.info.preferredTreeForDiagnostics = env.tree;
             try {
-                Symbol sym = findMethod(
-                    env1, env1.enclClass.sym.type, name, argtypes, typeargtypes,
+                Symbol sym = findMethodInScope(env1, env1.enclClass.type, name, argtypes, typeargtypes,
+                        env1.info.scope, bestSoFar, allowBoxing, useVarargs, true);
+                if (sym.exists()) {
+                    return sym;
+                }
+                sym = findMethod(
+                        env1, env1.enclClass.sym.type, name, argtypes, typeargtypes,
                     allowBoxing, useVarargs);
                 if (sym.exists()) {
                     if (staticOnly &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Oct 15 05:10:57 2019 +0000
@@ -1474,7 +1474,8 @@
          */
         class ScanNested extends TreeScanner {
             Set<Env<AttrContext>> dependencies = new LinkedHashSet<>();
-            protected boolean hasLambdas;
+            protected boolean needsLambdaToMethod;
+            protected boolean inMethod;
             @Override
             public void visitClassDef(JCClassDecl node) {
                 Type st = types.supertype(node.sym.type);
@@ -1484,17 +1485,17 @@
                     Env<AttrContext> stEnv = enter.getEnv(c);
                     if (stEnv != null && env != stEnv) {
                         if (dependencies.add(stEnv)) {
-                            boolean prevHasLambdas = hasLambdas;
+                            boolean prevHasLambdas = needsLambdaToMethod;
                             try {
                                 scan(stEnv.tree);
                             } finally {
                                 /*
-                                 * ignore any updates to hasLambdas made during
+                                 * ignore any updates to needsLambdaToMethod made during
                                  * the nested scan, this ensures an initalized
                                  * LambdaToMethod is available only to those
                                  * classes that contain lambdas
                                  */
-                                hasLambdas = prevHasLambdas;
+                                needsLambdaToMethod = prevHasLambdas;
                             }
                         }
                         envForSuperTypeFound = true;
@@ -1505,12 +1506,27 @@
             }
             @Override
             public void visitLambda(JCLambda tree) {
-                hasLambdas = true;
+                needsLambdaToMethod = true;
                 super.visitLambda(tree);
             }
+
+            @Override
+            public void visitMethodDef(JCMethodDecl tree) {
+                if (inMethod) {
+                    needsLambdaToMethod = true;
+                }
+                boolean prevInMethod = inMethod;
+                try {
+                    inMethod = true;
+                    super.visitMethodDef(tree);
+                } finally {
+                    inMethod = prevInMethod;
+                }
+            }
+
             @Override
             public void visitReference(JCMemberReference tree) {
-                hasLambdas = true;
+                needsLambdaToMethod = true;
                 super.visitReference(tree);
             }
         }
@@ -1558,7 +1574,7 @@
             env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
             compileStates.put(env, CompileState.TRANSTYPES);
 
-            if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) {
+            if (Feature.LAMBDA.allowedInSource(source) && scanner.needsLambdaToMethod) {
                 if (shouldStop(CompileState.UNLAMBDA))
                     return;
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Oct 15 05:10:57 2019 +0000
@@ -2584,6 +2584,28 @@
             log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum);
             dc = token.comment(CommentStyle.JAVADOC);
             return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+        case LT:
+            if (isExplicitConstructorCall()) {
+                JCExpression t = term(EXPR | TYPE);
+                t = checkExprStat(t);
+                accept(SEMI);
+                JCExpressionStatement expr = toP(F.at(pos).Exec(t));
+                return List.<JCStatement>of(expr);
+            }
+        case VOID: {
+            List<JCTypeParameter> params = typeParametersOpt();
+            JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
+            JCExpression returnType = null;
+            if (token.kind == VOID) {
+                accept(VOID);
+            } else {
+                returnType = term(EXPR | TYPE);
+            }
+            ListBuffer<JCStatement> stats = new ListBuffer<>();
+            stats.add(methodDeclaratorRest(pos, mods, returnType, ident(), params, false, returnType == null, null));
+            storeEnd(stats.last(), S.prevToken().endPos);
+            return stats.toList();
+        }
         case IDENTIFIER:
             if (token.name() == names.yield && allowYieldStatement) {
                 Token next = S.token(1);
@@ -2653,14 +2675,44 @@
     }
     //where
         private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
-            ListBuffer<JCStatement> stats =
-                    variableDeclarators(mods, type, new ListBuffer<>(), true);
-            // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
-            accept(SEMI);
+            ListBuffer<JCStatement> stats;
+            if (peekToken(LPAREN)) {
+                stats = new ListBuffer<>();
+                stats.add(methodDeclaratorRest(token.pos, mods, type, ident(), List.nil(), false, false, null));
+            } else {
+                stats = variableDeclarators(mods, type, new ListBuffer<JCStatement>(), true);
+                // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
+                accept(SEMI);
+            }
             storeEnd(stats.last(), S.prevToken().endPos);
             return stats.toList();
         }
 
+    boolean isExplicitConstructorCall() {
+        int depth = 0;
+        for (int lookahead = 0 ; ; lookahead++) {
+            TokenKind tk = S.token(lookahead).kind;
+            switch (tk) {
+                case LT:
+                    depth++;
+                    break;
+                case GT:
+                    depth--;
+                    break;
+                case GTGT:
+                    depth -= 2;
+                    break;
+                case GTGTGT:
+                    depth -= 3;
+                    break;
+            }
+            if (depth == 0) {
+                Token name = S.token(lookahead + 1);
+                return name.kind == SUPER || name.kind == THIS;
+            }
+        }
+    }
+
     /** Statement =
      *       Block
      *     | IF ParExpression Statement [ELSE Statement]
@@ -4085,7 +4137,7 @@
      *  ConstructorDeclaratorRest =
      *      "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
      */
-    protected JCTree methodDeclaratorRest(int pos,
+    protected JCStatement methodDeclaratorRest(int pos,
                               JCModifiers mods,
                               JCExpression type,
                               Name name,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Oct 15 05:10:57 2019 +0000
@@ -351,6 +351,9 @@
 compiler.misc.inner.cls=\
     an inner class
 
+compiler.misc.local.meth=\
+    a local method
+
 # 0: type
 compiler.err.cant.deref=\
     {0} cannot be dereferenced
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Oct 15 05:10:57 2019 +0000
@@ -827,7 +827,7 @@
     /**
      * A method definition.
      */
-    public static class JCMethodDecl extends JCTree implements MethodTree {
+    public static class JCMethodDecl extends JCStatement implements MethodTree {
         /** method modifiers */
         public JCModifiers mods;
         /** method name */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Fri Oct 11 20:56:57 2019 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Tue Oct 15 05:10:57 2019 +0000
@@ -187,6 +187,7 @@
     public final Name metafactory;
     public final Name altMetafactory;
     public final Name dollarThis;
+    public final Name local;
 
     // string concat
     public final Name makeConcat;
@@ -338,6 +339,7 @@
         lambda = fromString("lambda$");
         metafactory = fromString("metafactory");
         altMetafactory = fromString("altMetafactory");
+        local = fromString("local$");
 
         // string concat
         makeConcat = fromString("makeConcat");