8177466: Add compiler support for local variable type-inference

Add support for 'var' in implicitly typed local variable declarations

Reviewed-by: vromero, jlahoda
This commit is contained in:
Maurizio Cimadamore 2017-09-26 12:52:53 +01:00
parent 02ba926da2
commit c825188cd8
62 changed files with 2269 additions and 378 deletions

View File

@ -71,6 +71,7 @@ public class Kinds {
HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
MISSING_ENCL(Category.RESOLUTION), // not overloaded non-target
BAD_VAR(Category.RESOLUTION), // not overloaded non-target
ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target

View File

@ -227,6 +227,7 @@ public enum Source {
return compareTo(JDK1_8) <= 0;
}
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
public static SourceVersion toSourceVersion(Source source) {
switch(source) {
case JDK1_2:

View File

@ -1616,6 +1616,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
public TypeVar(Name name, Symbol owner, Type lower) {
super(null, TypeMetadata.EMPTY);
Assert.checkNonNull(lower);
tsym = new TypeVariableSymbol(0, name, this, owner);
this.bound = null;
this.lower = lower;
@ -1628,6 +1629,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
TypeMetadata metadata) {
super(tsym, metadata);
Assert.checkNonNull(lower);
this.bound = bound;
this.lower = lower;
}

View File

@ -1247,7 +1247,9 @@ public class TypeAnnotations {
final TypeAnnotationPosition pos =
TypeAnnotationPosition.localVariable(currentLambda,
tree.pos);
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
if (!tree.isImplicitlyTyped()) {
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
}
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
final TypeAnnotationPosition pos =
TypeAnnotationPosition.exceptionParameter(currentLambda,

View File

@ -190,6 +190,245 @@ public class Types {
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="projections">
/**
* A projection kind. See {@link TypeProjection}
*/
enum ProjectionKind {
UPWARDS() {
@Override
ProjectionKind complement() {
return DOWNWARDS;
}
},
DOWNWARDS() {
@Override
ProjectionKind complement() {
return UPWARDS;
}
};
abstract ProjectionKind complement();
}
/**
* This visitor performs upwards and downwards projections on types.
*
* A projection is defined as a function that takes a type T, a set of type variables V and that
* produces another type S.
*
* An upwards projection maps a type T into a type S such that (i) T has no variables in V,
* and (ii) S is an upper bound of T.
*
* A downwards projection maps a type T into a type S such that (i) T has no variables in V,
* and (ii) S is a lower bound of T.
*
* Note that projections are only allowed to touch variables in V. Theferore it is possible for
* a projection to leave its input type unchanged if it does not contain any variables in V.
*
* Moreover, note that while an upwards projection is always defined (every type as an upper bound),
* a downwards projection is not always defined.
*
* Examples:
*
* {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
* {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
* {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
* {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
*/
class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
List<Type> vars;
Set<Type> seen = new HashSet<>();
public TypeProjection(List<Type> vars) {
this.vars = vars;
}
@Override
public Type visitClassType(ClassType t, ProjectionKind pkind) {
if (t.isCompound()) {
List<Type> components = directSupertypes(t);
List<Type> components1 = components.map(c -> c.map(this, pkind));
if (components == components1) return t;
else return makeIntersectionType(components1);
} else {
Type outer = t.getEnclosingType();
Type outer1 = visit(outer, pkind);
List<Type> typarams = t.getTypeArguments();
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
//not defined
return syms.botType;
}
if (outer1 == outer && typarams1 == typarams) return t;
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
@Override
protected boolean needsStripping() {
return true;
}
};
}
}
protected Type makeWildcard(Type upper, Type lower) {
BoundKind bk;
Type bound;
if (upper.hasTag(BOT)) {
upper = syms.objectType;
}
boolean isUpperObject = isSameType(upper, syms.objectType);
if (!lower.hasTag(BOT) && isUpperObject) {
bound = lower;
bk = SUPER;
} else {
bound = upper;
bk = isUpperObject ? UNBOUND : EXTENDS;
}
return new WildcardType(bound, bk, syms.boundClass);
}
@Override
public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
if (vars.contains(t)) {
try {
if (seen.add(t)) {
final Type bound;
switch (pkind) {
case UPWARDS:
bound = t.getUpperBound();
break;
case DOWNWARDS:
bound = (t.getLowerBound() == null) ?
syms.botType :
t.getLowerBound();
break;
default:
Assert.error();
return null;
}
return bound.map(this, pkind);
} else {
//cycle
return syms.objectType;
}
} finally {
seen.remove(t);
}
} else {
return t;
}
}
@Override
public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
switch (pkind) {
case UPWARDS:
return wt.isExtendsBound() ?
wt.type.map(this, pkind) :
syms.objectType;
case DOWNWARDS:
return wt.isSuperBound() ?
wt.type.map(this, pkind) :
syms.botType;
default:
Assert.error();
return null;
}
}
private Type mapTypeArgument(Type t, ProjectionKind pkind) {
if (!t.containsAny(vars)) {
return t;
} else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
//not defined
return syms.botType;
} else {
Type upper = t.map(this, pkind);
Type lower = t.map(this, pkind.complement());
return makeWildcard(upper, lower);
}
}
}
/**
* Computes an upward projection of given type, and vars. See {@link TypeProjection}.
*
* @param t the type to be projected
* @param vars the set of type variables to be mapped
* @return the type obtained as result of the projection
*/
public Type upward(Type t, List<Type> vars) {
return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
}
/**
* Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
* This routine is typically used to computed the input set of variables to be used during
* an upwards projection (see {@link Types#upward(Type, List)}).
*
* @param t the type where occurrences of captured variables have to be found
* @return the set of captured variables found in t
*/
public List<Type> captures(Type t) {
CaptureScanner cs = new CaptureScanner();
Set<Type> captures = new HashSet<>();
cs.visit(t, captures);
return List.from(captures);
}
/**
* This visitor scans a type recursively looking for occurrences of captured type variables.
*/
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
@Override
public Void visitType(Type t, Set<Type> types) {
return null;
}
@Override
public Void visitClassType(ClassType t, Set<Type> seen) {
if (t.isCompound()) {
directSupertypes(t).forEach(s -> visit(s, seen));
} else {
t.allparams().forEach(ta -> visit(ta, seen));
}
return null;
}
@Override
public Void visitArrayType(ArrayType t, Set<Type> seen) {
return visit(t.elemtype, seen);
}
@Override
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
visit(t.type, seen);
return null;
}
@Override
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
visit(t.getUpperBound(), seen);
}
return null;
}
@Override
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
if (seen.add(t)) {
visit(t.getUpperBound(), seen);
visit(t.getLowerBound(), seen);
}
return null;
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="isUnbounded">
/**
* Checks that all the arguments to a class are unbounded

View File

@ -83,6 +83,7 @@ import com.sun.tools.javac.util.DiagnosticSource;
import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
@ -139,7 +140,8 @@ public class Analyzer {
enum AnalyzerMode {
DIAMOND("diamond", Source::allowDiamond),
LAMBDA("lambda", Source::allowLambda),
METHOD("method", Source::allowGraphInference);
METHOD("method", Source::allowGraphInference),
LOCAL("local", Source::allowLocalVariableTypeInference);
final String opt;
final Predicate<Source> sourceFilter;
@ -341,11 +343,91 @@ public class Analyzer {
}
}
/**
* Base class for local variable inference analyzers.
*/
abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
super(AnalyzerMode.LOCAL, tag);
}
/**
* Map a variable tree into a new declaration using implicit type.
*/
JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
newTree.vartype = null;
return newTree;
}
/**
* Analyze results of local variable inference.
*/
void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
if (!hasErrors) {
if (types.isSameType(oldTree.type, newTree.type)) {
log.warning(oldTree, Warnings.LocalRedundantType);
}
}
}
}
/**
* This analyzer checks if a local variable declaration has redundant type.
*/
class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
RedundantLocalVarTypeAnalyzer() {
super(VARDEF);
}
boolean match(JCVariableDecl tree){
return tree.sym.owner.kind == Kind.MTH &&
tree.init != null && !tree.isImplicitlyTyped() &&
attr.canInferLocalVarType(tree) == null;
}
@Override
JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
return mapVar(oldTree, newTree);
}
@Override
void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
processVar(oldTree, newTree, hasErrors);
}
}
/**
* This analyzer checks if a for each variable declaration has redundant type.
*/
class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
RedundantLocalVarTypeAnalyzerForEach() {
super(FOREACHLOOP);
}
@Override
boolean match(JCEnhancedForLoop tree){
return !tree.var.isImplicitlyTyped();
}
@Override
JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
newTree.var = mapVar(oldTree.var, newTree.var);
newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
return newTree;
}
@Override
void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
processVar(oldTree.var, newTree.var, hasErrors);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
new DiamondInitializer(),
new LambdaAnalyzer(),
new RedundantTypeArgAnalyzer()
new RedundantTypeArgAnalyzer(),
new RedundantLocalVarTypeAnalyzer(),
new RedundantLocalVarTypeAnalyzerForEach()
};
/**

View File

@ -28,9 +28,11 @@ package com.sun.tools.javac.comp;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.Compound;
import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Kinds.KindSelector;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.*;
@ -602,7 +604,7 @@ public class Annotate {
}
private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
Type result = attr.attribExpr(tree, env, expectedElementType);
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
Symbol sym = TreeInfo.symbol(tree);
if (sym == null ||
TreeInfo.nonstaticSelect(tree) ||
@ -616,7 +618,7 @@ public class Annotate {
}
private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
Type result = attr.attribExpr(tree, env, expectedElementType);
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
if (result.isErroneous()) {
// Does it look like an unresolved class literal?
if (TreeInfo.name(tree) == names._class &&
@ -642,7 +644,7 @@ public class Annotate {
}
private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
Type result = attr.attribExpr(tree, env, expectedElementType);
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
if (result.isErroneous())
return new Attribute.Error(result.getOriginalType());
if (result.constValue() == null) {
@ -653,6 +655,22 @@ public class Annotate {
return new Attribute.Constant(expectedElementType, result.constValue());
}
private Attr.ResultInfo annotationValueInfo(Type pt) {
return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
}
class AnnotationValueContext extends Check.NestedCheckContext {
AnnotationValueContext(CheckContext enclosingContext) {
super(enclosingContext);
}
@Override
public boolean compatible(Type found, Type req, Warner warn) {
//handle non-final implicitly-typed vars (will be rejected later on)
return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
}
}
private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
// Special case, implicit array
if (!tree.hasTag(NEWARRAY)) {

View File

@ -36,7 +36,6 @@ import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.TreeVisitor;
import com.sun.source.util.SimpleTreeVisitor;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Directive.RequiresFlag;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Symbol.*;
@ -46,7 +45,6 @@ import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
import com.sun.tools.javac.comp.Check.CheckContext;
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
import com.sun.tools.javac.jvm.*;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@ -830,6 +828,10 @@ public class Attr extends JCTree.Visitor {
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
try {
Type itype = attribExpr(variable.init, env, type);
if (variable.isImplicitlyTyped()) {
//fixup local variable type
type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
}
if (itype.constValue() != null) {
return coerce(itype, type).constValue();
} else {
@ -1108,6 +1110,21 @@ 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.init == null) {
//cannot use 'var' without initializer
log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
tree.vartype = make.Erroneous();
} 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.Erroneous();
}
}
}
try {
annotate.blockAnnotations();
memberEnter.memberEnter(tree, env);
@ -1131,7 +1148,7 @@ public class Attr extends JCTree.Visitor {
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
(tree.sym.flags() & PARAMETER) != 0;
chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
try {
v.getConstValue(); // ensure compile-time constant initializer is evaluated
@ -1152,6 +1169,10 @@ public class Attr extends JCTree.Visitor {
// marking the variable as undefined.
initEnv.info.enclVar = v;
attribExpr(tree.init, initEnv, v.type);
if (tree.isImplicitlyTyped()) {
//fixup local variable type
v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
}
}
}
result = tree.type = v.type;
@ -1161,6 +1182,71 @@ public class Attr extends JCTree.Visitor {
}
}
Fragment canInferLocalVarType(JCVariableDecl tree) {
LocalInitScanner lis = new LocalInitScanner();
lis.scan(tree.init);
return lis.badInferenceMsg;
}
static class LocalInitScanner extends TreeScanner {
Fragment badInferenceMsg = null;
boolean needsTarget = true;
@Override
public void visitNewArray(JCNewArray tree) {
if (tree.elemtype == null && needsTarget) {
badInferenceMsg = Fragments.LocalArrayMissingTarget;
}
}
@Override
public void visitLambda(JCLambda tree) {
if (needsTarget) {
badInferenceMsg = Fragments.LocalLambdaMissingTarget;
}
}
@Override
public void visitTypeCast(JCTypeCast tree) {
boolean prevNeedsTarget = needsTarget;
try {
needsTarget = false;
super.visitTypeCast(tree);
} finally {
needsTarget = prevNeedsTarget;
}
}
@Override
public void visitReference(JCMemberReference tree) {
if (needsTarget) {
badInferenceMsg = Fragments.LocalMrefMissingTarget;
}
}
@Override
public void visitNewClass(JCNewClass tree) {
boolean prevNeedsTarget = needsTarget;
try {
needsTarget = false;
super.visitNewClass(tree);
} finally {
needsTarget = prevNeedsTarget;
}
}
@Override
public void visitApply(JCMethodInvocation tree) {
boolean prevNeedsTarget = needsTarget;
try {
needsTarget = false;
super.visitApply(tree);
} finally {
needsTarget = prevNeedsTarget;
}
}
}
public void visitSkip(JCSkip tree) {
result = null;
}
@ -1243,7 +1329,6 @@ public class Attr extends JCTree.Visitor {
//attributing the for-each expression; we mimick this by attributing
//the for-each expression first (against original scope).
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
attribStat(tree.var, loopEnv);
chk.checkNonVoid(tree.pos(), exprType);
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
if (elemtype == null) {
@ -1261,6 +1346,15 @@ public class Attr extends JCTree.Visitor {
: types.wildUpperBound(iterableParams.head);
}
}
if (tree.var.isImplicitlyTyped()) {
Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
if (inferredType.isErroneous()) {
tree.var.vartype = make.at(tree.var.vartype).Erroneous();
} else {
tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
}
}
attribStat(tree.var, loopEnv);
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
loopEnv.tree = tree; // before, we were not in loop!
attribStat(tree.body, loopEnv);
@ -2379,7 +2473,8 @@ public class Attr extends JCTree.Visitor {
if (pt().hasTag(ARRAY)) {
elemtype = types.elemtype(pt());
} else {
if (!pt().hasTag(ERROR)) {
if (!pt().hasTag(ERROR) &&
(env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
log.error(tree.pos(),
Errors.IllegalInitializerForType(pt()));
}
@ -2404,7 +2499,7 @@ public class Attr extends JCTree.Visitor {
@Override
public void visitLambda(final JCLambda that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
if (pt().hasTag(NONE)) {
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//lambda only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedLambda);
}
@ -2837,7 +2932,7 @@ public class Attr extends JCTree.Visitor {
@Override
public void visitReference(final JCMemberReference that) {
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
if (pt().hasTag(NONE)) {
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
//method reference only allowed in assignment or method invocation/cast context
log.error(that.pos(), Errors.UnexpectedMref);
}
@ -3811,6 +3906,14 @@ public class Attr extends JCTree.Visitor {
break;
case VAR:
VarSymbol v = (VarSymbol)sym;
if (env.info.enclVar != null
&& v.type.hasTag(NONE)) {
//self reference to implicitly typed variable declaration
log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
return v.type = types.createErrorType(v.type);
}
// Test (4): if symbol is an instance field of a raw type,
// which is being assigned to, issue an unchecked warning if
// its type changes under erasure.
@ -4135,6 +4238,9 @@ public class Attr extends JCTree.Visitor {
public void visitTypeArray(JCArrayTypeTree tree) {
Type etype = attribType(tree.elemtype, env);
Type type = new ArrayType(etype, syms.arrayClass);
if (etype.isErroneous()) {
type = types.createErrorType(type);
}
result = check(tree, type, KindSelector.TYP, resultInfo);
}
@ -4776,7 +4882,7 @@ public class Attr extends JCTree.Visitor {
}
public void visitVarDef(final JCVariableDecl tree) {
//System.err.println("validateTypeAnnotations.visitVarDef " + tree);
if (tree.sym != null && tree.sym.type != null)
if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
validateAnnotatedType(tree.vartype, tree.sym.type);
scan(tree.mods);
scan(tree.vartype);
@ -4904,17 +5010,16 @@ public class Attr extends JCTree.Visitor {
repeat = false;
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
JCWildcard wc = (JCWildcard) enclTr;
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
} else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
validateAnnotatedType(wc.getBound(), wc.getBound().type);
} else {
// Nothing to do for UNBOUND
}
repeat = false;
} else if (enclTr.hasTag(TYPEARRAY)) {
JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
validateAnnotatedType(art.getType(), art.elemtype.type);
repeat = false;
} else if (enclTr.hasTag(TYPEUNION)) {
JCTypeUnion ut = (JCTypeUnion) enclTr;

View File

@ -843,26 +843,30 @@ public class Check {
List<Type> checkDiamondDenotable(ClassType t) {
ListBuffer<Type> buf = new ListBuffer<>();
for (Type arg : t.allparams()) {
if (!diamondTypeChecker.visit(arg, null)) {
if (!checkDenotable(arg)) {
buf.append(arg);
}
}
return buf.toList();
}
boolean checkDenotable(Type t) {
return denotableChecker.visit(t, null);
}
// where
/** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
* types. The visit methods return false as soon as a non-denotable type is encountered and true
* otherwise.
*/
private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
@Override
public Boolean visitType(Type t, Void s) {
return true;
}
@Override
public Boolean visitClassType(ClassType t, Void s) {
if (t.isCompound()) {
if (t.isUnion() || t.isIntersection()) {
return false;
}
for (Type targ : t.allparams()) {
@ -878,7 +882,7 @@ public class Check {
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by inference (18.4))
*/
return t.tsym.owner.type.getTypeArguments().contains(t);
return (t.tsym.flags() & SYNTHETIC) == 0;
}
@Override
@ -941,6 +945,17 @@ public class Check {
(allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
}
Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
//upward project the initializer type
t = types.upward(t, types.captures(t));
//check that resulting type is not the null type
if (t.hasTag(BOT)) {
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
return types.createErrorType(t);
}
return t;
}
Type checkMethod(final Type mtype,
final Symbol sym,
final Env<AttrContext> env,
@ -3159,7 +3174,10 @@ public class Check {
if (s.kind == PCK)
return true;
} else if (target == names.TYPE_USE) {
if (s.kind == TYP || s.kind == VAR ||
if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
//cannot type annotate implictly typed locals
return false;
} else if (s.kind == TYP || s.kind == VAR ||
(s.kind == MTH && !s.isConstructor() &&
!s.type.getReturnType().hasTag(VOID)) ||
(s.kind == MTH && s.isConstructor())) {

View File

@ -529,7 +529,7 @@ public class Infer {
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
if (Type.containsAny(upperBounds, vars)) {
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
todo.append(uv);
uv.setInst(fresh_tvar.type);
} else if (upperBounds.nonEmpty()) {

View File

@ -259,7 +259,7 @@ public class MemberEnter extends JCTree.Visitor {
try {
if (TreeInfo.isEnumInit(tree)) {
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
} else {
} else if (!tree.isImplicitlyTyped()) {
attr.attribType(tree.vartype, localEnv);
if (TreeInfo.isReceiverParam(tree))
checkReceiver(tree, localEnv);
@ -279,8 +279,8 @@ public class MemberEnter extends JCTree.Visitor {
tree.vartype.type = atype.makeVarargs();
}
WriteableScope enclScope = enter.enterScope(env);
VarSymbol v =
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
tree.sym = v;
if (tree.init != null) {
@ -298,7 +298,9 @@ public class MemberEnter extends JCTree.Visitor {
}
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
if (!tree.isImplicitlyTyped()) {
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
}
v.pos = tree.pos;
}

View File

@ -105,6 +105,7 @@ public class Resolve {
public final boolean allowModules;
public final boolean checkVarargsAccessAfterResolution;
private final boolean compactMethodDiags;
private final boolean allowLocalVariableTypeInference;
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
WriteableScope polymorphicSignatureScope;
@ -136,6 +137,7 @@ public class Resolve {
Target target = Target.instance(context);
allowMethodHandles = target.hasMethodHandles();
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
checkVarargsAccessAfterResolution =
source.allowPostApplicabilityVarargsAccessCheck();
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
@ -2325,6 +2327,10 @@ public class Resolve {
* (a subset of VAL, TYP, PCK).
*/
Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
return checkVarType(findIdentInternal(env, name, kind), name);
}
Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound;
Symbol sym;
@ -2354,6 +2360,11 @@ public class Resolve {
*/
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
Name name, KindSelector kind) {
return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
}
Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
Name name, KindSelector kind) {
Name fullname = TypeSymbol.formFullName(name, pck);
Symbol bestSoFar = typeNotFound;
if (kind.contains(KindSelector.TYP)) {
@ -2383,6 +2394,11 @@ public class Resolve {
*/
Symbol findIdentInType(Env<AttrContext> env, Type site,
Name name, KindSelector kind) {
return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
}
Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
Name name, KindSelector kind) {
Symbol bestSoFar = typeNotFound;
Symbol sym;
if (kind.contains(KindSelector.VAL)) {
@ -2399,6 +2415,14 @@ public class Resolve {
return bestSoFar;
}
private Symbol checkVarType(Symbol bestSoFar, Name name) {
if (allowLocalVariableTypeInference && name.equals(names.var) &&
(bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
bestSoFar = new BadVarTypeError();
}
return bestSoFar;
}
/* ***************************************************************************
* Access checking
* The following methods convert ResolveErrors to ErrorSymbols, issuing
@ -3774,6 +3798,17 @@ public class Resolve {
}
}
class BadVarTypeError extends ResolveError {
BadVarTypeError() {
super(Kind.BAD_VAR, "bad var use");
}
@Override
JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
}
}
/**
* InvalidSymbolError error class indicating that a symbol matching a
* given name does not exists in a given site.

View File

@ -179,6 +179,7 @@ public class JavacParser implements Parser {
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
this.keepDocComments = keepDocComments;
this.parseModuleInfo = parseModuleInfo;
docComments = newDocCommentTable(keepDocComments, fac);
@ -270,11 +271,14 @@ public class JavacParser implements Parser {
*/
boolean allowThisIdent;
/** Switch: is local variable inference allowed?
*/
boolean allowLocalVariableTypeInference;
/** The type of the method receiver, as specified by a first "this" parameter.
*/
JCVariableDecl receiverParam;
/** When terms are parsed, the mode determines which is expected:
* mode = EXPR : an expression
* mode = TYPE : a type
@ -808,12 +812,16 @@ public class JavacParser implements Parser {
* parsing annotations.
*/
public JCExpression parseType() {
List<JCAnnotation> annotations = typeAnnotationsOpt();
return parseType(annotations);
return parseType(false);
}
public JCExpression parseType(List<JCAnnotation> annotations) {
JCExpression result = unannotatedType();
public JCExpression parseType(boolean allowVar) {
List<JCAnnotation> annotations = typeAnnotationsOpt();
return parseType(allowVar, annotations);
}
public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
JCExpression result = unannotatedType(allowVar);
if (annotations.nonEmpty()) {
result = insertAnnotationsToMostInner(result, annotations, false);
@ -822,10 +830,18 @@ public class JavacParser implements Parser {
return result;
}
public JCExpression unannotatedType() {
return term(TYPE);
public JCExpression unannotatedType(boolean allowVar) {
JCExpression result = term(TYPE);
if (!allowVar && isRestrictedLocalVarTypeName(result)) {
syntaxError(result.pos, "var.not.allowed.here");
}
return result;
}
protected JCExpression term(int newmode) {
int prevmode = mode;
mode = newmode;
@ -1152,11 +1168,11 @@ public class JavacParser implements Parser {
accept(LPAREN);
mode = TYPE;
int pos1 = pos;
List<JCExpression> targets = List.of(t = term3());
List<JCExpression> targets = List.of(t = parseType());
while (token.kind == AMP) {
checkIntersectionTypesInCast();
accept(AMP);
targets = targets.prepend(term3());
targets = targets.prepend(parseType());
}
if (targets.length() > 1) {
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
@ -1912,7 +1928,7 @@ public class JavacParser implements Parser {
*/
JCExpression typeArgument() {
List<JCAnnotation> annotations = typeAnnotationsOpt();
if (token.kind != QUES) return parseType(annotations);
if (token.kind != QUES) return parseType(false, annotations);
int pos = token.pos;
nextToken();
JCExpression result;
@ -2425,13 +2441,8 @@ public class JavacParser implements Parser {
token.kind == ENUM) {
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
} else {
JCExpression t = parseType();
ListBuffer<JCStatement> stats =
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
accept(SEMI);
storeEnd(stats.last(), S.prevToken().endPos);
return stats.toList();
JCExpression t = parseType(true);
return localVariableDeclarations(mods, t);
}
}
case ABSTRACT: case STRICTFP: {
@ -2458,12 +2469,7 @@ public class JavacParser implements Parser {
pos = token.pos;
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
F.at(pos);
ListBuffer<JCStatement> stats =
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
accept(SEMI);
storeEnd(stats.last(), S.prevToken().endPos);
return stats.toList();
return localVariableDeclarations(mods, t);
} else {
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
t = checkExprStat(t);
@ -2473,6 +2479,15 @@ public class JavacParser implements Parser {
}
}
}
//where
private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
ListBuffer<JCStatement> stats =
variableDeclarators(mods, type, new ListBuffer<>(), true);
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
accept(SEMI);
storeEnd(stats.last(), S.prevToken().endPos);
return stats.toList();
}
/** Statement =
* Block
@ -2766,11 +2781,11 @@ public class JavacParser implements Parser {
ListBuffer<JCStatement> stats = new ListBuffer<>();
int pos = token.pos;
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
return variableDeclarators(optFinal(0), parseType(), stats).toList();
return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
} else {
JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
return variableDeclarators(modifiersOpt(), t, stats).toList();
return variableDeclarators(modifiersOpt(), t, stats, true).toList();
} else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
error(pos, "bad.initializer", "for-loop");
return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
@ -2989,9 +3004,10 @@ public class JavacParser implements Parser {
*/
public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
JCExpression type,
T vdefs)
T vdefs,
boolean localDecl)
{
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
}
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
@ -3006,14 +3022,20 @@ public class JavacParser implements Parser {
Name name,
boolean reqInit,
Comment dc,
T vdefs)
T vdefs,
boolean localDecl)
{
vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
vdefs.append(head);
while (token.kind == COMMA) {
if (implicit) {
reportSyntaxError(pos, "var.not.allowed.compound");
}
// All but last of multiple declarators subsume a comma
storeEnd((JCTree)vdefs.last(), token.endPos);
nextToken();
vdefs.append(variableDeclarator(mods, type, reqInit, dc));
vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
}
return vdefs;
}
@ -3021,8 +3043,8 @@ public class JavacParser implements Parser {
/** VariableDeclarator = Ident VariableDeclaratorRest
* ConstantDeclarator = Ident ConstantDeclaratorRest
*/
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
}
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
@ -3032,7 +3054,7 @@ public class JavacParser implements Parser {
* @param dc The documentation comment for the variable declarations, or null.
*/
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
boolean reqInit, Comment dc) {
boolean reqInit, Comment dc, boolean localDecl) {
type = bracketsOpt(type);
JCExpression init = null;
if (token.kind == EQ) {
@ -3040,12 +3062,40 @@ public class JavacParser implements Parser {
init = variableInitializer();
}
else if (reqInit) syntaxError(token.pos, "expected", EQ);
JCTree elemType = TreeInfo.innermostType(type, true);
if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
Name typeName = ((JCIdent)elemType).name;
if (isRestrictedLocalVarTypeName(typeName)) {
if (type.hasTag(TYPEARRAY)) {
//error - 'var' and arrays
reportSyntaxError(pos, "var.not.allowed.array");
} else {
//implicit type
type = null;
}
}
}
JCVariableDecl result =
toP(F.at(pos).VarDef(mods, name, type, init));
attach(result, dc);
return result;
}
boolean isRestrictedLocalVarTypeName(JCExpression e) {
switch (e.getTag()) {
case IDENT:
return isRestrictedLocalVarTypeName(((JCIdent)e).name);
case TYPEARRAY:
return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
default:
return false;
}
}
boolean isRestrictedLocalVarTypeName(Name name) {
return allowLocalVariableTypeInference && name == names.var;
}
/** VariableDeclaratorId = Ident BracketsOpt
*/
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
@ -3111,13 +3161,13 @@ public class JavacParser implements Parser {
int startPos = token.pos;
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
JCModifiers mods = optFinal(Flags.FINAL);
JCExpression t = parseType();
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
JCExpression t = parseType(true);
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
}
JCExpression t = term(EXPR | TYPE);
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
} else {
checkVariableInTryWithResources(startPos);
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
@ -3397,7 +3447,7 @@ public class JavacParser implements Parser {
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos;
accept(CLASS);
Name name = ident();
Name name = typeName();
List<JCTypeParameter> typarams = typeParametersOpt();
@ -3418,6 +3468,15 @@ public class JavacParser implements Parser {
return result;
}
Name typeName() {
int pos = token.pos;
Name name = ident();
if (isRestrictedLocalVarTypeName(name)) {
reportSyntaxError(pos, "var.not.allowed", name);
}
return name;
}
/** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
* [EXTENDS TypeList] InterfaceBody
* @param mods The modifiers starting the interface declaration
@ -3426,7 +3485,8 @@ public class JavacParser implements Parser {
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos;
accept(INTERFACE);
Name name = ident();
Name name = typeName();
List<JCTypeParameter> typarams = typeParametersOpt();
@ -3449,7 +3509,8 @@ public class JavacParser implements Parser {
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
int pos = token.pos;
accept(ENUM);
Name name = ident();
Name name = typeName();
List<JCExpression> implementing = List.nil();
if (token.kind == IMPLEMENTS) {
@ -3647,7 +3708,7 @@ public class JavacParser implements Parser {
nextToken();
} else {
// method returns types are un-annotated types
type = unannotatedType();
type = unannotatedType(false);
}
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
if (isInterface || tk.name() != className)
@ -3667,7 +3728,7 @@ public class JavacParser implements Parser {
} else if (!isVoid && typarams.isEmpty()) {
List<JCTree> defs =
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
new ListBuffer<JCTree>()).toList();
new ListBuffer<JCTree>(), false).toList();
accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos);
return defs;
@ -3809,7 +3870,7 @@ public class JavacParser implements Parser {
JCTypeParameter typeParameter() {
int pos = token.pos;
List<JCAnnotation> annos = typeAnnotationsOpt();
Name name = ident();
Name name = typeName();
ListBuffer<JCExpression> bounds = new ListBuffer<>();
if (token.kind == EXTENDS) {
nextToken();

View File

@ -1190,6 +1190,47 @@ compiler.err.io.exception=\
compiler.err.undef.label=\
undefined label: {0}
# 0: name (type)
compiler.err.illegal.ref.to.var.type=\
illegal reference to restricted type ''{0}''
# 0: token
compiler.err.var.not.allowed=\
''{0}'' not allowed here\n\
as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
# 0: name (variable), 1: message segment
compiler.err.cant.infer.local.var.type=\
cannot infer type for local variable {0}\n\
({1})
compiler.err.var.not.allowed.here=\
''var'' is not allowed here
compiler.err.var.not.allowed.array=\
''var'' is not allowed as an element type of an array
compiler.err.var.not.allowed.compound=\
''var'' is not allowed in a compound declaration
compiler.misc.local.cant.infer.null=\
variable initializer is ''null''
compiler.misc.local.missing.init=\
cannot use ''var'' on variable without initializer
compiler.misc.local.lambda.missing.target=\
lambda expression needs an explicit target-type
compiler.misc.local.mref.missing.target=\
method reference needs an explicit target-type
compiler.misc.local.array.missing.target=\
array initializer needs an explicit target-type
compiler.misc.local.self.ref=\
cannot use ''var'' on self-referencing variable
# 0: message segment, 1: unused
compiler.err.cant.apply.diamond=\
cannot infer type arguments for {0}
@ -1873,6 +1914,9 @@ compiler.warn.raw.class.use=\
compiler.warn.diamond.redundant.args=\
Redundant type arguments in new expression (use diamond operator instead).
compiler.warn.local.redundant.type=\
Redundant type for local variable (replace explicit type with ''var'').
compiler.warn.potential.lambda.found=\
This anonymous inner class creation can be turned into a lambda expression.

View File

@ -946,6 +946,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
}
}
public boolean isImplicitlyTyped() {
return vartype == null;
}
@Override
public void accept(Visitor v) { v.visitVarDef(this); }

View File

@ -1359,7 +1359,7 @@ public class Pretty extends JCTree.Visitor {
// Prints the inner element type of a nested array
private void printBaseElementType(JCTree tree) throws IOException {
printExpr(TreeInfo.innermostType(tree));
printExpr(TreeInfo.innermostType(tree, false));
}
// prints the brackets of a nested array in reverse order

View File

@ -1136,7 +1136,7 @@ public class TreeInfo {
* For an array that contains an annotated type, return that annotated type.
* TODO: currently only used by Pretty. Describe behavior better.
*/
public static JCTree innermostType(JCTree type) {
public static JCTree innermostType(JCTree type, boolean skipAnnos) {
JCTree lastAnnotatedType = null;
JCTree cur = type;
loop: while (true) {
@ -1157,7 +1157,7 @@ public class TreeInfo {
break loop;
}
}
if (lastAnnotatedType!=null) {
if (!skipAnnos && lastAnnotatedType!=null) {
return lastAnnotatedType;
} else {
return cur;

View File

@ -63,6 +63,7 @@ public class Names {
public final Name _default;
public final Name _super;
public final Name _this;
public final Name var;
public final Name exports;
public final Name opens;
public final Name module;
@ -224,6 +225,7 @@ public class Names {
_default = fromString("default");
_super = fromString("super");
_this = fromString("this");
var = fromString("var");
exports = fromString("exports");
opens = fromString("opens");
module = fromString("module");

View File

@ -106,7 +106,8 @@ module jdk.compiler {
exports com.sun.tools.javac.jvm to
jdk.javadoc;
exports com.sun.tools.javac.main to
jdk.javadoc;
jdk.javadoc,
jdk.jshell;
exports com.sun.tools.javac.model to
jdk.javadoc;
exports com.sun.tools.javac.parser to

View File

@ -40,6 +40,7 @@ import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.tools.javac.tree.JCTree;
@ -59,6 +60,7 @@ import jdk.jshell.TaskFactory.AnalyzeTask;
import jdk.jshell.TaskFactory.BaseTask;
import jdk.jshell.TaskFactory.CompileTask;
import jdk.jshell.TaskFactory.ParseTask;
import jdk.jshell.Wrap.CompoundWrap;
import jdk.jshell.Wrap.Range;
import jdk.jshell.Snippet.Status;
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
@ -274,26 +276,119 @@ class Eval {
for (Tree unitTree : units) {
VariableTree vt = (VariableTree) unitTree;
String name = vt.getName().toString();
String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
Tree baseType = vt.getType();
String typeName;
String fullTypeName;
TreeDependencyScanner tds = new TreeDependencyScanner();
tds.scan(baseType); // Not dependent on initializer
Wrap typeWrap;
Wrap anonDeclareWrap = null;
Wrap winit = null;
StringBuilder sbBrackets = new StringBuilder();
while (baseType instanceof ArrayTypeTree) {
//TODO handle annotations too
baseType = ((ArrayTypeTree) baseType).getType();
sbBrackets.append("[]");
Tree baseType = vt.getType();
if (baseType != null) {
tds.scan(baseType); // Not dependent on initializer
fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
while (baseType instanceof ArrayTypeTree) {
//TODO handle annotations too
baseType = ((ArrayTypeTree) baseType).getType();
sbBrackets.append("[]");
}
Range rtype = dis.treeToRange(baseType);
typeWrap = Wrap.rangeWrap(compileSource, rtype);
} else {
Tree init = vt.getInitializer();
if (init != null) {
Range rinit = dis.treeToRange(init);
String initCode = rinit.part(compileSource);
ExpressionInfo ei =
ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
typeName = ei == null ? "java.lang.Object" : ei.typeName;
fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
((NewClassTree) init).getClassBody() != null) {
NewClassTree nct = (NewClassTree) init;
StringBuilder constructor = new StringBuilder();
constructor.append(fullTypeName).append("(");
String sep = "";
if (ei.enclosingInstanceType != null) {
constructor.append(ei.enclosingInstanceType);
constructor.append(" encl");
sep = ", ";
}
int idx = 0;
for (String type : ei.parameterTypes) {
constructor.append(sep);
constructor.append(type);
constructor.append(" ");
constructor.append("arg" + idx++);
sep = ", ";
}
if (ei.enclosingInstanceType != null) {
constructor.append(") { encl.super (");
} else {
constructor.append(") { super (");
}
sep = "";
for (int i = 0; i < idx; i++) {
constructor.append(sep);
constructor.append("arg" + i++);
sep = ", ";
}
constructor.append("); }");
List<? extends Tree> members = nct.getClassBody().getMembers();
Range bodyRange = dis.treeListToRange(members);
Wrap bodyWrap;
if (bodyRange != null) {
bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
} else {
bodyWrap = Wrap.simpleWrap(" ");
}
Range argRange = dis.treeListToRange(nct.getArguments());
Wrap argWrap;
if (argRange != null) {
argWrap = Wrap.rangeWrap(compileSource, argRange);
} else {
argWrap = Wrap.simpleWrap(" ");
}
if (ei.enclosingInstanceType != null) {
Range enclosingRanges =
dis.treeToRange(nct.getEnclosingExpression());
Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
Wrap.simpleWrap(","),
argWrap)
: enclosingWrap;
}
Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
(ei.isClass ? " extends " : " implements ") +
typeName + " { " + constructor);
anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
String superType = typeName;
typeName = fullTypeName;
fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
: "<anonymous class implementing " + superType + ">";
}
tds.scan(init);
} else {
fullTypeName = typeName = "java.lang.Object";
}
typeWrap = Wrap.identityWrap(typeName);
}
Range rtype = dis.treeToRange(baseType);
Range runit = dis.treeToRange(vt);
runit = new Range(runit.begin, runit.end - 1);
ExpressionTree it = vt.getInitializer();
Range rinit = null;
int nameMax = runit.end - 1;
SubKind subkind;
if (it != null) {
subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
rinit = dis.treeToRange(it);
Range rinit = dis.treeToRange(it);
winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
nameMax = rinit.begin - 1;
} else {
subkind = SubKind.VAR_DECLARATION_SUBKIND;
@ -304,10 +399,11 @@ class Eval {
}
int nameEnd = nameStart + name.length();
Range rname = new Range(nameStart, nameEnd);
Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
winit, anonDeclareWrap);
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
name, subkind, typeName,
name, subkind, fullTypeName,
tds.declareReferences(), modDiag);
snippets.add(snip);
}

View File

@ -29,14 +29,20 @@ import com.sun.source.tree.ReturnTree;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ConditionalExpressionTree;
import com.sun.source.tree.ExpressionStatementTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.util.List;
import jdk.jshell.TaskFactory.AnalyzeTask;
/**
@ -63,6 +69,10 @@ class ExpressionToTypeInfo {
public static class ExpressionInfo {
ExpressionTree tree;
String typeName;
String fullTypeName;
List<String> parameterTypes;
String enclosingInstanceType;
boolean isClass;
boolean isNonVoid;
}
@ -111,6 +121,16 @@ class ExpressionToTypeInfo {
return null;
}
}
@Override
public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
if (isTargetContext) {
throw new Result(getCurrentPath());
} else {
return null;
}
}
}
private Type pathToType(TreePath tp) {
@ -156,6 +176,30 @@ class ExpressionToTypeInfo {
}
}
/**
* Entry method: get expression info corresponding to a local variable declaration if its type
* has been inferred automatically from the given initializer.
* @param code the initializer as a string
* @param state a JShell instance
* @return type information
*/
public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
if (code == null || code.isEmpty()) {
return null;
}
try {
OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + code));
AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
CompilationUnitTree cu = at.firstCuTree();
if (at.hasErrors() || cu == null) {
return null;
}
return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
} catch (Exception ex) {
return null;
}
}
private ExpressionInfo typeOfExpression() {
return treeToInfo(findExpressionPath());
}
@ -172,9 +216,11 @@ class ExpressionToTypeInfo {
private ExpressionInfo treeToInfo(TreePath tp) {
if (tp != null) {
Tree tree = tp.getLeaf();
if (tree instanceof ExpressionTree) {
boolean isExpression = tree instanceof ExpressionTree;
if (isExpression || tree.getKind() == Kind.VARIABLE) {
ExpressionInfo ei = new ExpressionInfo();
ei.tree = (ExpressionTree) tree;
if (isExpression)
ei.tree = (ExpressionTree) tree;
Type type = pathToType(tp, tree);
if (type != null) {
switch (type.getKind()) {
@ -189,27 +235,56 @@ class ExpressionToTypeInfo {
break;
default: {
ei.isNonVoid = true;
ei.typeName = varTypeName(type);
if (ei.typeName == null) {
ei.typeName = OBJECT_TYPE_NAME;
}
ei.typeName = varTypeName(type, false);
ei.fullTypeName = varTypeName(type, true);
break;
}
}
}
if (tree.getKind() == Tree.Kind.VARIABLE) {
Tree init = ((VariableTree) tree).getInitializer();
if (init.getKind() == Tree.Kind.NEW_CLASS &&
((NewClassTree) init).getClassBody() != null) {
NewClassTree nct = (NewClassTree) init;
ClassTree clazz = nct.getClassBody();
MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
ExpressionStatementTree superCallStatement =
(ExpressionStatementTree) constructor.getBody().getStatements().get(0);
MethodInvocationTree superCall =
(MethodInvocationTree) superCallStatement.getExpression();
TreePath superCallPath =
at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
Type constrType = pathToType(superCallPath);
ei.parameterTypes = constrType.getParameterTypes()
.stream()
.map(t -> varTypeName(t, false))
.collect(List.collector());
if (nct.getEnclosingExpression() != null) {
TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
}
ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
}
}
return ei;
}
}
return null;
}
private String varTypeName(Type type) {
private String varTypeName(Type type, boolean printIntersectionTypes) {
try {
TypePrinter tp = new VarTypePrinter(at.messages(),
state.maps::fullClassNameAndPackageToClass, syms, types);
return tp.toString(type);
TypePrinter tp = new TypePrinter(at.messages(),
state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
List<Type> captures = types.captures(type);
String res = tp.toString(types.upward(type, captures));
if (res == null)
res = OBJECT_TYPE_NAME;
return res;
} catch (Exception ex) {
return null;
return OBJECT_TYPE_NAME;
}
}

View File

@ -232,7 +232,7 @@ class ReplParser extends JavacParser {
//mods.flags |= Flags.STATIC;
List<JCTree> defs
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
new ListBuffer<JCTree>()).toList();
new ListBuffer<JCTree>(), true).toList();
accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos);
return defs;

View File

@ -134,6 +134,8 @@ import static jdk.jshell.TreeDissector.printType;
import static java.util.stream.Collectors.joining;
import javax.lang.model.type.IntersectionType;
/**
* The concrete implementation of SourceCodeAnalysis.
* @author Robert Field
@ -715,6 +717,13 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
return Collections.emptyList();
switch (site.getKind()) {
case INTERSECTION: {
List<Element> result = new ArrayList<>();
for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
}
return result;
}
case DECLARED: {
TypeElement element = (TypeElement) at.getTypes().asElement(site);
List<Element> result = new ArrayList<>();

View File

@ -61,7 +61,20 @@ import javax.lang.model.util.Elements;
import javax.tools.FileObject;
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
import java.lang.Runtime.Version;
import java.nio.CharBuffer;
import com.sun.source.tree.Tree.Kind;
import com.sun.tools.javac.code.Kinds;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.Tag;
import com.sun.tools.javac.util.Context.Factory;
import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
import jdk.jshell.Snippet.Status;
/**
* The primary interface to the compiler API. Parsing, analysis, and
@ -355,6 +368,7 @@ class TaskFactory {
Iterable<? extends JavaFileObject> compilationUnits = inputs
.map(in -> sh.sourceToFileObject(fileManager, in))
.collect(Collectors.toList());
JShellJavaCompiler.preRegister(context, state);
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
fileManager, diagnostics, options, null,
compilationUnits, context);
@ -464,4 +478,57 @@ class TaskFactory {
}
}
private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
public static void preRegister(Context c, JShell state) {
c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
}
private final JShell state;
public JShellJavaCompiler(Context context, JShell state) {
super(context);
this.state = state;
}
@Override
public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
super.processAnnotations(roots, classnames);
state.maps
.snippetList()
.stream()
.filter(s -> s.status() == Status.VALID)
.filter(s -> s.kind() == Snippet.Kind.VAR)
.filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
.forEach(s -> setVariableType(roots, (VarSnippet) s));
}
private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
if (clazz == null || !clazz.isCompleted())
return;
VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
if (field != null) {
JavaFileObject prev = log.useSource(null);
DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
try {
String typeName = s.typeName();
CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
Parser parser = parserFactory.newParser(buf, false, false, false);
JCExpression expr = parser.parseExpression();
if (expr.hasTag(Tag.TYPECAST)) {
JCTypeCast tree = (JCTypeCast) expr;
if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
field.type = attr.attribType(tree.clazz,
((JCClassDecl) roots.head.getTypeDecls().head).sym);
}
}
} finally {
log.popDiagnosticHandler(h);
log.useSource(prev);
}
}
}
}
}

View File

@ -227,7 +227,7 @@ class TreeDissector {
Type typeImpl = (Type) type;
try {
TypePrinter tp = new TypePrinter(at.messages(),
state.maps::fullClassNameAndPackageToClass);
state.maps::fullClassNameAndPackageToClass, true);
return tp.toString(typeImpl);
} catch (Exception ex) {
return null;

View File

@ -32,9 +32,11 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.Type.IntersectionClassType;
import com.sun.tools.javac.util.JavacMessages;
import java.util.Locale;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
/**
* Print types in source form.
@ -45,10 +47,14 @@ class TypePrinter extends Printer {
private final JavacMessages messages;
private final BinaryOperator<String> fullClassNameAndPackageToClass;
private final boolean printEnhancedTypes;
TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
TypePrinter(JavacMessages messages,
BinaryOperator<String> fullClassNameAndPackageToClass,
boolean printEnhancedTypes) {
this.messages = messages;
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
this.printEnhancedTypes = printEnhancedTypes;
}
String toString(Type t) {
@ -92,8 +98,18 @@ class TypePrinter extends Printer {
protected String className(ClassType t, boolean longform, Locale locale) {
Symbol sym = t.tsym;
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
return OBJECT;
if (printEnhancedTypes) {
return ((IntersectionClassType) t).getExplicitComponents()
.stream()
.map(i -> visit(i, locale))
.collect(Collectors.joining("&"));
} else {
return OBJECT;
}
} else if (sym.name.length() == 0) {
if (printEnhancedTypes) {
return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
}
// Anonymous
String s;
ClassType norm = (ClassType) t.tsym.type;

View File

@ -1,265 +0,0 @@
/*
* Copyright (c) 2016, 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 jdk.jshell;
import java.util.HashSet;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.util.JavacMessages;
import java.util.Locale;
import java.util.Set;
import java.util.function.BinaryOperator;
import com.sun.tools.javac.code.BoundKind;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.code.Type.StructuralTypeMapping;
import com.sun.tools.javac.code.Type.TypeVar;
import com.sun.tools.javac.code.Type.WildcardType;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.code.Types.SimpleVisitor;
import com.sun.tools.javac.util.List;
import static com.sun.tools.javac.code.BoundKind.EXTENDS;
import static com.sun.tools.javac.code.BoundKind.SUPER;
import static com.sun.tools.javac.code.BoundKind.UNBOUND;
import static com.sun.tools.javac.code.Type.ArrayType;
import static com.sun.tools.javac.code.TypeTag.BOT;
import static com.sun.tools.javac.code.TypeTag.WILDCARD;
/**
* Print variable types in source form.
* TypeProjection and CaptureScanner are copied from Types in the JEP-286
* Sandbox by Maurizio. The checks for Non-Denotable in TypePrinter are
* cribbed from denotableChecker of the same source.
*
* @author Maurizio Cimadamore
* @author Robert Field
*/
class VarTypePrinter extends TypePrinter {
private static final String WILD = "?";
private final Symtab syms;
private final Types types;
VarTypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass,
Symtab syms, Types types) {
super(messages, fullClassNameAndPackageToClass);
this.syms = syms;
this.types = types;
}
@Override
String toString(Type t) {
return super.toString(upward(t));
}
@Override
public String visitTypeVar(TypeVar t, Locale locale) {
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by inference (18.4))
*/
// and beyond that, there are no global type vars, so if there are any
// type variables left, they need to be eliminated
return WILD; // Non-denotable
}
@Override
public String visitCapturedType(CapturedType t, Locale locale) {
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
(i.e cannot have been produced by capture conversion (5.1.10))
*/
return WILD; // Non-denotable
}
public Type upward(Type t) {
List<Type> captures = captures(t);
return upward(t, captures);
}
/************* Following from JEP-286 Types.java ***********/
public Type upward(Type t, List<Type> vars) {
return t.map(new TypeProjection(vars), true);
}
public List<Type> captures(Type t) {
CaptureScanner cs = new CaptureScanner();
Set<Type> captures = new HashSet<>();
cs.visit(t, captures);
return List.from(captures);
}
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
@Override
public Void visitType(Type t, Set<Type> types) {
return null;
}
@Override
public Void visitClassType(ClassType t, Set<Type> seen) {
if (t.isCompound()) {
types.directSupertypes(t).forEach(s -> visit(s, seen));
} else {
t.allparams().forEach(ta -> visit(ta, seen));
}
return null;
}
@Override
public Void visitArrayType(ArrayType t, Set<Type> seen) {
return visit(t.elemtype, seen);
}
@Override
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
visit(t.type, seen);
return null;
}
@Override
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
visit(t.getUpperBound(), seen);
}
return null;
}
@Override
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
if (seen.add(t)) {
visit(t.getUpperBound(), seen);
visit(t.getLowerBound(), seen);
}
return null;
}
}
class TypeProjection extends StructuralTypeMapping<Boolean> {
List<Type> vars;
Set<Type> seen = new HashSet<>();
public TypeProjection(List<Type> vars) {
this.vars = vars;
}
@Override
public Type visitClassType(ClassType t, Boolean upward) {
if (upward && !t.isCompound() && t.tsym.name.isEmpty()) {
//lift anonymous class type to first supertype (class or interface)
return types.directSupertypes(t).last();
} else if (t.isCompound()) {
List<Type> components = types.directSupertypes(t);
List<Type> components1 = components.map(c -> c.map(this, upward));
if (components == components1) return t;
else return types.makeIntersectionType(components1);
} else {
Type outer = t.getEnclosingType();
Type outer1 = visit(outer, upward);
List<Type> typarams = t.getTypeArguments();
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, upward));
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
//not defined
return syms.botType;
}
if (outer1 == outer && typarams1 == typarams) return t;
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
@Override
protected boolean needsStripping() {
return true;
}
};
}
}
protected Type makeWildcard(Type upper, Type lower) {
BoundKind bk;
Type bound;
if (upper.hasTag(BOT)) {
upper = syms.objectType;
}
boolean isUpperObject = types.isSameType(upper, syms.objectType);
if (!lower.hasTag(BOT) && isUpperObject) {
bound = lower;
bk = SUPER;
} else {
bound = upper;
bk = isUpperObject ? UNBOUND : EXTENDS;
}
return new WildcardType(bound, bk, syms.boundClass);
}
@Override
public Type visitTypeVar(TypeVar t, Boolean upward) {
if (vars.contains(t)) {
try {
if (seen.add(t)) {
return (upward ?
t.getUpperBound() :
(t.getLowerBound() == null) ?
syms.botType :
t.getLowerBound())
.map(this, upward);
} else {
//cycle
return syms.objectType;
}
} finally {
seen.remove(t);
}
} else {
return t;
}
}
@Override
public Type visitWildcardType(WildcardType wt, Boolean upward) {
if (upward) {
return wt.isExtendsBound() ?
wt.type.map(this, upward) :
syms.objectType;
} else {
return wt.isSuperBound() ?
wt.type.map(this, upward) :
syms.botType;
}
}
private Type mapTypeArgument(Type t, boolean upward) {
if (!t.containsAny(vars)) {
return t;
} else if (!t.hasTag(WILDCARD) && !upward) {
//not defined
return syms.botType;
} else {
Type upper = t.map(this, upward);
Type lower = t.map(this, !upward);
return makeWildcard(upper, lower);
}
}
}
}

View File

@ -74,16 +74,15 @@ abstract class Wrap implements GeneralWrap {
* @param rdecl Type name and name
* @return
*/
public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
public static Wrap varWrap(String source, Wrap wtype, String brackets,
Range rname, Wrap winit, Wrap anonDeclareWrap) {
RangeWrap wname = new RangeWrap(source, rname);
RangeWrap wtype = new RangeWrap(source, rtype);
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
Wrap wmeth;
if (rinit == null) {
if (winit == null) {
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
} else {
RangeWrap winit = new RangeWrap(source, rinit);
// int x = y
// int x_ = y; return x = x_;
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
@ -93,7 +92,8 @@ abstract class Wrap implements GeneralWrap {
);
}
Wrap wInitMeth = new DoitMethodWrap(wmeth);
return new CompoundWrap(wVarDecl, wInitMeth);
return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
: new CompoundWrap(wVarDecl, wInitMeth);
}
public static Wrap tempVarWrap(String source, String typename, String name) {
@ -112,6 +112,14 @@ abstract class Wrap implements GeneralWrap {
return new NoWrap(source);
}
public static Wrap identityWrap(String source) {
return new NoWrap(source);
}
public static Wrap rangeWrap(String source, Range range) {
return new RangeWrap(source, range);
}
public static Wrap classMemberWrap(String source) {
Wrap w = new NoWrap(source);
return new CompoundWrap(" public static\n ", w);

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110
* @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466
* @summary Test Completion and Documentation
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
@ -645,6 +645,22 @@ public class CompletionSuggestionTest extends KullaTesting {
assertCompletion("Foo.m(new Baz<>(|", true, "str");
}
public void testIntersection() {
assertEval("<Z extends Runnable & CharSequence> Z get() { return null; }");
assertEval("var v = get();");
assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
assertCompletion("Runnable r = |", true, "get()", "v");
assertCompletion("CharSequence r = |", true, "get()", "v");
assertCompletion("Number r = |", true);
}
public void testAnonymous() {
assertEval("var v = new Runnable() { public void run() { } public int length() { return 0; } };");
assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
assertCompletion("Runnable r = |", true, "v");
assertCompletion("CharSequence r = |", true);
}
@BeforeMethod
public void setUp() {
super.setUp();

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466
* @summary Simple jshell tool tests
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@ -740,4 +740,26 @@ public class ToolSimpleTest extends ReplToolTesting {
(a) -> assertCommandOutputContains(a, "1234", "==> 1234")
);
}
@Test
public void testIntersection() {
test(
(a) -> assertCommandOutputContains(a, "<Z extends Runnable&CharSequence> Z get1() { return null; }", "get1()"),
(a) -> assertCommandOutputContains(a, "var g1 = get1()", "g1"),
(a) -> assertCommand(a, "/vars g1", "| CharSequence&Runnable g1 = null"),
(a) -> assertCommandOutputContains(a, "<Z extends Number&CharSequence> Z get2() { return null; }", "get2()"),
(a) -> assertCommandOutputContains(a, "var g2 = get2()", "g2"),
(a) -> assertCommand(a, "/vars g2", "| Number&CharSequence g2 = null")
);
}
@Test
public void testAnonymous() {
test(
(a) -> assertCommandOutputContains(a, "var r1 = new Object() {}", "r1"),
(a) -> assertCommandOutputContains(a, "/vars r1", "| <anonymous class extending Object> r1 = "),
(a) -> assertCommandOutputContains(a, "var r2 = new Runnable() { public void run() { } }", "r2"),
(a) -> assertCommandOutputContains(a, "/vars r2", "| <anonymous class implementing Runnable> r2 = ")
);
}
}

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8144903
* @bug 8144903 8177466
* @summary Tests for EvaluationState.variables
* @build KullaTesting TestingInputStream ExpectedDiagnostic
* @run testng VariablesTest
@ -337,4 +337,30 @@ public class VariablesTest extends KullaTesting {
assertEquals(unr.get(0), "class undefined");
assertVariables(variable("undefined", "d"));
}
public void lvti() {
assertEval("var d = 234;", "234");
assertEval("class Test<T> { T[][] get() { return null; } }", added(VALID));
assertEval("Test<? extends String> test() { return new Test<>(); }", added(VALID));
assertEval("var t = test().get();", added(VALID));
assertEval("<Z extends Runnable & CharSequence> Z get1() { return null; }", added(VALID));
assertEval("var i1 = get1();", added(VALID));
assertEval("void t1() { i1.run(); i1.length(); }", added(VALID));
assertEval("i1 = 1;", DiagCheck.DIAG_ERROR, DiagCheck.DIAG_OK, ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null));
assertEval("<Z extends Number & CharSequence> Z get2() { return null; }", added(VALID));
assertEval("var i2 = get2();", added(VALID));
assertEval("void t2() { i2.length(); }", added(VALID));
assertEval("var r1 = new Runnable() { public void run() { } public String get() { return \"good\"; } };", added(VALID));
assertEval("Runnable r2 = r1;");
assertEval("r1.get()", "\"good\"");
assertEval("var v = r1.get();", "\"good\"");
assertEval("var r3 = new java.util.ArrayList<String>(42) { public String get() { return \"good\"; } };", added(VALID));
assertEval("r3.get()", "\"good\"");
assertEval("class O { public class Inner { public String test() { return \"good\"; } } }");
assertEval("var r4 = new O().new Inner() { public String get() { return \"good\"; } };");
assertEval("r4.get()", "\"good\"");
assertEval("class O2 { public class Inner { public Inner(int i) { } public String test() { return \"good\"; } } }");
assertEval("var r5 = new O2().new Inner(1) { public String get() { return \"good\"; } };");
assertEval("r5.get()", "\"good\"");
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.illegal.ref.to.var.type
import java.util.List;
class IllegalRefToVarType {
var<String> list() { return null; }
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.cant.infer.local.var.type
// key: compiler.misc.local.array.missing.target
class LocalArrayMissingTarget {
void test() {
var x = { 1, 2, 3 };
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.cant.infer.local.var.type
// key: compiler.misc.local.cant.infer.null
class LocalCantInferNull {
void test() {
var s = null;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.cant.infer.local.var.type
// key: compiler.misc.local.lambda.missing.target
class LocalLambdaMissingTarget {
void test() {
var x = () -> { };
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.cant.infer.local.var.type
// key: compiler.misc.local.missing.init
class LocalMissingInit {
void test() {
var s;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.cant.infer.local.var.type
// key: compiler.misc.local.mref.missing.target
class LocalMrefMissingTarget {
void test() {
var x = this::test;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2016, 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.
*/
// options: -XDfind=local
// key: compiler.warn.local.redundant.type
class LocalRedundantType {
void test() {
String s = "";
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.cant.infer.local.var.type
// key: compiler.misc.local.self.ref
class LocalSelfRef {
void test() {
var x = m(x);
}
String m(String s) { return s; }
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.var.not.allowed
class var { }

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.var.not.allowed.array
class VarNotAllowedArray {
void test(String[] s) {
var[] x = s;
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2017, 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.
*/
// key: compiler.err.var.not.allowed.compound
class VarNotAllowedCompound {
void test() {
var x = 1, y = 2;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2016, 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.
*/
// key: compiler.err.var.not.allowed.here
class VarNotAllowedField {
var s = "";
}

View File

@ -0,0 +1,33 @@
/*
* @test /nodynamiccopyright/
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @compile/fail/ref=BadLocalVarInferenceTest.out -XDrawDiagnostics BadLocalVarInferenceTest.java
*/
class BadLocalVarInferenceTest {
interface Foo<X> {
void m(X x);
}
interface Supplier<X> {
void m(X x);
}
void test() {
var x;
var f = () -> { };
var m = this::l;
var g = null;
var d = d = 1;
var k = { 1 , 2 };
var l = new Foo<>() { //LHS was Foo<String>
@Override
void m(String s) { }
};
var s = f(x -> { x.charAt(0); }); //LHS was String
}
<Z> Z f(Supplier<Z> sz) { return null; }
}

View File

@ -0,0 +1,10 @@
BadLocalVarInferenceTest.java:19:13: compiler.err.cant.infer.local.var.type: x, (compiler.misc.local.missing.init)
BadLocalVarInferenceTest.java:20:13: compiler.err.cant.infer.local.var.type: f, (compiler.misc.local.lambda.missing.target)
BadLocalVarInferenceTest.java:21:13: compiler.err.cant.infer.local.var.type: m, (compiler.misc.local.mref.missing.target)
BadLocalVarInferenceTest.java:22:13: compiler.err.cant.infer.local.var.type: g, (compiler.misc.local.cant.infer.null)
BadLocalVarInferenceTest.java:23:13: compiler.err.cant.infer.local.var.type: d, (compiler.misc.local.self.ref)
BadLocalVarInferenceTest.java:24:13: compiler.err.cant.infer.local.var.type: k, (compiler.misc.local.array.missing.target)
BadLocalVarInferenceTest.java:25:29: compiler.err.does.not.override.abstract: compiler.misc.anonymous.class: BadLocalVarInferenceTest$1, m(java.lang.Object), BadLocalVarInferenceTest.Foo
BadLocalVarInferenceTest.java:26:13: compiler.err.method.does.not.override.superclass
BadLocalVarInferenceTest.java:29:27: compiler.err.cant.resolve.location.args: kindname.method, charAt, , int, (compiler.misc.location.1: kindname.variable, x, java.lang.Object)
9 errors

View File

@ -0,0 +1,47 @@
/*
* @test /nodynamiccopyright/
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @compile/fail/ref=FoldingTest.out -XDrawDiagnostics FoldingTest.java
*/
class FoldingTest {
void testReachability() {
for(var i = 0; i < 3; i++) {
// ok
}
System.out.println("foo"); //this should be reachable
}
void testCase(String s) {
var c = "";
final String c2 = "" + c;
switch (s) {
case c: break; //error!
case c2: break; //error!
}
}
void testAnno() {
@Anno1(s1) //error
var s1 = "";
@Anno2(s2) //error
var s2 = "";
@Anno3(s3) //error
var s3 = "";
}
@interface Anno1 {
String value();
}
@interface Anno2 {
Class<?> value();
}
@interface Anno3 {
Foo value();
}
enum Foo {
A, B;
}
}

View File

@ -0,0 +1,6 @@
FoldingTest.java:20:18: compiler.err.string.const.req
FoldingTest.java:21:18: compiler.err.string.const.req
FoldingTest.java:26:16: compiler.err.attribute.value.must.be.constant
FoldingTest.java:28:16: compiler.err.annotation.value.must.be.class.literal
FoldingTest.java:30:16: compiler.err.enum.annotation.must.be.enum.constant
5 errors

View File

@ -0,0 +1,71 @@
/*
* @test /nodynamiccopyright/
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @compile -source 9 ParserTest.java
* @compile/fail/ref=ParserTest.out -XDrawDiagnostics ParserTest.java
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.function.Function;
import java.util.List;
class ParserTest<var> {
static class TestClass {
static class var { } //illegal
}
static class TestInterface {
interface var { } //illegal
}
static class TestEnum {
enum var { } //illegal
}
static class TestAnno {
@interface var { } //illegal
}
@Target(ElementType.TYPE_USE)
@interface TA { }
@interface DA { }
static class var extends RuntimeException { } //illegal
var x = null; //illegal
void test() {
var[] x1 = null; //illegal
var x2[] = null; //illegal
var[][] x3 = null; //illegal
var x4[][] = null; //illegal
var[] x5 = null; //illegal
var x6[] = null; //illegal
var@TA[]@TA[] x7 = null; //illegal
var x8@TA[]@TA[] = null; //illegal
var x9 = null, y = null; //illegal
final @DA var x10 = m(); //ok
@DA final var x11 = m(); //ok
}
var m() { //illegal
return null;
}
void test2(var x) { //error
List<var> l1; //error
List<? extends var> l2; //error
List<? super var> l3; //error
try {
Function<var, String> f = (var x2) -> ""; //error
} catch (var ex) { } //error
}
void test3(Object o) {
boolean b1 = o instanceof var; //error
Object o2 = (var)o; //error
}
}

View File

@ -0,0 +1,25 @@
ParserTest.java:14:18: compiler.err.var.not.allowed: var
ParserTest.java:16:22: compiler.err.var.not.allowed: var
ParserTest.java:20:19: compiler.err.var.not.allowed: var
ParserTest.java:24:14: compiler.err.var.not.allowed: var
ParserTest.java:28:20: compiler.err.var.not.allowed: var
ParserTest.java:36:18: compiler.err.var.not.allowed: var
ParserTest.java:38:5: compiler.err.var.not.allowed.here
ParserTest.java:41:15: compiler.err.var.not.allowed.array
ParserTest.java:42:13: compiler.err.var.not.allowed.array
ParserTest.java:43:17: compiler.err.var.not.allowed.array
ParserTest.java:44:13: compiler.err.var.not.allowed.array
ParserTest.java:45:15: compiler.err.var.not.allowed.array
ParserTest.java:46:13: compiler.err.var.not.allowed.array
ParserTest.java:49:13: compiler.err.var.not.allowed.compound
ParserTest.java:54:5: compiler.err.var.not.allowed.here
ParserTest.java:58:16: compiler.err.var.not.allowed.here
ParserTest.java:59:14: compiler.err.var.not.allowed.here
ParserTest.java:60:24: compiler.err.var.not.allowed.here
ParserTest.java:61:22: compiler.err.var.not.allowed.here
ParserTest.java:63:22: compiler.err.var.not.allowed.here
ParserTest.java:63:40: compiler.err.var.not.allowed.here
ParserTest.java:64:18: compiler.err.var.not.allowed.here
ParserTest.java:68:35: compiler.err.var.not.allowed.here
ParserTest.java:69:22: compiler.err.var.not.allowed.here
24 errors

View File

@ -0,0 +1,23 @@
/*
* @test /nodynamiccopyright/
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @compile/fail/ref=SelfRefTest.out -XDrawDiagnostics SelfRefTest.java
*/
import java.util.function.Function;
class SelfRefTest {
int q() { return 42; }
int m(int t) { return t; }
void test(boolean cond) {
var x = cond ? x : x; //error - self reference
var y = (Function<Integer, Integer>)(Integer y) -> y; //error - bad shadowing
var z = (Runnable)() -> { int z2 = m(z); }; //error - self reference
var w = new Object() { int w = 42; void test() { int w2 = w; } }; //ok
int u = u; //ok
int q = q(); //ok
}
}

View File

@ -0,0 +1,4 @@
SelfRefTest.java:16:12: compiler.err.cant.infer.local.var.type: x, (compiler.misc.local.self.ref)
SelfRefTest.java:17:53: compiler.err.already.defined: kindname.variable, y, kindname.method, test(boolean)
SelfRefTest.java:18:12: compiler.err.cant.infer.local.var.type: z, (compiler.misc.local.self.ref)
3 errors

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2017, 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.
*/
/*
* @test /nodynamioccopyright/
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @compile -source 8 pkg/var.java
* @compile pkg/nested/var/A.java
* @compile/fail/ref=BadTypeReference.out -XDrawDiagnostics BadTypeReference.java
*/
import pkg.*;
public class BadTypeReference {
void test(Object o) {
var<String> vs = null; //error
Object o2 = var.x; //error
pkg.nested.var.A a = new pkg.nested.var.A(); //ok
}
}

View File

@ -0,0 +1,3 @@
BadTypeReference.java:39:9: compiler.err.illegal.ref.to.var.type: var
BadTypeReference.java:40:21: compiler.err.illegal.ref.to.var.type: var
2 errors

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2017, 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 pkg.nested.var;
public class A {
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2017, 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 pkg;
public class var {
public static Object x = "";
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2016, 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.
*/
public @interface InferredType {
String value();
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2016, 2017 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.
*/
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeMirror;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TreePathScanner;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Printer;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.code.Types;
import com.sun.tools.javac.util.Log;
import static javax.tools.StandardLocation.SOURCE_PATH;
public class LocalVariableInferenceTester {
static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
public static void main(String[] args) throws IOException {
try {
if (args.length != 1) {
System.err.println("Usage: LocalVariableInferenceTester <sourcefile>");
System.exit(1);
}
File path = new File(System.getProperty("test.src"));
fm.setLocation(SOURCE_PATH, Arrays.asList(path));
File input = new File(path, args[0]);
JavaFileObject jfo = fm.getJavaFileObjects(input).iterator().next();
new LocalVariableInferenceTester().compileAndCheck(jfo);
} finally {
fm.close();
}
}
int errors = 0;
int checks = 0;
void compileAndCheck(JavaFileObject input) throws IOException {
JavaCompiler c = ToolProvider.getSystemJavaCompiler();
JavacTask task = (JavacTask) c.getTask(null, fm, null, null, null, Arrays.asList(input));
JavacTrees trees = JavacTrees.instance(task);
Types types = Types.instance(((JavacTaskImpl)task).getContext());
Iterable<? extends CompilationUnitTree> roots = task.parse();
task.analyze(); //force attribution
Log log = Log.instance(((JavacTaskImpl)task).getContext());
errors += log.nerrors;
new LocalVarTypeChecker(trees, types).scan(roots, null);
System.err.println("Checks executed: " + checks);
if (errors != 0) {
throw new AssertionError("Errors were found");
}
}
void error(Tree node, String msg) {
System.err.println(node);
System.err.println("ERROR: " + msg);
errors++;
}
class LocalVarTypeChecker extends TreePathScanner<Void, Void> {
JavacTrees trees;
Types types;
LocalVarTypeChecker(JavacTrees trees, Types types) {
this.trees = trees;
this.types = types;
}
@Override
public Void visitVariable(VariableTree node, Void aVoid) {
Element e = trees.getElement(getCurrentPath());
if (e.getKind() == ElementKind.LOCAL_VARIABLE) {
TypeMirror type = e.asType();
InferredType inferredAnno = e.getAnnotation(InferredType.class);
if (inferredAnno != null) {
checks++;
String req = inferredAnno.value();
String found = new TypePrinter().visit((Type)type, null);
if (!req.equals(found)) {
error(node, "Inferred type mismatch; expected: " + req + " - found: " + found);
}
}
}
return super.visitVariable(node, null);
}
class TypePrinter extends Printer {
Map<Type, Integer> capturedIdMap = new HashMap<>();
@Override
protected String localize(Locale locale, String key, Object... args) {
throw new UnsupportedOperationException();
}
@Override
public String visitCapturedType(CapturedType t, Locale locale) {
return "CAP#" + capturedVarId(t, locale);
}
@Override
protected String capturedVarId(CapturedType t, Locale locale) {
return String.valueOf(capturedIdMap.getOrDefault(t, capturedIdMap.size()));
}
@Override
public String visitClassType(ClassType t, Locale locale) {
if (!t.isCompound() && t.tsym.name.isEmpty()) {
return "#ANON(" + types.directSupertypes(t) + ")";
} else if (t.isCompound()) {
return "#INT(" + types.directSupertypes(t) + ")";
} else {
return super.visitClassType(t, locale);
}
}
}
}
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2016, 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.
*/
/*
* @test
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @modules jdk.compiler/com.sun.source.tree
* jdk.compiler/com.sun.source.util
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.util
* @build LocalVariableInferenceTester
* @run main LocalVariableInferenceTester NonDenotableTest.java
*/
import java.util.List;
class NonDenotableTest {
static final String OBJECT = "java.lang.Object";
static final String STRING = "java.lang.String";
static final String ANON_OBJECT = "#ANON(java.lang.Object)";
static final String ANON_RUNNABLE = "#ANON(java.lang.Object,java.lang.Runnable)";
static final String LIST_EXT = "java.util.List<? extends java.lang.String>";
static final String LIST_SUP = "java.util.List<? super java.lang.String>";
static final String LIST_UNB = "java.util.List<?>";
static final String COMP_UNB = "java.lang.Comparable<?>";
static final String LIST_EXT_COMP_UNB = "java.util.List<? extends java.lang.Comparable<?>>";
static final String LIST_SUP_COMP_UNB = "java.util.List<? super java.lang.Comparable<?>>";
static final String INT_INTEGER_DOUBLE = "#INT(java.lang.Number,java.lang.Comparable<? extends java.lang.Number&java.lang.Comparable<?>>)";
void testExtends() {
@InferredType(LIST_EXT)
var s = extString();
for (@InferredType(LIST_EXT) var s2 = extString() ; ; ) { break; }
for (@InferredType(LIST_EXT) var s2 : extStringArr()) { break; }
for (@InferredType(LIST_EXT) var s2 : extStringIter()) { break; }
for (@InferredType(STRING) var s2 : extString()) { break; }
}
void testExtendsFbound() {
@InferredType(LIST_EXT_COMP_UNB)
var s = extFbound();
for (@InferredType(LIST_EXT_COMP_UNB) var s2 = extFbound() ; ; ) { break; }
for (@InferredType(LIST_EXT_COMP_UNB) var s2 : extFboundArr()) { break; }
for (@InferredType(LIST_EXT_COMP_UNB) var s2 : extFboundIter()) { break; }
for (@InferredType(COMP_UNB) var s2 : extFbound()) { break; }
}
void testSuperFbound() {
@InferredType(LIST_UNB)
var s = supFbound();
for (@InferredType(LIST_UNB) var s2 = supFbound() ; ; ) { break; }
for (@InferredType(LIST_UNB) var s2 : supFboundArr()) { break; }
for (@InferredType(LIST_UNB) var s2 : supFboundIter()) { break; }
for (@InferredType(OBJECT) var s2 : supFbound()) { break; }
}
void testSuper() {
@InferredType(LIST_SUP)
var s = supString();
for (@InferredType(LIST_SUP) var s2 = supString() ; ; ) { break; }
for (@InferredType(LIST_SUP) var s2 : supStringArr()) { break; }
for (@InferredType(LIST_SUP) var s2 : supStringIter()) { break; }
for (@InferredType(OBJECT) var s2 : supString()) { break; }
}
void testUnbound() {
@InferredType(LIST_UNB)
var s = unbString();
for (@InferredType(LIST_UNB) var s2 = unbString() ; ; ) { break; }
for (@InferredType(LIST_UNB) var s2 : unbStringArr()) { break; }
for (@InferredType(LIST_UNB) var s2 : unbStringIter()) { break; }
for (@InferredType(OBJECT) var s2 : unbString()) { break; }
}
void testAnonymousClass() {
@InferredType(ANON_OBJECT)
var o = new Object() { };
for (@InferredType(ANON_OBJECT) var s2 = new Object() { } ; ; ) { break; }
for (@InferredType(ANON_OBJECT) var s2 : arrayOf(new Object() { })) { break; }
for (@InferredType(ANON_OBJECT) var s2 : listOf(new Object() { })) { break; }
}
void testAnonymousInterface() {
@InferredType(ANON_RUNNABLE)
var r = new Runnable() { public void run() { } };
for (@InferredType(ANON_RUNNABLE) var s2 = new Runnable() { public void run() { } } ; ; ) { break; }
for (@InferredType(ANON_RUNNABLE) var s2 : arrayOf(new Runnable() { public void run() { } })) { break; }
for (@InferredType(ANON_RUNNABLE) var s2 : listOf(new Runnable() { public void run() { } })) { break; }
}
void testIntersection() {
@InferredType(INT_INTEGER_DOUBLE)
var c = choose(1, 1L);
for (@InferredType(INT_INTEGER_DOUBLE) var s2 = choose(1, 1L) ; ;) { break; }
for (@InferredType(INT_INTEGER_DOUBLE) var s2 : arrayOf(choose(1, 1L))) { break; }
for (@InferredType(INT_INTEGER_DOUBLE) var s2 : listOf(choose(1, 1L))) { break; }
}
List<? extends String> extString() { return null; }
List<? super String> supString() { return null; }
List<?> unbString() { return null; }
List<? extends String>[] extStringArr() { return null; }
List<? super String>[] supStringArr() { return null; }
List<?>[] unbStringArr() { return null; }
Iterable<? extends List<? extends String>> extStringIter() { return null; }
Iterable<? extends List<? super String>> supStringIter() { return null; }
Iterable<? extends List<?>> unbStringIter() { return null; }
<Z extends Comparable<Z>> List<? extends Z> extFbound() { return null; }
<Z extends Comparable<Z>> List<? super Z> supFbound() { return null; }
<Z extends Comparable<Z>> List<? extends Z>[] extFboundArr() { return null; }
<Z extends Comparable<Z>> List<? super Z>[] supFboundArr() { return null; }
<Z extends Comparable<Z>> Iterable<? extends List<? extends Z>> extFboundIter() { return null; }
<Z extends Comparable<Z>> Iterable<? extends List<? super Z>> supFboundIter() { return null; }
<Z> List<Z> listOf(Z z) { return null; }
<Z> Z[] arrayOf(Z z) { return null; }
<Z> Z choose(Z z1, Z z2) { return z1; }
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2016, 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.
*/
/*
* @test
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @modules jdk.compiler/com.sun.source.tree
* jdk.compiler/com.sun.source.util
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.util
* @build LocalVariableInferenceTester
* @run main LocalVariableInferenceTester PrimitiveTypeTest.java
*/
class PrimitiveTypeTest {
byte[] b_arr = { 0 };
short[] s_arr = { 0 };
int[] i_arr = { 0 };
long[] l_arr = { 0 };
float[] f_arr = { 0 };
double[] d_arr = { 0 };
char[] c_arr = { 0 };
boolean[] z_arr = { false };
void testPrimitive() {
@InferredType("byte")
var b = (byte)0;
@InferredType("short")
var s = (short)0;
@InferredType("int")
var i = 0;
@InferredType("long")
var l = 0L;
@InferredType("float")
var f = 0f;
@InferredType("double")
var d = 0d;
@InferredType("char")
var c = 'c';
@InferredType("boolean")
var z = false;
}
void testPrimitiveArray() {
@InferredType("byte[]")
var b = b_arr;
@InferredType("short[]")
var s = s_arr;
@InferredType("int[]")
var i = i_arr;
@InferredType("long[]")
var l = l_arr;
@InferredType("float[]")
var f = f_arr;
@InferredType("double[]")
var d = d_arr;
@InferredType("char[]")
var c = c_arr;
@InferredType("boolean[]")
var z = z_arr;
}
void testForEachPrimitive() {
for (@InferredType("byte") var b : b_arr) { break; }
for (@InferredType("short") var s : s_arr) { break; }
for (@InferredType("int") var i : i_arr) { break; }
for (@InferredType("long") var l : l_arr) { break; }
for (@InferredType("float") var f : f_arr) { break; }
for (@InferredType("double") var d : d_arr) { break; }
for (@InferredType("char") var c : c_arr) { break; }
for (@InferredType("boolean") var z : z_arr) { break; }
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2016, 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.
*/
/*
* @test
* @bug 8177466
* @summary Add compiler support for local variable type-inference
* @modules jdk.compiler/com.sun.source.tree
* jdk.compiler/com.sun.source.util
* jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.code
* jdk.compiler/com.sun.tools.javac.util
* @build LocalVariableInferenceTester
* @run main LocalVariableInferenceTester ReferenceTypeTest.java
*/
class ReferenceTypeTest {
static final String STRING = "java.lang.String";
static final String FOO = "ReferenceTypeTest.Foo";
void test() {
@InferredType(STRING)
var s = "";
for (@InferredType(STRING) var s2 = "" ; ; ) { break; }
for (@InferredType(STRING) var s2 : stringArray()) { break; }
for (@InferredType(STRING) var s2 : stringIterable()) { break; }
try (@InferredType(FOO) var s2 = new Foo()) { } finally { }
try (@InferredType(FOO) var s2 = new Foo(); @InferredType(FOO) var s3 = new Foo()) { } finally { }
}
String[] stringArray() { return null; }
Iterable<String> stringIterable() { return null; }
static class Foo implements AutoCloseable {
@Override
public void close() { }
}
}

View File

@ -224,7 +224,7 @@ class TrialParser extends JavacParser {
//mods.flags |= Flags.STATIC;
List<JCTree> defs
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
new ListBuffer<JCTree>()).toList();
new ListBuffer<JCTree>(), true).toList();
accept(SEMI);
storeEnd(defs.last(), S.prevToken().endPos);
return defs;

View File

@ -354,7 +354,7 @@ public class TypeHarness {
public TypeVar TypeVariable(Type bound) {
TypeSymbol tvsym = new TypeVariableSymbol(0, syntheticName(), null, predef.noSymbol);
tvsym.type = new TypeVar(tvsym, bound, null);
tvsym.type = new TypeVar(tvsym, bound, Type.noType);
return (TypeVar)tvsym.type;
}