OpenJDK / amber / amber
changeset 56792:580d718c8ddb patterns-deconstruction
A prototype of deconstruction patterns.
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();