changeset 56792:580d718c8ddb patterns-deconstruction

A prototype of deconstruction patterns.
author jlahoda
date Fri, 14 Jun 2019 13:24:13 +0200
parents 185f25e1aac8
children a9a1999af6da
files src/jdk.compiler/share/classes/com/sun/source/tree/DeconstructionPatternTree.java src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java test/langtools/tools/javac/patterns/BindingsTest1.java test/langtools/tools/javac/patterns/PatternMatchTest1.java test/langtools/tools/javac/patterns/PatternTypeTest1.java test/langtools/tools/javac/patterns/SimpleDeconstructionPattern.java test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java test/langtools/tools/javac/patterns/scope/ScopeTest.java
diffstat 25 files changed, 802 insertions(+), 110 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/DeconstructionPatternTree.java	Fri Jun 14 13:24:13 2019 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, 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 javax.lang.model.element.Name;
+
+import java.util.List;
+
+/**
+ * XXX
+ */
+public interface DeconstructionPatternTree extends PatternTree {
+
+    /**
+     * XXX
+     * @return XXX
+     */
+    Tree getDeconstructor();
+
+    /**
+     * XXX
+     * @return XXX
+     */
+    List<? extends PatternTree> getNestedPatterns();
+
+    /**
+     * A binding variable name.
+     * @return something
+     */
+    Name getBinding();
+
+}
+
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Fri Jun 14 13:24:13 2019 +0200
@@ -225,6 +225,11 @@
         BINDING_PATTERN(BindingPatternTree.class),
 
         /**
+         * Used for instances of {@link DeconstructionPatternTree}.
+         */
+        DECONSTRUCTION_PATTERN(DeconstructionPatternTree.class),
+
+        /**
          * Used for instances of {@link LiteralPatternTree}.
          */
         LITERAL_PATTERN(LiteralPatternTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Jun 14 13:24:13 2019 +0200
@@ -266,6 +266,14 @@
     R visitBindingPattern(BindingPatternTree node, P p);
 
     /**
+     * Visits an DeconstructionPatternTree node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitDeconstructionPattern(DeconstructionPatternTree node, P p);
+
+    /**
      * Visits a LiteralPattern node.
      * @param node the node being visited
      * @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Fri Jun 14 13:24:13 2019 +0200
@@ -578,6 +578,18 @@
      * @return  the result of {@code defaultAction}
      */
     @Override
+    public R visitDeconstructionPattern(DeconstructionPatternTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation calls {@code defaultAction}.
+     *
+     * @param node {@inheritDoc}
+     * @param p {@inheritDoc}
+     * @return  the result of {@code defaultAction}
+     */
+    @Override
     public R visitLiteralPattern(LiteralPatternTree node, P p) {
         return defaultAction(node, p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Jun 14 13:24:13 2019 +0200
@@ -704,6 +704,20 @@
      * @return a result value
      */
     @Override
+    public R visitDeconstructionPattern(DeconstructionPatternTree node, P p) {
+        R r = scan(node.getDeconstructor(), p);
+        return scanAndReduce(node.getNestedPatterns(), p, r);
+    }
+
+    
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    @Override
     public R visitLiteralPattern(LiteralPatternTree node, P p) {
         return scan(node.getValue(), p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 14 13:24:13 2019 +0200
@@ -25,6 +25,8 @@
 
 package com.sun.tools.javac.comp;
 
+import sun.invoke.util.BytecodeName;
+
 import java.util.*;
 import java.util.function.BiConsumer;
 import java.util.stream.Collectors;
@@ -123,6 +125,7 @@
     final Dependencies dependencies;
     final Annotate annotate;
     final ArgumentAttr argumentAttr;
+    final ClassReader reader;
 
     public static Attr instance(Context context) {
         Attr instance = context.get(attrKey);
@@ -158,6 +161,7 @@
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
         argumentAttr = ArgumentAttr.instance(context);
+        reader = ClassReader.instance(context);
 
         Options options = Options.instance(context);
 
@@ -3849,6 +3853,37 @@
         result = tree.type;
     }
 
+    @Override
+    public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
+        Type site = tree.type = attribType(tree.deconstructor, env);
+        ListBuffer<Type> components = new ListBuffer<>();
+        for (JCPattern n : tree.nested) {
+            components.append(attribExpr(n, env));
+        }
+        MethodSymbol foundPattern = null;
+        Iterable<Symbol> patterns = site.tsym.members().getSymbols(sym -> sym.kind == Kind.MTH && sym.name.startsWith(names.fromString("\\%pattern\\%")));
+        for (Symbol pattern : patterns) {
+            String[] parts = BytecodeName.toSourceName(pattern.name.toString()).split("\\$", 4);
+            if (!parts[2].contentEquals(site.tsym.name))
+                continue;
+            ListBuffer<Type> patternComponents = new ListBuffer<>();
+            byte[] sig = Convert.string2utf(parts[3]);
+            int[] idx = {1};
+            while (sig[idx[0]] != ')') {//TODO: handle errors
+                patternComponents.append(reader.decodeType(env.toplevel.modle, sig, idx));
+            }
+            if (types.isSameTypes(components.toList(), patternComponents.toList())) {
+                //found:
+                foundPattern = (MethodSymbol) pattern;
+                tree.innerTypes = patternComponents.toList();
+                break;
+            }
+        }
+        tree.extractorResolver = foundPattern;
+//        //TODO: some checks....
+        result = tree.type;
+    }
+
     public void visitLiteralPattern(JCLiteralPattern tree) {
         Type patType = attribTree(tree.value, env, resultInfo);
 
@@ -5576,7 +5611,7 @@
             }
             super.visitBindingPattern(that);
         }
-
+        //XXX: DeconstructionPattern!!!!
         @Override
         public void visitNewClass(JCNewClass that) {
             if (that.constructor == null) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Jun 14 13:24:13 2019 +0200
@@ -25,8 +25,6 @@
 
 package com.sun.tools.javac.comp;
 
-import sun.invoke.util.BytecodeName;
-
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.function.Function;
@@ -58,6 +56,7 @@
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.BLOCK;
+import com.sun.tools.javac.code.Kinds.Kind;
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
@@ -2547,15 +2546,8 @@
     JCTree recordExtractor(JCClassDecl tree, MethodHandleSymbol[] getterMethHandles) {
         make_at(tree.pos());
         List<Type> fieldTypes = TreeInfo.types(TreeInfo.recordFields(tree));
-        String argsTypeSig = '(' + argsTypeSig(fieldTypes) + ')';
-        String extractorStr = BytecodeName.toBytecodeName("$pattern$" + tree.sym.name + "$" + argsTypeSig);
-        Name extractorName = names.fromString(extractorStr);
-        // public Extractor extractorName () { return ???; }
-        MethodType extractorMT = new MethodType(List.nil(), syms.extractorType, List.nil(), syms.methodClass);
-        MethodSymbol extractorSym = new MethodSymbol(
-                Flags.PUBLIC | Flags.RECORD | Flags.STATIC,
-                extractorName, extractorMT, tree.sym);
-        tree.sym.members().enter(extractorSym);
+        MethodSymbol extractorSym =
+                (MethodSymbol) tree.sym.members().getSymbols(sym -> sym.kind == Kind.MTH && (sym.flags() & Flags.RECORD) != 0).iterator().next();
 
         Name bootstrapName = names.makeLazyExtractor;
         LoadableConstant[] staticArgsValues = new LoadableConstant[1 + getterMethHandles.length];
@@ -2600,47 +2592,6 @@
         }
     }
 
-    private String argsTypeSig(List<Type> typeList) {
-        LowerSignatureGenerator sg = new LowerSignatureGenerator();
-        sg.assembleSig(typeList);
-        return sg.toString();
-    }
-
-    /**
-     * Signature Generation
-     */
-    private class LowerSignatureGenerator extends Types.SignatureGenerator {
-
-        /**
-         * An output buffer for type signatures.
-         */
-        StringBuilder sb = new StringBuilder();
-
-        LowerSignatureGenerator() {
-            super(types);
-        }
-
-        @Override
-        protected void append(char ch) {
-            sb.append(ch);
-        }
-
-        @Override
-        protected void append(byte[] ba) {
-            sb.append(new String(ba));
-        }
-
-        @Override
-        protected void append(Name name) {
-            sb.append(name.toString());
-        }
-
-        @Override
-        public String toString() {
-            return sb.toString();
-        }
-    }
-
     /**
      * Creates an indy qualifier, helpful to be part of an indy invocation
      * @param site                the site
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java	Fri Jun 14 13:24:13 2019 +0200
@@ -37,6 +37,8 @@
 import com.sun.tools.javac.tree.JCTree.JCLiteralPattern;
 import com.sun.tools.javac.tree.JCTree.JCUnary;
 import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
+import com.sun.tools.javac.tree.JCTree.JCDeconstructionPattern;
+import com.sun.tools.javac.tree.JCTree.JCPattern;
 import com.sun.tools.javac.tree.TreeScanner;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Log;
@@ -64,6 +66,16 @@
     }
 
     @Override
+    public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
+        List<BindingSymbol> outBindings = List.nil();
+        for (JCPattern nested : tree.nested) {
+            scan(nested);
+            outBindings = union(tree, outBindings, bindings);
+        }
+        bindings = outBindings;
+    }
+
+    @Override
     public void visitLiteralPattern(JCLiteralPattern tree) {
         //noop
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Fri Jun 14 13:24:13 2019 +0200
@@ -25,17 +25,18 @@
 
 package com.sun.tools.javac.comp;
 
+
 import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
+import com.sun.tools.javac.code.Symbol.MethodHandleSymbol;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
-import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.GenericSwitch.SwitchKind;
 import com.sun.tools.javac.tree.JCTree.JCAssign;
 import com.sun.tools.javac.tree.JCTree.JCBinary;
-import com.sun.tools.javac.tree.JCTree.JCBlock;
 import com.sun.tools.javac.tree.JCTree.JCBreak;
 import com.sun.tools.javac.tree.JCTree.JCCase;
 import com.sun.tools.javac.tree.JCTree.JCConditional;
@@ -46,9 +47,7 @@
 import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
 import com.sun.tools.javac.tree.JCTree.JCLabeledStatement;
 import com.sun.tools.javac.tree.JCTree.JCLiteralPattern;
-import com.sun.tools.javac.tree.JCTree.JCLiteralPattern.LiteralPatternKind;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
-import com.sun.tools.javac.tree.JCTree.JCStatement;
 import com.sun.tools.javac.tree.JCTree.JCSwitch;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.JCTree.JCBindingPattern;
@@ -58,7 +57,6 @@
 import com.sun.tools.javac.tree.TreeTranslator;
 import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Names;
@@ -69,6 +67,8 @@
 import java.util.stream.Collectors;
 
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.comp.MatchBindingsComputer.BindingSymbol;
 import com.sun.tools.javac.tree.JCTree.JCBlock;
 import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
@@ -76,7 +76,16 @@
 import com.sun.tools.javac.util.List;
 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
 import static com.sun.tools.javac.code.TypeTag.BOT;
+import com.sun.tools.javac.jvm.ClassFile;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCAssignOp;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCDeconstructionPattern;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCPattern;
 import static com.sun.tools.javac.tree.JCTree.Tag.SWITCH;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
 /**
  * This pass translates pattern-matching constructs, such as instanceof <pattern> and switch.
@@ -94,11 +103,13 @@
 
     private Symtab syms;
     private TreeMaker make;
+    private Env<AttrContext> env;
     private Types types;
     private Operators operators;
     private Log log;
     private ConstFold constFold;
     private Names names;
+    private Resolve rs;
 
     BindingContext bindingContext = new BindingContext() {
         @Override
@@ -132,6 +143,11 @@
 
     boolean debugTransPatterns;
 
+    private JCClassDecl currentClass;
+    private MethodSymbol adaptBootstrap; //hack: we should be able to call Extractor.adapt directly, or something equivalent
+    private JCMethodDecl adaptBootstrapTree;
+    private MethodSymbol nullBootstrap; //hack: for ofConstant(null).
+    private JCMethodDecl nullBootstrapTree;
     private MethodSymbol currentMethodSym = null;
 
     protected TransPatterns(Context context) {
@@ -143,60 +159,343 @@
         log = Log.instance(context);
         constFold = ConstFold.instance(context);
         names = Names.instance(context);
+        rs = Resolve.instance(context);
         debugTransPatterns = Options.instance(context).isSet("debug.patterns");
     }
 
+    int idx;
     @Override
     public void visitTypeTest(JCInstanceOf tree) {
-        if (tree.pattern.hasTag(Tag.BINDINGPATTERN)) {
-            JCBindingPattern patt = (JCBindingPattern)tree.pattern;
-            VarSymbol pattSym = patt.symbol;
+        if (tree.pattern.hasTag(Tag.BINDINGPATTERN) || tree.pattern.hasTag(Tag.DECONSTRUCTIONPATTERN) || tree.pattern.hasTag(Tag.LITERALPATTERN)) {
+            JCPattern patt = (JCPattern) tree.pattern;
+            ListBuffer<JCStatement> statements = new ListBuffer<>();
             Type tempType = tree.expr.type.hasTag(BOT) ?
                     syms.objectType
                     : tree.expr.type;
-            VarSymbol temp = new VarSymbol(pattSym.flags(),
-                    pattSym.name.append(names.fromString("$temp")),
+            VarSymbol temp = new VarSymbol(0,
+                    names.fromString("" + (idx++)).append(names.fromString("$temp")), //XXX: use a better name if possible: pattSym.name
                     tempType,
-                    patt.symbol.owner);
+                    currentMethodSym); //XXX: currentMethodSym may not exist!!!!
             JCExpression translatedExpr = translate(tree.expr);
-            Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types));
-            if (patt.vartype == null || tree.expr.type.isPrimitive()) {
-                result = make.Literal(BOOLEAN,1).setType(syms.booleanType);
-            } else {
-                result = makeTypeTest(make.Ident(temp), make.Type(castTargetType));
+            statements.append(make.at(tree.pos).VarDef(temp, translatedExpr));
+            ListBuffer<VarSymbol> bindingVars = new ListBuffer<>();
+            Symbol.DynamicVarSymbol extractor = preparePatternExtractor(patt, tree.expr.type, bindingVars);
+            JCIdent qualifier = make.Ident(patt.type.tsym);
+            qualifier.sym = extractor;
+            qualifier.type = extractor.type;
+            VarSymbol e = new VarSymbol(0,
+                    names.fromString("$e$" + tree.pos),
+                    syms.extractorType,
+                    currentMethodSym); //XXX: currentMethodSym may not exist!!!!
+            statements.add(make.VarDef(e, qualifier));
+            
+            VarSymbol tryMatch = new VarSymbol(0,
+                    names.fromString("$tryMatch$" + tree.pos),
+                    syms.methodHandleType,
+                    currentMethodSym); //XXX: currentMethodSym may not exist!!!!
+            MethodSymbol tryMatchMethod = rs.resolveInternalMethod(patt.pos(), env, syms.extractorType, names.fromString("tryMatch"), List.nil(), List.nil());
+            statements.append(make.VarDef(tryMatch, makeApply(make.Ident(e), tryMatchMethod, List.nil())));
+            VarSymbol carrierMatch = new VarSymbol(0,
+                    names.fromString("$carrier$" + tree.pos),
+                    syms.objectType,
+                    currentMethodSym); //XXX: currentMethodSym may not exist!!!!
+            MethodSymbol invokeMethodObject = rs.resolveInternalMethod(patt.pos(), env, syms.methodHandleType, names.fromString("invoke"), List.of(syms.objectType), List.nil());
+            statements.append(make.VarDef(carrierMatch, makeApply(make.Ident(tryMatch), invokeMethodObject, List.of(translate(tree.expr)))));
+            result = makeBinary(Tag.NE, make.Ident(carrierMatch), makeNull());
+
+            int idx = 0;
+            for (VarSymbol bindingVar : bindingVars) {
+                if (bindingVar != syms.lengthVar) {
+                    VarSymbol component = new VarSymbol(0,
+                            names.fromString("$component$" + tree.pos + "$" + idx),
+                            syms.methodHandleType,
+                            currentMethodSym); //XXX: currentMethodSym may not exist!!!!
+                    MethodSymbol componentMethod = rs.resolveInternalMethod(patt.pos(), env, syms.extractorType, names.fromString("component"), List.of(syms.intType), List.nil());
+                    statements.append(make.VarDef(component, makeApply(make.Ident(e), componentMethod, List.of(make.Literal(idx)))));
+                    Type componentType = types.erasure(bindingVar.type.baseType());
+                    JCTree oldNextTree = env.next.tree;
+                    JCTree oldTree = env.tree;
+                    MethodSymbol invokeMethodForComponent;
+                    try {
+                        env.next.tree = make.TypeCast(componentType, (JCExpression) (env.tree = make.Erroneous()));
+                        invokeMethodForComponent = rs.resolveInternalMethod(patt.pos(), env, syms.methodHandleType, names.fromString("invoke"), List.of(syms.objectType), List.nil());
+                    } finally {
+                        env.next.tree = oldNextTree;
+                        env.tree = oldTree;
+                    }
+                    Type castTargetType = bindingVar.erasure(types);
+                    JCAssign bindingInit = (JCAssign)make.at(tree.pos).Assign(
+                            make.Ident(bindingVar), convert(makeApply(make.Ident(component), invokeMethodForComponent, List.of(make.Ident(carrierMatch))), castTargetType)).setType(bindingVar.erasure(types));
+                    JCExpression assignBoolExpr = make.at(tree.pos).LetExpr(List.of(make.Exec(bindingInit)), make.Literal(true)).setType(syms.booleanType);
+                    result = makeBinary(Tag.AND, (JCExpression)result, assignBoolExpr);
+                }
+                idx++;
             }
-
-            VarSymbol bindingVar = bindingContext.getBindingFor(patt.symbol);
-            if (bindingVar != null) {
-                JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign(
-                        make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types));
-                result = makeBinary(Tag.AND, (JCExpression)result,
-                        makeBinary(Tag.EQ, fakeInit, convert(make.Ident(temp), castTargetType)));
-            }
-            result = make.at(tree.pos).LetExpr(make.VarDef(temp, translatedExpr), (JCExpression)result).setType(syms.booleanType);
-        } else if (tree.pattern.hasTag(Tag.LITERALPATTERN)) {
-            //XXX: should this be here, or do we change switch desugaring?
-            JCLiteralPattern patt = (JCLiteralPattern)tree.pattern;
-            if (patt.patternKind == LiteralPatternKind.TYPE) {
-                result = makeTypeTest(tree.expr, patt.value);
-            } else {
-                JCExpression ce = patt.value;
-                JCExpression lhs = ce.type.hasTag(BOT) ?
-                        tree.expr
-                        : make.TypeCast(make.Type(ce.type), tree.expr).setType(ce.type.baseType());
-                if (!ce.type.hasTag(BOT) && tree.expr.type.isReference()) {
-                    result = translate(makeBinary(
-                            Tag.AND,
-                            makeTypeTest(tree.expr, make.Type(types.boxedTypeOrType(ce.type))),
-                            makeBinary(JCTree.Tag.EQ, lhs, ce)));
-                } else {
-                    result = translate(makeBinary(JCTree.Tag.EQ, lhs, ce));
-                }
-            }
+            result = make.at(tree.pos).LetExpr(statements.toList(), (JCExpression)result).setType(syms.booleanType);
         } else {
             super.visitTypeTest(tree);
         }
     }
+    
+    private Symbol.DynamicVarSymbol preparePatternExtractor(JCPattern patt, Type target, ListBuffer<VarSymbol> bindingVars) {
+        if (patt.hasTag(Tag.BINDINGPATTERN)) {
+            Type tempType = patt.type.hasTag(BOT) ?
+                    syms.objectType
+                    : types.boxedTypeOrType(patt.type);
+            Type indyType = syms.objectType;
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                                syms.stringType,
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(syms.extractorType),
+                                                              syms.classType.tsym),
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(tempType),
+                                                              syms.classType.tsym));
+            
+            Symbol ofType = rs.resolveInternalMethod(patt.pos(), env, syms.extractorType,
+                    names.fromString("ofType"), bsm_staticArgs, List.nil());
+            
+            Symbol.DynamicVarSymbol dynSym = new Symbol.DynamicVarSymbol(names.fromString("ofType"),
+                    syms.noSymbol,
+                    new Symbol.MethodHandleSymbol(ofType),
+                    indyType,
+                    new LoadableConstant[] {(ClassType) tempType});
+
+            VarSymbol binding = bindingContext.getBindingFor(((JCBindingPattern) patt).symbol);
+            
+            Assert.checkNonNull(binding);
+
+            bindingVars.append(binding);
+
+            return wrapWithAdapt(patt.pos(), dynSym, target);
+        } else if (patt.hasTag(Tag.DECONSTRUCTIONPATTERN)) {
+            JCDeconstructionPattern dpatt = (JCDeconstructionPattern) patt;
+            Type tempType = patt.type.hasTag(BOT) ?
+                    syms.objectType
+                    : patt.type;
+            Type indyType = syms.objectType;
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                                syms.stringType,
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(syms.extractorType),
+                                                              syms.classType.tsym),
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(tempType),
+                                                              syms.classType.tsym),
+                                                syms.methodTypeType,
+                                                syms.stringType,
+                                                syms.intType);
+            
+            Symbol ofType = rs.resolveInternalMethod(patt.pos(), env, syms.extractorType,
+                    names.fromString("findExtractor"), bsm_staticArgs, List.nil());
+
+            Symbol.DynamicVarSymbol outter = new Symbol.DynamicVarSymbol(names.fromString("findExtractor"),
+                    syms.noSymbol,
+                    new Symbol.MethodHandleSymbol(ofType),
+                    indyType,
+                    new LoadableConstant[] {(ClassType) tempType,
+                                            new MethodType(dpatt.innerTypes, syms.voidType, List.nil(), syms.methodClass),
+                                            LoadableConstant.String(dpatt.extractorResolver.name.toString()),
+                                            LoadableConstant.Int(ClassFile.REF_newInvokeSpecial)});
+
+            DynamicVarSymbol[] params = new DynamicVarSymbol[((JCDeconstructionPattern) patt).getNestedPatterns().size() + 1];
+            params[0] = outter;
+            @SuppressWarnings({"rawtypes", "unchecked"})
+            ListBuffer<VarSymbol>[] nestedBindings = new ListBuffer[((JCDeconstructionPattern) patt).getNestedPatterns().size()];
+
+            for (int i = 0; i < ((JCDeconstructionPattern) patt).getNestedPatterns().size(); i++) {
+                JCPattern nested = ((JCDeconstructionPattern) patt).getNestedPatterns().get(i);
+                params[i + 1] = preparePatternExtractor(nested, nested.type, nestedBindings[i] = new ListBuffer<>());
+                if (nested.hasTag(Tag.DECONSTRUCTIONPATTERN)) {
+                    bindingVars.append(syms.lengthVar);
+                } else {
+                    bindingVars.appendList(nestedBindings[i].toList());
+                    nestedBindings[i].clear();
+                }
+            }
+            
+            for (ListBuffer<VarSymbol> nested : nestedBindings) {
+                if (nested.isEmpty())
+                    continue;
+                bindingVars.appendList(nested.toList());
+            }
+
+            List<Type> bsm_staticArgsNested = List.of(syms.methodHandleLookupType,
+                                                      syms.stringType,
+                                                      new ClassType(syms.classType.getEnclosingType(),
+                                                                    List.of(syms.extractorType),
+                                                                    syms.classType.tsym),
+                                                      syms.extractorType,
+                                                      types.makeArrayType(syms.extractorType));
+
+            Symbol ofNested = rs.resolveInternalMethod(patt.pos(), env, syms.extractorType,
+                    names.fromString("ofNested"), bsm_staticArgsNested, List.nil());
+            
+            Symbol.DynamicVarSymbol ofNestedSym = new Symbol.DynamicVarSymbol(ofNested.name,
+                    syms.noSymbol,
+                    new Symbol.MethodHandleSymbol(ofNested),
+                    indyType, //???
+                    params);
+
+            return wrapWithAdapt(patt.pos(), ofNestedSym, target);
+        } else if (patt.hasTag(Tag.LITERALPATTERN)) {
+            JCLiteralPattern lpatt = (JCLiteralPattern) patt;
+            Type indyType = syms.objectType;
+
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                                syms.stringType,
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(syms.extractorType),
+                                                              syms.classType.tsym),
+                                                syms.objectType);
+            
+            Symbol ofType = rs.resolveInternalMethod(patt.pos(), env, syms.extractorType,
+                    names.fromString("ofConstant"), bsm_staticArgs, List.nil());
+
+            LoadableConstant lc;
+            Object constValue = lpatt.value.type.constValue();
+            if (constValue instanceof Double) {
+                lc = LoadableConstant.Double((Double) constValue);
+            } else if (constValue instanceof Float) {
+                lc = LoadableConstant.Float((Float) constValue);
+            } else  if (constValue instanceof Integer) {
+                lc = LoadableConstant.Int((Integer) constValue);
+            } else if (constValue instanceof Long) {
+                lc = LoadableConstant.Long((Long) constValue);
+            } else if (constValue instanceof String) {
+                lc = LoadableConstant.String((String) constValue);
+            } else if (constValue == null) {
+                lc = nullBootstrap();
+            } else {
+                Assert.error(constValue.getClass().getName());
+                throw new InternalError();
+            }
+
+            Symbol.DynamicVarSymbol ofConstant =
+                    new Symbol.DynamicVarSymbol(names.fromString("ofConstant"),
+                                                syms.noSymbol,
+                                                new Symbol.MethodHandleSymbol(ofType),
+                                                indyType,
+                                                new LoadableConstant[] {lc});
+            return wrapWithAdapt(patt.pos(), ofConstant, target);
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    private Symbol.DynamicVarSymbol wrapWithAdapt(DiagnosticPosition pos, Symbol.DynamicVarSymbol extractor, Type target) {
+        if (types.boxedTypeOrType(target) != target) {
+            //XXX: cannot adapt primitive types
+            return extractor;
+        }
+
+        if (target == syms.botType) {
+            target = syms.objectType;
+        }
+
+        Assert.checkNonNull(currentClass);
+
+        if (adaptBootstrap == null) {
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                                syms.stringType,
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(syms.extractorType),
+                                                              syms.classType.tsym),
+                                                syms.extractorType,
+                                                syms.classType);
+
+            MethodType indyType = new MethodType(bsm_staticArgs, syms.extractorType, List.nil(),syms.methodClass);
+
+            adaptBootstrap = new MethodSymbol(Flags.STATIC | Flags.SYNTHETIC, names.fromString("$adapt$bootstrap"), indyType, currentClass.sym);
+
+            currentClass.sym.members().enter(adaptBootstrap);
+
+            Symbol adapt = rs.resolveInternalMethod(pos, env, syms.extractorType,
+                    names.fromString("adapt"), List.of(syms.extractorType, syms.classType), List.nil());
+
+            adaptBootstrapTree = make.MethodDef(adaptBootstrap,
+                                                adaptBootstrap.externalType(types),
+                                                make.Block(0, List.of(make.Return(make.Apply(List.nil(), make.QualIdent(adapt), List.of(make.Ident(adaptBootstrap.params().get(3)), make.Ident(adaptBootstrap.params().get(4)))).setType(syms.extractorType)))));
+        }
+
+        return new Symbol.DynamicVarSymbol(adaptBootstrap.name,
+                                           syms.noSymbol,
+                                           new MethodHandleSymbol(adaptBootstrap),
+                                           syms.extractorType,
+                                           new LoadableConstant[] {extractor, (LoadableConstant) target});
+    }
+
+    private Symbol.DynamicVarSymbol nullBootstrap() {
+        Assert.checkNonNull(currentClass);
+
+        if (nullBootstrap == null) {
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                                syms.stringType,
+                                                new ClassType(syms.classType.getEnclosingType(),
+                                                              List.of(syms.objectType),
+                                                              syms.classType.tsym));
+
+            MethodType indyType = new MethodType(bsm_staticArgs, syms.objectType, List.nil(), syms.methodClass);
+
+            nullBootstrap = new MethodSymbol(Flags.STATIC | Flags.SYNTHETIC, names.fromString("$null$bootstrap"), indyType, currentClass.sym);
+
+            currentClass.sym.members().enter(nullBootstrap);
+
+            nullBootstrapTree = make.MethodDef(nullBootstrap,
+                                               nullBootstrap.externalType(types),
+                                               make.Block(0, List.of(make.Return(make.Literal(BOT, null).setType(syms.botType)))));
+        }
+
+        return new Symbol.DynamicVarSymbol(nullBootstrap.name,
+                                           syms.noSymbol,
+                                           new MethodHandleSymbol(nullBootstrap),
+                                           syms.objectType,
+                                           new LoadableConstant[0]);
+    }
+
+    private JCExpression makeApply(JCExpression site, Symbol method, List<JCExpression> params) {
+        JCFieldAccess acc = make.Select(site, method.name);
+        acc.sym = method;
+        acc.type = method.type;
+        return make.Apply(List.nil(), acc, params).setType(acc.type.getReturnType());
+    }
+
+    //from Lower:
+    /** Make an attributed tree representing a literal. This will be an
+     *  Ident node in the case of boolean literals, a Literal node in all
+     *  other cases.
+     *  @param type       The literal's type.
+     *  @param value      The literal's value.
+     */
+    JCExpression makeLit(Type type, Object value) {
+        return make.Literal(type.getTag(), value).setType(type.constType(value));
+    }
+
+    /** Make an attributed tree representing null.
+     */
+    JCExpression makeNull() {
+        return makeLit(syms.botType, null);
+    }
+    
+    /** Make an attributed assignop expression.
+     *  @param optag    The operators tree tag.
+     *  @param lhs      The operator's left argument.
+     *  @param rhs      The operator's right argument.
+     */
+    JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
+        JCAssignOp tree = make.Assignop(optag, lhs, rhs);
+        tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), lhs.type, rhs.type);
+        tree.type = lhs.type;
+        return tree;
+    }
+    
+//    JCNewArray makeArray(Type type, JCExpression... elements) {
+//        JCNewArray newArray = make.NewArray(make.Type(types.erasure(type)),
+//                                          List.nil(),
+//                                          List.from(elements));
+//        newArray.type = types.makeArrayType(newArray.elemtype.type);
+//        return newArray;
+//    }
 
     @Override
     public void visitBinary(JCBinary tree) {
@@ -332,6 +631,35 @@
     }
 
     @Override
+    public void visitClassDef(JCTree.JCClassDecl tree) {
+        JCClassDecl prevCurrentClass = currentClass;
+        MethodSymbol prevAdaptBootstrap = adaptBootstrap;
+        JCMethodDecl prevAdaptBootstrapTree = adaptBootstrapTree;
+        MethodSymbol prevNullBootstrap = nullBootstrap;
+        JCMethodDecl prevNullBootstrapTree = nullBootstrapTree;
+        try {
+            currentClass = tree;
+            adaptBootstrap = null;
+            adaptBootstrapTree = null;
+            nullBootstrap = null;
+            nullBootstrapTree = null;
+            super.visitClassDef(tree);
+        } finally {
+            if (adaptBootstrapTree != null) {
+                currentClass.defs = currentClass.defs.prepend(adaptBootstrapTree);
+            }
+            if (nullBootstrapTree != null) {
+                currentClass.defs = currentClass.defs.prepend(nullBootstrapTree);
+            }
+            currentClass = prevCurrentClass;
+            adaptBootstrap = prevAdaptBootstrap;
+            adaptBootstrapTree = prevAdaptBootstrapTree;
+            nullBootstrap = prevNullBootstrap;
+            nullBootstrapTree = prevNullBootstrapTree;
+        }
+    }
+
+    @Override
     public void visitMethodDef(JCMethodDecl tree) {
         MethodSymbol prevMethodSym = currentMethodSym;
         try {
@@ -380,10 +708,12 @@
     public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
         try {
             this.make = make;
+            this.env = env;
             translate(cdef);
         } finally {
             // note that recursive invocations of this method fail hard
             this.make = null;
+            this.env = null;
         }
 
         if (debugTransPatterns) {
@@ -482,7 +812,7 @@
             this.parent = bindingContext;
             this.hoistedVarMap = matchBindings.stream()
                     .filter(v -> parent.getBindingFor(v) == null)
-                    .collect(Collectors.toMap(v -> v, v -> new VarSymbol(v.flags(), v.name.append(names.fromString("$binding")), v.type, v.owner)));
+                    .collect(Collectors.toMap(v -> v, v -> new VarSymbol(v.flags() & ~Flags.MATCH_BINDING, v.name.append(names.fromString("$binding")), v.type, v.owner)));
         }
 
         @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Jun 14 13:24:13 2019 +0200
@@ -585,6 +585,13 @@
         result = retype(tree, tree.type, pt);
     }
 
+    @Override
+    public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
+        tree.deconstructor = translate(tree.deconstructor, null);
+        tree.nested = translate(tree.nested, null);
+        result = tree;
+    }
+
     public void visitSynchronized(JCSynchronized tree) {
         tree.lock = translate(tree.lock, erasure(tree.lock.type));
         tree.body = translate(tree.body);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Fri Jun 14 13:24:13 2019 +0200
@@ -48,6 +48,8 @@
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.tree.JCTree.*;
 
+import sun.invoke.util.BytecodeName;
+
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.ANNOTATION;
 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
@@ -1190,8 +1192,58 @@
                     memberEnter.memberEnter(readResolve, env);
                 }
             }
