OpenJDK / amber / amber
changeset 56968:ded304317aee patterns-deconstruction
Merging branch patterns into branch patterns-deconstruction.
author | jlahoda |
---|---|
date | Mon, 05 Aug 2019 12:15:25 +0200 |
parents | 22e1747208b6 1c6121460b51 |
children | bcd0f33734b3 |
files | src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java |
diffstat | 7 files changed, 332 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Mon Jul 15 16:02:04 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Mon Aug 05 12:15:25 2019 +0200 @@ -77,6 +77,7 @@ import com.sun.tools.javac.util.Names; import static com.sun.tools.javac.code.Kinds.Kind.*; +import com.sun.tools.javac.tree.JCTree; /** * Contains operations specific to processing type annotations. @@ -390,22 +391,26 @@ sym.getKind() == ElementKind.LOCAL_VARIABLE || sym.getKind() == ElementKind.RESOURCE_VARIABLE || sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { - // Make sure all type annotations from the symbol are also - // on the owner. If the owner is an initializer block, propagate - // to the type. - final long ownerFlags = sym.owner.flags(); - if ((ownerFlags & Flags.BLOCK) != 0) { - // Store init and clinit type annotations with the ClassSymbol - // to allow output in Gen.normalizeDefs. - ClassSymbol cs = (ClassSymbol) sym.owner.owner; - if ((ownerFlags & Flags.STATIC) != 0) { - cs.appendClassInitTypeAttributes(typeAnnotations); - } else { - cs.appendInitTypeAttributes(typeAnnotations); - } + appendTypeAnnotationsToOwner(sym, typeAnnotations); + } + } + + private void appendTypeAnnotationsToOwner(Symbol sym, List<Attribute.TypeCompound> typeAnnotations) { + // Make sure all type annotations from the symbol are also + // on the owner. If the owner is an initializer block, propagate + // to the type. + final long ownerFlags = sym.owner.flags(); + if ((ownerFlags & Flags.BLOCK) != 0) { + // Store init and clinit type annotations with the ClassSymbol + // to allow output in Gen.normalizeDefs. + ClassSymbol cs = (ClassSymbol) sym.owner.owner; + if ((ownerFlags & Flags.STATIC) != 0) { + cs.appendClassInitTypeAttributes(typeAnnotations); } else { - sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes()); + cs.appendInitTypeAttributes(typeAnnotations); } + } else { + sym.owner.appendUniqueTypeAttributes(typeAnnotations); } } @@ -943,10 +948,11 @@ " within frame " + frame); } + case BINDING_PATTERN: case VARIABLE: - VarSymbol v = ((JCVariableDecl)frame).sym; + VarSymbol v = frame.hasTag(Tag.BINDINGPATTERN) ? ((JCBindingPattern) frame).symbol : ((JCVariableDecl) frame).sym; if (v.getKind() != ElementKind.FIELD) { - v.owner.appendUniqueTypeAttributes(v.getRawTypeAttributes()); + appendTypeAnnotationsToOwner(v, v.getRawTypeAttributes()); } switch (v.getKind()) { case LOCAL_VARIABLE: @@ -1067,13 +1073,6 @@ outer_type_index, location); } - case BINDING_PATTERN: { - final List<JCTree> newPath = path.tail; - return resolveFrame(newPath.head, newPath.tail.head, - newPath, currentLambda, - outer_type_index, location); - } - default: throw new AssertionError("Unresolved frame: " + frame + " of kind: " + frame.getKind() +
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Jul 15 16:02:04 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java Mon Aug 05 12:15:25 2019 +0200 @@ -57,6 +57,7 @@ import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; import static com.sun.tools.javac.code.TypeTag.ARRAY; import static com.sun.tools.javac.code.TypeTag.CLASS; +import com.sun.tools.javac.tree.JCTree; import static com.sun.tools.javac.tree.JCTree.Tag.ANNOTATION; import static com.sun.tools.javac.tree.JCTree.Tag.ASSIGN; import static com.sun.tools.javac.tree.JCTree.Tag.IDENT; @@ -1107,6 +1108,13 @@ } @Override + public void visitBindingPattern(JCTree.JCBindingPattern tree) { + //type binding pattern's type will be annotated separatelly, avoid + //adding its annotations into the owning method here (would clash + //with repeatable annotations). + } + + @Override public void visitClassDef(JCClassDecl tree) { // We can only hit a classdef if it is declared within // a method. Ignore it - the class will be visited
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Mon Jul 15 16:02:04 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Mon Aug 05 12:15:25 2019 +0200 @@ -3859,6 +3859,8 @@ chk.checkTransparentVar(tree.pos(), v, env.info.scope); // env.info.scope.enter(v); // we inject into scopes expressly at various points. } + annotate.queueScanTreeAndTypeAnnotate(tree.vartype, env, v, tree.pos()); + annotate.flush(); result = tree.type; }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java Mon Jul 15 16:02:04 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java Mon Aug 05 12:15:25 2019 +0200 @@ -74,6 +74,7 @@ import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.LetExpr; 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; @@ -237,6 +238,7 @@ idx++; } result = make.at(tree.pos).LetExpr(statements.toList(), (JCExpression)result).setType(syms.booleanType); + ((LetExpr) result).needsCond = true; } else { super.visitTypeTest(tree); } @@ -856,7 +858,11 @@ this.parent = bindingContext; this.hoistedVarMap = matchBindings.stream() .filter(v -> parent.getBindingFor(v) == null) - .collect(Collectors.toMap(v -> v, v -> new VarSymbol(v.flags() & ~Flags.MATCH_BINDING, v.name, v.type, v.owner))); + .collect(Collectors.toMap(v -> v, v -> { + VarSymbol res = new VarSymbol(v.flags() & ~Flags.MATCH_BINDING, v.name, v.type, v.owner); + res.setTypeAttributes(v.getRawTypeAttributes()); + return res; + })); } @Override @@ -908,7 +914,7 @@ } private JCVariableDecl makeHoistedVarDecl(int pos, VarSymbol varSymbol) { - return make.at(pos).VarDef(varSymbol, makeDefaultValue(pos, varSymbol.erasure(types))); + return make.at(pos).VarDef(varSymbol, null/*makeDefaultValue(pos, varSymbol.erasure(types))*/); } } }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Mon Jul 15 16:02:04 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java Mon Aug 05 12:15:25 2019 +0200 @@ -50,6 +50,7 @@ import static com.sun.tools.javac.jvm.ClassFile.CONSTANT_String; import static com.sun.tools.javac.jvm.UninitializedType.*; import static com.sun.tools.javac.jvm.ClassWriter.StackMapTableFrame; +import java.util.Arrays; /** An internal structure that corresponds to the code attribute of * methods in a classfile. The class also provides some utility operations to @@ -2075,6 +2076,7 @@ lvar[adr] = v.dup(); v.closeRange(length); putVar(v); + fillLocalVarPosition(v); } else { v.removeLastRange(); } @@ -2106,20 +2108,31 @@ private void fillLocalVarPosition(LocalVar lv) { if (lv == null || lv.sym == null || lv.sym.isExceptionParameter()|| !lv.sym.hasTypeAnnotations()) return; - LocalVar.Range widestRange = lv.getWidestRange(); + LocalVar.Range[] validRanges = lv.aliveRanges.stream().filter(r -> r.closed() && r.length > 0).toArray(s -> new LocalVar.Range[s]); + if (validRanges.length == 0) + return ; + int[] lvarOffset = Arrays.stream(validRanges).mapToInt(r -> r.start_pc).toArray(); + int[] lvarLength = Arrays.stream(validRanges).mapToInt(r -> r.length).toArray(); + int[] lvarIndex = Arrays.stream(validRanges).mapToInt(r -> lv.reg).toArray(); for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) { TypeAnnotationPosition p = ta.position; - if (widestRange.closed() && widestRange.length > 0) { - p.lvarOffset = new int[] { (int)widestRange.start_pc }; - p.lvarLength = new int[] { (int)widestRange.length }; - p.lvarIndex = new int[] { (int)lv.reg }; - p.isValidOffset = true; - } else { - p.isValidOffset = false; - } + p.lvarOffset = appendArray(p.lvarOffset, lvarOffset); + p.lvarLength = appendArray(p.lvarLength, lvarLength); + p.lvarIndex = appendArray(p.lvarIndex, lvarIndex); + p.isValidOffset = true; } } + private int[] appendArray(int[] source, int[] append) { + if (source == null || source.length == 0) return append; + + int[] result = new int[source.length + append.length]; + + System.arraycopy(source, 0, result, 0, source.length); + System.arraycopy(append, 0, result, source.length, append.length); + return result; + } + // Method to be called after compressCatchTable to // fill in the exception table index for type // annotations on exception parameters.
--- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java Mon Jul 15 16:02:04 2019 +0200 +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java Mon Aug 05 12:15:25 2019 +0200 @@ -45,7 +45,9 @@ src5("(repeating) type annotations on field in anonymous class", false), src6("(repeating) type annotations on void method declaration", false), src7("(repeating) type annotations in use of instanceof", true), - src8("(repeating) type annotations in use of instanceof in method", true); + src7p("(repeating) type annotations in use of instanceof with type test pattern", true), + src8("(repeating) type annotations in use of instanceof in method", true), + src8p("(repeating) type annotations in use of instanceof with type test pattern in method", true); String description; Boolean local; @@ -92,8 +94,12 @@ test( 0, 0, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src6); test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7); test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7); + test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7p); + test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7p); test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8); test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8); + test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8p); + test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8p); break; case "FIELD": test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src1); @@ -385,6 +391,22 @@ "\n\n"; hasInnerClass=false; break; + case src7p: // (repeating) type annotations in use of instanceof with type test pattern + /* + * class Test10{ + * String data = "test"; + * boolean dataIsString = ( data instanceof @A @B @A @B String str); + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " String data = \"test\";\n" + + " boolean dataIsString = ( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" + + "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n\n"; + hasInnerClass=false; + break; case src8: // (repeating) type annotations in use of instanceof /* * class Test20{ @@ -411,6 +433,32 @@ "\n\n"; hasInnerClass=false; break; + case src8p: // (repeating) type annotations in use of instanceof with type test pattern + /* + * class Test20{ + * String data = "test"; + * Boolean isString() { + * if( data instanceof @A @B @A @B String ) + * return true; + * else + * return( data instanceof @A @B @A @B String ); + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " String data = \"test\";\n" + + " Boolean isString() { \n" + + " if( data instanceof _As_ _Bs_ String str)\n" + + " return true;\n" + + " else\n" + + " return( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" + + " }\n" + + "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n\n"; + hasInnerClass=false; + break; } return imports + source;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/Patterns.java Mon Aug 05 12:15:25 2019 +0200 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Verify type annotation on binding patterns + * @library /tools/lib + * @modules java.compiler + * @build toolbox.JavapTask + * @compile --enable-preview -source ${jdk.version} Patterns.java + * @run main/othervm --enable-preview Patterns + */ + +import java.lang.annotation.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import toolbox.JavapTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class Patterns { + + private ToolBox tb = new ToolBox(); + + public static void main(String[] args) throws Exception { + new Patterns().run(); + } + + public void run() throws Exception { + String out = new JavapTask(tb) + .options("-private", + "-verbose") + .classpath(System.getProperty("test.classes")) + .classes("Patterns$SimpleBindingPattern") + .run() + .getOutputLines(Task.OutputKind.DIRECT) + .stream() + .collect(Collectors.joining("\n")); + + String constantPool = out.substring(0, out.indexOf('{')); + + out = out.replaceAll("(?ms) *Code:.*?\n( *RuntimeInvisibleTypeAnnotations:)", "$1"); + out = out.substring(out.indexOf('{')); + out = out.substring(0, out.lastIndexOf('}') + 1); + + String A = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$A;"); + String CA = snipCPNumber(constantPool, "LPatterns$SimpleBindingPattern$CA;"); + String value = snipCPNumber(constantPool, "value"); + + String expected = """ + { + private static final java.lang.Object o; + descriptor: Ljava/lang/Object; + flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL + + private static final boolean B1s; + descriptor: Z + flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL + + private static final boolean B1m; + descriptor: Z + flags: (0x001a) ACC_PRIVATE, ACC_STATIC, ACC_FINAL + + private final boolean B2s; + descriptor: Z + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + + private final boolean B2m; + descriptor: Z + flags: (0x0012) ACC_PRIVATE, ACC_FINAL + + public Patterns$SimpleBindingPattern(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + RuntimeInvisibleTypeAnnotations: + 0: #_A_(): LOCAL_VARIABLE, {start_pc=257, length=18, index=2} + Patterns$SimpleBindingPattern$A + 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=297, length=19, index=3} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + 2: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=1} + Patterns$SimpleBindingPattern$A + 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=62, length=18, index=1} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + 4: #_A_(): LOCAL_VARIABLE, {start_pc=101, length=18, index=2} + Patterns$SimpleBindingPattern$A + 5: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=141, length=19, index=3} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + 6: #_A_(): LOCAL_VARIABLE, {start_pc=179, length=18, index=2} + Patterns$SimpleBindingPattern$A + 7: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=219, length=19, index=3} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + + void testPatterns(); + descriptor: ()V + flags: (0x0000) + RuntimeInvisibleTypeAnnotations: + 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=18, index=2} + Patterns$SimpleBindingPattern$A + 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=57, length=19, index=3} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + + void testPatternsDesugared(); + descriptor: ()V + flags: (0x0000) + RuntimeInvisibleTypeAnnotations: + 0: #_A_(): LOCAL_VARIABLE, {start_pc=17, length=15, index=1; start_pc=51, length=15, index=1} + Patterns$SimpleBindingPattern$A + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + RuntimeInvisibleTypeAnnotations: + 0: #_A_(): LOCAL_VARIABLE, {start_pc=22, length=18, index=0} + Patterns$SimpleBindingPattern$A + 1: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=61, length=18, index=0} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + 2: #_A_(): LOCAL_VARIABLE, {start_pc=100, length=18, index=1} + Patterns$SimpleBindingPattern$A + 3: #_CA_(#_value_=[@#_A_(),@#_A_()]): LOCAL_VARIABLE, {start_pc=137, length=18, index=2} + Patterns$SimpleBindingPattern$CA( + value=[@Patterns$SimpleBindingPattern$A,@Patterns$SimpleBindingPattern$A] + ) + }""".replace("_A_", A).replace("_CA_", CA).replace("_value_", value); + + if (!expected.equals(out)) { + throw new AssertionError("Unexpected output:\n" + out + "\nexpected:\n" + expected); + } + } + + private String snipCPNumber(String constantPool, String expectedConstant) { + Matcher m = Pattern.compile("#([0-9]+).*" + Pattern.quote(expectedConstant)) + .matcher(constantPool); + if (!m.find()) { + throw new AssertionError("Cannot find constant pool item"); + } + + return m.group(1); + } + + /*********************** Test class *************************/ + static class SimpleBindingPattern { + @Target(ElementType.TYPE_USE) + @Repeatable(CA.class) + @interface A {} + @Target(ElementType.TYPE_USE) + @interface CA { + public A[] value(); + } + + private static final Object o = ""; + private static final boolean B1s = o instanceof @A String s && s.isEmpty(); + private static final boolean B1m = o instanceof @A @A String s && s.isEmpty(); + private final boolean B2s = o instanceof @A String s && s.isEmpty(); + private final boolean B2m = o instanceof @A @A String s && s.isEmpty(); + + static { + boolean B3s = o instanceof @A String s && s.isEmpty(); + boolean B3m = o instanceof @A @A String s && s.isEmpty(); + } + + { + boolean B4s = o instanceof @A String s && s.isEmpty(); + boolean B4m = o instanceof @A @A String s && s.isEmpty(); + } + + { + boolean B5s = o instanceof @A String s && s.isEmpty(); + boolean B5m = o instanceof @A @A String s && s.isEmpty(); + } + + public SimpleBindingPattern() { + boolean B6s = o instanceof @A String s && s.isEmpty(); + boolean B6m = o instanceof @A @A String s && s.isEmpty(); + } + + void testPatterns() { + boolean B7s = o instanceof @A String s && s.isEmpty(); + boolean B7m = o instanceof @A @A String s && s.isEmpty(); + } + + void testPatternsDesugared() { + @A String s; + boolean B8s = o instanceof String && (s = (String) o) == s && s.isEmpty(); + boolean B8sx = o instanceof String && (s = (String) o) == s && s.isEmpty(); + } + } +}