changeset 56793:a9a1999af6da patterns-deconstruction

Adding var/any patterns inside deconstruction patterns.
author jlahoda
date Fri, 14 Jun 2019 13:26:15 +0200
parents 580d718c8ddb
children 424c4d694771
files src/jdk.compiler/share/classes/com/sun/source/tree/AnyPatternTree.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/TransPatterns.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/SimpleDeconstructionPattern.java
diffstat 14 files changed, 213 insertions(+), 15 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/AnyPatternTree.java	Fri Jun 14 13:26:15 2019 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * Any pattern tree
+ */
+public interface AnyPatternTree extends PatternTree {
+}
+
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java	Fri Jun 14 13:26:15 2019 +0200
@@ -220,6 +220,11 @@
         PARENTHESIZED(ParenthesizedTree.class),
 
         /**
+         * Used for instances of {@link AnyPatternTree}.
+         */
+        ANY_PATTERN(AnyPatternTree.class),
+
+        /**
          * Used for instances of {@link BindingPatternTree}.
          */
         BINDING_PATTERN(BindingPatternTree.class),
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java	Fri Jun 14 13:26:15 2019 +0200
@@ -258,6 +258,14 @@
     R visitLiteral(LiteralTree node, P p);
 
     /**
+     * Visits an AnyPattern node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitAnyPattern(AnyPatternTree node, P p);
+
+    /**
      * Visits an BindingPattern 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:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java	Fri Jun 14 13:26:15 2019 +0200
@@ -566,6 +566,18 @@
      * @return  the result of {@code defaultAction}
      */
     @Override
