8339296: Record deconstruction pattern in switch fails to compile

Reviewed-by: vromero, mcimadamore
This commit is contained in:
Jan Lahoda 2024-10-24 06:45:16 +00:00
parent e96b4cf0a8
commit f0b130e54f
6 changed files with 156 additions and 38 deletions

View File

@ -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("<any?>"), 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");

View File

@ -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, P> R accept(TypeVisitor<R, P> 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

View File

@ -121,10 +121,6 @@ public enum TypeTag {
*/
ERROR,
/** The tag of an unknown type
*/
UNKNOWN,
/** The tag of all instantiatable type variables.
*/
UNDETVAR,

View File

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

View File

@ -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<Object, Integer> 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

View File

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