+            List<Type> fieldTypes = TreeInfo.recordFields(tree).stream().map(f -> f.sym.type).collect(List.collector());
+            String argsTypeSig = '(' + argsTypeSig(fieldTypes) + ')';
+            String extractorStr = BytecodeName.toBytecodeName("$pattern$" + tree.sym.name + "$" + argsTypeSig);
+            Name extractorName = names.fromString(extractorStr);
+            // public Extractor extractorName () { return ???; }
+            MethodType extractorMT = new MethodType(List.nil(), syms.extractorType, List.nil(), syms.methodClass);
+            MethodSymbol extractorSym = new MethodSymbol(
+                    Flags.PUBLIC | Flags.RECORD | Flags.STATIC,
+                    extractorName, extractorMT, tree.sym);
+            tree.sym.members().enter(extractorSym);
         }
+        //where:
+            private String argsTypeSig(List<Type> typeList) {
+                LowerSignatureGenerator sg = new LowerSignatureGenerator();
+                sg.assembleSig(typeList);
+                return sg.toString();
+            }
 
+            /**
+             * Signature Generation
+             */
+            private class LowerSignatureGenerator extends Types.SignatureGenerator {
+
+                /**
+                 * An output buffer for type signatures.
+                 */
+                StringBuilder sb = new StringBuilder();
+
+                LowerSignatureGenerator() {
+                    super(types);
+                }
+
+                @Override
+                protected void append(char ch) {
+                    sb.append(ch);
+                }
+
+                @Override
+                protected void append(byte[] ba) {
+                    sb.append(new String(ba));
+                }
+
+                @Override
+                protected void append(Name name) {
+                    sb.append(name.toString());
+                }
+
+                @Override
+                public String toString() {
+                    return sb.toString();
+                }
+            }
     }
 
     private Symbol lookupMethod(TypeSymbol tsym, Name name, List<Type> argtypes) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Fri Jun 14 13:24:13 2019 +0200
