8268850: AST model for 'var' variables should more closely adhere to the source code

Reviewed-by: vromero
This commit is contained in:
Jan Lahoda 2026-02-26 08:10:37 +00:00
parent fd48f68a2c
commit a39a1f10f7
33 changed files with 873 additions and 113 deletions

View File

@ -266,6 +266,13 @@ public interface Tree {
*/
PRIMITIVE_TYPE(PrimitiveTypeTree.class),
/**
* Used for instances of {@link VarTypeTree}.
*
* @since 27
*/
VAR_TYPE(VarTypeTree.class),
/**
* Used for instances of {@link ReturnTree}.
*/

View File

@ -498,6 +498,15 @@ public interface TreeVisitor<R,P> {
*/
R visitPrimitiveType(PrimitiveTypeTree node, P p);
/**
* Visits a {@code VarTypeTree} node.
* @param node the node being visited
* @param p a parameter value
* @return a result value
* @since 27
*/
R visitVarType(VarTypeTree node, P p);
/**
* Visits a {@code TypeParameterTree} node.
* @param node the node being visited

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2026, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.source.tree;
import javax.lang.model.type.TypeKind;
/**
* A tree node for a {@code var} contextual keyword used as a type.
*
* @since 27
*/
public interface VarTypeTree extends Tree {
}

View File

@ -65,10 +65,13 @@ public interface VariableTree extends StatementTree {
*/
ExpressionTree getNameExpression();
/**
* Returns the type of the variable being declared.
* @return the type
*/
/// {@return the type of the variable being declared.}
///
/// @apiNote
/// The type of the variable can be one of the following:
/// - if the variable is declared using {@code var}, then the returned value is a {@link VarTypeTree},
/// - if the variable is a lambda parameter declared without a type (i.e. relying on type inferrence), then the returned value is {@code null},
/// - otherwise, the variable is declared with an explicit type, and the returned value is that type.
Tree getType();
/**

View File

@ -803,6 +803,21 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
return defaultAction(node, p);
}
/**
* {@inheritDoc}
*
* @implSpec This implementation calls {@code defaultAction}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of {@code defaultAction}
* @since 27
*/
@Override
public R visitVarType(VarTypeTree node, P p) {
return defaultAction(node, p);
}
/**
* {@inheritDoc}
*

View File

@ -939,6 +939,21 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
return null;
}
/**
* {@inheritDoc}
*
* @implSpec This implementation returns {@code null}.
*
* @param node {@inheritDoc}
* @param p {@inheritDoc}
* @return the result of scanning
* @since 27
*/
@Override
public R visitVarType(VarTypeTree node, P p) {
return null;
}
/**
* {@inheritDoc}
*

View File

@ -370,7 +370,6 @@ public class Analyzer {
*/
JCVariableDecl rewriteVarType(JCVariableDecl oldTree) {
JCVariableDecl newTree = copier.copy(oldTree);
newTree.vartype = null;
return newTree;
}
@ -751,7 +750,6 @@ public class Analyzer {
if (oldLambda.paramKind == ParameterKind.IMPLICIT) {
//reset implicit lambda parameters (whose type might have been set during attr)
newLambda.paramKind = ParameterKind.IMPLICIT;
newLambda.params.forEach(p -> p.vartype = null);
}
return newLambda;
}

View File

@ -1263,18 +1263,18 @@ public class Attr extends JCTree.Visitor {
// parameters have already been entered
env.info.scope.enter(tree.sym);
} else {
if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0 && tree.type == null) {
if (tree.init == null) {
//cannot use 'var' without initializer
log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
tree.vartype = make.at(tree.pos()).Erroneous();
tree.type = syms.errType;
} else {
Fragment msg = canInferLocalVarType(tree);
if (msg != null) {
//cannot use 'var' with initializer which require an explicit target
//(e.g. lambda, method reference, array initializer).
log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
tree.vartype = make.at(tree.pos()).Erroneous();
tree.type = syms.errType;
}
}
}
@ -1323,7 +1323,7 @@ public class Attr extends JCTree.Visitor {
}
}
if (tree.isImplicitlyTyped()) {
setSyntheticVariableType(tree, v.type);
setupImplicitlyTypedVariable(tree, v.type);
}
}
result = tree.type = v.type;
@ -1597,7 +1597,8 @@ public class Attr extends JCTree.Visitor {
}
if (tree.var.isImplicitlyTyped()) {
Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
setSyntheticVariableType(tree.var, inferredType);
tree.var.type = inferredType;
setupImplicitlyTypedVariable(tree.var, inferredType);
}
attribStat(tree.var, loopEnv);
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
@ -3223,8 +3224,10 @@ public class Attr extends JCTree.Visitor {
Type argType = arityMismatch ?
syms.errType :
actuals.head;
if (params.head.isImplicitlyTyped()) {
setSyntheticVariableType(params.head, argType);
if (params.head.type == null &&
params.head.isImplicitlyTyped()) { //error recovery
params.head.type = argType;
setupImplicitlyTypedVariable(params.head, argType);
}
params.head.sym = null;
actuals = actuals.isEmpty() ?
@ -3442,7 +3445,7 @@ public class Attr extends JCTree.Visitor {
JCLambda lambda = (JCLambda)tree;
List<Type> argtypes = List.nil();
for (JCVariableDecl param : lambda.params) {
argtypes = param.vartype != null && param.vartype.type != null ?
argtypes = !param.isImplicitlyTyped() && param.vartype.type != null ?
argtypes.append(param.vartype.type) :
argtypes.append(syms.errType);
}
@ -4218,7 +4221,7 @@ public class Attr extends JCTree.Visitor {
public void visitBindingPattern(JCBindingPattern tree) {
Type type;
if (tree.var.vartype != null) {
if (!tree.var.isImplicitlyTyped()) {
type = attribType(tree.var.vartype, env);
} else {
type = resultInfo.pt;
@ -4231,11 +4234,11 @@ public class Attr extends JCTree.Visitor {
if (chk.checkUnique(tree.var.pos(), v, env.info.scope)) {
chk.checkTransparentVar(tree.var.pos(), v, env.info.scope);
}
chk.validate(tree.var.vartype, env, true);
if (tree.var.isImplicitlyTyped()) {
setSyntheticVariableType(tree.var, type == Type.noType ? syms.errType
: type);
setupImplicitlyTypedVariable(tree.var, type == Type.noType ? syms.errType
: type);
}
chk.validate(tree.var.vartype, env, true);
annotate.annotateLater(tree.var.mods.annotations, env, v);
if (!tree.var.isImplicitlyTyped()) {
annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v);
@ -4254,7 +4257,7 @@ public class Attr extends JCTree.Visitor {
public void visitRecordPattern(JCRecordPattern tree) {
Type site;
if (tree.deconstructor == null) {
if (tree.deconstructor.hasTag(VARTYPE)) {
log.error(tree.pos(), Errors.DeconstructionPatternVarNotAllowed);
tree.record = syms.errSymbol;
site = tree.type = types.createErrorType(tree.record.type);
@ -4270,6 +4273,7 @@ public class Attr extends JCTree.Visitor {
}
tree.type = tree.deconstructor.type = type;
site = types.capture(tree.type);
chk.validate(tree.deconstructor, env, true);
}
List<Type> expectedRecordTypes;
@ -4315,7 +4319,6 @@ public class Attr extends JCTree.Visitor {
} finally {
localEnv.info.scope.leave();
}
chk.validate(tree.deconstructor, env, true);
result = tree.type;
matchBindings = new MatchBindings(outBindings.toList(), List.nil());
}
@ -5731,15 +5734,20 @@ public class Attr extends JCTree.Visitor {
return types.capture(type);
}
private void setSyntheticVariableType(JCVariableDecl tree, Type type) {
if (type.isErroneous()) {
tree.vartype = make.at(tree.pos()).Erroneous();
} else if (tree.declaredUsingVar()) {
Assert.check(tree.typePos != Position.NOPOS);
tree.vartype = make.at(tree.typePos).Type(type);
} else {
tree.vartype = make.at(tree.pos()).Type(type);
private void setupImplicitlyTypedVariable(JCVariableDecl tree, Type type) {
Assert.check(tree.isImplicitlyTyped());
type.complete();
if (tree.vartype == null) {
return ;
}
Assert.check(tree.vartype.hasTag(VARTYPE));
JCVarType vartype = (JCVarType) tree.vartype;
vartype.type = type;
}
public void validateTypeAnnotations(JCTree tree, boolean sigOnly) {
@ -6068,9 +6076,6 @@ public class Attr extends JCTree.Visitor {
that.sym = new VarSymbol(0, that.name, that.type, syms.noSymbol);
that.sym.adr = 0;
}
if (that.vartype == null) {
that.vartype = make.at(Position.NOPOS).Erroneous();
}
super.visitVarDef(that);
}
@ -6145,6 +6150,11 @@ public class Attr extends JCTree.Visitor {
syms.noSymbol);
}
}
@Override
public void visitVarType(JCVarType that) {
initTypeIfNeeded(that);
}
}
// </editor-fold>

View File

@ -117,11 +117,6 @@ public class AttrRecover {
? formals.head : ((ArrayType) formals.head).elemtype;
if (arg.hasTag(JCTree.Tag.LAMBDA)) {
final JCTree.JCLambda lambda = (JCLambda) arg;
if (lambda.paramKind == JCLambda.ParameterKind.IMPLICIT) {
for (JCVariableDecl var : lambda.params) {
var.vartype = null; //reset type
}
}
if (types.isFunctionalInterface(formal)) {
Type functionalType = types.findDescriptorType(formal);
boolean voidCompatible = functionalType.getReturnType().hasTag(TypeTag.VOID);

View File

@ -3692,11 +3692,12 @@ public class Lower extends TreeTranslator {
if (tree.var.type.isPrimitive())
vardefinit = make.TypeCast(types.cvarUpperBound(iteratorTarget), vardefinit);
else
vardefinit = make.TypeCast(tree.var.type, vardefinit);
vardefinit = transTypes.coerce(attrEnv, vardefinit, tree.var.type);
JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
tree.var.name,
tree.var.vartype,
vardefinit).setType(tree.var.type);
vardefinit,
tree.var.declKind).setType(tree.var.type);
indexDef.sym = tree.var.sym;
JCBlock body = make.Block(0, List.of(indexDef, tree.body));
body.bracePos = TreeInfo.endPos(tree.body);

View File

@ -114,7 +114,7 @@ public class MemberEnter extends JCTree.Visitor {
ListBuffer<Type> argbuf = new ListBuffer<>();
for (List<JCVariableDecl> l = params; l.nonEmpty(); l = l.tail) {
memberEnter(l.head, env);
argbuf.append(l.head.vartype.type);
argbuf.append(l.head.sym.type);
}
// Attribute result type, if one is given.
@ -276,9 +276,13 @@ public class MemberEnter extends JCTree.Visitor {
tree.vartype.type = atype.makeVarargs();
}
WriteableScope enclScope = enter.enterScope(env);
Type vartype = tree.isImplicitlyTyped()
? env.info.scope.owner.kind == MTH ? Type.noType : syms.errType
: tree.vartype.type;
Type vartype = switch (tree.declKind) {
case IMPLICIT -> tree.type;
case EXPLICIT -> tree.vartype.type;
case VAR -> tree.type != null ? tree.type
: env.info.scope.owner.kind == MTH ? Type.noType
: syms.errType;
};
Name name = tree.name;
VarSymbol v = new VarSymbol(0, name, vartype, enclScope.owner);
v.flags_field = chk.checkFlags(tree.mods.flags | tree.declKind.additionalSymbolFlags, v, tree);

View File

@ -93,6 +93,7 @@ import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCTypeUnion;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCUses;
import com.sun.tools.javac.tree.JCTree.JCVarType;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCWildcard;
@ -631,6 +632,11 @@ public class TreeDiffer extends TreeScanner {
result = tree.typetag == that.typetag;
}
@Override
public void visitVarType(JCVarType tree) {
result = true;
}
@Override
public void visitTypeIntersection(JCTypeIntersection tree) {
JCTypeIntersection that = (JCTypeIntersection) parameter;

View File

@ -977,13 +977,11 @@ public class JavacParser implements Parser {
pattern = toP(F.at(token.pos).AnyPattern());
}
else {
int varTypePos = Position.NOPOS;
if (parsedType == null) {
boolean var = token.kind == IDENTIFIER && token.name() == names.var;
e = unannotatedType(allowVar, TYPE | NOLAMBDA);
if (var) {
varTypePos = e.pos;
e = null;
e = replaceTypeWithVar(e);
}
} else {
e = parsedType;
@ -1021,12 +1019,9 @@ public class JavacParser implements Parser {
name = names.empty;
}
JCVariableDecl var = toP(F.at(varPos).VarDef(mods, name, e, null,
varTypePos != Position.NOPOS ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT,
varTypePos));
if (e == null) {
if (var.name == names.underscore && !allowVar) {
log.error(DiagnosticFlag.SYNTAX, varPos, Errors.UseOfUnderscoreNotAllowed);
}
e.hasTag(VARTYPE) ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT));
if (var.name == names.underscore && !allowVar) {
log.error(DiagnosticFlag.SYNTAX, varPos, Errors.UseOfUnderscoreNotAllowed);
}
pattern = toP(F.at(pos).BindingPattern(var));
}
@ -2178,8 +2173,7 @@ public class JavacParser implements Parser {
&& restrictedTypeName(param.vartype, true) != null) {
checkSourceLevel(param.pos, Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS);
param.declKind = JCVariableDecl.DeclKind.VAR;
param.typePos = TreeInfo.getStartPos(param.vartype);
param.vartype = null;
param.vartype = replaceTypeWithVar(param.vartype);
}
}
}
@ -3792,7 +3786,6 @@ public class JavacParser implements Parser {
*/
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
boolean reqInit, Comment dc, boolean localDecl, boolean compound) {
boolean declaredUsingVar = false;
JCExpression init = null;
type = bracketsOpt(type);
@ -3818,7 +3811,6 @@ public class JavacParser implements Parser {
syntaxError(token.pos, Errors.Expected(EQ));
}
int varTypePos = Position.NOPOS;
JCTree elemType = TreeInfo.innermostType(type, true);
if (elemType.hasTag(IDENT)) {
Name typeName = ((JCIdent) elemType).name;
@ -3829,21 +3821,27 @@ public class JavacParser implements Parser {
//error - 'var' and arrays
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedArray(typeName));
} else {
declaredUsingVar = true;
varTypePos = elemType.pos;
type = replaceTypeWithVar(type);
if (compound)
//error - 'var' in compound local var decl
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedCompound(typeName));
//implicit type
type = null;
}
}
}
JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init,
declaredUsingVar ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT, varTypePos));
type.hasTag(VARTYPE) ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT));
return attach(result, dc);
}
JCExpression replaceTypeWithVar(JCExpression type) {
JCVarType varType = F.at(type).VarType();
varType.endpos = type.endpos;
return varType;
}
Name restrictedTypeName(JCExpression e, boolean shouldWarn) {
switch (e.getTag()) {
case IDENT:
@ -3954,11 +3952,10 @@ public class JavacParser implements Parser {
name = names.empty;
}
boolean declaredUsingVar = type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var;
boolean declaredUsingVar = type != null && type.hasTag(VARTYPE);
JCVariableDecl.DeclKind declKind = declaredUsingVar ? JCVariableDecl.DeclKind.VAR :
type != null ? JCVariableDecl.DeclKind.EXPLICIT : JCVariableDecl.DeclKind.IMPLICIT;
int typePos = type != null ? type.pos : pos;
return toP(F.at(pos).VarDef(mods, name, type, null, declKind, typePos));
return toP(F.at(pos).VarDef(mods, name, type, null, declKind));
}
/** Resources = Resource { ";" Resources }

View File

@ -277,6 +277,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
*/
TYPEIDENT,
/** 'var' type.
*/
VARTYPE,
/** Array types, of type TypeArray.
*/
TYPEARRAY,
@ -1038,15 +1042,13 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public VarSymbol sym;
/** how the variable's type was declared */
public DeclKind declKind;
/** a source code position to use for "vartype" when null (can happen if declKind != EXPLICIT) */
public int typePos;
protected JCVariableDecl(JCModifiers mods,
Name name,
JCExpression vartype,
JCExpression init,
VarSymbol sym) {
this(mods, name, vartype, init, sym, DeclKind.EXPLICIT, Position.NOPOS);
this(mods, name, vartype, init, sym, DeclKind.EXPLICIT);
}
protected JCVariableDecl(JCModifiers mods,
@ -1054,21 +1056,19 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
JCExpression vartype,
JCExpression init,
VarSymbol sym,
DeclKind declKind,
int typePos) {
DeclKind declKind) {
this.mods = mods;
this.name = name;
this.vartype = vartype;
this.init = init;
this.sym = sym;
this.declKind = declKind;
this.typePos = typePos;
}
protected JCVariableDecl(JCModifiers mods,
JCExpression nameexpr,
JCExpression vartype) {
this(mods, null, vartype, null, null, DeclKind.EXPLICIT, Position.NOPOS);
this(mods, null, vartype, null, null, DeclKind.EXPLICIT);
this.nameexpr = nameexpr;
if (nameexpr.hasTag(Tag.IDENT)) {
this.name = ((JCIdent)nameexpr).name;
@ -1078,8 +1078,9 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
}
}
@DefinedBy(Api.COMPILER_TREE)
public boolean isImplicitlyTyped() {
return vartype == null;
return declKind != DeclKind.EXPLICIT;
}
public boolean declaredUsingVar() {
@ -2047,7 +2048,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
this.params = params;
this.body = body;
if (params.isEmpty() ||
params.head.vartype != null) {
!params.head.isImplicitlyTyped()) {
paramKind = ParameterKind.EXPLICIT;
} else {
paramKind = ParameterKind.IMPLICIT;
@ -2827,6 +2828,24 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
}
}
public static class JCVarType extends JCExpression implements VarTypeTree {
public JCVarType() {}
@Override
public void accept(Visitor v) { v.visitVarType(this); }
@DefinedBy(Api.COMPILER_TREE)
public Kind getKind() { return Kind.VAR_TYPE; }
@Override @DefinedBy(Api.COMPILER_TREE)
public <R,D> R accept(TreeVisitor<R,D> v, D d) {
return v.visitVarType(this, d);
}
@Override
public Tag getTag() {
return VARTYPE;
}
}
/**
* An array type, A[]
*/
@ -3604,6 +3623,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
public void visitIdent(JCIdent that) { visitTree(that); }
public void visitLiteral(JCLiteral that) { visitTree(that); }
public void visitTypeIdent(JCPrimitiveTypeTree that) { visitTree(that); }
public void visitVarType(JCVarType that) { visitTree(that); }
public void visitTypeArray(JCArrayTypeTree that) { visitTree(that); }
public void visitTypeApply(JCTypeApply that) { visitTree(that); }
public void visitTypeUnion(JCTypeUnion that) { visitTree(that); }

View File

@ -1529,6 +1529,15 @@ public class Pretty extends JCTree.Visitor {
}
}
@Override
public void visitVarType(JCVarType that) {
try {
print("var");
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public void visitTypeArray(JCArrayTypeTree tree) {
try {
printBaseElementType(tree);

View File

@ -480,6 +480,12 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
return M.at(t.pos).TypeIdent(t.typetag);
}
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitVarType(VarTypeTree node, P p) {
JCVarType t = (JCVarType) node;
return M.at(t.pos).VarType();
}
@DefinedBy(Api.COMPILER_TREE)
public JCTree visitTypeParameter(TypeParameterTree node, P p) {
JCTypeParameter t = (JCTypeParameter) node;
@ -551,7 +557,7 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
JCExpression vartype = copy(t.vartype, p);
if (t.nameexpr == null) {
JCExpression init = copy(t.init, p);
return M.at(t.pos).VarDef(mods, t.name, vartype, init, t.declKind, t.typePos);
return M.at(t.pos).VarDef(mods, t.name, vartype, init, t.declKind);
} else {
JCExpression nameexpr = copy(t.nameexpr, p);
return M.at(t.pos).ReceiverVarDef(mods, nameexpr, vartype);

View File

@ -621,8 +621,6 @@ public class TreeInfo {
return node.mods.pos;
} else if (node.vartype != null) {
return getStartPos(node.vartype);
} else if (node.typePos != Position.NOPOS) {
return node.typePos;
}
break;
}

View File

@ -238,8 +238,8 @@ public class TreeMaker implements JCTree.Factory {
}
public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init,
JCVariableDecl.DeclKind declKind, int typePos) {
JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, declKind, typePos);
JCVariableDecl.DeclKind declKind) {
JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, declKind);
tree.pos = pos;
return tree;
}
@ -566,6 +566,12 @@ public class TreeMaker implements JCTree.Factory {
return tree;
}
public JCVarType VarType() {
JCVarType tree = new JCVarType();
tree.pos = pos;
return tree;
}
public JCArrayTypeTree TypeArray(JCExpression elemtype) {
JCArrayTypeTree tree = new JCArrayTypeTree(elemtype);
tree.pos = pos;

View File

@ -361,6 +361,9 @@ public class TreeScanner extends Visitor {
public void visitTypeIdent(JCPrimitiveTypeTree tree) {
}
public void visitVarType(JCVarType tree) {
}
public void visitTypeArray(JCArrayTypeTree tree) {
scan(tree.elemtype);
}

View File

@ -418,6 +418,10 @@ public class TreeTranslator extends JCTree.Visitor {
result = tree;
}
public void visitVarType(JCVarType tree) {
result = tree;
}
public void visitTypeArray(JCArrayTypeTree tree) {
tree.elemtype = translate(tree.elemtype);
result = tree;

View File

@ -337,7 +337,7 @@ class Eval {
Set<String> anonymousClasses = Collections.emptySet();
StringBuilder sbBrackets = new StringBuilder();
Tree baseType = vt.getType();
if (baseType != null) {
if (vt.getType() != null && vt.getType().getKind() != Tree.Kind.VAR_TYPE) {
tds.scan(baseType); // Not dependent on initializer
fullTypeName = displayType = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
while (baseType instanceof ArrayTypeTree) {

View File

@ -816,7 +816,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
SourcePositions sp = trees.getSourcePositions();
List<Token> tokens = new ArrayList<>();
Context ctx = new Context();
ctx.put(DiagnosticListener.class, (DiagnosticListener) d -> {});
ctx.put(DiagnosticListener.class, (DiagnosticListener<?>) d -> {});
Scanner scanner = ScannerFactory.instance(ctx).newScanner(wrappedCode, false);
Log.instance(ctx).useSource(cut.getSourceFile());
scanner.nextToken();
@ -932,7 +932,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
@Override
public Void visitVariable(VariableTree node, Void p) {
int pos = ((JCTree) node).pos;
if (sp.getEndPosition(cut, node.getType()) == (-1)) {
if (node.getType() != null && node.getType().getKind() == Kind.VAR_TYPE) {
Token varCandidate = findTokensBefore(pos, TokenKind.IDENTIFIER);
if (varCandidate != null && "var".equals(varCandidate.name().toString())) {
addKeyword.accept(varCandidate);

View File

@ -4,6 +4,4 @@ VarVariables.java:24:14: compiler.err.annotation.type.not.applicable
VarVariables.java:27:14: compiler.err.annotation.type.not.applicable
VarVariables.java:32:14: compiler.err.annotation.type.not.applicable
VarVariables.java:36:37: compiler.err.annotation.type.not.applicable
VarVariables.java:32:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.AutoCloseable
VarVariables.java:36:41: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.String
8 errors
6 errors

View File

@ -4,6 +4,4 @@ VarVariables.java:24:14: compiler.err.annotation.type.not.applicable
VarVariables.java:27:14: compiler.err.annotation.type.not.applicable
VarVariables.java:32:14: compiler.err.annotation.type.not.applicable
VarVariables.java:36:37: compiler.err.annotation.type.not.applicable
VarVariables.java:32:18: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.AutoCloseable
VarVariables.java:36:41: compiler.err.type.annotation.inadmissible: (compiler.misc.type.annotation.1: @VarVariables.TA), java.lang, @VarVariables.TA java.lang.String
8 errors
6 errors

View File

@ -0,0 +1,393 @@
/*
* Copyright (c) 2026, 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
* @summary Check behavior of var when the inferred type is inaccessible
* @library /tools/lib
* @modules java.logging
* java.sql
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.util
* @build toolbox.ToolBox toolbox.JavacTask
* @run junit VarAccessibility
*/
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import toolbox.JavacTask;
import toolbox.JavaTask;
import toolbox.Task;
import toolbox.ToolBox;
public class VarAccessibility {
private static final ToolBox tb = new ToolBox();
@Test
public void testInaccessibleInferredTypeLocalVariable() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
public class API {
public static PackagePrivate get() {
return new PackagePrivate();
}
}
""",
"""
package p1;
class PackagePrivate {
public String toString() {
return "pass";
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
var v = API.get();
System.out.println(v);
}
}
""");
Files.createDirectories(classes);
new JavacTask(tb)
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.SUCCESS)
.writeAll();
var out = new JavaTask(tb)
.classpath(classes.toString())
.className("p2.Test")
.run()
.writeAll()
.getOutputLines(Task.OutputKind.STDOUT);
var expectedOut = List.of("pass");
if (!Objects.equals(expectedOut, out)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + out);
}
}
@Test
public void testInaccessibleInferredTypeForEachIterable() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
import java.util.List;
public class API {
public static Iterable<PackagePrivate> get() {
return List.of(new PackagePrivate());
}
}
""",
"""
package p1;
class PackagePrivate {
public String toString() {
return "pass";
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
for (var v : API.get()) {
System.out.println(v);
}
}
}
""");
Files.createDirectories(classes);
var out = new JavacTask(tb)
.options("-XDrawDiagnostics")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
var expectedOut = List.of(
"Test.java:5:22: compiler.err.not.def.public.cant.access: p1.PackagePrivate, p1",
"1 error");
if (!Objects.equals(expectedOut, out)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + out);
}
}
@Test
public void testInaccessibleInferredTypeForEachArray() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
import java.util.List;
public class API {
public static PackagePrivate[] get() {
return new PackagePrivate[] {new PackagePrivate()};
}
}
""",
"""
package p1;
class PackagePrivate {
public String toString() {
return "pass";
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
for (var v : API.get()) {
System.out.println(v);
}
}
}
""");
Files.createDirectories(classes);
new JavacTask(tb)
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.SUCCESS)
.writeAll();
var out = new JavaTask(tb)
.classpath(classes.toString())
.className("p2.Test")
.run()
.writeAll()
.getOutputLines(Task.OutputKind.STDOUT);
var expectedOut = List.of("pass");
if (!Objects.equals(expectedOut, out)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + out);
}
}
@Test
public void testInaccessibleInferredTypeLambda() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
import java.util.function.Consumer;
public class API {
public static void run(Consumer<PackagePrivate> c) {
c.accept(new PackagePrivate());
}
}
""",
"""
package p1;
class PackagePrivate {
public String toString() {
return "pass";
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
API.run(v -> System.out.println(v));
API.run((var v) -> System.out.println(v));
}
}
""");
Files.createDirectories(classes);
var out = new JavacTask(tb)
.options("-XDrawDiagnostics")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
var expectedOut = List.of(
"Test.java:5:17: compiler.err.not.def.public.cant.access: p1.PackagePrivate, p1",
"Test.java:6:17: compiler.err.not.def.public.cant.access: p1.PackagePrivate, p1",
"2 errors");
if (!Objects.equals(expectedOut, out)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + out);
}
}
@Test
public void testInaccessibleInferredTypeCanUse() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
public class API {
public static PackagePrivate get() {
return null;
}
}
""",
"""
package p1;
class PackagePrivate {
public String toString() {
return "pass";
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
var v = API.get();
System.out.println(v.toString());
}
}
""");
Files.createDirectories(classes);
List<String> log = new JavacTask(tb)
.options("-XDrawDiagnostics")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
var expectedOut = List.of(
"Test.java:6:29: compiler.err.not.def.access.class.intf.cant.access: toString(), p1.PackagePrivate",
"1 error"
);
if (!Objects.equals(expectedOut, log)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + log);
}
}
@Test
public void testInaccessibleInferredBindingPattern() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
public record API(PackagePrivate p) {
public static API create() {
return new API(new PackagePrivate());
}
}
""",
"""
package p1;
class PackagePrivate {
public String toString() {
return "pass";
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
Object o = API.create();
if (o instanceof API(var v)) {
System.out.println(v.toString());
}
}
}
""");
Files.createDirectories(classes);
List<String> log = new JavacTask(tb)
.options("-XDrawDiagnostics")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.FAIL)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
var expectedOut = List.of(
"Test.java:7:33: compiler.err.not.def.access.class.intf.cant.access: toString(), p1.PackagePrivate",
"1 error"
);
if (!Objects.equals(expectedOut, log)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + log);
}
}
}

View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2026, 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
* @summary Check behavior of warnings related to var
* @library /tools/lib
* @modules java.logging
* java.sql
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.compiler/com.sun.tools.javac.util
* @build toolbox.ToolBox toolbox.JavacTask
* @run junit VarWarnings
*/
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import org.junit.jupiter.api.Test;
import toolbox.JavacTask;
import toolbox.Task;
import toolbox.ToolBox;
public class VarWarnings {
private static final ToolBox tb = new ToolBox();
@Test
public void testDeprecationWarning() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
import java.util.List;
import java.util.function.Consumer;
@SuppressWarnings("deprecation")
public class API {
public static DeprOutter<DeprInner> get() {
return new DeprOutter<>();
}
public static Iterable<DeprOutter<DeprInner>> getIterable() {
return null;
}
public static void run(Consumer<DeprOutter<DeprInner>> task) {
}
}
""",
"""
package p1;
@Deprecated
public class DeprInner {
}
""",
"""
package p1;
@Deprecated
public class DeprOutter<T> {
public T get() {
return null;
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
var v1 = API.get();
API.run(v -> v.get().toString());
API.run((var v) -> v.get().toString());
for (var v2 : API.getIterable()) {}
}
}
""");
Files.createDirectories(classes);
var out = new JavacTask(tb)
.options("-XDrawDiagnostics",
"-Werror",
"-Xlint:deprecation")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.SUCCESS)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
var expectedOut = List.of("");
if (!Objects.equals(expectedOut, out)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + out);
}
}
@Test
public void testRawTypeWarning() throws Exception {
Path base = Paths.get(".");
Path src = base.resolve("src");
Path classes = base.resolve("classes");
tb.writeJavaFiles(src,
"""
package p1;
import java.util.List;
import java.util.function.Consumer;
@SuppressWarnings("rawtypes")
public class API {
public static RawOutter<RawInner> get() {
return new RawOutter<>();
}
public static Iterable<RawOutter<RawInner>> getIterable() {
return null;
}
public static void run(Consumer<RawOutter<RawInner>> task) {
}
}
""",
"""
package p1;
public class RawInner<T> {
}
""",
"""
package p1;
public class RawOutter<T> {
public T get() {
return null;
}
}
""",
"""
package p2;
import p1.API;
public class Test {
public static void main(String... args) {
var v1 = API.get();
API.run(v -> v.get().toString());
API.run((var v) -> v.get().toString());
for (var v2 : API.getIterable()) {}
}
}
""");
Files.createDirectories(classes);
var out = new JavacTask(tb)
.options("-XDrawDiagnostics",
"-Werror",
"-Xlint:rawtypes")
.outdir(classes)
.files(tb.findJavaFiles(src))
.run(Task.Expect.SUCCESS)
.writeAll()
.getOutputLines(Task.OutputKind.DIRECT);
var expectedOut = List.of("");
if (!Objects.equals(expectedOut, out)) {
throw new AssertionError("Incorrect Output, expected: " + expectedOut +
", actual: " + out);
}
}
}

View File

@ -86,10 +86,12 @@ public class DeclarationEndPositions {
// For variable declarations using "var", verify the "var" position
if (tree instanceof JCVariableDecl varDecl && varDecl.declaredUsingVar()) {
int vpos = varDecl.typePos;
if (!input.substring(vpos).startsWith("var")) {
int varStart = varDecl.vartype.getStartPosition();
int varEnd = varDecl.vartype.getEndPosition();
if (!input.substring(varStart, varEnd).startsWith("var")) {
throw new AssertionError(String.format(
"wrong %s pos %d for \"%s\" in \"%s\"", "var", vpos, tree, input));
"wrong %s start pos %d end pos %d for \"%s\" in \"%s\"", "var", varStart, varEnd, tree, input));
}
}
}

View File

@ -87,7 +87,9 @@ import javax.tools.ToolProvider;
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.DefaultCaseLabelTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.ModuleTree;
import com.sun.source.tree.VarTypeTree;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.api.JavacTaskPool;
import com.sun.tools.javac.api.JavacTaskPool.Worker;
@ -1070,8 +1072,8 @@ public class JavacParserTest extends TestCase {
VariableTree stmt2 = (VariableTree) method.getBody().getStatements().get(1);
Tree v1Type = stmt1.getType();
Tree v2Type = stmt2.getType();
assertEquals("Implicit type for v1 is not correct: ", Kind.PRIMITIVE_TYPE, v1Type.getKind());
assertEquals("Implicit type for v2 is not correct: ", Kind.PRIMITIVE_TYPE, v2Type.getKind());
assertEquals("Implicit type for v1 is not correct: ", Kind.VAR_TYPE, v1Type.getKind());
assertEquals("Implicit type for v2 is not correct: ", Kind.VAR_TYPE, v2Type.getKind());
}
@Test
@ -3151,6 +3153,37 @@ public class JavacParserTest extends TestCase {
codes);
}
@Test
void testVarPositions() throws IOException {
String code = """
public class Test {
void t() {
var v =
}
}
""";
DiagnosticCollector<JavaFileObject> coll =
new DiagnosticCollector<>();
JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll,
null,
null, Arrays.asList(new MyFileObject(code)));
Trees trees = Trees.instance(ct);
SourcePositions sp = trees.getSourcePositions();
CompilationUnitTree cut = ct.parse().iterator().next();
new TreeScanner<Void, Void>() {
@Override
public Void visitVarType(VarTypeTree node, Void p) {
long start = sp.getStartPosition(cut, node);
long end = sp.getEndPosition(cut, node);
String text = code.substring((int) start, (int) end);
assertEquals("var start pos",
"var",
text);
return null;
}
};
}
void run(String[] args) throws Exception {
int passed = 0, failed = 0;
final Pattern p = (args != null && args.length > 0)

View File

@ -83,7 +83,7 @@ public class BindingPatternVarTypeModel {
new TreeScanner<Void, Void>() {
@Override
public Void visitBindingPattern(BindingPatternTree node, Void p) {
if (node.getVariable().getType().getKind() != Tree.Kind.PRIMITIVE_TYPE) {
if (node.getVariable().getType().getKind() != Tree.Kind.VAR_TYPE) {
throw new AssertionError("Unexpected type for var: " +
node.getVariable().getType().getKind() +
":" + node.getVariable().getType());

View File

@ -79,7 +79,7 @@ public class InstanceOfModelTest {
List<String> expectedInstanceOf = List.of(
"null:R",
"R r:R",
"R(int v):null"
"R(var v):null"
);
if (!Objects.equals(expectedInstanceOf, instanceOf)) {

View File

@ -52,27 +52,27 @@ public class VarTree {
public static void main(String... args) throws Exception {
VarTree test = new VarTree();
test.run("|var testVar = 0;| ",
"int testVar = 0");
"var testVar = 0");
test.run("|var testVar = 0;| undef undef;",
"int testVar = 0");
"var testVar = 0");
test.run("|final var testVar = 0;| ",
"final int testVar = 0");
"final var testVar = 0");
test.run("for (|var testVar| : java.util.Arrays.asList(0, 1)) {}",
"java.lang.Integer testVar");
"var testVar");
test.run("for (|final var testVar| : java.util.Arrays.asList(0, 1)) {}",
"final java.lang.Integer testVar");
"final var testVar");
test.run("java.util.function.Consumer<String> c = |testVar| -> {};",
"java.lang.String testVar");
"/*missing*/ testVar"); //TODO: is the /*missing*/ here ideal?
test.run("java.util.function.Consumer<String> c = (|testVar|) -> {};",
"java.lang.String testVar");
"/*missing*/ testVar"); //TODO: is the /*missing*/ here ideal?
test.run("java.util.function.Consumer<String> c = (|var testVar|) -> {};",
"java.lang.String testVar");
"var testVar");
test.run("java.util.function.Consumer<String> c = (|final var testVar|) -> {};",
"final java.lang.String testVar");
"final var testVar");
test.run("record Rec(int x) { }; switch (null) { case Rec(|var testVar|) -> {} default -> {} };",
"int testVar");
"var testVar");
test.run("record Rec(int x) { }; switch (null) { case Rec(|final var testVar|) -> {} default -> {} };",
"final int testVar");
"final var testVar");
}
void run(String code, String expected) throws IOException {
@ -136,11 +136,13 @@ public class VarTree {
throw new AssertionError("Unexpected span: " + snip);
}
int typeStart = (int) trees.getSourcePositions().getStartPosition(cut, node.getType());
int typeEnd = (int) trees.getSourcePositions().getEndPosition(cut, node.getType());
if (node.getType() != null) {
int typeStart = (int) trees.getSourcePositions().getStartPosition(cut, node.getType());
int typeEnd = (int) trees.getSourcePositions().getEndPosition(cut, node.getType());
if (typeStart != (-1) && typeEnd != (-1)) {
throw new AssertionError("Unexpected type position: " + typeStart + ", " + typeEnd);
if (typeStart + 3 != typeEnd) {
throw new AssertionError("Unexpected type position: " + typeStart + ", " + typeEnd);
}
}
found[0] = true;

View File

@ -25,6 +25,9 @@ public class VarWarnPosition {
// Test 4
Consumer<Depr> c3 = (final var d) -> { };
// Test 5
var d = deprecatedList.get(0);
}
}

View File

@ -1,8 +1,4 @@
VarWarnPosition.java:18:14: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
VarWarnPosition.java:21:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
VarWarnPosition.java:21:28: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
VarWarnPosition.java:24:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
VarWarnPosition.java:24:30: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
VarWarnPosition.java:27:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
VarWarnPosition.java:27:36: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package
7 warnings
3 warnings