8309235: Unnamed Variables (_) can't be used in JShell

Co-authored-by: Jan Lahoda <jlahoda@openjdk.org>
Co-authored-by: Aggelos Biboudis <abimpoudis@openjdk.org>
Reviewed-by: asotona
This commit is contained in:
Aggelos Biboudis 2023-06-08 07:25:25 +00:00 committed by Adam Sotona
parent 9d64a9d220
commit 79a4ac791c
8 changed files with 91 additions and 15 deletions

View File

@ -3350,7 +3350,8 @@ public class JShellTool implements MessageHandler {
String val = state.status(vk) == Status.VALID
? feedback.truncateVarValue(state.varValue(vk))
: getResourceString("jshell.msg.vars.not.active");
hard(" %s %s = %s", vk.typeName(), vk.name(), val);
String varName = vk.name();
hard(" %s %s = %s", vk.typeName(), varName.isEmpty() ? "_" : varName, val);
});
return true;
}

View File

@ -385,21 +385,28 @@ class Eval {
subkind = SubKind.VAR_DECLARATION_SUBKIND;
}
Wrap wname;
int nameStart = compileSource.lastIndexOf(name, nameMax);
if (nameStart < 0) {
// the name has been transformed (e.g. unicode).
// Use it directly
wname = Wrap.identityWrap(name);
String fieldName;
if (name.isEmpty()) {
fieldName = "$UNNAMED";
wname = Wrap.simpleWrap(fieldName);
} else {
int nameEnd = nameStart + name.length();
Range rname = new Range(nameStart, nameEnd);
wname = new Wrap.RangeWrap(compileSource, rname);
fieldName = name;
int nameStart = compileSource.lastIndexOf(name, nameMax);
if (nameStart < 0) {
// the name has been transformed (e.g. unicode).
// Use it directly
wname = Wrap.identityWrap(name);
} else {
int nameEnd = nameStart + name.length();
Range rname = new Range(nameStart, nameEnd);
wname = new Wrap.RangeWrap(compileSource, rname);
}
}
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), wname,
winit, enhancedDesugaring, anonDeclareWrap);
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
name, subkind, displayType, hasEnhancedType ? fullTypeName : null, anonymousClasses,
name, fieldName, subkind, displayType, hasEnhancedType ? fullTypeName : null, anonymousClasses,
tds.declareReferences(), modDiag);
snippets.add(snip);
}
@ -659,7 +666,7 @@ class Eval {
}
Collection<String> declareReferences = null; //TODO
snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, displayTypeName, fullTypeName, anonymousClasses, declareReferences, null);
name, name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, displayTypeName, fullTypeName, anonymousClasses, declareReferences, null);
} else {
guts = Wrap.methodReturnWrap(compileSource);
snip = new ExpressionSnippet(state.keyMap.keyForExpression(name, typeName), userSource, guts,

View File

@ -726,7 +726,7 @@ public class JShell implements AutoCloseable {
}
String value;
try {
value = executionControl().varValue(snippet.classFullName(), snippet.name());
value = executionControl().varValue(snippet.classFullName(), snippet.fieldName());
} catch (EngineTerminationException ex) {
throw new IllegalStateException(ex.getMessage());
} catch (ExecutionControlException ex) {

View File

@ -65,6 +65,10 @@ class KeyMap {
}
VarKey keyForVariable(String name) {
if (name.isEmpty()) {
return new VarKey(state, name);
}
return varMap.computeIfAbsent(name, k -> new VarKey(state, name));
}

View File

@ -229,7 +229,7 @@ class ReplParser extends JavacParser {
} else if ((isVoid || (lastmode & TYPE) != 0) && LAX_IDENTIFIER.test(token.kind)) {
// we have "Type Ident", so we can assume it is variable or method declaration
pos = token.pos;
Name name = ident();
Name name = identOrUnderscore();
if (token.kind == LPAREN) {
// method declaration
//mods.flags |= Flags.STATIC;

View File

@ -101,7 +101,7 @@ final class SnippetMaps {
StringBuilder sb = new StringBuilder();
sb.append("package ").append(REPL_PACKAGE).append(";\n");
for (Snippet si : keyIndexToSnippet) {
if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key()))) {
if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key())) && si.name() != null && !si.name().isEmpty()) {
sb.append(si.importLine(state));
}
}

View File

@ -58,8 +58,10 @@ public class VarSnippet extends DeclarationSnippet {
*/
final Set<String> anonymousClasses;
final String fieldName;
VarSnippet(VarKey key, String userSource, Wrap guts,
String name, SubKind subkind, String typeName, String fullTypeName,
String name, String fieldName, SubKind subkind, String typeName, String fullTypeName,
Set<String> anonymousClasses, Collection<String> declareReferences,
DiagList syntheticDiags) {
super(key, userSource, guts, name, subkind, null, declareReferences,
@ -67,6 +69,11 @@ public class VarSnippet extends DeclarationSnippet {
this.typeName = typeName;
this.fullTypeName = fullTypeName;
this.anonymousClasses = anonymousClasses;
this.fieldName = fieldName;
}
String fieldName() {
return fieldName;
}
/**

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2023, 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 9999999
* @summary Tests for unnamed variables
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.jshell
* @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic
* @run testng UnnamedTest
*/
import java.util.function.Consumer;
import jdk.jshell.VarSnippet;
import org.testng.Assert;
import org.testng.annotations.Test;
import jdk.jshell.JShell;
public class UnnamedTest extends KullaTesting {
@Test
public void unnamed() {
VarSnippet sn1 = varKey(assertEval("int _ = 0;"));
VarSnippet sn2 = varKey(assertEval("String _ = \"x\";"));
Assert.assertEquals(getState().varValue(sn1), "0");
Assert.assertEquals(getState().varValue(sn2), "\"x\"");
}
@Override
public void setUp(Consumer<JShell.Builder> bc) {
super.setUp(bc.andThen(b -> b.compilerOptions("--enable-preview", "--source", System.getProperty("java.specification.version"))));
}
}