+    public R visitAnyPattern(AnyPatternTree 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 visitBindingPattern(BindingPatternTree node, P p) {
         return defaultAction(node, p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Jun 14 13:26:15 2019 +0200
@@ -692,6 +692,18 @@
      * @return the result of scanning
      */
     @Override
+    public R visitAnyPattern(AnyPatternTree node, P p) {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc} This implementation scans the children in left to right order.
+     *
+     * @param node  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return the result of scanning
+     */
+    @Override
     public R visitBindingPattern(BindingPatternTree node, P p) {
         return scan(node.getType(), p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Jun 14 13:26:15 2019 +0200
@@ -3838,6 +3838,12 @@
                         });
     }
 
+    @Override
+    public void visitAnyPattern(JCAnyPattern tree) {
+        tree.type = resultInfo.pt;
+        result = tree.type;
+    }
+
     public void visitBindingPattern(JCBindingPattern tree) {
         if (tree.vartype != null) {
             ResultInfo varInfo = new ResultInfo(KindSelector.TYP, resultInfo.pt, resultInfo.checkContext);
@@ -3858,10 +3864,14 @@
         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;
+            if ((n.hasTag(BINDINGPATTERN) && ((JCBindingPattern) n).vartype == null) || n.hasTag(ANYPATTERN)) {
+                components.append(Type.noType);
+            } else {
+                components.append(attribExpr(n, env));
+            }
+        }
         Iterable<Symbol> patterns = site.tsym.members().getSymbols(sym -> sym.kind == Kind.MTH && sym.name.startsWith(names.fromString("\\%pattern\\%")));
+        List<Pair<MethodSymbol, List<Type>>> foundPatterns = List.nil();
         for (Symbol pattern : patterns) {
             String[] parts = BytecodeName.toSourceName(pattern.name.toString()).split("\\$", 4);
             if (!parts[2].contentEquals(site.tsym.name))
@@ -3872,18 +3882,38 @@
             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;
+            if (isSameTypesIgnoreNone(components.toList(), patternComponents.toList())) {
+                //found a pattern:
+                foundPatterns = foundPatterns.prepend(Pair.of((MethodSymbol) pattern, patternComponents.toList()));
+            }
+        }
+        if (foundPatterns.size() == 1) {
+            tree.extractorResolver = foundPatterns.head.fst;
+            List<Type> currentTypes;
+            tree.innerTypes = currentTypes = foundPatterns.head.snd;
+            //fix var/any patterns:
+            for (JCPattern nestedPattern : tree.nested) {
+                if (nestedPattern.type == null) {
+                    attribExpr(nestedPattern, env, currentTypes.head);
+                }
+                currentTypes = currentTypes.tail;
+            }
+        } else {
+            //TODO: error:
+        }
 //        //TODO: some checks....
         result = tree.type;
     }
 
+    private boolean isSameTypesIgnoreNone(List<Type> ts, List<Type> ss) {
+        while (ts.tail != null && ss.tail != null &&
+               (ts.head == Type.noType || types.isSameType(ts.head, ss.head))) {
+            ts = ts.tail;
+            ss = ss.tail;
+        }
+        return ts.tail == null && ss.tail == null;
+    }
+
     public void visitLiteralPattern(JCLiteralPattern tree) {
         Type patType = attribTree(tree.value, env, resultInfo);
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java	Fri Jun 14 13:26:15 2019 +0200
@@ -251,10 +251,10 @@
                                                 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),
@@ -378,6 +378,30 @@
                                                 indyType,
                                                 new LoadableConstant[] {lc});
             return wrapWithAdapt(patt.pos(), ofConstant, target);
+        } else if (patt.hasTag(Tag.ANYPATTERN)) {
+            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});
+
+            return wrapWithAdapt(patt.pos(), dynSym, target);
         } else {
             throw new IllegalStateException();
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Jun 14 13:26:15 2019 +0200
@@ -752,7 +752,10 @@
 
     public JCPattern parsePattern() {
         int pos = token.pos;
-        if (token.kind == IDENTIFIER && token.name() == names.var) {
+        if (token.kind == UNDERSCORE) {
+            nextToken();
+            return toP(F.at(pos).AnyPattern());
+        } else if (token.kind == IDENTIFIER && token.name() == names.var) {
             nextToken();
             return toP(F.at(pos).BindingPattern(ident(), null));
         } else {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Jun 14 13:26:15 2019 +0200
@@ -243,6 +243,7 @@
 
         /** Patterns.
          */
+        ANYPATTERN,
         BINDINGPATTERN,
         DECONSTRUCTIONPATTERN,
         LITERALPATTERN,
@@ -2246,6 +2247,34 @@
         }
     }
 
+    public static class JCAnyPattern extends JCPattern
+            implements AnyPatternTree {
+
+        protected JCAnyPattern() {
+        }
+
+        @Override
+        public void accept(Visitor v) {
+            v.visitAnyPattern(this);
+        }
+
+        @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return Kind.ANY_PATTERN;
+        }
+
+        @Override
+        @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(TreeVisitor<R, D> v, D d) {
+            return v.visitAnyPattern(this, d);
+        }
+
+        @Override
+        public Tag getTag() {
+            return ANYPATTERN;
+        }
+    }
+
     public static class JCBindingPattern extends JCPattern
             implements BindingPatternTree {
         public Name name;
@@ -3430,6 +3459,7 @@
         public void visitBinary(JCBinary that)               { visitTree(that); }
         public void visitTypeCast(JCTypeCast that)           { visitTree(that); }
         public void visitTypeTest(JCInstanceOf that)         { visitTree(that); }
+        public void visitAnyPattern(JCAnyPattern that)       { visitTree(that); }
         public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
         public void visitDeconstructionPattern(JCDeconstructionPattern that) { visitTree(that); }
         public void visitLiteralPattern(JCLiteralPattern that) { visitTree(that); }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Jun 14 13:26:15 2019 +0200
@@ -487,6 +487,12 @@
     }
 
     @DefinedBy(Api.COMPILER_TREE)
+    public JCTree visitAnyPattern(AnyPatternTree node, P p) {
+        JCAnyPattern t = (JCAnyPattern) node;
+        return M.at(t.pos).AnyPattern();
+    }
+
+    @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitBindingPattern(BindingPatternTree node, P p) {
         JCBindingPattern t = (JCBindingPattern) node;
         JCTree vartype = copy(t.vartype, p);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Jun 14 13:26:15 2019 +0200
@@ -485,6 +485,12 @@
         return tree;
     }
 
+    public JCAnyPattern AnyPattern() {
+        JCAnyPattern tree = new JCAnyPattern();
+        tree.pos = pos;
+        return tree;
+    }
+
     public JCBindingPattern BindingPattern(Name name, JCTree vartype) {
         JCBindingPattern tree = new JCBindingPattern(name, null, vartype);
         tree.pos = pos;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Jun 14 13:26:15 2019 +0200
@@ -303,6 +303,10 @@
         scan(tree.pattern);
     }
 
+    @Override
+    public void visitAnyPattern(JCTree.JCAnyPattern that) {
+    }
+
     public void visitBindingPattern(JCBindingPattern tree) {
         if (tree.vartype != null)
             scan(tree.vartype);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Jun 14 13:26:15 2019 +0200
@@ -359,6 +359,11 @@
         result = tree;
     }
 
+    @Override
+    public void visitAnyPattern(JCAnyPattern tree) {
+        result = tree;
+    }
+
     public void visitBindingPattern(JCBindingPattern tree) {
         if (tree.vartype != null) {
             tree.vartype = translate(tree.vartype);
--- a/test/langtools/tools/javac/patterns/SimpleDeconstructionPattern.java	Fri Jun 14 13:24:13 2019 +0200
+++ b/test/langtools/tools/javac/patterns/SimpleDeconstructionPattern.java	Fri Jun 14 13:26:15 2019 +0200
@@ -1,6 +1,6 @@
 /**
  * @test
- * @compile SimpleDeconstructionPattern.java
+ * @compile -doe SimpleDeconstructionPattern.java
  * @run main SimpleDeconstructionPattern
  */
 
@@ -37,6 +37,18 @@
         if (test4(new P2(new P(42), "a"))) {
             throw new IllegalStateException();
         }
+        if (!test5(new P(42))) {
+            throw new IllegalStateException();
+        }
+        if (test5(new P(41))) {
+            throw new IllegalStateException();
+        }
+        if (!test6(new P(42))) {
+            throw new IllegalStateException();
+        }
+        if (!test6(new P(41))) {
+            throw new IllegalStateException();
+        }
     }
 
     private static boolean test1(Object o) throws Throwable {
@@ -55,6 +67,14 @@
         return o instanceof P2(P(int i), String s) && i == 42 && "".equals(s);
     }
 
+    private static boolean test5(Object o) throws Throwable {
+        return o instanceof P(var i) && i == 42;
+    }
+
+    private static boolean test6(Object o) throws Throwable {
+        return o instanceof P(_);
+    }
+
     public record P(int i) {
     }