8359145: Implement JEP 530: Primitive Types in Patterns, instanceof, and switch (Fourth Preview)

Reviewed-by: jlahoda
This commit is contained in:
Aggelos Biboudis 2025-11-19 08:47:57 +00:00
parent 02ff38f2d7
commit 99135d2e05
22 changed files with 776 additions and 59 deletions

View File

@ -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);

View File

@ -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:

View File

@ -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 {
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Unconditionality">
/** Check unconditionality between any combination of reference or primitive types.
// <editor-fold defaultstate="collapsed" desc="Unconditional Exactness">
/** 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));
}
// </editor-fold>

View File

@ -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);

View File

@ -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 ||

View File

@ -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;
}

View File

@ -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());

View File

@ -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<JCCaseLabel> newLabel;

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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 -> {}
};
}
}

View File

@ -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

View File

@ -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 <T extends Integer> 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
}
}
}

View File

@ -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
52 errors

View File

@ -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 = <constant short> 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 = <constant char> 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 = <constant int> 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 = <constant short> 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 = <constant int> 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 = <constant char> 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 = <constant int> 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();
}
}

View File

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

View File

@ -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
};
}
}

View File

@ -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

View File

@ -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
};
}
}

View File

@ -0,0 +1,2 @@
T8332463b.java:36:18: compiler.err.pattern.dominated
1 error

View File

@ -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),

View File

@ -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);