test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java
changeset 49541 4f6887eade94
parent 49429 752ecccb0b7f
child 55306 ea43db53de91
equal deleted inserted replaced
49540:9704789737c1 49541:4f6887eade94
    20  * or visit www.oracle.com if you need additional information or have any
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 
    23 
    24 /**
    24 /**
    25  * @test 8200301
    25  * @test 8200301 8201194
    26  * @summary deduplicate lambda methods with the same body, target type, and captured state
    26  * @summary deduplicate lambda methods with the same body, target type, and captured state
    27  * @modules jdk.jdeps/com.sun.tools.classfile jdk.compiler/com.sun.tools.javac.api
    27  * @modules jdk.jdeps/com.sun.tools.classfile jdk.compiler/com.sun.tools.javac.api
    28  *     jdk.compiler/com.sun.tools.javac.code jdk.compiler/com.sun.tools.javac.comp
    28  *     jdk.compiler/com.sun.tools.javac.code jdk.compiler/com.sun.tools.javac.comp
    29  *     jdk.compiler/com.sun.tools.javac.file jdk.compiler/com.sun.tools.javac.main
    29  *     jdk.compiler/com.sun.tools.javac.file jdk.compiler/com.sun.tools.javac.main
    30  *     jdk.compiler/com.sun.tools.javac.tree jdk.compiler/com.sun.tools.javac.util
    30  *     jdk.compiler/com.sun.tools.javac.tree jdk.compiler/com.sun.tools.javac.util
    31  * @run main DeduplicationTest
    31  * @run main DeduplicationTest
    32  */
    32  */
    33 import static java.nio.charset.StandardCharsets.UTF_8;
    33 import static java.nio.charset.StandardCharsets.UTF_8;
    34 import static java.util.stream.Collectors.joining;
    34 import static java.util.stream.Collectors.joining;
       
    35 import static java.util.stream.Collectors.toList;
    35 import static java.util.stream.Collectors.toMap;
    36 import static java.util.stream.Collectors.toMap;
    36 import static java.util.stream.Collectors.toSet;
    37 import static java.util.stream.Collectors.toSet;
    37 
    38 
    38 import com.sun.source.util.JavacTask;
    39 import com.sun.source.util.JavacTask;
    39 import com.sun.source.util.TaskEvent;
    40 import com.sun.source.util.TaskEvent;
    55 import com.sun.tools.javac.tree.JCTree.JCExpression;
    56 import com.sun.tools.javac.tree.JCTree.JCExpression;
    56 import com.sun.tools.javac.tree.JCTree.JCIdent;
    57 import com.sun.tools.javac.tree.JCTree.JCIdent;
    57 import com.sun.tools.javac.tree.JCTree.JCLambda;
    58 import com.sun.tools.javac.tree.JCTree.JCLambda;
    58 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
    59 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
    59 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
    60 import com.sun.tools.javac.tree.JCTree.JCTypeCast;
    60 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
       
    61 import com.sun.tools.javac.tree.JCTree.Tag;
    61 import com.sun.tools.javac.tree.JCTree.Tag;
    62 import com.sun.tools.javac.tree.TreeScanner;
    62 import com.sun.tools.javac.tree.TreeScanner;
    63 import com.sun.tools.javac.util.Context;
    63 import com.sun.tools.javac.util.Context;
    64 import com.sun.tools.javac.util.JCDiagnostic;
    64 import com.sun.tools.javac.util.JCDiagnostic;
    65 import java.nio.file.Path;
    65 import java.nio.file.Path;
    68 import java.util.Arrays;
    68 import java.util.Arrays;
    69 import java.util.LinkedHashMap;
    69 import java.util.LinkedHashMap;
    70 import java.util.List;
    70 import java.util.List;
    71 import java.util.Locale;
    71 import java.util.Locale;
    72 import java.util.Map;
    72 import java.util.Map;
    73 import java.util.Objects;
       
    74 import java.util.Set;
    73 import java.util.Set;
    75 import java.util.TreeSet;
    74 import java.util.TreeSet;
    76 import java.util.function.BiFunction;
       
    77 import javax.tools.Diagnostic;
    75 import javax.tools.Diagnostic;
    78 import javax.tools.DiagnosticListener;
    76 import javax.tools.DiagnosticListener;
    79 import javax.tools.JavaFileObject;
    77 import javax.tools.JavaFileObject;
    80 
    78 
    81 public class DeduplicationTest {
    79 public class DeduplicationTest {
   158                             "expected deduplicated methods: %s, but saw: %s",
   156                             "expected deduplicated methods: %s, but saw: %s",
   159                             deduplicatedNames, bootstrapMethodNames));
   157                             deduplicatedNames, bootstrapMethodNames));
   160         }
   158         }
   161     }
   159     }
   162 
   160 
   163     /**
   161     /** Returns the parameter symbols of the given lambda. */
   164      * Returns a symbol comparator that treats symbols that correspond to the same parameter of each
   162     private static List<Symbol> paramSymbols(JCLambda lambda) {
   165      * of the given lambdas as equal.
   163         return lambda.params.stream().map(x -> x.sym).collect(toList());
   166      */
       
   167     private static BiFunction<Symbol, Symbol, Boolean> paramsEqual(JCLambda lhs, JCLambda rhs) {
       
   168         return (x, y) -> {
       
   169             Integer idx = paramIndex(lhs, x);
       
   170             if (idx != null && idx != -1) {
       
   171                 if (Objects.equals(idx, paramIndex(rhs, y))) {
       
   172                     return true;
       
   173                 }
       
   174             }
       
   175             return null;
       
   176         };
       
   177     }
       
   178 
       
   179     /**
       
   180      * Returns the index of the given symbol as a parameter of the given lambda, or else {@code -1}
       
   181      * if is not a parameter.
       
   182      */
       
   183     private static Integer paramIndex(JCLambda lambda, Symbol sym) {
       
   184         if (sym != null) {
       
   185             int idx = 0;
       
   186             for (JCVariableDecl param : lambda.params) {
       
   187                 if (sym == param.sym) {
       
   188                     return idx;
       
   189                 }
       
   190             }
       
   191         }
       
   192         return null;
       
   193     }
   164     }
   194 
   165 
   195     /** A diagnostic listener that records debug messages related to lambda desugaring. */
   166     /** A diagnostic listener that records debug messages related to lambda desugaring. */
   196     @Trusted
   167     @Trusted
   197     static class Listener implements DiagnosticListener<JavaFileObject> {
   168     static class Listener implements DiagnosticListener<JavaFileObject> {
   308                         first = lhs;
   279                         first = lhs;
   309                     } else {
   280                     } else {
   310                         dedupedLambdas.put(lhs, first);
   281                         dedupedLambdas.put(lhs, first);
   311                     }
   282                     }
   312                     for (JCLambda rhs : curr) {
   283                     for (JCLambda rhs : curr) {
   313                         if (!new TreeDiffer(paramsEqual(lhs, rhs)).scan(lhs.body, rhs.body)) {
   284                         if (!new TreeDiffer(paramSymbols(lhs), paramSymbols(rhs))
       
   285                                 .scan(lhs.body, rhs.body)) {
   314                             throw new AssertionError(
   286                             throw new AssertionError(
   315                                     String.format(
   287                                     String.format(
   316                                             "expected lambdas to be equal\n%s\n%s", lhs, rhs));
   288                                             "expected lambdas to be equal\n%s\n%s", lhs, rhs));
   317                         }
   289                         }
   318                         if (TreeHasher.hash(lhs, sym -> paramIndex(lhs, sym))
   290                         if (TreeHasher.hash(lhs, paramSymbols(lhs))
   319                                 != TreeHasher.hash(rhs, sym -> paramIndex(rhs, sym))) {
   291                                 != TreeHasher.hash(rhs, paramSymbols(rhs))) {
   320                             throw new AssertionError(
   292                             throw new AssertionError(
   321                                     String.format(
   293                                     String.format(
   322                                             "expected lambdas to hash to the same value\n%s\n%s",
   294                                             "expected lambdas to hash to the same value\n%s\n%s",
   323                                             lhs, rhs));
   295                                             lhs, rhs));
   324                         }
   296                         }
   332                     if (i == j) {
   304                     if (i == j) {
   333                         continue;
   305                         continue;
   334                     }
   306                     }
   335                     for (JCLambda lhs : curr) {
   307                     for (JCLambda lhs : curr) {
   336                         for (JCLambda rhs : lambdaGroups.get(j)) {
   308                         for (JCLambda rhs : lambdaGroups.get(j)) {
   337                             if (new TreeDiffer(paramsEqual(lhs, rhs)).scan(lhs.body, rhs.body)) {
   309                             if (new TreeDiffer(paramSymbols(lhs), paramSymbols(rhs))
       
   310                                     .scan(lhs.body, rhs.body)) {
   338                                 throw new AssertionError(
   311                                 throw new AssertionError(
   339                                         String.format(
   312                                         String.format(
   340                                                 "expected lambdas to not be equal\n%s\n%s",
   313                                                 "expected lambdas to not be equal\n%s\n%s",
   341                                                 lhs, rhs));
   314                                                 lhs, rhs));
   342                             }
   315                             }
   343                             if (TreeHasher.hash(lhs, sym -> paramIndex(lhs, sym))
   316                             if (TreeHasher.hash(lhs, paramSymbols(lhs))
   344                                     == TreeHasher.hash(rhs, sym -> paramIndex(rhs, sym))) {
   317                                     == TreeHasher.hash(rhs, paramSymbols(rhs))) {
   345                                 throw new AssertionError(
   318                                 throw new AssertionError(
   346                                         String.format(
   319                                         String.format(
   347                                                 "expected lambdas to hash to different values\n%s\n%s",
   320                                                 "expected lambdas to hash to different values\n%s\n%s",
   348                                                 lhs, rhs));
   321                                                 lhs, rhs));
   349                             }
   322                             }