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();
+        }
+    }
+}