From f0b130e54f33d3190640ce33c991e35f27e9f812 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 24 Oct 2024 06:45:16 +0000 Subject: [PATCH] 8339296: Record deconstruction pattern in switch fails to compile Reviewed-by: vromero, mcimadamore --- .../com/sun/tools/javac/code/Symtab.java | 8 +- .../com/sun/tools/javac/code/Type.java | 24 ---- .../com/sun/tools/javac/code/TypeTag.java | 4 - .../com/sun/tools/javac/code/Types.java | 6 +- .../tools/javac/patterns/Switches.java | 23 +++- .../tools/javac/types/UnknownTypeTest.java | 129 ++++++++++++++++++ 6 files changed, 156 insertions(+), 38 deletions(-) create mode 100644 test/langtools/tools/javac/types/UnknownTypeTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index cee6a16a10f..cfe4ef662e5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -51,7 +51,6 @@ import com.sun.tools.javac.code.Type.ErrorType; import com.sun.tools.javac.code.Type.JCPrimitiveType; import com.sun.tools.javac.code.Type.JCVoidType; import com.sun.tools.javac.code.Type.MethodType; -import com.sun.tools.javac.code.Type.UnknownType; import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Modules; import com.sun.tools.javac.jvm.Target; @@ -408,9 +407,6 @@ public class Symtab { names = Names.instance(context); - // Create the unknown type - unknownType = new UnknownType(); - messages = JavacMessages.instance(context); MissingInfoHandler missingInfoHandler = MissingInfoHandler.instance(context); @@ -483,8 +479,8 @@ public class Symtab { errType = new ErrorType(errSymbol, Type.noType); unknownSymbol = new ClassSymbol(PUBLIC|STATIC|ACYCLIC, names.fromString(""), null, rootPackage); - unknownSymbol.members_field = new Scope.ErrorScope(unknownSymbol); - unknownSymbol.type = unknownType; + // Create the unknown type + unknownType = new ErrorType(unknownSymbol, Type.noType); // initialize builtin types initType(byteType, "byte", "Byte"); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java index 151c39fae40..bd10dea6f89 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java @@ -2408,30 +2408,6 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons } } - public static class UnknownType extends Type { - - public UnknownType() { - // Unknown is a synthesized internal type, so it cannot be - // annotated. - super(null, List.nil()); - } - - @Override - public TypeTag getTag() { - return UNKNOWN; - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public R accept(TypeVisitor v, P p) { - return v.visitUnknown(this, p); - } - - @Override - public boolean isPartial() { - return true; - } - } - /** * A visitor for types. A visitor is used to implement operations * (or relations) on types. Most common operations on types are 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 94449476071..51d3deec88b 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 @@ -121,10 +121,6 @@ public enum TypeTag { */ ERROR, - /** The tag of an unknown type - */ - UNKNOWN, - /** The tag of all instantiatable type variables. */ UNDETVAR, 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 8576d8cfb2f..aa71c9446dc 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 @@ -1216,7 +1216,7 @@ public class Types { @Override public Boolean visitUndetVar(UndetVar t, Type s) { //todo: test against origin needed? or replace with substitution? - if (t == s || t.qtype == s || s.hasTag(ERROR) || s.hasTag(UNKNOWN)) { + if (t == s || t.qtype == s || s.hasTag(ERROR)) { return true; } else if (s.hasTag(BOT)) { //if 's' is 'null' there's no instantiated type U for which @@ -1466,7 +1466,7 @@ public class Types { return false; } - if (t == s || t.qtype == s || s.hasTag(ERROR) || s.hasTag(UNKNOWN)) { + if (t == s || t.qtype == s || s.hasTag(ERROR)) { return true; } @@ -2422,7 +2422,7 @@ public class Types { ARRAY, MODULE, TYPEVAR, WILDCARD, BOT: return s.dropMetadata(Annotations.class); case VOID, METHOD, PACKAGE, FORALL, DEFERRED, - NONE, ERROR, UNKNOWN, UNDETVAR, UNINITIALIZED_THIS, + NONE, ERROR, UNDETVAR, UNINITIALIZED_THIS, UNINITIALIZED_OBJECT: return s; default: diff --git a/test/langtools/tools/javac/patterns/Switches.java b/test/langtools/tools/javac/patterns/Switches.java index 9adf3cded40..7d7cb83e02f 100644 --- a/test/langtools/tools/javac/patterns/Switches.java +++ b/test/langtools/tools/javac/patterns/Switches.java @@ -28,7 +28,7 @@ import java.util.function.Function; /* * @test - * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 8277864 8290709 + * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 8277864 8290709 8339296 * @summary Check behavior of pattern switches. */ public class Switches { @@ -117,6 +117,9 @@ public class Switches { assertEquals(0, constantAndPatternGuardEnum(E.B, true)); assertEquals(1, constantAndPatternGuardEnum(E.B, false)); assertEquals(2, constantAndPatternGuardEnum(E.A, false)); + assertEquals(0, nestedSwitchesInArgumentPosition(1)); + assertEquals(1, nestedSwitchesInArgumentPosition(new R(1))); + assertEquals(5, nestedSwitchesInArgumentPosition(new R(new R("hello")))); } void run(Function mapper) { @@ -749,6 +752,24 @@ public class Switches { }; } + int nestedSwitchesInArgumentPosition(Object o1) { + return id(switch (o1) { + case R(var o2) -> switch (o2) { + case R(String s) -> s; + default -> "n"; + }; + default -> ""; + }); + } + + int id(String s) { + return s.length(); + } + + int id(int i) { + return i; + } + //verify that for cases like: //case ConstantClassClash -> //ConstantClassClash is interpreted as a field, not as a class diff --git a/test/langtools/tools/javac/types/UnknownTypeTest.java b/test/langtools/tools/javac/types/UnknownTypeTest.java new file mode 100644 index 00000000000..edb4ab3a9be --- /dev/null +++ b/test/langtools/tools/javac/types/UnknownTypeTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024, 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 + * @bug 8339296 + * @summary Verify that the UnknownType behaves as an erroneous type + * @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 + * @run main UnknownTypeTest + */ + +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type.TypeVar; +import com.sun.tools.javac.code.Type.UnionClassType; +import com.sun.tools.javac.util.List; +import java.util.Objects; + +public class UnknownTypeTest extends TypeHarness { + + private final Type error; + private final Type unknown; + private final Type[] testTypes; + private final Operation[] testOperations; + + UnknownTypeTest() { + Symtab syms = Symtab.instance(context); + error = syms.errType; + unknown = syms.unknownType; + testTypes = new Type[] { + syms.objectType, + syms.errType, + syms.unknownType, + new TypeVar(syms.unknownSymbol, syms.objectType, syms.objectType), + types.makeIntersectionType(List.of(syms.annotationType, syms.stringType)), + new UnionClassType((Type.ClassType) syms.annotationType, List.of(syms.stringType)), + syms.intType, + types.makeArrayType(syms.stringType) + }; + testOperations = new Operation[] { + types::containedBy, + types::containsType, + types::isAssignable, + types::isCastable, + types::isConvertible, + types::isSameType, + types::isSubtype, + types::isSuperType, + types::isUnconditionallyExact, + (t1, _) -> types.isArray(t1), + (t1, _) -> types.isDerivedRaw(t1), + (t1, _) -> types.isReifiable(t1), + (t1, _) -> types.isUnbounded(t1), + (t1, _) -> types.boxedTypeOrType(t1), + (t1, _) -> types.unboxedType(t1), + (t1, _) -> types.unboxedTypeOrType(t1), + }; + } + + void test(Type[] testTypes, Operation[] testOperations) { + for (int typeIndex = 0; typeIndex < testTypes.length ; typeIndex++) { + for (int operationIndex = 0; operationIndex < testOperations.length ; operationIndex++) { + Object expected; + Object actual; + expected = testOperations[operationIndex].run(error, testTypes[typeIndex]); + actual = testOperations[operationIndex].run(unknown, testTypes[typeIndex]); + checkEquals("Type index: " + typeIndex + ", operationIndex: " + operationIndex + ", unknown in the first position", expected, actual); + expected = testOperations[operationIndex].run(testTypes[typeIndex], error); + actual = testOperations[operationIndex].run(testTypes[typeIndex], unknown); + checkEquals("Type index: " + typeIndex + ", operationIndex: " + operationIndex + ", unknown in the second position", expected, actual); + } + } + } + + void checkEquals(String message, Object expected, Object actual) { + boolean matches; + + if (expected instanceof Type t1 && actual instanceof Type t2) { + matches = types.isSameType(t1, t2); + } else { + matches = Objects.equals(expected, actual); + } + + if (!matches) { + throw new AssertionError("Unexpected outcome: " + actual + + ", expected: " + expected + + ", for test: " + message); + } + } + + void runTests() { + test(testTypes, testOperations); + } + + public static void main(String[] args) { + new UnknownTypeTest().runTests(); + } + + interface Operation { + public Object run(Type t1, Type t2); + } +}