changeset 49143:54fd9c57223e switch

Adding support for switch over long, float and double.
author jlahoda
date Mon, 12 Feb 2018 16:49:27 +0100
parents d8cf1d526ccb
children e9bd0bef9745
files src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java test/langtools/tools/javac/switchextra/SwitchExtra.java test/langtools/tools/javac/switchextra/SwitchObject.java test/langtools/tools/javac/switchextra/SwitchObject.out
diffstat 7 files changed, 220 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Feb 12 12:31:18 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Feb 12 16:49:27 2018 +0100
@@ -1460,14 +1460,17 @@
             env.dup(switchTree, env.info.dup(env.info.scope.dup()));
 
         try {
-
             boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
             boolean stringSwitch = types.isSameType(seltype, syms.stringType);
             if (stringSwitch && !allowStringsInSwitch) {
                 log.error(DiagnosticFlag.SOURCE_LEVEL, selector.pos(), Feature.STRINGS_IN_SWITCH.error(sourceName));
             }
-            if (!enumSwitch && !stringSwitch)
-                seltype = chk.checkType(selector.pos(), seltype, syms.intType);
+            Type unboxedSelType = types.unboxedTypeOrType(seltype);
+            if (!enumSwitch && !stringSwitch && !types.isSubtype(unboxedSelType, syms.intType) &&
+                !types.isSameType(unboxedSelType, syms.longType) && !types.isSubtype(unboxedSelType, syms.floatType) &&
+                !types.isSameType(unboxedSelType, syms.doubleType)) {
+                log.error(selector.pos(), Errors.SwitchInvalidType(seltype));
+            }
 
             // Attribute all cases and
             // check that there are no duplicate case labels or default clauses.
@@ -1494,7 +1497,7 @@
                             log.error(c.pos(), Errors.DuplicateCaseLabel);
                         }
                     } else {
-                        Type pattype = attribExpr(pat, switchEnv, seltype);
+                        Type pattype = attribExpr(pat, switchEnv, unboxedSelType);
                         if (!pattype.hasTag(ERROR)) {
                             if (pattype.constValue() == null) {
                                 log.error(pat.pos(),
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Feb 12 12:31:18 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Mon Feb 12 16:49:27 2018 +0100
@@ -3411,12 +3411,14 @@
             (tree.selector.type.tsym.flags() & ENUM) != 0;
         boolean stringSwitch = selsuper != null &&
             types.isSameType(tree.selector.type, syms.stringType);
+        Type unboxed = types.unboxedTypeOrType(tree.selector.type);
+        boolean intSwitch = types.isSubtype(unboxed, syms.intType);
         boolean boxSwitch = selsuper != null &&
-            types.unboxedType(tree.selector.type).isPrimitive();
+            unboxed.isPrimitive();
         Type target = enumSwitch ? tree.selector.type :
             (stringSwitch? syms.stringType : syms.intType);
 
-        if (generateNewSwitch && ((boxSwitch && hasNullCase(tree)) || stringSwitch || enumSwitch)) {
+        if (generateNewSwitch && ((boxSwitch && hasNullCase(tree)) || stringSwitch || enumSwitch || !intSwitch)) {
             tree.selector = translate(tree.selector);
             tree.cases = translateCases(tree.cases);
 
@@ -3439,9 +3441,25 @@
                                                       false,
                                                       pat -> pat.type.constValue());
             } else {
+                Name switchName;
+                Type methodType;
+                if (types.isSameType(unboxed, syms.longType)) {
+                    switchName = names.longSwitch;
+                    methodType = syms.longType;
+                } else if (types.isSameType(unboxed, syms.floatType)) {
+                    switchName = names.floatSwitch;
+                    methodType = syms.floatType;
+                } else if (types.isSameType(unboxed, syms.doubleType)) {
+                    switchName = names.doubleSwitch;
+                    methodType = syms.doubleType;
+                } else {
+                    switchName = names.intSwitch;
+                    methodType = syms.intType;
+                }
+
                 qualifier = prepareSwitchIndySelector(tree,
-                                                      names.intSwitch,
-                                                      syms.intType,
+                                                      switchName,
+                                                      methodType,
                                                       tree.selector.type,
                                                       tree.selector.type,
                                                       false,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Feb 12 12:31:18 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Feb 12 16:49:27 2018 +0100
@@ -3209,3 +3209,7 @@
 compiler.err.switch.null.must.be.reference=\
     case null must only be used in a reference string
 
+# 0: type
+compiler.err.switch.invalid.type=\
+    the switch selector must be either String, enum, a primitive type or a boxed primitive type, found: {0}
+
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Mon Feb 12 12:31:18 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Mon Feb 12 16:49:27 2018 +0100
@@ -204,9 +204,12 @@
     public final Name makeConcatWithConstants;
 
     // switch
-    public final Name intSwitch;
     public final Name stringSwitch;
     public final Name enumSwitch;
+    public final Name intSwitch;
+    public final Name longSwitch;
+    public final Name floatSwitch;
+    public final Name doubleSwitch;
 
     public final Name.Table table;
 
@@ -371,9 +374,12 @@
         makeConcatWithConstants = fromString("makeConcatWithConstants");
 
         //switch desugaring:
-        intSwitch = fromString("intSwitch");
         stringSwitch = fromString("stringSwitch");
         enumSwitch = fromString("enumSwitch");
+        intSwitch = fromString("intSwitch");
+        longSwitch = fromString("longSwitch");
+        floatSwitch = fromString("floatSwitch");
+        doubleSwitch = fromString("doubleSwitch");
     }
 
     protected Name.Table createTable(Options options) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchExtra.java	Mon Feb 12 16:49:27 2018 +0100
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018, 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
+ * @compile SwitchExtra.java
+ * @run main SwitchExtra
+ */
+public class SwitchExtra {
+    public static void main(String... args) {
+        new SwitchExtra().run();
+    }
+
+    private static final long LONG_KEY = 2L << 32;
+
+    private void run() {
+        assertEquals(0, longSwitch(-1));
+        assertEquals(1, longSwitch(Long.MIN_VALUE));
+        assertEquals(2, longSwitch(Long.MAX_VALUE));
+        assertEquals(3, longSwitch(LONG_KEY));
+        assertEquals(4, longSwitch(0));
+        assertEquals(5, longSwitch(LONG_KEY + 1));
+        assertEquals(0, longSwitchBoxed(-1l));
+        assertEquals(1, longSwitchBoxed(Long.MIN_VALUE));
+        assertEquals(2, longSwitchBoxed(Long.MAX_VALUE));
+        assertEquals(3, longSwitchBoxed(LONG_KEY));
+        assertEquals(4, longSwitchBoxed(0l));
+        assertEquals(5, longSwitchBoxed(LONG_KEY + 1));
+        assertEquals(0, floatSwitch(-1f));
+        assertEquals(1, floatSwitch(Float.MIN_VALUE));
+        assertEquals(2, floatSwitch(Float.MAX_VALUE));
+        assertEquals(3, floatSwitch(Float.NaN));
+        assertEquals(4, floatSwitch(Float.NEGATIVE_INFINITY));
+        assertEquals(5, floatSwitch(Float.POSITIVE_INFINITY));
+        assertEquals(6, floatSwitch(0));
+        assertEquals(7, floatSwitch(3.14f));
+        assertEquals(0, floatSwitchBoxed(-1f));
+        assertEquals(1, floatSwitchBoxed(Float.MIN_VALUE));
+        assertEquals(2, floatSwitchBoxed(Float.MAX_VALUE));
+        assertEquals(3, floatSwitchBoxed(Float.NaN));
+        assertEquals(4, floatSwitchBoxed(Float.NEGATIVE_INFINITY));
+        assertEquals(5, floatSwitchBoxed(Float.POSITIVE_INFINITY));
+        assertEquals(6, floatSwitchBoxed(0f));
+        assertEquals(7, floatSwitchBoxed(3.14f));
+        assertEquals(0, doubleSwitch(-1d));
+        assertEquals(1, doubleSwitch(Double.MIN_VALUE));
+        assertEquals(2, doubleSwitch(Double.MAX_VALUE));
+        assertEquals(3, doubleSwitch(Double.NaN));
+        assertEquals(4, doubleSwitch(Double.NEGATIVE_INFINITY));
+        assertEquals(5, doubleSwitch(Double.POSITIVE_INFINITY));
+        assertEquals(6, doubleSwitch(0));
+        assertEquals(7, doubleSwitch(3.14));
+        assertEquals(0, doubleSwitchBoxed(-1d));
+        assertEquals(1, doubleSwitchBoxed(Double.MIN_VALUE));
+        assertEquals(2, doubleSwitchBoxed(Double.MAX_VALUE));
+        assertEquals(3, doubleSwitchBoxed(Double.NaN));
+        assertEquals(4, doubleSwitchBoxed(Double.NEGATIVE_INFINITY));
+        assertEquals(5, doubleSwitchBoxed(Double.POSITIVE_INFINITY));
+        assertEquals(6, doubleSwitchBoxed(0d));
+        assertEquals(7, doubleSwitchBoxed(3.14));
+    }
+
+    private int longSwitch(long l) {
+        switch (l) {
+            case -1: return 0;
+            case Long.MIN_VALUE: return 1;
+            case Long.MAX_VALUE: return 2;
+            case LONG_KEY: return 3;
+            case 0: return 4;
+            default: return 5;
+        }
+    }
+
+    private int longSwitchBoxed(Long l) {
+        switch (l) {
+            case -1: return 0;
+            case Long.MIN_VALUE: return 1;
+            case Long.MAX_VALUE: return 2;
+            case LONG_KEY: return 3;
+            case 0: return 4;
+            default: return 5;
+        }
+    }
+
+    private int floatSwitch(float f) {
+        switch (f) {
+            case -1: return 0;
+            case Float.MIN_VALUE: return 1;
+            case Float.MAX_VALUE: return 2;
+            case Float.NaN: return 3;
+            case Float.NEGATIVE_INFINITY: return 4;
+            case Float.POSITIVE_INFINITY: return 5;
+            case 0.0f: return 6;
+            default: return 7;
+        }
+    }
+
+    private int floatSwitchBoxed(Float f) {
+        switch (f) {
+            case -1: return 0;
+            case Float.MIN_VALUE: return 1;
+            case Float.MAX_VALUE: return 2;
+            case Float.NaN: return 3;
+            case Float.NEGATIVE_INFINITY: return 4;
+            case Float.POSITIVE_INFINITY: return 5;
+            case 0.0f: return 6;
+            default: return 7;
+        }
+    }
+
+    private int doubleSwitch(double d) {
+        switch (d) {
+            case -1: return 0;
+            case Double.MIN_VALUE: return 1;
+            case Double.MAX_VALUE: return 2;
+            case Double.NaN: return 3;
+            case Double.NEGATIVE_INFINITY: return 4;
+            case Double.POSITIVE_INFINITY: return 5;
+            case 0.0: return 6;
+            default: return 7;
+        }
+    }
+
+    private int doubleSwitchBoxed(Double d) {
+        switch (d) {
+            case -1: return 0;
+            case Double.MIN_VALUE: return 1;
+            case Double.MAX_VALUE: return 2;
+            case Double.NaN: return 3;
+            case Double.NEGATIVE_INFINITY: return 4;
+            case Double.POSITIVE_INFINITY: return 5;
+            case 0.0: return 6;
+            default: return 7;
+        }
+    }
+
+    private void assertEquals(int expected, int actual) {
+        if (expected != actual) {
+            throw new AssertionError();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchObject.java	Mon Feb 12 16:49:27 2018 +0100
@@ -0,0 +1,15 @@
+/*
+ * @test /nodynamiccopyright/
+ * @compile/fail/ref=SwitchObject.out -XDrawDiagnostics SwitchObject.java
+ */
+public class SwitchObject {
+
+    private int longSwitch(Object o) {
+        switch (o) {
+            case -1: return 0;
+            case "": return 1;
+            default: return 3;
+        }
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchObject.out	Mon Feb 12 16:49:27 2018 +0100
@@ -0,0 +1,2 @@
+SwitchObject.java:8:16: compiler.err.switch.invalid.type: java.lang.Object
+1 error