8142876: Javac does not correctly implement wildcards removal from functional interfaces
authormcimadamore
Thu, 17 Dec 2015 12:29:26 +0000
changeset 34757 85ceb9850b1d
parent 34756 d31f11c4cc75
child 34758 a3bbf6c7209a
8142876: Javac does not correctly implement wildcards removal from functional interfaces Summary: Rewrite code for removing wildcard from target functional interface to be in sync with JLS 9.9 Reviewed-by: vromero, dlsmith
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
langtools/test/tools/javac/lambda/8142876/T8142876.java
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Dec 16 14:23:08 2015 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Thu Dec 17 12:29:26 2015 +0000
@@ -597,36 +597,42 @@
     }
 
     public Type removeWildcards(Type site) {
-        Type capturedSite = capture(site);
-        if (capturedSite != site) {
-            Type formalInterface = site.tsym.type;
-            ListBuffer<Type> typeargs = new ListBuffer<>();
-            List<Type> actualTypeargs = site.getTypeArguments();
-            List<Type> capturedTypeargs = capturedSite.getTypeArguments();
-            //simply replace the wildcards with its bound
-            for (Type t : formalInterface.getTypeArguments()) {
-                if (actualTypeargs.head.hasTag(WILDCARD)) {
-                    WildcardType wt = (WildcardType)actualTypeargs.head;
-                    Type bound;
-                    switch (wt.kind) {
-                        case EXTENDS:
-                        case UNBOUND:
-                            CapturedType capVar = (CapturedType)capturedTypeargs.head;
-                            //use declared bound if it doesn't depend on formal type-args
-                            bound = capVar.bound.containsAny(capturedSite.getTypeArguments()) ?
-                                    wt.type : capVar.bound;
-                            break;
-                        default:
-                            bound = wt.type;
+        if (site.getTypeArguments().stream().anyMatch(t -> t.hasTag(WILDCARD))) {
+            //compute non-wildcard parameterization - JLS 9.9
+            List<Type> actuals = site.getTypeArguments();
+            List<Type> formals = site.tsym.type.getTypeArguments();
+            ListBuffer<Type> targs = new ListBuffer<>();
+            for (Type formal : formals) {
+                Type actual = actuals.head;
+                Type bound = formal.getUpperBound();
+                if (actuals.head.hasTag(WILDCARD)) {
+                    WildcardType wt = (WildcardType)actual;
+                    //check that bound does not contain other formals
+                    if (bound.containsAny(formals)) {
+                        targs.add(wt.type);
+                    } else {
+                        //compute new type-argument based on declared bound and wildcard bound
+                        switch (wt.kind) {
+                            case UNBOUND:
+                                targs.add(bound);
+                                break;
+                            case EXTENDS:
+                                targs.add(glb(bound, wt.type));
+                                break;
+                            case SUPER:
+                                targs.add(wt.type);
+                                break;
+                            default:
+                                Assert.error("Cannot get here!");
+                        }
                     }
-                    typeargs.append(bound);
                 } else {
-                    typeargs.append(actualTypeargs.head);
+                    //not a wildcard - the new type argument remains unchanged
+                    targs.add(actual);
                 }
-                actualTypeargs = actualTypeargs.tail;
-                capturedTypeargs = capturedTypeargs.tail;
+                actuals = actuals.tail;
             }
-            return subst(formalInterface, formalInterface.getTypeArguments(), typeargs.toList());
+            return subst(site.tsym.type, formals, targs.toList());
         } else {
             return site;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8142876/T8142876.java	Thu Dec 17 12:29:26 2015 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+/*
+ * @test
+ * @bug 8142876
+ * @summary Javac does not correctly implement wildcards removal from functional interfaces
+ * @compile T8142876.java
+ */
+class T8142876 {
+    interface I<R extends Runnable, T> {
+        void m();
+    }
+
+    void test() {
+        I<? extends O, String> succeed = this::ff;
+        I<? extends Comparable<String>, String> failed = this::ff;
+    }
+
+    interface O {}
+
+    private void ff(){}
+}