diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 99716baf439..30b6df0073e 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -777,7 +777,7 @@ public final class SwitchBootstraps { return name + "$$TypeSwitch"; } - // this method should be in sync with com.sun.tools.javac.code.Types.checkUnconditionallyExactPrimitives + // this method should be in sync with com.sun.tools.javac.code.Types.isUnconditionallyExactTypeBased private static boolean unconditionalExactnessCheck(Class selectorType, Class targetType) { Wrapper selectorWrapper = Wrapper.forBasicType(selectorType); Wrapper targetWrapper = Wrapper.forBasicType(targetType); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java index 0b97b119119..b2771556eb2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java @@ -26,7 +26,7 @@ package com.sun.tools.javac.code; import com.sun.source.tree.Tree.Kind; - +import java.lang.runtime.ExactConversionsSupport; import javax.lang.model.type.TypeKind; import static com.sun.tools.javac.code.TypeTag.NumericClasses.*; @@ -186,6 +186,10 @@ public enum TypeTag { return (this.numericClass & tag.superClasses) != 0; } + public boolean isNumeric() { + return this.numericClass != 0; + } + /** Returns the number of type tags. */ public static int getTypeTagCount() { @@ -247,11 +251,11 @@ public enum TypeTag { case BOOLEAN: return 0 <= value && value <= 1; case BYTE: - return Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE; + return ExactConversionsSupport.isIntToByteExact(value); case CHAR: - return Character.MIN_VALUE <= value && value <= Character.MAX_VALUE; + return ExactConversionsSupport.isIntToCharExact(value); case SHORT: - return Short.MIN_VALUE <= value && value <= Short.MAX_VALUE; + return ExactConversionsSupport.isIntToShortExact(value); case INT: return true; default: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index d59505555f2..3f3eb1f9623 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -26,6 +26,7 @@ package com.sun.tools.javac.code; import java.lang.ref.SoftReference; +import java.lang.runtime.ExactConversionsSupport; import java.util.HashSet; import java.util.HashMap; import java.util.Locale; @@ -5086,46 +5087,128 @@ public class Types { } // - // - /** Check unconditionality between any combination of reference or primitive types. + // + /** Check type-based unconditional exactness between any combination of + * reference or primitive types according to JLS 5.7.2. * - * Rules: - * an identity conversion - * a widening reference conversion - * a widening primitive conversion (delegates to `checkUnconditionallyExactPrimitives`) - * a boxing conversion - * a boxing conversion followed by a widening reference conversion + * The following are unconditionally exact regardless of the input + * expression: + * + * - an identity conversion + * - a widening reference conversion + * - an exact widening primitive conversion + * - a boxing conversion + * - a boxing conversion followed by a widening reference conversion * * @param source Source primitive or reference type * @param target Target primitive or reference type */ - public boolean isUnconditionallyExact(Type source, Type target) { + public boolean isUnconditionallyExactTypeBased(Type source, Type target) { if (isSameType(source, target)) { return true; } - return target.isPrimitive() - ? isUnconditionallyExactPrimitives(source, target) - : isSubtype(boxedTypeOrType(erasure(source)), target); + if (target.isPrimitive()) { + if (source.isPrimitive() && + ((source.getTag().isStrictSubRangeOf(target.getTag())) && + !((source.hasTag(BYTE) && target.hasTag(CHAR)) || + (source.hasTag(INT) && target.hasTag(FLOAT)) || + (source.hasTag(LONG) && (target.hasTag(DOUBLE) || target.hasTag(FLOAT)))))) return true; + else { + return false; + } + } else { + return isSubtype(boxedTypeOrType(erasure(source)), target); + } } - /** Check unconditionality between primitive types. + /** Check value-based unconditional exactness between any combination of + * reference or primitive types for the value of a constant expression + * according to JLS 5.7.2. * - * - widening from one integral type to another, - * - widening from one floating point type to another, - * - widening from byte, short, or char to a floating point type, - * - widening from int to double. + * The following can be unconditionally exact if the source primitive is a + * constant expression and the conversions is exact for that constant + * expression: * - * @param selectorType Type of selector - * @param targetType Target type + * - a narrowing primitive conversion + * - a widening and narrowing primitive conversion + * - a widening primitive conversion that is not exact + * + * @param source Source primitive or reference type, should be a numeric value + * @param target Target primitive or reference type */ - public boolean isUnconditionallyExactPrimitives(Type selectorType, Type targetType) { - return isSameType(selectorType, targetType) || - (selectorType.isPrimitive() && targetType.isPrimitive()) && - ((selectorType.getTag().isStrictSubRangeOf(targetType.getTag())) && - !((selectorType.hasTag(BYTE) && targetType.hasTag(CHAR)) || - (selectorType.hasTag(INT) && targetType.hasTag(FLOAT)) || - (selectorType.hasTag(LONG) && (targetType.hasTag(DOUBLE) || targetType.hasTag(FLOAT))))); + public boolean isUnconditionallyExactValueBased(Type source, Type target) { + if (!(source.constValue() instanceof Number value) || !target.getTag().isNumeric()) return false; + + switch (source.getTag()) { + case BYTE: + switch (target.getTag()) { + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); + } + break; + case CHAR: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); + case SHORT: return ExactConversionsSupport.isIntToShortExact(value.intValue()); + } + break; + case SHORT: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); + } + break; + case INT: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); + case SHORT: return ExactConversionsSupport.isIntToShortExact(value.intValue()); + case FLOAT: return ExactConversionsSupport.isIntToFloatExact(value.intValue()); + } + break; + case FLOAT: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isFloatToByteExact(value.floatValue()); + case CHAR: return ExactConversionsSupport.isFloatToCharExact(value.floatValue()); + case SHORT: return ExactConversionsSupport.isFloatToShortExact(value.floatValue()); + case INT: return ExactConversionsSupport.isFloatToIntExact(value.floatValue()); + case LONG: return ExactConversionsSupport.isFloatToLongExact(value.floatValue()); + } + break; + case LONG: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isLongToByteExact(value.longValue()); + case CHAR: return ExactConversionsSupport.isLongToCharExact(value.longValue()); + case SHORT: return ExactConversionsSupport.isLongToShortExact(value.longValue()); + case INT: return ExactConversionsSupport.isLongToIntExact(value.longValue()); + case FLOAT: return ExactConversionsSupport.isLongToFloatExact(value.longValue()); + case DOUBLE: return ExactConversionsSupport.isLongToDoubleExact(value.longValue()); + } + break; + case DOUBLE: + switch (target.getTag()) { + case BYTE: return ExactConversionsSupport.isDoubleToByteExact(value.doubleValue()); + case CHAR: return ExactConversionsSupport.isDoubleToCharExact(value.doubleValue()); + case SHORT: return ExactConversionsSupport.isDoubleToShortExact(value.doubleValue()); + case INT: return ExactConversionsSupport.isDoubleToIntExact(value.doubleValue()); + case FLOAT: return ExactConversionsSupport.isDoubleToFloatExact(value.doubleValue()); + case LONG: return ExactConversionsSupport.isDoubleToLongExact(value.doubleValue()); + } + break; + } + return true; + } + + /** Check both type or value-based unconditional exactness between any + * combination of reference or primitive types for the value of a constant + * expression according to JLS 5.7.2. + * + * @param source Source primitive or reference type, should be a numeric value + * @param target Target primitive or reference type + */ + public boolean isUnconditionallyExactCombined(Type currentType, Type testType) { + return isUnconditionallyExactTypeBased(currentType, testType) || + (currentType.constValue() instanceof Number && isUnconditionallyExactValueBased(currentType, testType)); } // diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index a45f7466f9e..ad41adcc135 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1861,7 +1861,7 @@ public class Attr extends JCTree.Visitor { boolean unconditional = unguarded && !patternType.isErroneous() && - types.isUnconditionallyExact(seltype, patternType); + types.isUnconditionallyExactTypeBased(seltype, patternType); if (unconditional) { if (hasUnconditionalPattern) { log.error(pat.pos(), Errors.DuplicateUnconditionalPattern); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index 9098568f42a..94b14f3122f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -28,7 +28,6 @@ package com.sun.tools.javac.comp; import java.util.*; import java.util.function.BiConsumer; import java.util.function.BiPredicate; -import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.ToIntBiFunction; @@ -167,6 +166,7 @@ public class Check { allowModules = Feature.MODULES.allowedInSource(source); allowRecords = Feature.RECORDS.allowedInSource(source); allowSealed = Feature.SEALED_CLASSES.allowedInSource(source); + allowPrimitivePatterns = preview.isEnabled() && Feature.PRIMITIVE_PATTERNS.allowedInSource(source); } /** Character for synthetic names @@ -190,6 +190,10 @@ public class Check { */ private final boolean allowSealed; + /** Are primitive patterns allowed + */ + private final boolean allowPrimitivePatterns; + /** Whether to force suppression of deprecation and preview warnings. * This happens when attributing import statements for JDK 9+. * @see Feature#DEPRECATION_ON_IMPORT @@ -4764,21 +4768,26 @@ public class Check { JCCase testCase = caseAndLabel.fst; JCCaseLabel testCaseLabel = caseAndLabel.snd; Type testType = labelType(testCaseLabel); + + // an unconditional pattern cannot be followed by any other label + if (allowPrimitivePatterns && unconditionalCaseLabel == testCaseLabel && unconditionalCaseLabel != label) { + log.error(label.pos(), Errors.PatternDominated); + continue; + } + boolean dominated = false; - if (types.isUnconditionallyExact(currentType, testType) && - !currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) { - //the current label is potentially dominated by the existing (test) label, check: - if (label instanceof JCConstantCaseLabel) { - dominated |= !(testCaseLabel instanceof JCConstantCaseLabel) && + if (!currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) { + // the current label is potentially dominated by the existing (test) label, check: + if (types.isUnconditionallyExactCombined(currentType, testType) && + label instanceof JCConstantCaseLabel) { + dominated = !(testCaseLabel instanceof JCConstantCaseLabel) && TreeInfo.unguardedCase(testCase); } else if (label instanceof JCPatternCaseLabel patternCL && testCaseLabel instanceof JCPatternCaseLabel testPatternCaseLabel && (testCase.equals(c) || TreeInfo.unguardedCase(testCase))) { - dominated = patternDominated(testPatternCaseLabel.pat, - patternCL.pat); + dominated = patternDominated(testPatternCaseLabel.pat, patternCL.pat); } } - if (dominated) { log.error(label.pos(), Errors.PatternDominated); } @@ -4798,7 +4807,7 @@ public class Check { private boolean patternDominated(JCPattern existingPattern, JCPattern currentPattern) { Type existingPatternType = types.erasure(existingPattern.type); Type currentPatternType = types.erasure(currentPattern.type); - if (!types.isUnconditionallyExact(currentPatternType, existingPatternType)) { + if (!types.isUnconditionallyExactTypeBased(currentPatternType, existingPatternType)) { return false; } if (currentPattern instanceof JCBindingPattern || diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java index 036e86dff5e..bbc330832f3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java @@ -568,8 +568,8 @@ public class ExhaustivenessComputer { Type pattype = types.erasure(bp.type); return seltype.isPrimitive() ? - types.isUnconditionallyExact(seltype, pattype) : - (bp.type.isPrimitive() && types.isUnconditionallyExact(types.unboxedType(seltype), bp.type)) || types.isSubtype(seltype, pattype); + types.isUnconditionallyExactTypeBased(seltype, pattype) : + (bp.type.isPrimitive() && types.isUnconditionallyExactTypeBased(types.unboxedType(seltype), bp.type)) || types.isSubtype(seltype, pattype); } return false; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index aee7f0afe39..2db3435a382 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -36,7 +36,6 @@ import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.main.Option.PkgInfo; import com.sun.tools.javac.resources.CompilerProperties.Fragments; -import com.sun.tools.javac.resources.CompilerProperties.Notes; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -2835,7 +2834,7 @@ public class Lower extends TreeTranslator { JCExpression exactnessCheck; JCExpression instanceOfExpr = translate(tree.expr); - if (types.isUnconditionallyExact(tree.expr.type, tree.pattern.type)) { + if (types.isUnconditionallyExactTypeBased(tree.expr.type, tree.pattern.type)) { // instanceOfExpr; true prefixStatement = make.Exec(instanceOfExpr); exactnessCheck = make.Literal(BOOLEAN, 1).setType(syms.booleanType.constType(1)); @@ -2844,7 +2843,7 @@ public class Lower extends TreeTranslator { prefixStatement = null; exactnessCheck = getExactnessCheck(tree, instanceOfExpr); } else if (tree.expr.type.isReference()) { - if (types.isUnconditionallyExact(types.unboxedType(tree.expr.type), tree.pattern.type)) { + if (types.isUnconditionallyExactTypeBased(types.unboxedType(tree.expr.type), tree.pattern.type)) { // instanceOfExpr != null prefixStatement = null; exactnessCheck = makeBinary(NE, instanceOfExpr, makeNull()); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 58c36a5cf7c..11774c313e3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -921,7 +921,7 @@ public class TransPatterns extends TreeTranslator { JCBindingPattern binding = (JCBindingPattern) instanceofCheck.pattern; hasUnconditional = (!types.erasure(binding.type).isPrimitive() ? instanceofCheck.allowNull : - types.isUnconditionallyExact(commonNestedExpression.type, types.erasure(binding.type))) && + types.isUnconditionallyExactTypeBased(commonNestedExpression.type, types.erasure(binding.type))) && accList.tail.isEmpty(); List newLabel; diff --git a/test/langtools/tools/javac/patterns/Domination.java b/test/langtools/tools/javac/patterns/Domination.java index a5cdb99b9c8..dd9d1153696 100644 --- a/test/langtools/tools/javac/patterns/Domination.java +++ b/test/langtools/tools/javac/patterns/Domination.java @@ -26,8 +26,8 @@ * @bug 8262891 8290709 * @summary Check the pattern domination error are reported correctly. * @compile/fail/ref=Domination.out -XDrawDiagnostics Domination.java + * @compile/fail/ref=DominationWithPP.out --enable-preview --source ${jdk.version} -XDrawDiagnostics Domination.java */ - public class Domination { int testDominatesError1(Object o) { switch (o) { @@ -218,4 +218,14 @@ public class Domination { case null : return -1; } } + + int testCasePatternDominatedbyPreceedingUnconditionalCasePattern () { + interface A {} + interface B {} + A aa = new A() {}; + switch (aa) { + case A a : return 1; + case B b : return -1; + } + } } diff --git a/test/langtools/tools/javac/patterns/DominationWithPP.out b/test/langtools/tools/javac/patterns/DominationWithPP.out new file mode 100644 index 00000000000..119cc003d07 --- /dev/null +++ b/test/langtools/tools/javac/patterns/DominationWithPP.out @@ -0,0 +1,14 @@ +Domination.java:35:18: compiler.err.pattern.dominated +Domination.java:43:18: compiler.err.pattern.dominated +Domination.java:51:18: compiler.err.pattern.dominated +Domination.java:67:18: compiler.err.pattern.dominated +Domination.java:88:18: compiler.err.pattern.dominated +Domination.java:113:18: compiler.err.pattern.dominated +Domination.java:144:18: compiler.err.pattern.dominated +Domination.java:153:18: compiler.err.pattern.dominated +Domination.java:184:18: compiler.err.pattern.dominated +Domination.java:193:18: compiler.err.pattern.dominated +Domination.java:202:18: compiler.err.pattern.dominated +Domination.java:211:18: compiler.err.pattern.dominated +Domination.java:228:18: compiler.err.pattern.dominated +13 errors diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java new file mode 100644 index 00000000000..2890b315e62 --- /dev/null +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.java @@ -0,0 +1,71 @@ +/* + * @test /nodynamiccopyright/ + * @summary Retain exhaustiveness properties of switches with a constant selector + * @enablePreview + * @compile/fail/ref=PrimitivePatternsSwitchConstants.out -XDrawDiagnostics -XDshould-stop.at=FLOW PrimitivePatternsSwitchConstants.java + */ +public class PrimitivePatternsSwitchConstants { + void testConstExpressions() { + switch (42) { // error: not exhaustive + case byte _ : + } + + switch (42l) { // error: not exhaustive + case byte _ : + } + + switch (123456) { // error: not exhaustive + case byte _ : + } + + switch (16_777_216) { // error: not exhaustive + case float _ : + } + + switch (16_777_217) { // error: not exhaustive + case float _ : + } + + switch (42d) { // error: not exhaustive + case float _ : + } + + switch (1) { // OK + case long _ : + } + + final int i = 42; + switch (i) { // OK + case long _ : + } + + switch (1) { // error: non-exhaustive + case Long _ : // error: widening primitive conversion and boxing is not supported + } + + switch (42) { + case byte bb -> {} + case int ii -> {} // OK + }; + + switch (42) { + case 42 -> {} + case int ii -> {} // OK + }; + + switch (42) { + case (byte) 42 -> {} + case int ii -> {} // OK + }; + + switch (42) { + case 42 -> {} + default -> {} // OK + }; + + switch (42) { + default -> {} // OK + case 42 -> {} + }; + } +} diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.out b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.out new file mode 100644 index 00000000000..9a983a86437 --- /dev/null +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchConstants.out @@ -0,0 +1,11 @@ +PrimitivePatternsSwitchConstants.java:43:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.Long) +PrimitivePatternsSwitchConstants.java:9:9: compiler.err.not.exhaustive.statement +PrimitivePatternsSwitchConstants.java:13:9: compiler.err.not.exhaustive.statement +PrimitivePatternsSwitchConstants.java:17:9: compiler.err.not.exhaustive.statement +PrimitivePatternsSwitchConstants.java:21:9: compiler.err.not.exhaustive.statement +PrimitivePatternsSwitchConstants.java:25:9: compiler.err.not.exhaustive.statement +PrimitivePatternsSwitchConstants.java:29:9: compiler.err.not.exhaustive.statement +PrimitivePatternsSwitchConstants.java:42:9: compiler.err.not.exhaustive.statement +- compiler.note.preview.filename: PrimitivePatternsSwitchConstants.java, DEFAULT +- compiler.note.preview.recompile +8 errors diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java index 3d47c4ac9bc..dacd48f441c 100644 --- a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java @@ -59,7 +59,7 @@ public class PrimitivePatternsSwitchErrors { int i = 42; return switch (i) { case Integer ib -> ib; - case byte ip -> ip; // OK - not dominated! + case byte ip -> ip; // Error - dominated! }; } @@ -265,4 +265,69 @@ public class PrimitivePatternsSwitchErrors { public static boolean wideningReferenceConversionUnboxingAndNarrowingPrimitive(T i) { return i instanceof byte b; // not allowed as a conversion } + + public static void dominanceIntFloat() { + int ii = 42; + switch (ii) { + case int i -> {} + case float f -> {} // Error - dominated! + } + } + + public static void noDominanceIntFloat() { + int ii = 42; + switch (ii) { + case float f -> {} + case int i -> {} // ok + } + } + + public static void strengtheningDominance() { + byte x = 42; + switch (x) { + case short s -> {} + case 42 -> {} // error: dominated + } + + long l = 42l; + switch (l) { + case short s -> {} + case 42l -> {} // error: dominated + case long _ -> {} + } + + char c = 'a'; + switch (c) { + case short s -> {} + case 42 -> {} // error: dominated + case char _ -> {} + } + + int x2 = 42; + switch(x2) { + case float f -> {} + case 16_777_216 -> {} // error: dominated + default -> {} + } + + switch(x2) { + case float f -> {} + case 16_777_217 -> {} // OK + default -> {} + } + + switch(x2) { + case int ii -> {} + case float f -> {} // error: dominated + } + } + + public static void unconditionalFollowedByDefault() { + int ii = 42; + switch (ii) { + case int i -> {} + case float f -> {} // Error - dominated! + default -> {} // Error - unconditional and default + } + } } diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out index 75fd62016a0..5a0822a9aef 100644 --- a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out @@ -1,6 +1,7 @@ PrimitivePatternsSwitchErrors.java:15:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:24:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:31:24: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.Long) +PrimitivePatternsSwitchErrors.java:62:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:70:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:78:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:84:18: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: long, byte) @@ -29,6 +30,14 @@ PrimitivePatternsSwitchErrors.java:248:18: compiler.err.prob.found.req: (compile PrimitivePatternsSwitchErrors.java:255:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Long, int) PrimitivePatternsSwitchErrors.java:261:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Short, char) PrimitivePatternsSwitchErrors.java:266:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: T, byte) +PrimitivePatternsSwitchErrors.java:273:18: compiler.err.pattern.dominated +PrimitivePatternsSwitchErrors.java:289:18: compiler.err.pattern.dominated +PrimitivePatternsSwitchErrors.java:295:18: compiler.err.pattern.dominated +PrimitivePatternsSwitchErrors.java:302:18: compiler.err.pattern.dominated +PrimitivePatternsSwitchErrors.java:309:18: compiler.err.pattern.dominated +PrimitivePatternsSwitchErrors.java:321:18: compiler.err.pattern.dominated +PrimitivePatternsSwitchErrors.java:330:13: compiler.err.unconditional.pattern.and.default +PrimitivePatternsSwitchErrors.java:329:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:30:16: compiler.err.not.exhaustive PrimitivePatternsSwitchErrors.java:37:16: compiler.err.not.exhaustive PrimitivePatternsSwitchErrors.java:44:16: compiler.err.not.exhaustive @@ -43,4 +52,4 @@ PrimitivePatternsSwitchErrors.java:254:16: compiler.err.not.exhaustive PrimitivePatternsSwitchErrors.java:260:16: compiler.err.not.exhaustive - compiler.note.preview.filename: PrimitivePatternsSwitchErrors.java, DEFAULT - compiler.note.preview.recompile -43 errors \ No newline at end of file +52 errors diff --git a/test/langtools/tools/javac/patterns/PrimitiveUnconditionallyExactInAssignability.java b/test/langtools/tools/javac/patterns/PrimitiveUnconditionallyExactInAssignability.java new file mode 100644 index 00000000000..c75dff3f8ad --- /dev/null +++ b/test/langtools/tools/javac/patterns/PrimitiveUnconditionallyExactInAssignability.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025, 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 Check assignability of narrowing p.c. with constant expressions vs exact conversion methods + * @library /tools/lib/types + * @modules jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.util + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * @build TypeHarness + * @compile PrimitiveUnconditionallyExactInAssignability.java + * @run main PrimitiveUnconditionallyExactInAssignability + */ + +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.TypeTag; + +import java.lang.runtime.ExactConversionsSupport; + +import static com.sun.tools.javac.code.TypeTag.ERROR; +import static com.sun.tools.javac.code.TypeTag.INT; + +public class PrimitiveUnconditionallyExactInAssignability extends TypeHarness { + PrimitiveUnconditionallyExactInAssignability() { + } + + void assertOriginalAssignmentNarrowingAndUnconditionality() { + // byte b = vs ExactConversionsSupport::isIntToByteExact + assertOriginaAndUpdatedAssignable(fac.Constant(Short.MIN_VALUE), predef.byteType, ExactConversionsSupport.isIntToByteExact(Short.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((short) (Byte.MIN_VALUE - 1)), predef.byteType, ExactConversionsSupport.isIntToByteExact((short) (Byte.MIN_VALUE - 1))); + assertOriginaAndUpdatedAssignable(fac.Constant((short) (Byte.MAX_VALUE + 1)), predef.byteType, ExactConversionsSupport.isIntToByteExact((short) (Byte.MAX_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Short.MAX_VALUE), predef.byteType, ExactConversionsSupport.isIntToByteExact(Short.MAX_VALUE)); + + // byte b = vs ExactConversionsSupport::isIntToByteExact + assertOriginaAndUpdatedAssignable(fac.Constant(Character.MIN_VALUE), predef.byteType, ExactConversionsSupport.isIntToByteExact(Character.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((char) (Byte.MAX_VALUE + 1)), predef.byteType, ExactConversionsSupport.isIntToByteExact((char) (Byte.MAX_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Character.MAX_VALUE), predef.byteType, ExactConversionsSupport.isIntToByteExact(Character.MAX_VALUE)); + + // byte b = vs ExactConversionsSupport::isIntToByteExact + assertOriginaAndUpdatedAssignable(fac.Constant(Integer.MIN_VALUE), predef.byteType, ExactConversionsSupport.isIntToByteExact(Integer.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((int) (Byte.MIN_VALUE - 1)), predef.byteType, ExactConversionsSupport.isIntToByteExact((int) (Byte.MIN_VALUE - 1))); + assertOriginaAndUpdatedAssignable(fac.Constant((int) (Byte.MAX_VALUE + 1)), predef.byteType, ExactConversionsSupport.isIntToByteExact((int) (Byte.MAX_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Integer.MAX_VALUE), predef.byteType, ExactConversionsSupport.isIntToByteExact(Integer.MAX_VALUE)); + + // char c = vs ExactConversionsSupport::isIntToCharExact + assertOriginaAndUpdatedAssignable(fac.Constant(Short.MIN_VALUE), predef.charType, ExactConversionsSupport.isIntToCharExact(Short.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((short) (Character.MIN_VALUE - 1)), predef.charType, ExactConversionsSupport.isIntToCharExact((short) (Character.MIN_VALUE - 1))); + assertOriginaAndUpdatedAssignable(fac.Constant((short) (Character.MAX_VALUE + 1)), predef.charType, ExactConversionsSupport.isIntToCharExact((short) (Character.MIN_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Short.MAX_VALUE), predef.charType, ExactConversionsSupport.isIntToCharExact(Short.MAX_VALUE)); + + // char c = vs ExactConversionsSupport::isIntToCharExact + assertOriginaAndUpdatedAssignable(fac.Constant(Integer.MIN_VALUE), predef.charType, ExactConversionsSupport.isIntToCharExact(Integer.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((int) (Character.MIN_VALUE - 1)), predef.charType, ExactConversionsSupport.isIntToCharExact((int) (Character.MIN_VALUE - 1))); + assertOriginaAndUpdatedAssignable(fac.Constant((int) (Character.MAX_VALUE + 1)), predef.charType, ExactConversionsSupport.isIntToCharExact((int) (Character.MAX_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Integer.MAX_VALUE), predef.charType, ExactConversionsSupport.isIntToCharExact(Integer.MAX_VALUE)); + + // short b = vs ExactConversionsSupport::isIntToShortExact + assertOriginaAndUpdatedAssignable(fac.Constant(Character.MIN_VALUE), predef.shortType, ExactConversionsSupport.isIntToShortExact(Character.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((char) (Character.MAX_VALUE + 1)), predef.shortType, ExactConversionsSupport.isIntToShortExact((char) (Character.MAX_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Character.MAX_VALUE), predef.shortType, ExactConversionsSupport.isIntToShortExact(Character.MAX_VALUE)); + + // short b = vs ExactConversionsSupport::isIntToShortExact + assertOriginaAndUpdatedAssignable(fac.Constant(Integer.MIN_VALUE), predef.shortType, ExactConversionsSupport.isIntToShortExact(Integer.MIN_VALUE)); + assertOriginaAndUpdatedAssignable(fac.Constant((int) (Short.MIN_VALUE - 1)), predef.shortType, ExactConversionsSupport.isIntToShortExact((int) (Short.MIN_VALUE - 1))); + assertOriginaAndUpdatedAssignable(fac.Constant((int) (Short.MAX_VALUE + 1)), predef.shortType, ExactConversionsSupport.isIntToShortExact((int) (Short.MAX_VALUE + 1))); + assertOriginaAndUpdatedAssignable(fac.Constant(Integer.MAX_VALUE), predef.shortType, ExactConversionsSupport.isIntToShortExact(Integer.MAX_VALUE)); + } + // where + public void assertOriginaAndUpdatedAssignable(Type s, Type t, boolean expected) { + assertAssignable(s, t, originalIsAssignable(s, t)); + } + public boolean originalIsAssignable(Type t, Type s) { + if (t.hasTag(ERROR)) + return true; + if (t.getTag().isSubRangeOf(INT) && t.constValue() != null) { + int value = ((Number)t.constValue()).intValue(); + switch (s.getTag()) { + case BYTE: + case CHAR: + case SHORT: + case INT: + if (originalCheckRange(s.getTag(), value)) + return true; + break; + } + } + return types.isConvertible(t, s); + } + public boolean originalCheckRange(TypeTag that, int value) { + switch (that) { + case BOOLEAN: + return 0 <= value && value <= 1; + case BYTE: + return Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE; + case CHAR: + return Character.MIN_VALUE <= value && value <= Character.MAX_VALUE; + case SHORT: + return Short.MIN_VALUE <= value && value <= Short.MAX_VALUE; + case INT: + return true; + default: + throw new AssertionError(); + } + } + + private void error(String msg) { + throw new AssertionError("Unexpected result in original isAssignable: " + msg); + } + + public static void main(String[] args) { + PrimitiveUnconditionallyExactInAssignability harness = new PrimitiveUnconditionallyExactInAssignability(); + harness.assertOriginalAssignmentNarrowingAndUnconditionality(); + } +} diff --git a/test/langtools/tools/javac/patterns/PrimitiveUnconditionallyExactInExhaustiveSwitches.java b/test/langtools/tools/javac/patterns/PrimitiveUnconditionallyExactInExhaustiveSwitches.java new file mode 100644 index 00000000000..e6a204968dd --- /dev/null +++ b/test/langtools/tools/javac/patterns/PrimitiveUnconditionallyExactInExhaustiveSwitches.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2025, 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 Check the unconditionally exact for constant primitives used in the exhaustiveness check + * @library /tools/lib/types + * @modules jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.comp + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.util + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.tree + * @build TypeHarness + * @compile PrimitiveUnconditionallyExactInExhaustiveSwitches.java + * @run main PrimitiveUnconditionallyExactInExhaustiveSwitches + */ + +public class PrimitiveUnconditionallyExactInExhaustiveSwitches extends TypeHarness { + + PrimitiveUnconditionallyExactInExhaustiveSwitches() { + } + public void testByte() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))), predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (0))),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.byteType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.byteType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.byteType, true); + } + public void testShort() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (0))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.shortType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.shortType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.shortType, true); + } + public void testChar() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (0))),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.charType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.charType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.charType, true); + } + public void testInt() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (0))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.intType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.intType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.intType, true); + } + public void testLong() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (0))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.longType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.longType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.longType, true); + } + public void testFloat() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((byte) (0)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.floatType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.floatType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.floatType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.floatType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.floatType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.floatType, true); + } + public void testDouble() { + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MAX_VALUE))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (0))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((byte) (Byte.MIN_VALUE))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MAX_VALUE))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (0))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((short) (Short.MIN_VALUE))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MAX_VALUE))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((char) (Character.MIN_VALUE))),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MAX_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Integer.MIN_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MAX_VALUE)),predef.doubleType, false); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((0L)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Long.MIN_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MAX_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((float) 0)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.MIN_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NaN)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.POSITIVE_INFINITY)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Float.NEGATIVE_INFINITY)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0f)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0f)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MAX_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant(((double) 0)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.MIN_VALUE)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NaN)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.POSITIVE_INFINITY)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((Double.NEGATIVE_INFINITY)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((-0.0d)),predef.doubleType, true); + assertIsUnconditionallyExactConstantPrimitives(fac.Constant((+0.0d)),predef.doubleType, true); + } + + + public static void main(String[] args) { + PrimitiveUnconditionallyExactInExhaustiveSwitches harness = new PrimitiveUnconditionallyExactInExhaustiveSwitches(); + harness.testByte(); + harness.testShort(); + harness.testChar(); + harness.testInt(); + harness.testDouble(); + harness.testLong(); + harness.testFloat(); + } +} diff --git a/test/langtools/tools/javac/patterns/T8332463a.java b/test/langtools/tools/javac/patterns/T8332463a.java index 96aaad86a85..2501a330af2 100644 --- a/test/langtools/tools/javac/patterns/T8332463a.java +++ b/test/langtools/tools/javac/patterns/T8332463a.java @@ -25,14 +25,14 @@ * @test * @bug 8332463 * @summary Byte conditional pattern case element dominates short constant case element - * @compile --enable-preview --source ${jdk.version} T8332463a.java + * @compile/fail/ref=T8332463a.out -XDrawDiagnostics --enable-preview --source ${jdk.version} T8332463a.java */ public class T8332463a { public int test2() { Byte i = (byte) 42; return switch (i) { case Byte ib -> 1; - case short s -> 2; + case short s -> 2; // dominated }; } @@ -40,7 +40,7 @@ public class T8332463a { int i = 42; return switch (i) { case Integer ib -> 1; - case byte ip -> 2; + case byte ip -> 2; // dominated }; } @@ -48,7 +48,7 @@ public class T8332463a { int i = 42; return switch (i) { case Integer ib -> 1; - case (byte) 0 -> 2; + case (byte) 0 -> 2; // dominated }; } } diff --git a/test/langtools/tools/javac/patterns/T8332463a.out b/test/langtools/tools/javac/patterns/T8332463a.out new file mode 100644 index 00000000000..5a4eec46d82 --- /dev/null +++ b/test/langtools/tools/javac/patterns/T8332463a.out @@ -0,0 +1,6 @@ +T8332463a.java:35:18: compiler.err.pattern.dominated +T8332463a.java:43:18: compiler.err.pattern.dominated +T8332463a.java:51:18: compiler.err.pattern.dominated +- compiler.note.preview.filename: T8332463a.java, DEFAULT +- compiler.note.preview.recompile +3 errors diff --git a/test/langtools/tools/javac/patterns/T8332463b.java b/test/langtools/tools/javac/patterns/T8332463b.java index 7956fd31f9f..73338b2bd8a 100644 --- a/test/langtools/tools/javac/patterns/T8332463b.java +++ b/test/langtools/tools/javac/patterns/T8332463b.java @@ -26,15 +26,14 @@ * @bug 8332463 * @summary Byte conditional pattern case element dominates short constant case element * @enablePreview - * @compile T8332463b.java - * @compile --enable-preview --source ${jdk.version} T8332463b.java + * @compile/fail/ref=T8332463b.out -XDrawDiagnostics --enable-preview --source ${jdk.version} T8332463b.java */ public class T8332463b { public int test1() { Byte i = (byte) 42; return switch (i) { case Byte ib -> 1; - case (short) 0 -> 2; + case (short) 0 -> 2; // dominated }; } } diff --git a/test/langtools/tools/javac/patterns/T8332463b.out b/test/langtools/tools/javac/patterns/T8332463b.out new file mode 100644 index 00000000000..f912242a6c6 --- /dev/null +++ b/test/langtools/tools/javac/patterns/T8332463b.out @@ -0,0 +1,2 @@ +T8332463b.java:36:18: compiler.err.pattern.dominated +1 error diff --git a/test/langtools/tools/javac/types/UnknownTypeTest.java b/test/langtools/tools/javac/types/UnknownTypeTest.java index edb4ab3a9be..e79c583f142 100644 --- a/test/langtools/tools/javac/types/UnknownTypeTest.java +++ b/test/langtools/tools/javac/types/UnknownTypeTest.java @@ -73,7 +73,9 @@ public class UnknownTypeTest extends TypeHarness { types::isSameType, types::isSubtype, types::isSuperType, - types::isUnconditionallyExact, + types::isUnconditionallyExactValueBased, + types::isUnconditionallyExactTypeBased, + types::isUnconditionallyExactCombined, (t1, _) -> types.isArray(t1), (t1, _) -> types.isDerivedRaw(t1), (t1, _) -> types.isReifiable(t1), diff --git a/test/langtools/tools/lib/types/TypeHarness.java b/test/langtools/tools/lib/types/TypeHarness.java index 43bf2f961e9..296ea8d3f9b 100644 --- a/test/langtools/tools/lib/types/TypeHarness.java +++ b/test/langtools/tools/lib/types/TypeHarness.java @@ -188,6 +188,21 @@ public class TypeHarness { } } + /** assert that 's' is unconditionally exact to 't' */ + public void assertIsUnconditionallyExactConstantPrimitives(Type s, Type t) { + assertIsUnconditionallyExactConstantPrimitives(s, t, true); + } + + /** assert that 's' is/is not unconditionally exact to 't' */ + public void assertIsUnconditionallyExactConstantPrimitives(Type s, Type t, boolean expected) { + if (types.isUnconditionallyExactValueBased(s, t) != expected) { + String msg = expected ? + " is not unconditionally exact to " : + " is unconditionally exact to "; + error(s + msg + t); + } + } + /** assert that generic type 't' is well-formed */ public void assertValidGenericType(Type t) { assertValidGenericType(t, true);