|
26 | 26 | package com.sun.tools.javac.code; |
27 | 27 |
|
28 | 28 | import java.lang.ref.SoftReference; |
| 29 | +import java.lang.runtime.ExactConversionsSupport; |
29 | 30 | import java.util.HashSet; |
30 | 31 | import java.util.HashMap; |
31 | 32 | import java.util.Locale; |
@@ -5086,46 +5087,128 @@ public Type visitCapturedType(CapturedType t, S s) { |
5086 | 5087 | } |
5087 | 5088 | // </editor-fold> |
5088 | 5089 |
|
5089 | | - // <editor-fold defaultstate="collapsed" desc="Unconditionality"> |
5090 | | - /** Check unconditionality between any combination of reference or primitive types. |
| 5090 | + // <editor-fold defaultstate="collapsed" desc="Unconditional Exactness"> |
| 5091 | + /** Check type-based unconditional exactness between any combination of |
| 5092 | + * reference or primitive types according to JLS 5.7.2. |
5091 | 5093 | * |
5092 | | - * Rules: |
5093 | | - * an identity conversion |
5094 | | - * a widening reference conversion |
5095 | | - * a widening primitive conversion (delegates to `checkUnconditionallyExactPrimitives`) |
5096 | | - * a boxing conversion |
5097 | | - * a boxing conversion followed by a widening reference conversion |
| 5094 | + * The following are unconditionally exact regardless of the input |
| 5095 | + * expression: |
| 5096 | + * |
| 5097 | + * - an identity conversion |
| 5098 | + * - a widening reference conversion |
| 5099 | + * - an exact widening primitive conversion |
| 5100 | + * - a boxing conversion |
| 5101 | + * - a boxing conversion followed by a widening reference conversion |
5098 | 5102 | * |
5099 | 5103 | * @param source Source primitive or reference type |
5100 | 5104 | * @param target Target primitive or reference type |
5101 | 5105 | */ |
5102 | | - public boolean isUnconditionallyExact(Type source, Type target) { |
| 5106 | + public boolean isUnconditionallyExactTypeBased(Type source, Type target) { |
5103 | 5107 | if (isSameType(source, target)) { |
5104 | 5108 | return true; |
5105 | 5109 | } |
5106 | 5110 |
|
5107 | | - return target.isPrimitive() |
5108 | | - ? isUnconditionallyExactPrimitives(source, target) |
5109 | | - : isSubtype(boxedTypeOrType(erasure(source)), target); |
| 5111 | + if (target.isPrimitive()) { |
| 5112 | + if (source.isPrimitive() && |
| 5113 | + ((source.getTag().isStrictSubRangeOf(target.getTag())) && |
| 5114 | + !((source.hasTag(BYTE) && target.hasTag(CHAR)) || |
| 5115 | + (source.hasTag(INT) && target.hasTag(FLOAT)) || |
| 5116 | + (source.hasTag(LONG) && (target.hasTag(DOUBLE) || target.hasTag(FLOAT)))))) return true; |
| 5117 | + else { |
| 5118 | + return false; |
| 5119 | + } |
| 5120 | + } else { |
| 5121 | + return isSubtype(boxedTypeOrType(erasure(source)), target); |
| 5122 | + } |
5110 | 5123 | } |
5111 | 5124 |
|
5112 | | - /** Check unconditionality between primitive types. |
| 5125 | + /** Check value-based unconditional exactness between any combination of |
| 5126 | + * reference or primitive types for the value of a constant expression |
| 5127 | + * according to JLS 5.7.2. |
| 5128 | + * |
| 5129 | + * The following can be unconditionally exact if the source primitive is a |
| 5130 | + * constant expression and the conversions is exact for that constant |
| 5131 | + * expression: |
5113 | 5132 | * |
5114 | | - * - widening from one integral type to another, |
5115 | | - * - widening from one floating point type to another, |
5116 | | - * - widening from byte, short, or char to a floating point type, |
5117 | | - * - widening from int to double. |
| 5133 | + * - a narrowing primitive conversion |
| 5134 | + * - a widening and narrowing primitive conversion |
| 5135 | + * - a widening primitive conversion that is not exact |
| 5136 | + * |
| 5137 | + * @param source Source primitive or reference type, should be a numeric value |
| 5138 | + * @param target Target primitive or reference type |
| 5139 | + */ |
| 5140 | + public boolean isUnconditionallyExactValueBased(Type source, Type target) { |
| 5141 | + if (!(source.constValue() instanceof Number value) || !target.getTag().isNumeric()) return false; |
| 5142 | + |
| 5143 | + switch (source.getTag()) { |
| 5144 | + case BYTE: |
| 5145 | + switch (target.getTag()) { |
| 5146 | + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); |
| 5147 | + } |
| 5148 | + break; |
| 5149 | + case CHAR: |
| 5150 | + switch (target.getTag()) { |
| 5151 | + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); |
| 5152 | + case SHORT: return ExactConversionsSupport.isIntToShortExact(value.intValue()); |
| 5153 | + } |
| 5154 | + break; |
| 5155 | + case SHORT: |
| 5156 | + switch (target.getTag()) { |
| 5157 | + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); |
| 5158 | + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); |
| 5159 | + } |
| 5160 | + break; |
| 5161 | + case INT: |
| 5162 | + switch (target.getTag()) { |
| 5163 | + case BYTE: return ExactConversionsSupport.isIntToByteExact(value.intValue()); |
| 5164 | + case CHAR: return ExactConversionsSupport.isIntToCharExact(value.intValue()); |
| 5165 | + case SHORT: return ExactConversionsSupport.isIntToShortExact(value.intValue()); |
| 5166 | + case FLOAT: return ExactConversionsSupport.isIntToFloatExact(value.intValue()); |
| 5167 | + } |
| 5168 | + break; |
| 5169 | + case FLOAT: |
| 5170 | + switch (target.getTag()) { |
| 5171 | + case BYTE: return ExactConversionsSupport.isFloatToByteExact(value.floatValue()); |
| 5172 | + case CHAR: return ExactConversionsSupport.isFloatToCharExact(value.floatValue()); |
| 5173 | + case SHORT: return ExactConversionsSupport.isFloatToShortExact(value.floatValue()); |
| 5174 | + case INT: return ExactConversionsSupport.isFloatToIntExact(value.floatValue()); |
| 5175 | + case LONG: return ExactConversionsSupport.isFloatToLongExact(value.floatValue()); |
| 5176 | + } |
| 5177 | + break; |
| 5178 | + case LONG: |
| 5179 | + switch (target.getTag()) { |
| 5180 | + case BYTE: return ExactConversionsSupport.isLongToByteExact(value.longValue()); |
| 5181 | + case CHAR: return ExactConversionsSupport.isLongToCharExact(value.longValue()); |
| 5182 | + case SHORT: return ExactConversionsSupport.isLongToShortExact(value.longValue()); |
| 5183 | + case INT: return ExactConversionsSupport.isLongToIntExact(value.longValue()); |
| 5184 | + case FLOAT: return ExactConversionsSupport.isLongToFloatExact(value.longValue()); |
| 5185 | + case DOUBLE: return ExactConversionsSupport.isLongToDoubleExact(value.longValue()); |
| 5186 | + } |
| 5187 | + break; |
| 5188 | + case DOUBLE: |
| 5189 | + switch (target.getTag()) { |
| 5190 | + case BYTE: return ExactConversionsSupport.isDoubleToByteExact(value.doubleValue()); |
| 5191 | + case CHAR: return ExactConversionsSupport.isDoubleToCharExact(value.doubleValue()); |
| 5192 | + case SHORT: return ExactConversionsSupport.isDoubleToShortExact(value.doubleValue()); |
| 5193 | + case INT: return ExactConversionsSupport.isDoubleToIntExact(value.doubleValue()); |
| 5194 | + case FLOAT: return ExactConversionsSupport.isDoubleToFloatExact(value.doubleValue()); |
| 5195 | + case LONG: return ExactConversionsSupport.isDoubleToLongExact(value.doubleValue()); |
| 5196 | + } |
| 5197 | + break; |
| 5198 | + } |
| 5199 | + return true; |
| 5200 | + } |
| 5201 | + |
| 5202 | + /** Check both type or value-based unconditional exactness between any |
| 5203 | + * combination of reference or primitive types for the value of a constant |
| 5204 | + * expression according to JLS 5.7.2. |
5118 | 5205 | * |
5119 | | - * @param selectorType Type of selector |
5120 | | - * @param targetType Target type |
| 5206 | + * @param source Source primitive or reference type, should be a numeric value |
| 5207 | + * @param target Target primitive or reference type |
5121 | 5208 | */ |
5122 | | - public boolean isUnconditionallyExactPrimitives(Type selectorType, Type targetType) { |
5123 | | - return isSameType(selectorType, targetType) || |
5124 | | - (selectorType.isPrimitive() && targetType.isPrimitive()) && |
5125 | | - ((selectorType.getTag().isStrictSubRangeOf(targetType.getTag())) && |
5126 | | - !((selectorType.hasTag(BYTE) && targetType.hasTag(CHAR)) || |
5127 | | - (selectorType.hasTag(INT) && targetType.hasTag(FLOAT)) || |
5128 | | - (selectorType.hasTag(LONG) && (targetType.hasTag(DOUBLE) || targetType.hasTag(FLOAT))))); |
| 5209 | + public boolean isUnconditionallyExactCombined(Type currentType, Type testType) { |
| 5210 | + return isUnconditionallyExactTypeBased(currentType, testType) || |
| 5211 | + (currentType.constValue() instanceof Number && isUnconditionallyExactValueBased(currentType, testType)); |
5129 | 5212 | } |
5130 | 5213 | // </editor-fold> |
5131 | 5214 |
|
|
0 commit comments