@@ -406,6 +406,20 @@
  * Reading Types
  ***********************************************************************/
 
+    public Type decodeType(ModuleSymbol msym, byte[] sig, int[] idx) {
+        signature = sig;
+        sigp = idx[0];
+        siglimit = sig.length;
+        ModuleSymbol prevModule = currentModule;
+        currentModule = msym;
+        try {
+            return sigToType();
+        } finally {
+            idx[0] = sigp;
+            currentModule = prevModule;
+        }
+    }
+
     /** The unread portion of the currently read type is
      *  signature[sigp..siglimit-1].
      */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Jun 14 13:24:13 2019 +0200
@@ -930,6 +930,20 @@
      */
     void writeBootstrapMethods() {
         int alenIdx = writeAttr(names.BootstrapMethods);
+        OUTER: while (true) {
+            int size = poolWriter.bootstrapMethods.size();
+            for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
+                //ensure all is in pool:
+                LoadableConstant[] uniqueArgs = bsmKey.staticArgs;
+                for (LoadableConstant arg : uniqueArgs) {
+                    poolWriter.putConstant(arg);
+                    if (size != poolWriter.bootstrapMethods.size()) {
+                        continue OUTER;
+                    }
+                }
+            }
+            break;
+        }
         databuf.appendChar(poolWriter.bootstrapMethods.size());
         for (BsmKey bsmKey : poolWriter.bootstrapMethods.keySet()) {
             //write BSM handle
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jun 14 13:24:13 2019 +0200
@@ -56,6 +56,7 @@
 import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
 import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
+import static com.sun.tools.javac.parser.Tokens.TokenKind.VAR;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.ImplicitAndExplicitNotAllowed;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed;
@@ -234,12 +235,15 @@
     protected static final int TYPEARG = 0x8;
     protected static final int DIAMOND = 0x10;
     protected static final int NOLAMBDA = 0x20;
+    protected static final int NOINVOCATION = 0x20;
 
     protected void selectExprMode() {
+        //TODO: copy NOINVOCATION
         mode = (mode & NOLAMBDA) | EXPR;
     }
 
     protected void selectTypeMode() {
+        //TODO: copy NOINVOCATION
         mode = (mode & NOLAMBDA) | TYPE;
     }
 
@@ -752,9 +756,21 @@
             nextToken();
             return toP(F.at(pos).BindingPattern(ident(), null));
         } else {
-            JCExpression e = term(EXPR | TYPE | NOLAMBDA);
+            JCExpression e = term(EXPR | TYPE | NOLAMBDA | NOINVOCATION);
             if (token.kind == IDENTIFIER) {
                 return toP(F.at(pos).BindingPattern(ident(), e));
+            } else if (token.kind == LPAREN) {
+                ListBuffer<JCPattern> nested = new ListBuffer<>();
+                do {
+                    nextToken();
+                    nested.append(parsePattern());
+                } while (token.kind == COMMA);
+                Name name = null;
+                if (token.kind == IDENTIFIER) {
+                    name = ident();
+                }
+                accept(RPAREN);
+                return toP(F.at(pos).DeconstructionPattern(name, e, nested.toList()));
             } else {
                 return toP(F.at(pos).LiteralPattern(e));
             }
@@ -947,6 +963,18 @@
                         pattern = null;
                     }
                     pattern = toP(F.at(patternPos).BindingPattern(ident(), pattern));
