mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-29 12:38:24 +00:00
Merge
This commit is contained in:
commit
dfd6b2be7d
@ -11539,7 +11539,7 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe du
|
||||
%}
|
||||
|
||||
// Small ClearArray AVX512 non-constant length.
|
||||
instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2));
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
ins_cost(125);
|
||||
@ -11650,7 +11650,7 @@ instruct rep_stos_large(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Unive
|
||||
%}
|
||||
|
||||
// Large ClearArray AVX512.
|
||||
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, regD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
|
||||
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());
|
||||
match(Set dummy (ClearArray cnt base));
|
||||
effect(USE_KILL cnt, USE_KILL base, TEMP tmp, TEMP ktmp, KILL zero, KILL cr);
|
||||
|
||||
@ -11100,7 +11100,7 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
|
||||
%}
|
||||
|
||||
// Small ClearArray AVX512 non-constant length.
|
||||
instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
|
||||
instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
|
||||
Universe dummy, rFlagsReg cr)
|
||||
%{
|
||||
predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2));
|
||||
@ -11212,7 +11212,7 @@ instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
|
||||
%}
|
||||
|
||||
// Large ClearArray AVX512.
|
||||
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, regD tmp, kReg ktmp, rax_RegI zero,
|
||||
instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero,
|
||||
Universe dummy, rFlagsReg cr)
|
||||
%{
|
||||
predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large());
|
||||
|
||||
@ -1411,8 +1411,14 @@ Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
Node* SafePointNode::Identity(PhaseGVN* phase) {
|
||||
|
||||
// If you have back to back safepoints, remove one
|
||||
if( in(TypeFunc::Control)->is_SafePoint() )
|
||||
return in(TypeFunc::Control);
|
||||
if (in(TypeFunc::Control)->is_SafePoint()) {
|
||||
Node* out_c = unique_ctrl_out();
|
||||
// This can be the safepoint of an outer strip mined loop if the inner loop's backedge was removed. Replacing the
|
||||
// outer loop's safepoint could confuse removal of the outer loop.
|
||||
if (out_c != NULL && !out_c->is_OuterStripMinedLoopEnd()) {
|
||||
return in(TypeFunc::Control);
|
||||
}
|
||||
}
|
||||
|
||||
// Transforming long counted loops requires a safepoint node. Do not
|
||||
// eliminate a safepoint until loop opts are over.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2021, 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
|
||||
@ -156,6 +156,10 @@ public class ByteArrayInputStream extends InputStream {
|
||||
* {@code b[off+k-1]} in the manner performed by {@code System.arraycopy}.
|
||||
* The value {@code k} is added into {@code pos} and {@code k} is returned.
|
||||
* <p>
|
||||
* Unlike the {@link InputStream#read(byte[],int,int) overridden method}
|
||||
* of {@code InputStream}, this method returns {@code -1} instead of zero
|
||||
* if the end of the stream has been reached and {@code len == 0}.
|
||||
* <p>
|
||||
* This {@code read} method cannot block.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
|
||||
@ -26,12 +26,11 @@
|
||||
package java.lang.runtime;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.ConstantBootstraps;
|
||||
import java.lang.invoke.ConstantCallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
@ -53,12 +52,15 @@ public class SwitchBootstraps {
|
||||
|
||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
private static final MethodHandle DO_SWITCH;
|
||||
private static final MethodHandle DO_TYPE_SWITCH;
|
||||
private static final MethodHandle DO_ENUM_SWITCH;
|
||||
|
||||
static {
|
||||
try {
|
||||
DO_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doSwitch",
|
||||
DO_TYPE_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doTypeSwitch",
|
||||
MethodType.methodType(int.class, Object.class, int.class, Object[].class));
|
||||
DO_ENUM_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "doEnumSwitch",
|
||||
MethodType.methodType(int.class, Enum.class, int.class, Object[].class));
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
@ -108,14 +110,13 @@ public class SwitchBootstraps {
|
||||
* second parameter of type {@code int} and with {@code int} as its return type,
|
||||
* or if {@code labels} contains an element that is not of type {@code String},
|
||||
* {@code Integer} or {@code Class}.
|
||||
* @throws Throwable if there is any error linking the call site
|
||||
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
|
||||
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
|
||||
*/
|
||||
public static CallSite typeSwitch(MethodHandles.Lookup lookup,
|
||||
String invocationName,
|
||||
MethodType invocationType,
|
||||
Object... labels) throws Throwable {
|
||||
Object... labels) {
|
||||
if (invocationType.parameterCount() != 2
|
||||
|| (!invocationType.returnType().equals(int.class))
|
||||
|| invocationType.parameterType(0).isPrimitive()
|
||||
@ -126,7 +127,7 @@ public class SwitchBootstraps {
|
||||
labels = labels.clone();
|
||||
Stream.of(labels).forEach(SwitchBootstraps::verifyLabel);
|
||||
|
||||
MethodHandle target = MethodHandles.insertArguments(DO_SWITCH, 2, (Object) labels);
|
||||
MethodHandle target = MethodHandles.insertArguments(DO_TYPE_SWITCH, 2, (Object) labels);
|
||||
return new ConstantCallSite(target);
|
||||
}
|
||||
|
||||
@ -142,7 +143,7 @@ public class SwitchBootstraps {
|
||||
}
|
||||
}
|
||||
|
||||
private static int doSwitch(Object target, int startIndex, Object[] labels) {
|
||||
private static int doTypeSwitch(Object target, int startIndex, Object[] labels) {
|
||||
if (target == null)
|
||||
return -1;
|
||||
|
||||
@ -167,4 +168,124 @@ public class SwitchBootstraps {
|
||||
return labels.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap method for linking an {@code invokedynamic} call site that
|
||||
* implements a {@code switch} on a target of an enum type. The static
|
||||
* arguments are used to encode the case labels associated to the switch
|
||||
* construct, where each label can be encoded in two ways:
|
||||
* <ul>
|
||||
* <li>as a {@code String} value, which represents the name of
|
||||
* the enum constant associated with the label</li>
|
||||
* <li>as a {@code Class} value, which represents the enum type
|
||||
* associated with a type test pattern</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The returned {@code CallSite}'s method handle will have
|
||||
* a return type of {@code int} and accepts two parameters: the first argument
|
||||
* will be an {@code Enum} instance ({@code target}) and the second
|
||||
* will be {@code int} ({@code restart}).
|
||||
* <p>
|
||||
* If the {@code target} is {@code null}, then the method of the call site
|
||||
* returns {@literal -1}.
|
||||
* <p>
|
||||
* If the {@code target} is not {@code null}, then the method of the call site
|
||||
* returns the index of the first element in the {@code labels} array starting from
|
||||
* the {@code restart} index matching one of the following conditions:
|
||||
* <ul>
|
||||
* <li>the element is of type {@code Class} that is assignable
|
||||
* from the target's class; or</li>
|
||||
* <li>the element is of type {@code String} and equals to the target
|
||||
* enum constant's {@link Enum#name()}.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* If no element in the {@code labels} array matches the target, then
|
||||
* the method of the call site return the length of the {@code labels} array.
|
||||
*
|
||||
* @param lookup Represents a lookup context with the accessibility
|
||||
* privileges of the caller. When used with {@code invokedynamic},
|
||||
* this is stacked automatically by the VM.
|
||||
* @param invocationName unused
|
||||
* @param invocationType The invocation type of the {@code CallSite} with two parameters,
|
||||
* an enum type, an {@code int}, and {@code int} as a return type.
|
||||
* @param labels case labels - {@code String} constants and {@code Class} instances,
|
||||
* in any combination
|
||||
* @return a {@code CallSite} returning the first matching element as described above
|
||||
*
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IllegalArgumentException if any element in the labels array is null, if the
|
||||
* invocation type is not a method type whose first parameter type is an enum type,
|
||||
* second parameter of type {@code int} and whose return type is {@code int},
|
||||
* or if {@code labels} contains an element that is not of type {@code String} or
|
||||
* {@code Class} of the target enum type.
|
||||
* @jvms 4.4.6 The CONSTANT_NameAndType_info Structure
|
||||
* @jvms 4.4.10 The CONSTANT_Dynamic_info and CONSTANT_InvokeDynamic_info Structures
|
||||
*/
|
||||
public static CallSite enumSwitch(MethodHandles.Lookup lookup,
|
||||
String invocationName,
|
||||
MethodType invocationType,
|
||||
Object... labels) {
|
||||
if (invocationType.parameterCount() != 2
|
||||
|| (!invocationType.returnType().equals(int.class))
|
||||
|| invocationType.parameterType(0).isPrimitive()
|
||||
|| !invocationType.parameterType(0).isEnum()
|
||||
|| !invocationType.parameterType(1).equals(int.class))
|
||||
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
|
||||
requireNonNull(labels);
|
||||
|
||||
labels = labels.clone();
|
||||
|
||||
Class<?> enumClass = invocationType.parameterType(0);
|
||||
labels = Stream.of(labels).map(l -> convertEnumConstants(lookup, enumClass, l)).toArray();
|
||||
|
||||
MethodHandle target =
|
||||
MethodHandles.insertArguments(DO_ENUM_SWITCH, 2, (Object) labels);
|
||||
target = target.asType(invocationType);
|
||||
|
||||
return new ConstantCallSite(target);
|
||||
}
|
||||
|
||||
private static <E extends Enum<E>> Object convertEnumConstants(MethodHandles.Lookup lookup, Class<?> enumClassTemplate, Object label) {
|
||||
if (label == null) {
|
||||
throw new IllegalArgumentException("null label found");
|
||||
}
|
||||
Class<?> labelClass = label.getClass();
|
||||
if (labelClass == Class.class) {
|
||||
if (label != enumClassTemplate) {
|
||||
throw new IllegalArgumentException("the Class label: " + label +
|
||||
", expected the provided enum class: " + enumClassTemplate);
|
||||
}
|
||||
return label;
|
||||
} else if (labelClass == String.class) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<E> enumClass = (Class<E>) enumClassTemplate;
|
||||
try {
|
||||
return ConstantBootstraps.enumConstant(lookup, (String) label, enumClass);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("label with illegal type found: " + labelClass +
|
||||
", expected label of type either String or Class");
|
||||
}
|
||||
}
|
||||
|
||||
private static int doEnumSwitch(Enum<?> target, int startIndex, Object[] labels) {
|
||||
if (target == null)
|
||||
return -1;
|
||||
|
||||
// Dumbest possible strategy
|
||||
Class<?> targetClass = target.getClass();
|
||||
for (int i = startIndex; i < labels.length; i++) {
|
||||
Object label = labels[i];
|
||||
if (label instanceof Class<?> c) {
|
||||
if (c.isAssignableFrom(targetClass))
|
||||
return i;
|
||||
} else if (label == target) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return labels.length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -664,7 +664,11 @@ public class Flow {
|
||||
ListBuffer<PendingExit> prevPendingExits = pendingExits;
|
||||
pendingExits = new ListBuffer<>();
|
||||
scan(tree.selector);
|
||||
Set<Symbol> constants = tree.patternSwitch ? new HashSet<>() : null;
|
||||
boolean exhaustiveSwitch = tree.patternSwitch ||
|
||||
tree.cases.stream()
|
||||
.flatMap(c -> c.labels.stream())
|
||||
.anyMatch(l -> TreeInfo.isNull(l));
|
||||
Set<Symbol> constants = exhaustiveSwitch ? new HashSet<>() : null;
|
||||
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
|
||||
alive = Liveness.ALIVE;
|
||||
JCCase c = l.head;
|
||||
@ -686,7 +690,7 @@ public class Flow {
|
||||
l.tail.head.pos(),
|
||||
Warnings.PossibleFallThroughIntoCase);
|
||||
}
|
||||
if (!tree.hasTotalPattern && tree.patternSwitch &&
|
||||
if (!tree.hasTotalPattern && exhaustiveSwitch &&
|
||||
!TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases) &&
|
||||
(constants == null || !isExhaustive(tree.selector.type, constants))) {
|
||||
log.error(tree, Errors.NotExhaustiveStatement);
|
||||
|
||||
@ -35,6 +35,7 @@ import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.BindingSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
@ -58,6 +59,7 @@ import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.tree.TreeTranslator;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
import com.sun.tools.javac.util.Options;
|
||||
|
||||
@ -93,6 +95,7 @@ import com.sun.tools.javac.tree.JCTree.LetExpr;
|
||||
import com.sun.tools.javac.tree.TreeInfo;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* This pass translates pattern-matching constructs, such as instanceof <pattern>.
|
||||
@ -275,7 +278,6 @@ public class TransPatterns extends TreeTranslator {
|
||||
boolean hasTotalPattern,
|
||||
boolean patternSwitch) {
|
||||
Type seltype = selector.type;
|
||||
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
|
||||
|
||||
if (patternSwitch) {
|
||||
Assert.check(preview.isEnabled());
|
||||
@ -315,27 +317,6 @@ public class TransPatterns extends TreeTranslator {
|
||||
//-case null is always desugared to case -1, as the typeSwitch bootstrap method will
|
||||
// return -1 when the input is null
|
||||
//
|
||||
//a special case for switches over enums with pattern case
|
||||
//with only a single unguarded (type) pattern case, which is equivalent
|
||||
//to a default with additional binding variable assignment:
|
||||
//switch ($enum) {
|
||||
// case $constant1: $stats$
|
||||
// case $constant2: $stats$
|
||||
// case typeof($enum) e: $stats$
|
||||
//}
|
||||
//=>
|
||||
//switch ($enum) {
|
||||
// case $constant1: $stats$
|
||||
// case $constant2: $stats$
|
||||
// default: typeof($enum) e = $enum; $stats$
|
||||
//}
|
||||
//constant labels in switches over enums with one or more pattern cases
|
||||
//with guards are desugared into guards:
|
||||
//case $constant1: $stats$
|
||||
//=>
|
||||
//case typeof($enum) e && e == $constant1: $stats$
|
||||
//and handled as a normal pattern matching switch
|
||||
//
|
||||
//note the selector is evaluated only once and stored in a temporary variable
|
||||
ListBuffer<JCCase> newCases = new ListBuffer<>();
|
||||
for (List<JCCase> c = cases; c.nonEmpty(); c = c.tail) {
|
||||
@ -345,27 +326,6 @@ public class TransPatterns extends TreeTranslator {
|
||||
newCases.add(c.head);
|
||||
}
|
||||
}
|
||||
if (enumSwitch && hasGuards(newCases)) {
|
||||
for (JCCase c : newCases) {
|
||||
for (List<JCCaseLabel> l = c.labels; l.nonEmpty(); l = l.tail) {
|
||||
if (l.head.isExpression() && !TreeInfo.isNull(l.head)) {
|
||||
BindingSymbol temp = new BindingSymbol(Flags.SYNTHETIC,
|
||||
names.fromString("enumGuard" + c.pos +
|
||||
target.syntheticNameChar() + "temp"),
|
||||
seltype,
|
||||
currentMethodSym);
|
||||
JCBindingPattern binding =
|
||||
make.at(l.head.pos()).BindingPattern(make.VarDef(temp, null));
|
||||
binding.setType(seltype);
|
||||
l.head = make.GuardPattern(binding,
|
||||
makeBinary(Tag.EQ,
|
||||
make.Ident(temp),
|
||||
(JCExpression) l.head));
|
||||
}
|
||||
}
|
||||
}
|
||||
enumSwitch = false;
|
||||
}
|
||||
cases = newCases.toList();
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<>();
|
||||
VarSymbol temp = new VarSymbol(Flags.SYNTHETIC,
|
||||
@ -395,46 +355,44 @@ public class TransPatterns extends TreeTranslator {
|
||||
currentMethodSym);
|
||||
statements.append(make.at(tree.pos).VarDef(index, makeLit(syms.intType, 0)));
|
||||
|
||||
if (enumSwitch) {
|
||||
selector = make.Ident(temp);
|
||||
} else {
|
||||
List<Type> staticArgTypes = List.of(syms.methodHandleLookupType,
|
||||
syms.stringType,
|
||||
syms.methodTypeType,
|
||||
types.makeArrayType(new ClassType(syms.classType.getEnclosingType(),
|
||||
List.of(new WildcardType(syms.objectType, BoundKind.UNBOUND,
|
||||
syms.boundClass)),
|
||||
syms.classType.tsym)));
|
||||
LoadableConstant[] staticArgValues =
|
||||
cases.stream()
|
||||
.flatMap(c -> c.labels.stream())
|
||||
.map(l -> toLoadableConstant(l))
|
||||
.filter(c -> c != null)
|
||||
.toArray(s -> new LoadableConstant[s]);
|
||||
List<Type> staticArgTypes = List.of(syms.methodHandleLookupType,
|
||||
syms.stringType,
|
||||
syms.methodTypeType,
|
||||
types.makeArrayType(new ClassType(syms.classType.getEnclosingType(),
|
||||
List.of(new WildcardType(syms.objectType, BoundKind.UNBOUND,
|
||||
syms.boundClass)),
|
||||
syms.classType.tsym)));
|
||||
LoadableConstant[] staticArgValues =
|
||||
cases.stream()
|
||||
.flatMap(c -> c.labels.stream())
|
||||
.map(l -> toLoadableConstant(l, seltype))
|
||||
.filter(c -> c != null)
|
||||
.toArray(s -> new LoadableConstant[s]);
|
||||
|
||||
Symbol bsm = rs.resolveInternalMethod(tree.pos(), env, syms.switchBootstrapsType,
|
||||
names.fromString("typeSwitch"), staticArgTypes, List.nil());
|
||||
boolean enumSelector = seltype.tsym.isEnum();
|
||||
Name bootstrapName = enumSelector ? names.enumSwitch : names.typeSwitch;
|
||||
Symbol bsm = rs.resolveInternalMethod(tree.pos(), env, syms.switchBootstrapsType,
|
||||
bootstrapName, staticArgTypes, List.nil());
|
||||
|
||||
MethodType indyType = new MethodType(
|
||||
List.of(syms.objectType, syms.intType),
|
||||
syms.intType,
|
||||
List.nil(),
|
||||
syms.methodClass
|
||||
);
|
||||
DynamicMethodSymbol dynSym = new DynamicMethodSymbol(names.fromString("typeSwitch"),
|
||||
syms.noSymbol,
|
||||
((MethodSymbol)bsm).asHandle(),
|
||||
indyType,
|
||||
staticArgValues);
|
||||
MethodType indyType = new MethodType(
|
||||
List.of(enumSelector ? seltype : syms.objectType, syms.intType),
|
||||
syms.intType,
|
||||
List.nil(),
|
||||
syms.methodClass
|
||||
);
|
||||
DynamicMethodSymbol dynSym = new DynamicMethodSymbol(bootstrapName,
|
||||
syms.noSymbol,
|
||||
((MethodSymbol)bsm).asHandle(),
|
||||
indyType,
|
||||
staticArgValues);
|
||||
|
||||
JCFieldAccess qualifier = make.Select(make.QualIdent(bsm.owner), dynSym.name);
|
||||
qualifier.sym = dynSym;
|
||||
qualifier.type = syms.intType;
|
||||
selector = make.Apply(List.nil(),
|
||||
qualifier,
|
||||
List.of(make.Ident(temp), make.Ident(index)))
|
||||
.setType(syms.intType);
|
||||
}
|
||||
JCFieldAccess qualifier = make.Select(make.QualIdent(bsm.owner), dynSym.name);
|
||||
qualifier.sym = dynSym;
|
||||
qualifier.type = syms.intType;
|
||||
selector = make.Apply(List.nil(),
|
||||
qualifier,
|
||||
List.of(make.Ident(temp), make.Ident(index)))
|
||||
.setType(syms.intType);
|
||||
|
||||
int i = 0;
|
||||
boolean previousCompletesNormally = false;
|
||||
@ -473,38 +431,27 @@ public class TransPatterns extends TreeTranslator {
|
||||
} else {
|
||||
c.stats = translate(c.stats);
|
||||
}
|
||||
if (enumSwitch) {
|
||||
var labels = c.labels;
|
||||
|
||||
while (labels.nonEmpty()) {
|
||||
if (labels.head.isPattern()) {
|
||||
labels.head = make.DefaultCaseLabel();
|
||||
}
|
||||
labels = labels.tail;
|
||||
}
|
||||
} else {
|
||||
ListBuffer<JCCaseLabel> translatedLabels = new ListBuffer<>();
|
||||
for (var p : c.labels) {
|
||||
if (p.hasTag(Tag.DEFAULTCASELABEL)) {
|
||||
translatedLabels.add(p);
|
||||
hasDefault = true;
|
||||
} else if (hasTotalPattern && !hasDefault &&
|
||||
c == lastCase && p.isPattern()) {
|
||||
//If the switch has total pattern, the last case will contain it.
|
||||
//Convert the total pattern to default:
|
||||
translatedLabels.add(make.DefaultCaseLabel());
|
||||
ListBuffer<JCCaseLabel> translatedLabels = new ListBuffer<>();
|
||||
for (var p : c.labels) {
|
||||
if (p.hasTag(Tag.DEFAULTCASELABEL)) {
|
||||
translatedLabels.add(p);
|
||||
hasDefault = true;
|
||||
} else if (hasTotalPattern && !hasDefault &&
|
||||
c == lastCase && p.isPattern()) {
|
||||
//If the switch has total pattern, the last case will contain it.
|
||||
//Convert the total pattern to default:
|
||||
translatedLabels.add(make.DefaultCaseLabel());
|
||||
} else {
|
||||
int value;
|
||||
if (p.isNullPattern()) {
|
||||
value = -1;
|
||||
} else {
|
||||
int value;
|
||||
if (p.isNullPattern()) {
|
||||
value = -1;
|
||||
} else {
|
||||
value = i++;
|
||||
}
|
||||
translatedLabels.add(make.Literal(value));
|
||||
value = i++;
|
||||
}
|
||||
translatedLabels.add(make.Literal(value));
|
||||
}
|
||||
c.labels = translatedLabels.toList();
|
||||
}
|
||||
c.labels = translatedLabels.toList();
|
||||
if (c.caseKind == CaseTree.CaseKind.STATEMENT) {
|
||||
previousCompletesNormally = c.completesNormally;
|
||||
} else {
|
||||
@ -538,29 +485,31 @@ public class TransPatterns extends TreeTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasGuards(Collection<JCCase> cases) {
|
||||
return cases.stream()
|
||||
.flatMap(c -> c.labels.stream())
|
||||
.filter(JCCaseLabel::isPattern)
|
||||
.anyMatch(l -> !TreeInfo.primaryPatternType((JCPattern) l).unconditional());
|
||||
}
|
||||
|
||||
private Type principalType(JCPattern p) {
|
||||
return types.boxedTypeOrType(types.erasure(TreeInfo.primaryPatternType(p).type()));
|
||||
}
|
||||
|
||||
private LoadableConstant toLoadableConstant(JCCaseLabel l) {
|
||||
private LoadableConstant toLoadableConstant(JCCaseLabel l, Type selector) {
|
||||
if (l.isPattern()) {
|
||||
return (LoadableConstant) principalType((JCPattern) l);
|
||||
Type principalType = principalType((JCPattern) l);
|
||||
if (types.isSubtype(selector, principalType)) {
|
||||
return (LoadableConstant) selector;
|
||||
} else {
|
||||
return (LoadableConstant) principalType;
|
||||
}
|
||||
} else if (l.isExpression() && !TreeInfo.isNull((JCExpression) l)) {
|
||||
Assert.checkNonNull(l.type.constValue());
|
||||
if ((l.type.tsym.flags_field & Flags.ENUM) != 0) {
|
||||
return LoadableConstant.String(((JCIdent) l).name.toString());
|
||||
} else {
|
||||
Assert.checkNonNull(l.type.constValue());
|
||||
|
||||
return switch (l.type.getTag()) {
|
||||
case BYTE, CHAR,
|
||||
SHORT, INT -> LoadableConstant.Int((Integer) l.type.constValue());
|
||||
case CLASS -> LoadableConstant.String((String) l.type.constValue());
|
||||
default -> throw new AssertionError();
|
||||
};
|
||||
return switch (l.type.getTag()) {
|
||||
case BYTE, CHAR,
|
||||
SHORT, INT -> LoadableConstant.Int((Integer) l.type.constValue());
|
||||
case CLASS -> LoadableConstant.String((String) l.type.constValue());
|
||||
default -> throw new AssertionError();
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -819,7 +768,7 @@ public class TransPatterns extends TreeTranslator {
|
||||
VarSymbol bindingDeclared(BindingSymbol varSymbol) {
|
||||
VarSymbol res = parent.bindingDeclared(varSymbol);
|
||||
if (res == null) {
|
||||
res = new VarSymbol(varSymbol.flags(), varSymbol.name, varSymbol.type, varSymbol.owner);
|
||||
res = new VarSymbol(varSymbol.flags(), varSymbol.name, varSymbol.type, currentMethodSym);
|
||||
res.setTypeAttributes(varSymbol.getRawTypeAttributes());
|
||||
hoistedVarMap.put(varSymbol, res);
|
||||
}
|
||||
|
||||
@ -215,6 +215,10 @@ public class Names {
|
||||
public final Name permits;
|
||||
public final Name sealed;
|
||||
|
||||
// pattern switches
|
||||
public final Name typeSwitch;
|
||||
public final Name enumSwitch;
|
||||
|
||||
public final Name.Table table;
|
||||
|
||||
public Names(Context context) {
|
||||
@ -384,6 +388,10 @@ public class Names {
|
||||
// sealed types
|
||||
permits = fromString("permits");
|
||||
sealed = fromString("sealed");
|
||||
|
||||
// pattern switches
|
||||
typeSwitch = fromString("typeSwitch");
|
||||
enumSwitch = fromString("enumSwitch");
|
||||
}
|
||||
|
||||
protected Name.Table createTable(Options options) {
|
||||
|
||||
@ -75,6 +75,7 @@ import com.sun.source.doctree.StartElementTree;
|
||||
import com.sun.source.doctree.SummaryTree;
|
||||
import com.sun.source.doctree.SystemPropertyTree;
|
||||
import com.sun.source.doctree.TextTree;
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import com.sun.source.util.SimpleDocTreeVisitor;
|
||||
|
||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||
@ -1515,9 +1516,16 @@ public class HtmlDocletWriter {
|
||||
|
||||
@Override
|
||||
public Boolean visitErroneous(ErroneousTree node, Content c) {
|
||||
messages.warning(ch.getDocTreePath(node),
|
||||
"doclet.tag.invalid_usage", node);
|
||||
result.add(new RawHtml(node.toString()));
|
||||
DocTreePath dtp = ch.getDocTreePath(node);
|
||||
if (dtp != null) {
|
||||
String body = node.getBody();
|
||||
if (body.matches("(?i)\\{@[a-z]+.*")) {
|
||||
messages.warning(dtp,"doclet.tag.invalid_usage", body);
|
||||
} else {
|
||||
messages.warning(dtp, "doclet.tag.invalid_input", body);
|
||||
}
|
||||
}
|
||||
result.add(Text.of(node.toString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1542,7 +1550,10 @@ public class HtmlDocletWriter {
|
||||
public Boolean visitLink(LinkTree node, Content c) {
|
||||
var inTags = context.inTags;
|
||||
if (inTags.contains(LINK) || inTags.contains(LINK_PLAIN) || inTags.contains(SEE)) {
|
||||
messages.warning(ch.getDocTreePath(node), "doclet.see.nested_link", "{@" + node.getTagName() + "}");
|
||||
DocTreePath dtp = ch.getDocTreePath(node);
|
||||
if (dtp != null) {
|
||||
messages.warning(dtp, "doclet.see.nested_link", "{@" + node.getTagName() + "}");
|
||||
}
|
||||
Content label = commentTagsToContent(node, element, node.getLabel(), context);
|
||||
if (label.isEmpty()) {
|
||||
label = Text.of(node.getReference().getSignature());
|
||||
|
||||
@ -104,6 +104,7 @@ doclet.see.class_or_package_not_found=Tag {0}: reference not found: {1}
|
||||
doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
|
||||
doclet.see.nested_link=Tag {0}: nested link
|
||||
doclet.tag.invalid_usage=invalid usage of tag {0}
|
||||
doclet.tag.invalid_input=invalid input: ''{0}''
|
||||
doclet.Deprecated_API=Deprecated API
|
||||
doclet.Deprecated_Elements=Deprecated {0}
|
||||
doclet.Deprecated_In_Release=Deprecated in {0}
|
||||
|
||||
@ -114,6 +114,11 @@ serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.j
|
||||
serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all
|
||||
serviceability/dcmd/gc/RunFinalizationTest.java 8227120 linux-all,windows-x64
|
||||
|
||||
serviceability/sa/ClhsdbCDSCore.java 8269982 macosx-aarch64
|
||||
serviceability/sa/ClhsdbFindPC.java#id1 8269982 macosx-aarch64
|
||||
serviceability/sa/ClhsdbFindPC.java#id3 8269982 macosx-aarch64
|
||||
serviceability/sa/ClhsdbPstack.java#id1 8269982 macosx-aarch64
|
||||
|
||||
#############################################################################
|
||||
|
||||
# :hotspot_misc
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021, 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
|
||||
@ -33,7 +33,7 @@ import jdk.test.lib.RandomFactory;
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.RandomFactory
|
||||
* @run main ReadAllReadNTransferTo
|
||||
* @bug 8180451
|
||||
* @bug 6766844 8180451
|
||||
* @summary Verify ByteArrayInputStream readAllBytes, readNBytes, and transferTo
|
||||
* @key randomness
|
||||
*/
|
||||
@ -48,8 +48,16 @@ public class ReadAllReadNTransferTo {
|
||||
int position = random.nextInt(SIZE/2);
|
||||
int size = random.nextInt(SIZE - position);
|
||||
|
||||
ByteArrayInputStream bais =
|
||||
new ByteArrayInputStream(buf, position, size);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
|
||||
bais.readAllBytes();
|
||||
if (bais.read(new byte[0]) != -1) {
|
||||
throw new RuntimeException("read(byte[]) did not return -1");
|
||||
}
|
||||
if (bais.read(new byte[1], 0, 0) != -1) {
|
||||
throw new RuntimeException("read(byte[],int,int) did not return -1");
|
||||
}
|
||||
|
||||
bais = new ByteArrayInputStream(buf, position, size);
|
||||
int off = size < 2 ? 0 : random.nextInt(size / 2);
|
||||
int len = size - off < 1 ? 0 : random.nextInt(size - off);
|
||||
|
||||
@ -72,7 +80,6 @@ public class ReadAllReadNTransferTo {
|
||||
throw new RuntimeException("readAllBytes content");
|
||||
}
|
||||
|
||||
// XXX transferTo()
|
||||
bais = new ByteArrayInputStream(buf);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(buf.length);
|
||||
if (bais.transferTo(baos) != buf.length) {
|
||||
|
||||
@ -44,11 +44,14 @@ import static org.testng.Assert.fail;
|
||||
public class SwitchBootstrapsTest {
|
||||
|
||||
public static final MethodHandle BSM_TYPE_SWITCH;
|
||||
public static final MethodHandle BSM_ENUM_SWITCH;
|
||||
|
||||
static {
|
||||
try {
|
||||
BSM_TYPE_SWITCH = MethodHandles.lookup().findStatic(SwitchBootstraps.class, "typeSwitch",
|
||||
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class));
|
||||
BSM_ENUM_SWITCH = MethodHandles.lookup().findStatic(SwitchBootstraps.class, "enumSwitch",
|
||||
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, Object[].class));
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw new AssertionError("Should not happen", e);
|
||||
@ -62,8 +65,16 @@ public class SwitchBootstrapsTest {
|
||||
assertEquals(-1, (int) indy.invoke(null, start));
|
||||
}
|
||||
|
||||
private void testEnum(Enum<?> target, int start, int result, Object... labels) throws Throwable {
|
||||
MethodType switchType = MethodType.methodType(int.class, target.getClass(), int.class);
|
||||
MethodHandle indy = ((CallSite) BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", switchType, labels)).dynamicInvoker();
|
||||
assertEquals((int) indy.invoke(target, start), result);
|
||||
assertEquals(-1, (int) indy.invoke(null, start));
|
||||
}
|
||||
|
||||
public enum E1 {
|
||||
A;
|
||||
A,
|
||||
B;
|
||||
}
|
||||
|
||||
public enum E2 {
|
||||
@ -98,6 +109,24 @@ public class SwitchBootstrapsTest {
|
||||
testType("", 2, 2, String.class, String.class, String.class);
|
||||
}
|
||||
|
||||
public void testEnums() throws Throwable {
|
||||
testEnum(E1.A, 0, 2, "B", "C", "A", E1.class);
|
||||
testEnum(E1.B, 0, 0, "B", "C", "A", E1.class);
|
||||
testEnum(E1.B, 1, 3, "B", "C", "A", E1.class);
|
||||
try {
|
||||
testEnum(E1.B, 1, 3, "B", "C", "A", E2.class);
|
||||
fail("Didn't get the expected exception.");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//OK
|
||||
}
|
||||
try {
|
||||
testEnum(E1.B, 1, 3, "B", "C", "A", String.class);
|
||||
fail("Didn't get the expected exception.");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//OK
|
||||
}
|
||||
}
|
||||
|
||||
public void testWrongSwitchTypes() throws Throwable {
|
||||
MethodType[] switchTypes = new MethodType[] {
|
||||
MethodType.methodType(int.class, Object.class),
|
||||
@ -112,6 +141,20 @@ public class SwitchBootstrapsTest {
|
||||
//OK, expected
|
||||
}
|
||||
}
|
||||
MethodType[] enumSwitchTypes = new MethodType[] {
|
||||
MethodType.methodType(int.class, Enum.class),
|
||||
MethodType.methodType(int.class, Object.class, int.class),
|
||||
MethodType.methodType(int.class, double.class, int.class),
|
||||
MethodType.methodType(int.class, Enum.class, Integer.class)
|
||||
};
|
||||
for (MethodType enumSwitchType : enumSwitchTypes) {
|
||||
try {
|
||||
BSM_ENUM_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType);
|
||||
fail("Didn't get the expected exception.");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//OK, expected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testNullLabels() throws Throwable {
|
||||
@ -129,5 +172,19 @@ public class SwitchBootstrapsTest {
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//OK
|
||||
}
|
||||
MethodType enumSwitchType = MethodType.methodType(int.class, E1.class, int.class);
|
||||
try {
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType, (Object[]) null);
|
||||
fail("Didn't get the expected exception.");
|
||||
} catch (NullPointerException ex) {
|
||||
//OK
|
||||
}
|
||||
try {
|
||||
BSM_TYPE_SWITCH.invoke(MethodHandles.lookup(), "", enumSwitchType,
|
||||
new Object[] {1, null, String.class});
|
||||
fail("Didn't get the expected exception.");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
//OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 8269722
|
||||
* @summary NPE in HtmlDocletWriter, reporting errors on inherited tags
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestInherited
|
||||
*/
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestInherited extends JavadocTester {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
TestInherited tester = new TestInherited();
|
||||
tester.runTests(m -> new Object[] { Path.of(m.getName())});
|
||||
}
|
||||
|
||||
private final ToolBox tb = new ToolBox();
|
||||
|
||||
@Test
|
||||
public void testBadInheritedParam(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
public class BadParam {
|
||||
public static class Base {
|
||||
/**
|
||||
* @param i a < b
|
||||
*/
|
||||
public void m(int i) { }
|
||||
}
|
||||
|
||||
public static class Sub extends Base {
|
||||
public void m(int i) { }
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"-Xdoclint:-missing", "-XDdoe",
|
||||
src.resolve("BadParam.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadInheritedReturn(Path base) throws Exception {
|
||||
Path src = base.resolve("src");
|
||||
tb.writeJavaFiles(src, """
|
||||
public class BadReturn {
|
||||
public static class Base {
|
||||
/**
|
||||
* @return a < b
|
||||
*/
|
||||
public int m() { }
|
||||
}
|
||||
|
||||
public static class Sub extends Base {
|
||||
public int m() { }
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
javadoc("-d", base.resolve("out").toString(),
|
||||
"-Xdoclint:-missing",
|
||||
src.resolve("BadReturn.java").toString());
|
||||
checkExit(Exit.OK);
|
||||
}
|
||||
}
|
||||
@ -374,7 +374,7 @@ public class TestJavaFX extends JavadocTester {
|
||||
checkExit(Exit.OK);
|
||||
|
||||
// make sure the doclet indeed emits the warning
|
||||
checkOutput(Output.OUT, true, "C.java:31: warning: invalid usage of tag <");
|
||||
checkOutput(Output.OUT, true, "C.java:31: warning: invalid input: '<'");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -85,6 +85,6 @@ public class TestNonInlineHtmlTagRemoval extends JavadocTester {
|
||||
|
||||
checkOutput("Negative.html", true,
|
||||
"""
|
||||
<div class="block">case1: A hanging < : xx<</div>""");
|
||||
<div class="block">case1: A hanging < : xx<</div>""");
|
||||
}
|
||||
}
|
||||
|
||||
80
test/langtools/tools/javac/patterns/EnumTypeChanges.java
Normal file
80
test/langtools/tools/javac/patterns/EnumTypeChanges.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 8262891
|
||||
* @summary Verify pattern switches work properly when the set of enum constant changes.
|
||||
* @compile --enable-preview -source ${jdk.version} EnumTypeChanges.java
|
||||
* @compile --enable-preview -source ${jdk.version} EnumTypeChanges2.java
|
||||
* @run main/othervm --enable-preview EnumTypeChanges
|
||||
*/
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EnumTypeChanges {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new EnumTypeChanges().run();
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
doRun(this::statementEnum);
|
||||
doRun(this::expressionEnum);
|
||||
}
|
||||
|
||||
void doRun(Function<EnumTypeChangesEnum, String> c) throws Exception {
|
||||
assertEquals("A", c.apply(EnumTypeChangesEnum.A));
|
||||
assertEquals("D", c.apply(EnumTypeChangesEnum.valueOf("C")));
|
||||
}
|
||||
|
||||
String statementEnum(EnumTypeChangesEnum e) {
|
||||
switch (e) {
|
||||
case A -> { return "A"; }
|
||||
case EnumTypeChangesEnum e1 && false -> throw new AssertionError();
|
||||
case B -> { return "B"; }
|
||||
default -> { return "D"; }
|
||||
}
|
||||
}
|
||||
|
||||
String expressionEnum(EnumTypeChangesEnum e) {
|
||||
return switch (e) {
|
||||
case A -> "A";
|
||||
case EnumTypeChangesEnum e1 && false -> throw new AssertionError();
|
||||
case B -> "B";
|
||||
default -> "D";
|
||||
};
|
||||
}
|
||||
|
||||
private static void assertEquals(Object o1, Object o2) {
|
||||
if (!Objects.equals(o1, o2)) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum EnumTypeChangesEnum {
|
||||
A,
|
||||
B;
|
||||
}
|
||||
27
test/langtools/tools/javac/patterns/EnumTypeChanges2.java
Normal file
27
test/langtools/tools/javac/patterns/EnumTypeChanges2.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
enum EnumTypeChangesEnum {
|
||||
A,
|
||||
C;
|
||||
}
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8267610
|
||||
* @bug 8267610 8269738
|
||||
* @summary LambdaToMethod cannot capture pattern variables. So the TransPatterns should
|
||||
* transform the pattern variables and symbols to normal variables and symbols.
|
||||
* @compile --enable-preview -source ${jdk.version} LambdaCannotCapturePatternVariables.java
|
||||
@ -34,11 +34,24 @@ import java.util.function.Supplier;
|
||||
|
||||
public class LambdaCannotCapturePatternVariables {
|
||||
|
||||
static Number num1 = 1;
|
||||
static Number num2 = null;
|
||||
static Number staticNum1 = (num1 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
|
||||
static Number staticNum2 = (num2 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
|
||||
Number instanceNum1 = (num1 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
|
||||
Number instanceNum2 = (num2 instanceof Integer i) ? ((Supplier<Integer>) () -> i).get() : null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
var testVar = new LambdaCannotCapturePatternVariables();
|
||||
testVar.testInstanceOfPatternVariable(Integer.valueOf(1));
|
||||
testVar.testSwitchPatternVariable(Integer.valueOf(1));
|
||||
testVar.test(Integer.valueOf(1));
|
||||
assertTrue(staticNum1 != null, "staticNum1 is null unexpectedly");
|
||||
assertTrue(staticNum2 == null, "staticNum1 is not null unexpectedly");
|
||||
assertTrue(testVar.instanceNum1 != null, "instanceNum1 is null unexpectedly");
|
||||
assertTrue(testVar.instanceNum2 == null, "instanceNum2 is not null unexpectedly");
|
||||
assertTrue(staticNum1.intValue() == 1, "staticNum1.intValue() is not equal to 1");
|
||||
assertTrue(testVar.instanceNum1.intValue() == 1, "instanceNum1.intValue() is not equal to 1");
|
||||
}
|
||||
|
||||
public Integer testInstanceOfPatternVariable(Object x) {
|
||||
@ -69,4 +82,9 @@ public class LambdaCannotCapturePatternVariables {
|
||||
return ((y instanceof Integer z) ? z : bar);
|
||||
})).get() : bar);
|
||||
}
|
||||
|
||||
static void assertTrue(boolean cond, String info) {
|
||||
if (!cond)
|
||||
throw new AssertionError(info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,4 +185,9 @@ public class SwitchErrors {
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
void exhaustiveAndNull(String s) {
|
||||
switch (s) {
|
||||
case null: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ SwitchErrors.java:91:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:97:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:104:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:164:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:189:9: compiler.err.not.exhaustive.statement
|
||||
- compiler.note.preview.filename: SwitchErrors.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
44 errors
|
||||
45 errors
|
||||
|
||||
@ -53,8 +53,12 @@ public class Switches {
|
||||
runEnumTest(this::testEnumExpression2);
|
||||
runEnumTest(this::testEnumWithGuards1);
|
||||
runEnumTest(this::testEnumWithGuards2);
|
||||
runEnumTest(this::testEnumWithGuards3);
|
||||
runEnumTest(this::testEnumWithGuards4);
|
||||
runEnumTest(this::testEnumWithGuardsExpression1);
|
||||
runEnumTest(this::testEnumWithGuardsExpression2);
|
||||
runEnumTest(this::testEnumWithGuardsExpression3);
|
||||
runEnumTest(this::testEnumWithGuardsExpression4);
|
||||
runEnumTest(this::testStringWithGuards1);
|
||||
runEnumTest(this::testStringWithGuardsExpression1);
|
||||
runEnumTest(this::testIntegerWithGuards1);
|
||||
@ -288,6 +292,46 @@ public class Switches {
|
||||
};
|
||||
}
|
||||
|
||||
String testEnumWithGuards3(E e) {
|
||||
switch (e) {
|
||||
case A: return "a";
|
||||
case B: return "b";
|
||||
case Object x && "C".equals(x.toString()): return "C";
|
||||
case C: return "broken";
|
||||
case null, E x: return String.valueOf(x);
|
||||
}
|
||||
}
|
||||
|
||||
String testEnumWithGuardsExpression3(E e) {
|
||||
return switch (e) {
|
||||
case A -> "a";
|
||||
case B -> "b";
|
||||
case Object x && "C".equals(x.toString()) -> "C";
|
||||
case C -> "broken";
|
||||
case null, E x -> String.valueOf(x);
|
||||
};
|
||||
}
|
||||
|
||||
String testEnumWithGuards4(E e) {
|
||||
switch (e) {
|
||||
case A: return "a";
|
||||
case B: return "b";
|
||||
case Runnable x && "C".equals(x.toString()): return "C";
|
||||
case C: return "broken";
|
||||
case null, E x: return String.valueOf(x);
|
||||
}
|
||||
}
|
||||
|
||||
String testEnumWithGuardsExpression4(E e) {
|
||||
return switch (e) {
|
||||
case A -> "a";
|
||||
case B -> "b";
|
||||
case Runnable x && "C".equals(x.toString()) -> "C";
|
||||
case C -> "broken";
|
||||
case null, E x -> String.valueOf(x);
|
||||
};
|
||||
}
|
||||
|
||||
String testStringWithGuards1(E e) {
|
||||
switch (e != null ? e.name() : null) {
|
||||
case "A": return "a";
|
||||
@ -520,7 +564,9 @@ public class Switches {
|
||||
}
|
||||
}
|
||||
|
||||
public enum E {
|
||||
public enum E implements Runnable {
|
||||
A, B, C;
|
||||
|
||||
@Override public void run() {}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user