Skip to content

Commit 79a4ac7

Browse files
biboudislahodaj
authored andcommitted
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
1 parent 9d64a9d commit 79a4ac7

File tree

8 files changed

+91
-15
lines changed

8 files changed

+91
-15
lines changed

src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3350,7 +3350,8 @@ private boolean cmdVars(String arg) {
33503350
String val = state.status(vk) == Status.VALID
33513351
? feedback.truncateVarValue(state.varValue(vk))
33523352
: getResourceString("jshell.msg.vars.not.active");
3353-
hard(" %s %s = %s", vk.typeName(), vk.name(), val);
3353+
String varName = vk.name();
3354+
hard(" %s %s = %s", vk.typeName(), varName.isEmpty() ? "_" : varName, val);
33543355
});
33553356
return true;
33563357
}

src/jdk.jshell/share/classes/jdk/jshell/Eval.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -385,21 +385,28 @@ private List<Snippet> processVariables(String userSource, List<? extends Tree> u
385385
subkind = SubKind.VAR_DECLARATION_SUBKIND;
386386
}
387387
Wrap wname;
388-
int nameStart = compileSource.lastIndexOf(name, nameMax);
389-
if (nameStart < 0) {
390-
// the name has been transformed (e.g. unicode).
391-
// Use it directly
392-
wname = Wrap.identityWrap(name);
388+
String fieldName;
389+
if (name.isEmpty()) {
390+
fieldName = "$UNNAMED";
391+
wname = Wrap.simpleWrap(fieldName);
393392
} else {
394-
int nameEnd = nameStart + name.length();
395-
Range rname = new Range(nameStart, nameEnd);
396-
wname = new Wrap.RangeWrap(compileSource, rname);
393+
fieldName = name;
394+
int nameStart = compileSource.lastIndexOf(name, nameMax);
395+
if (nameStart < 0) {
396+
// the name has been transformed (e.g. unicode).
397+
// Use it directly
398+
wname = Wrap.identityWrap(name);
399+
} else {
400+
int nameEnd = nameStart + name.length();
401+
Range rname = new Range(nameStart, nameEnd);
402+
wname = new Wrap.RangeWrap(compileSource, rname);
403+
}
397404
}
398405
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), wname,
399406
winit, enhancedDesugaring, anonDeclareWrap);
400407
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
401408
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
402-
name, subkind, displayType, hasEnhancedType ? fullTypeName : null, anonymousClasses,
409+
name, fieldName, subkind, displayType, hasEnhancedType ? fullTypeName : null, anonymousClasses,
403410
tds.declareReferences(), modDiag);
404411
snippets.add(snip);
405412
}
@@ -659,7 +666,7 @@ private List<Snippet> processExpression(String userSource, Tree tree, String com
659666
}
660667
Collection<String> declareReferences = null; //TODO
661668
snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
662-
name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, displayTypeName, fullTypeName, anonymousClasses, declareReferences, null);
669+
name, name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, displayTypeName, fullTypeName, anonymousClasses, declareReferences, null);
663670
} else {
664671
guts = Wrap.methodReturnWrap(compileSource);
665672
snip = new ExpressionSnippet(state.keyMap.keyForExpression(name, typeName), userSource, guts,

src/jdk.jshell/share/classes/jdk/jshell/JShell.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ public String varValue(VarSnippet snippet) throws IllegalStateException {
726726
}
727727
String value;
728728
try {
729-
value = executionControl().varValue(snippet.classFullName(), snippet.name());
729+
value = executionControl().varValue(snippet.classFullName(), snippet.fieldName());
730730
} catch (EngineTerminationException ex) {
731731
throw new IllegalStateException(ex.getMessage());
732732
} catch (ExecutionControlException ex) {

src/jdk.jshell/share/classes/jdk/jshell/KeyMap.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ MethodKey keyForMethod(String name, String parameterTypes) {
6565
}
6666

6767
VarKey keyForVariable(String name) {
68+
if (name.isEmpty()) {
69+
return new VarKey(state, name);
70+
}
71+
6872
return varMap.computeIfAbsent(name, k -> new VarKey(state, name));
6973
}
7074

src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ List<? extends JCTree> replUnit(JCModifiers pmods, Comment dc) {
229229
} else if ((isVoid || (lastmode & TYPE) != 0) && LAX_IDENTIFIER.test(token.kind)) {
230230
// we have "Type Ident", so we can assume it is variable or method declaration
231231
pos = token.pos;
232-
Name name = ident();
232+
Name name = identOrUnderscore();
233233
if (token.kind == LPAREN) {
234234
// method declaration
235235
//mods.flags |= Flags.STATIC;

src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ String packageAndImportsExcept(Set<Key> except, Collection<Snippet> plus) {
101101
StringBuilder sb = new StringBuilder();
102102
sb.append("package ").append(REPL_PACKAGE).append(";\n");
103103
for (Snippet si : keyIndexToSnippet) {
104-
if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key()))) {
104+
if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key())) && si.name() != null && !si.name().isEmpty()) {
105105
sb.append(si.importLine(state));
106106
}
107107
}

src/jdk.jshell/share/classes/jdk/jshell/VarSnippet.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,22 @@ public class VarSnippet extends DeclarationSnippet {
5858
*/
5959
final Set<String> anonymousClasses;
6060

61+
final String fieldName;
62+
6163
VarSnippet(VarKey key, String userSource, Wrap guts,
62-
String name, SubKind subkind, String typeName, String fullTypeName,
64+
String name, String fieldName, SubKind subkind, String typeName, String fullTypeName,
6365
Set<String> anonymousClasses, Collection<String> declareReferences,
6466
DiagList syntheticDiags) {
6567
super(key, userSource, guts, name, subkind, null, declareReferences,
6668
null, syntheticDiags);
6769
this.typeName = typeName;
6870
this.fullTypeName = fullTypeName;
6971
this.anonymousClasses = anonymousClasses;
72+
this.fieldName = fieldName;
73+
}
74+
75+
String fieldName() {
76+
return fieldName;
7077
}
7178

7279
/**
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 9999999
27+
* @summary Tests for unnamed variables
28+
* @library /tools/lib
29+
* @modules jdk.compiler/com.sun.tools.javac.api
30+
* jdk.compiler/com.sun.tools.javac.main
31+
* jdk.jshell
32+
* @build Compiler KullaTesting TestingInputStream ExpectedDiagnostic
33+
* @run testng UnnamedTest
34+
*/
35+
36+
import java.util.function.Consumer;
37+
import jdk.jshell.VarSnippet;
38+
import org.testng.Assert;
39+
import org.testng.annotations.Test;
40+
41+
import jdk.jshell.JShell;
42+
43+
public class UnnamedTest extends KullaTesting {
44+
45+
@Test
46+
public void unnamed() {
47+
VarSnippet sn1 = varKey(assertEval("int _ = 0;"));
48+
VarSnippet sn2 = varKey(assertEval("String _ = \"x\";"));
49+
Assert.assertEquals(getState().varValue(sn1), "0");
50+
Assert.assertEquals(getState().varValue(sn2), "\"x\"");
51+
}
52+
53+
@Override
54+
public void setUp(Consumer<JShell.Builder> bc) {
55+
super.setUp(bc.andThen(b -> b.compilerOptions("--enable-preview", "--source", System.getProperty("java.specification.version"))));
56+
}
57+
}

0 commit comments

Comments
 (0)