From 185d23bc5ffd575251af4c8718d9e390789953c2 Mon Sep 17 00:00:00 2001 From: Stephan Herrmann Date: Thu, 24 Oct 2024 23:18:53 +0200 Subject: [PATCH] [Switch][Primitive type patterns] Unexpected operand error with switch pattern and widening unboxing conversion (#3158) fix direction of conversion extend existing test to loop over numerical types Fixes https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3113 --- .../internal/compiler/ast/TypePattern.java | 2 +- .../regression/PrimitiveInPatternsTestSH.java | 123 +++++++++++++++--- 2 files changed, 106 insertions(+), 19 deletions(-) diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypePattern.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypePattern.java index b4609a13231..4716fde7211 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypePattern.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/TypePattern.java @@ -145,7 +145,7 @@ public void generateTestingConversion(BlockScope scope, CodeStream codeStream) { case WIDENING_REFERENCE_AND_UNBOXING_COVERSION_AND_WIDENING_PRIMITIVE_CONVERSION: int rhsUnboxed = TypeIds.box2primitive(provided.superclass().id); codeStream.generateUnboxingConversion(rhsUnboxed); - this.computeConversion(scope, TypeBinding.wellKnownBaseType(rhsUnboxed), expected); + this.computeConversion(scope, expected, TypeBinding.wellKnownBaseType(rhsUnboxed)); codeStream.generateImplicitConversion(this.implicitConversion); break; case NARROWING_AND_UNBOXING_CONVERSION: diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PrimitiveInPatternsTestSH.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PrimitiveInPatternsTestSH.java index f8a9e4ca84e..8074258b506 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PrimitiveInPatternsTestSH.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PrimitiveInPatternsTestSH.java @@ -1510,29 +1510,93 @@ public static void main(String... args) { }, "12"); } - public void testInstanceof_widenUnbox() { - runConformTest(new String[] { - "X.java", - """ + void testInstanceof_widenUnbox(String fromBox, int idx, String expectedOuts) { + // for all numerical types challenge route WIDENING_REFERENCE_AND_UNBOXING_COVERSION_AND_WIDENING_PRIMITIVE_CONVERSION + // + // example (from="Integer", idx=4, ...): + // class X { + // // alternating for type variable (m1*) and wildcard (m2*): + // static long m1long(T in) { + // if (in instanceof long v) return v; + // return -1L; + // } + // static long m2Long(Optional in) { + // if (in.get() instanceof long v) return v; + // return -1L; + // } + // static float m1float(T in) { + // if (in instanceof float v) return v; + // return -1.0f; + // } + // ... + // public static void main(String... args) { + // Integer v = Integer.valueOf((int) 49); + // System.out.print(m1long(v)); + // System.out.print('+'); + // System.out.print(Optional.of(m2long(v)); + // System.out.print('|'); + // System.out.print(m1float(v)); + // System.out.print('|'); + // ... + // } + // } + String m1 = """ + static PRIM m1PRIM(T in) { + if (in instanceof PRIM v) return v; + return NEGVAL; + } + """.replace("FROM", fromBox); + String m2 = """ + static PRIM m2PRIM(Optional in) { + if (in.get() instanceof PRIM v) return v; + return NEGVAL; + } + """.replace("FROM", fromBox); + StringBuilder clazz = new StringBuilder(); + clazz.append(""" import java.util.Optional; public class X { - static int mInteger(T in) { - if (in instanceof int v) return v; - return -1; - } - static int mShort(Optional in) { - if (in.get() instanceof int v) return v; - return -1; - } - public static void main(String... args) { - System.out.print(mInteger(Integer.valueOf(1))); - System.out.print(mShort(Optional.of(Short.valueOf((short) 2)))); + """); + StringBuilder main = new StringBuilder(); + main.append("public static void main(String... args) {\n"); + main.append("\tFROM v = FROM.valueOf((CAST) VAL);\n" + .replace("FROM", fromBox) + .replace("CAST", PRIMITIVES[idx]) + .replace("VAL", GOODVALUES[idx])); + String call1Tmpl = "\tSystem.out.print(m1PRIM(v));\n".replace("FROM", fromBox); + String call2Tmpl = "\tSystem.out.print(m2PRIM(Optional.of(v)));\n".replace("FROM", fromBox); + for (int i=idx+1; i<8; i++) { + if (!IS_NUMERICAL[i]) continue; + clazz.append(fillIn(m1, i)); + clazz.append(fillIn(m2, i)); + main.append(fillIn(call1Tmpl, i)); + main.append("\tSystem.out.print('+');\n"); + main.append(fillIn(call2Tmpl, i)); + main.append("\tSystem.out.print('|');\n"); + } + clazz.append(main); + clazz.append(""" } } - """ - }, - "12"); + """); + runConformTest(new String[] {"X.java", clazz.toString()}, expectedOuts); + } + public void testInstanceof_widenUnbox_Byte() { + testInstanceof_widenUnbox("Byte", 1, "49+49|49+49|49+49|49.0+49.0|49.0+49.0|"); + } + public void testInstanceof_widenUnbox_Short() { + testInstanceof_widenUnbox("Short", 3, "49+49|49+49|49.0+49.0|49.0+49.0|"); + } + public void testInstanceof_widenUnbox_Integer() { + testInstanceof_widenUnbox("Integer", 4, "49+49|49.0+49.0|49.0+49.0|"); } + public void testInstanceof_widenUnbox_Long() { + testInstanceof_widenUnbox("Long", 5, "49.0+49.0|49.0+49.0|"); + } + public void testInstanceof_widenUnbox_Float() { + testInstanceof_widenUnbox("Float", 6, "49.0+49.0|"); + } + public void testInstanceof_genericExpression() { // regression test for a checkCast which we failed to generate earlier runConformTest(new String[] { "X.java", @@ -2324,6 +2388,29 @@ void foo() { """); } + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/3113 + // [Switch][Record patterns] Unexpected operand error with switch pattern and widening unboxing conversion + public void testGH3113_ok() { + runConformTest(new String[] { + "X.java", + """ + record Record(T t) {} + public class X { + public static double convert(Record r) { + return switch (r) { + case Record(double d) -> d; + default -> 2; + }; + } + public static void main(String[] args) { + System.out.print(convert(new Record(2))); + } + } + """ + }, + "2.0"); + } + // test from spec public void _testSpec001() { runConformTest(new String[] {