+                } else if (token.kind == LPAREN) {
+                    ListBuffer<JCPattern> nested = new ListBuffer<>();
+                    do {
+                        nextToken();
+                        nested.append(parsePattern());
+                    } while (token.kind == COMMA);
+                    Name name = null;
+                    if (token.kind == IDENTIFIER) {
+                        name = ident();
+                    }
+                    accept(RPAREN);
+                    pattern = toP(F.at(pos).DeconstructionPattern(name, (JCExpression) pattern, nested.toList()));
                 }
                 odStack[top] = F.at(pos).TypeTest(odStack[top], pattern);
             } else {
@@ -1276,7 +1304,7 @@
                         }
                         break loop;
                     case LPAREN:
-                        if ((mode & EXPR) != 0) {
+                        if ((mode & EXPR) != 0 && (mode & NOINVOCATION) == 0) {
                             selectExprMode();
                             t = arguments(typeArgs, t);
                             if (!annos.isEmpty()) t = illegal(annos.head.pos);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Jun 14 13:24:13 2019 +0200
@@ -244,6 +244,7 @@
         /** Patterns.
          */
         BINDINGPATTERN,
+        DECONSTRUCTIONPATTERN,
         LITERALPATTERN,
 
         /** Indexed array expressions, of type Indexed.
@@ -2289,6 +2290,58 @@
         }
     }
 
+    public static class JCDeconstructionPattern extends JCPattern
+            implements DeconstructionPatternTree {
+        public Name name; //possibly null
+//        public BindingSymbol symbol;
+        public JCExpression deconstructor;
+        public List<JCPattern> nested;
+        public Symbol extractorResolver; //TODO: MethodSymbol?; TODO: rename to pattern(Sym?)
+        public List<Type> innerTypes;
+
+        protected JCDeconstructionPattern(Name name, JCExpression deconstructor, List<JCPattern> nested) {
+            this.name = name;
+            this.deconstructor = deconstructor;
+            this.nested = nested;
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Name getBinding() {
+            return name;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Tree getDeconstructor() {
+            return deconstructor;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<? extends JCPattern> getNestedPatterns() {
+            return nested;
+        }
+
+        @Override
+        public void accept(Visitor v) {
+            v.visitDeconstructionPattern(this);
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.DECONSTRUCTION_PATTERN;
+        }
+
+        @Override
+        @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitDeconstructionPattern(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return DECONSTRUCTIONPATTERN;
+        }
+    }
+
     public static class JCLiteralPattern extends JCPattern
             implements LiteralPatternTree {
 
@@ -3210,11 +3263,11 @@
 
     /** (let int x = 3; in x+2) */
     public static class LetExpr extends JCExpression {
-        public List<JCStatement> defs;
+        public List<? extends JCStatement> defs;
         public JCExpression expr;
         /**true if a expr should be run through Gen.genCond:*/
         public boolean needsCond;
-        protected LetExpr(List<JCStatement> defs, JCExpression expr) {
+        protected LetExpr(List<? extends JCStatement> defs, JCExpression expr) {
             this.defs = defs;
             this.expr = expr;
         }
@@ -3332,7 +3385,7 @@
         JCProvides Provides(JCExpression serviceName, List<JCExpression> implNames);
         JCRequires Requires(boolean isTransitive, boolean isStaticPhase, JCExpression qualId);
         JCUses Uses(JCExpression qualId);
-        LetExpr LetExpr(List<JCStatement> defs, JCExpression expr);
+        LetExpr LetExpr(List<? extends JCStatement> defs, JCExpression expr);
     }
 
     /** A generic visitor class for trees.
@@ -3378,6 +3431,7 @@
         public void visitTypeCast(JCTypeCast that)           { visitTree(that); }
         public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
         public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
+        public void visitDeconstructionPattern(JCDeconstructionPattern that) { visitTree(that); }
         public void visitLiteralPattern(JCLiteralPattern that) { visitTree(that); }
         public void visitIndexed(JCArrayAccess that)         { visitTree(that); }
         public void visitSelect(JCFieldAccess that)          { visitTree(that); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Jun 14 13:24:13 2019 +0200
@@ -494,6 +494,14 @@
     }
 
     @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitDeconstructionPattern(DeconstructionPatternTree node, P p) {
+        JCDeconstructionPattern t = (JCDeconstructionPattern) node;
+        JCExpression deconstructor = copy(t.deconstructor, p);
+        List<JCPattern> nested = copy(t.nested, p);
+        return M.at(t.pos).DeconstructionPattern(t.name, deconstructor, nested);
+    }
+
+    @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitLiteralPattern(LiteralPatternTree node, P p) {
         JCLiteralPattern t = (JCLiteralPattern)node;
         JCExpression value = copy(t.value, p);
@@ -590,7 +598,7 @@
         switch (tree.getTag()) {
             case LETEXPR: {
                 LetExpr t = (LetExpr) node;
-                List<JCStatement> defs = copy(t.defs, p);
+                List<? extends JCStatement> defs = copy(t.defs, p);
                 JCExpression expr = copy(t.expr, p);
                 return M.at(t.pos).LetExpr(defs, expr);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Jun 14 13:24:13 2019 +0200
@@ -41,6 +41,11 @@
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.TypeTag.*;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCPattern;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
 
 /** Factory class for trees.
  *
@@ -486,6 +491,12 @@
         return tree;
     }
 
+    public JCDeconstructionPattern DeconstructionPattern(Name name, JCExpression deconstructor, List<JCPattern> nested) {
+        JCDeconstructionPattern tree = new JCDeconstructionPattern(name, deconstructor, nested);
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCLiteralPattern LiteralPattern(JCExpression cexp) {
         JCLiteralPattern tree = new JCLiteralPattern(cexp);
         tree.pos = pos;
@@ -657,7 +668,7 @@
         return tree;
     }
 
-    public LetExpr LetExpr(List<JCStatement> defs, JCExpression expr) {
+    public LetExpr LetExpr(List<? extends JCStatement> defs, JCExpression expr) {
         LetExpr tree = new LetExpr(defs, expr);
         tree.pos = pos;
         return tree;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Jun 14 13:24:13 2019 +0200
@@ -27,6 +27,7 @@
 
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCDeconstructionPattern;
 
 /** A subclass of Tree.Visitor, this class defines
  *  a general tree scanner pattern. Translation proceeds recursively in
@@ -307,6 +308,12 @@
             scan(tree.vartype);
     }
 
+    @Override
+    public void visitDeconstructionPattern(JCDeconstructionPattern that) {
+        scan(that.deconstructor);
+        scan(that.nested);
+    }
+
     public void visitLiteralPattern(JCLiteralPattern tree) {
         scan(tree.value);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Jun 14 13:24:13 2019 +0200
@@ -27,6 +27,7 @@
 
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree.JCDeconstructionPattern;
 
 /** A subclass of Tree.Visitor, this class defines
  *  a general tree translator pattern. Translation proceeds recursively in
@@ -463,6 +464,13 @@
         result = tree;
     }
 
+    @Override
+    public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
+        tree.deconstructor = translate(tree.deconstructor);
+        tree.nested = translate(tree.nested);
+        result = tree;
+    }
+
     public void visitTree(JCTree tree) {
         throw new AssertionError(tree);
     }
--- a/test/langtools/tools/javac/patterns/BindingsTest1.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/test/langtools/tools/javac/patterns/BindingsTest1.java	Fri Jun 14 13:24:13 2019 +0200
@@ -1,7 +1,7 @@
 /*
  * @test
  * @summary Basic tests for bindings from instanceof
- * @compile BindingsTest1.java
+ * @compile -doe BindingsTest1.java
  * @run main BindingsTest1
  */
 
@@ -42,6 +42,7 @@
         }
 
         // Test for (e1 || e2).F = union(e1.F, e2.F)
+        //XXX:
         if (!(o1 instanceof String s) || !(o3 instanceof Integer in)){
         } else {
             s.length();
--- a/test/langtools/tools/javac/patterns/PatternMatchTest1.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/test/langtools/tools/javac/patterns/PatternMatchTest1.java	Fri Jun 14 13:24:13 2019 +0200
@@ -24,11 +24,12 @@
 /*
  * @test
  * @summary Basic pattern switch test
+ * @compile PatternMatchTest1.java
  * @run main PatternMatchTest1
  */
 public class PatternMatchTest1 {
 
-    public static void main(String[] args) {
+    public static void main(String[] args) throws Throwable {
 
         Integer i = 42;
         String s = "Hello";
--- a/test/langtools/tools/javac/patterns/PatternTypeTest1.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/test/langtools/tools/javac/patterns/PatternTypeTest1.java	Fri Jun 14 13:24:13 2019 +0200
@@ -24,6 +24,7 @@
 /*
  * @test
  * @summary Basic pattern test
+ * @ignore
  * @run main PatternTypeTest1
  */
 public class PatternTypeTest1 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/patterns/SimpleDeconstructionPattern.java	Fri Jun 14 13:24:13 2019 +0200
@@ -0,0 +1,63 @@
+/**
+ * @test
+ * @compile SimpleDeconstructionPattern.java
+ * @run main SimpleDeconstructionPattern
+ */
+
+public class SimpleDeconstructionPattern {
+
+    public static void main(String... args) throws Throwable {
+        if (!test1(new P(42))) {
+            throw new IllegalStateException();
+        }
+        if (test1(new P(41))) {
+            throw new IllegalStateException();
+        }
+        if (!test2(new P(42))) {
+            throw new IllegalStateException();
+        }
+        if (test2(new P(41))) {
+            throw new IllegalStateException();
+        }
+        if (!test3(new P2(new P(42), ""))) {
+            throw new IllegalStateException();
+        }
+        if (test3(new P2(new P(41), ""))) {
+            throw new IllegalStateException();
+        }
+        if (test3(new P2(new P(42), "a"))) {
+            throw new IllegalStateException();
+        }
+        if (!test4(new P2(new P(42), ""))) {
+            throw new IllegalStateException();
+        }
+        if (test4(new P2(new P(41), ""))) {
+            throw new IllegalStateException();
+        }
+        if (test4(new P2(new P(42), "a"))) {
+            throw new IllegalStateException();
+        }
+    }
+
+    private static boolean test1(Object o) throws Throwable {
+        return o instanceof P(42);
+    }
+
+    private static boolean test2(Object o) throws Throwable {
+        return o instanceof P(int i) && i == 42;
+    }
+
+    private static boolean test3(Object o) throws Throwable {
+        return o instanceof P2(P(42), "");
+    }
+
+    private static boolean test4(Object o) throws Throwable {
+        return o instanceof P2(P(int i), String s) && i == 42 && "".equals(s);
+    }
+
+    public record P(int i) {
+    }
+
+    public record P2(P p, String s) {
+    }    
+}
\ No newline at end of file
--- a/test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java	Fri Jun 14 13:24:13 2019 +0200
@@ -24,7 +24,7 @@
 /*
  * @test
  * @summary Basic test for patterns in switch expression
- * @compile --enable-preview -source 12 SwitchExpressionWithPatterns.java
+ * @compile --enable-preview -source 13 SwitchExpressionWithPatterns.java
  * @run main/othervm --enable-preview SwitchExpressionWithPatterns
  */
 
--- a/test/langtools/tools/javac/patterns/scope/ScopeTest.java	Fri Jun 14 13:23:09 2019 +0200
+++ b/test/langtools/tools/javac/patterns/scope/ScopeTest.java	Fri Jun 14 13:24:13 2019 +0200
@@ -111,7 +111,7 @@
 
     private void assertFail(String expectedDiag, String block) {
         reset();
-        addCompileOptions("--enable-preview", "-source", "12");
+        addCompileOptions("--enable-preview", "-source", "13");
         program(block);
         try {
             compile();