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:
parent
02ba926da2
commit
c825188cd8
@ -71,6 +71,7 @@ public class Kinds {
|
|||||||
HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target
|
HIDDEN(Category.RESOLUTION_TARGET), // not overloaded non-target
|
||||||
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
|
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
|
||||||
MISSING_ENCL(Category.RESOLUTION), // not overloaded non-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
|
ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target
|
||||||
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
|
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
|
||||||
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target
|
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target
|
||||||
|
@ -227,6 +227,7 @@ public enum Source {
|
|||||||
return compareTo(JDK1_8) <= 0;
|
return compareTo(JDK1_8) <= 0;
|
||||||
}
|
}
|
||||||
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
|
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
|
||||||
|
public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
|
||||||
public static SourceVersion toSourceVersion(Source source) {
|
public static SourceVersion toSourceVersion(Source source) {
|
||||||
switch(source) {
|
switch(source) {
|
||||||
case JDK1_2:
|
case JDK1_2:
|
||||||
|
@ -1616,6 +1616,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
|||||||
|
|
||||||
public TypeVar(Name name, Symbol owner, Type lower) {
|
public TypeVar(Name name, Symbol owner, Type lower) {
|
||||||
super(null, TypeMetadata.EMPTY);
|
super(null, TypeMetadata.EMPTY);
|
||||||
|
Assert.checkNonNull(lower);
|
||||||
tsym = new TypeVariableSymbol(0, name, this, owner);
|
tsym = new TypeVariableSymbol(0, name, this, owner);
|
||||||
this.bound = null;
|
this.bound = null;
|
||||||
this.lower = lower;
|
this.lower = lower;
|
||||||
@ -1628,6 +1629,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
|||||||
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
|
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
|
||||||
TypeMetadata metadata) {
|
TypeMetadata metadata) {
|
||||||
super(tsym, metadata);
|
super(tsym, metadata);
|
||||||
|
Assert.checkNonNull(lower);
|
||||||
this.bound = bound;
|
this.bound = bound;
|
||||||
this.lower = lower;
|
this.lower = lower;
|
||||||
}
|
}
|
||||||
|
@ -1247,7 +1247,9 @@ public class TypeAnnotations {
|
|||||||
final TypeAnnotationPosition pos =
|
final TypeAnnotationPosition pos =
|
||||||
TypeAnnotationPosition.localVariable(currentLambda,
|
TypeAnnotationPosition.localVariable(currentLambda,
|
||||||
tree.pos);
|
tree.pos);
|
||||||
|
if (!tree.isImplicitlyTyped()) {
|
||||||
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
|
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
|
||||||
|
}
|
||||||
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
|
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
|
||||||
final TypeAnnotationPosition pos =
|
final TypeAnnotationPosition pos =
|
||||||
TypeAnnotationPosition.exceptionParameter(currentLambda,
|
TypeAnnotationPosition.exceptionParameter(currentLambda,
|
||||||
|
@ -190,6 +190,245 @@ public class Types {
|
|||||||
}
|
}
|
||||||
// </editor-fold>
|
// </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">
|
// <editor-fold defaultstate="collapsed" desc="isUnbounded">
|
||||||
/**
|
/**
|
||||||
* Checks that all the arguments to a class are unbounded
|
* Checks that all the arguments to a class are unbounded
|
||||||
|
@ -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.Flags.GENERATEDCONSTR;
|
||||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
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.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.LABELLED;
|
||||||
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
|
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
|
||||||
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
|
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
|
||||||
@ -139,7 +140,8 @@ public class Analyzer {
|
|||||||
enum AnalyzerMode {
|
enum AnalyzerMode {
|
||||||
DIAMOND("diamond", Source::allowDiamond),
|
DIAMOND("diamond", Source::allowDiamond),
|
||||||
LAMBDA("lambda", Source::allowLambda),
|
LAMBDA("lambda", Source::allowLambda),
|
||||||
METHOD("method", Source::allowGraphInference);
|
METHOD("method", Source::allowGraphInference),
|
||||||
|
LOCAL("local", Source::allowLocalVariableTypeInference);
|
||||||
|
|
||||||
final String opt;
|
final String opt;
|
||||||
final Predicate<Source> sourceFilter;
|
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"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
|
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
|
||||||
new DiamondInitializer(),
|
new DiamondInitializer(),
|
||||||
new LambdaAnalyzer(),
|
new LambdaAnalyzer(),
|
||||||
new RedundantTypeArgAnalyzer()
|
new RedundantTypeArgAnalyzer(),
|
||||||
|
new RedundantLocalVarTypeAnalyzer(),
|
||||||
|
new RedundantLocalVarTypeAnalyzerForEach()
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,9 +28,11 @@ package com.sun.tools.javac.comp;
|
|||||||
import com.sun.tools.javac.code.*;
|
import com.sun.tools.javac.code.*;
|
||||||
import com.sun.tools.javac.code.Attribute.Compound;
|
import com.sun.tools.javac.code.Attribute.Compound;
|
||||||
import com.sun.tools.javac.code.Attribute.TypeCompound;
|
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.Scope.WriteableScope;
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
import com.sun.tools.javac.code.Symbol.*;
|
||||||
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
|
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.resources.CompilerProperties.Errors;
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
import com.sun.tools.javac.tree.JCTree;
|
||||||
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) {
|
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);
|
Symbol sym = TreeInfo.symbol(tree);
|
||||||
if (sym == null ||
|
if (sym == null ||
|
||||||
TreeInfo.nonstaticSelect(tree) ||
|
TreeInfo.nonstaticSelect(tree) ||
|
||||||
@ -616,7 +618,7 @@ public class Annotate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
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()) {
|
if (result.isErroneous()) {
|
||||||
// Does it look like an unresolved class literal?
|
// Does it look like an unresolved class literal?
|
||||||
if (TreeInfo.name(tree) == names._class &&
|
if (TreeInfo.name(tree) == names._class &&
|
||||||
@ -642,7 +644,7 @@ public class Annotate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
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())
|
if (result.isErroneous())
|
||||||
return new Attribute.Error(result.getOriginalType());
|
return new Attribute.Error(result.getOriginalType());
|
||||||
if (result.constValue() == null) {
|
if (result.constValue() == null) {
|
||||||
@ -653,6 +655,22 @@ public class Annotate {
|
|||||||
return new Attribute.Constant(expectedElementType, result.constValue());
|
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) {
|
private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||||
// Special case, implicit array
|
// Special case, implicit array
|
||||||
if (!tree.hasTag(NEWARRAY)) {
|
if (!tree.hasTag(NEWARRAY)) {
|
||||||
|
@ -36,7 +36,6 @@ import com.sun.source.tree.MemberSelectTree;
|
|||||||
import com.sun.source.tree.TreeVisitor;
|
import com.sun.source.tree.TreeVisitor;
|
||||||
import com.sun.source.util.SimpleTreeVisitor;
|
import com.sun.source.util.SimpleTreeVisitor;
|
||||||
import com.sun.tools.javac.code.*;
|
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.Lint.LintCategory;
|
||||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||||
import com.sun.tools.javac.code.Symbol.*;
|
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.ArgumentAttr.LocalCacheContext;
|
||||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||||
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
|
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
|
||||||
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
|
||||||
import com.sun.tools.javac.jvm.*;
|
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.Diamond;
|
||||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
|
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);
|
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
|
||||||
try {
|
try {
|
||||||
Type itype = attribExpr(variable.init, env, type);
|
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) {
|
if (itype.constValue() != null) {
|
||||||
return coerce(itype, type).constValue();
|
return coerce(itype, type).constValue();
|
||||||
} else {
|
} else {
|
||||||
@ -1108,6 +1110,21 @@ public class Attr extends JCTree.Visitor {
|
|||||||
// parameters have already been entered
|
// parameters have already been entered
|
||||||
env.info.scope.enter(tree.sym);
|
env.info.scope.enter(tree.sym);
|
||||||
} else {
|
} 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 {
|
try {
|
||||||
annotate.blockAnnotations();
|
annotate.blockAnnotations();
|
||||||
memberEnter.memberEnter(tree, env);
|
memberEnter.memberEnter(tree, env);
|
||||||
@ -1131,7 +1148,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
|
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
|
||||||
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
|
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
|
||||||
(tree.sym.flags() & PARAMETER) != 0;
|
(tree.sym.flags() & PARAMETER) != 0;
|
||||||
chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
|
chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
v.getConstValue(); // ensure compile-time constant initializer is evaluated
|
v.getConstValue(); // ensure compile-time constant initializer is evaluated
|
||||||
@ -1152,6 +1169,10 @@ public class Attr extends JCTree.Visitor {
|
|||||||
// marking the variable as undefined.
|
// marking the variable as undefined.
|
||||||
initEnv.info.enclVar = v;
|
initEnv.info.enclVar = v;
|
||||||
attribExpr(tree.init, initEnv, v.type);
|
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;
|
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) {
|
public void visitSkip(JCSkip tree) {
|
||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
@ -1243,7 +1329,6 @@ public class Attr extends JCTree.Visitor {
|
|||||||
//attributing the for-each expression; we mimick this by attributing
|
//attributing the for-each expression; we mimick this by attributing
|
||||||
//the for-each expression first (against original scope).
|
//the for-each expression first (against original scope).
|
||||||
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
|
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
|
||||||
attribStat(tree.var, loopEnv);
|
|
||||||
chk.checkNonVoid(tree.pos(), exprType);
|
chk.checkNonVoid(tree.pos(), exprType);
|
||||||
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
|
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
|
||||||
if (elemtype == null) {
|
if (elemtype == null) {
|
||||||
@ -1261,6 +1346,15 @@ public class Attr extends JCTree.Visitor {
|
|||||||
: types.wildUpperBound(iterableParams.head);
|
: 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);
|
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
|
||||||
loopEnv.tree = tree; // before, we were not in loop!
|
loopEnv.tree = tree; // before, we were not in loop!
|
||||||
attribStat(tree.body, loopEnv);
|
attribStat(tree.body, loopEnv);
|
||||||
@ -2379,7 +2473,8 @@ public class Attr extends JCTree.Visitor {
|
|||||||
if (pt().hasTag(ARRAY)) {
|
if (pt().hasTag(ARRAY)) {
|
||||||
elemtype = types.elemtype(pt());
|
elemtype = types.elemtype(pt());
|
||||||
} else {
|
} else {
|
||||||
if (!pt().hasTag(ERROR)) {
|
if (!pt().hasTag(ERROR) &&
|
||||||
|
(env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||||
log.error(tree.pos(),
|
log.error(tree.pos(),
|
||||||
Errors.IllegalInitializerForType(pt()));
|
Errors.IllegalInitializerForType(pt()));
|
||||||
}
|
}
|
||||||
@ -2404,7 +2499,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
@Override
|
@Override
|
||||||
public void visitLambda(final JCLambda that) {
|
public void visitLambda(final JCLambda that) {
|
||||||
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
|
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
|
//lambda only allowed in assignment or method invocation/cast context
|
||||||
log.error(that.pos(), Errors.UnexpectedLambda);
|
log.error(that.pos(), Errors.UnexpectedLambda);
|
||||||
}
|
}
|
||||||
@ -2837,7 +2932,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
@Override
|
@Override
|
||||||
public void visitReference(final JCMemberReference that) {
|
public void visitReference(final JCMemberReference that) {
|
||||||
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
|
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
|
//method reference only allowed in assignment or method invocation/cast context
|
||||||
log.error(that.pos(), Errors.UnexpectedMref);
|
log.error(that.pos(), Errors.UnexpectedMref);
|
||||||
}
|
}
|
||||||
@ -3811,6 +3906,14 @@ public class Attr extends JCTree.Visitor {
|
|||||||
break;
|
break;
|
||||||
case VAR:
|
case VAR:
|
||||||
VarSymbol v = (VarSymbol)sym;
|
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,
|
// Test (4): if symbol is an instance field of a raw type,
|
||||||
// which is being assigned to, issue an unchecked warning if
|
// which is being assigned to, issue an unchecked warning if
|
||||||
// its type changes under erasure.
|
// its type changes under erasure.
|
||||||
@ -4135,6 +4238,9 @@ public class Attr extends JCTree.Visitor {
|
|||||||
public void visitTypeArray(JCArrayTypeTree tree) {
|
public void visitTypeArray(JCArrayTypeTree tree) {
|
||||||
Type etype = attribType(tree.elemtype, env);
|
Type etype = attribType(tree.elemtype, env);
|
||||||
Type type = new ArrayType(etype, syms.arrayClass);
|
Type type = new ArrayType(etype, syms.arrayClass);
|
||||||
|
if (etype.isErroneous()) {
|
||||||
|
type = types.createErrorType(type);
|
||||||
|
}
|
||||||
result = check(tree, type, KindSelector.TYP, resultInfo);
|
result = check(tree, type, KindSelector.TYP, resultInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4776,7 +4882,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
public void visitVarDef(final JCVariableDecl tree) {
|
public void visitVarDef(final JCVariableDecl tree) {
|
||||||
//System.err.println("validateTypeAnnotations.visitVarDef " + 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);
|
validateAnnotatedType(tree.vartype, tree.sym.type);
|
||||||
scan(tree.mods);
|
scan(tree.mods);
|
||||||
scan(tree.vartype);
|
scan(tree.vartype);
|
||||||
@ -4904,17 +5010,16 @@ public class Attr extends JCTree.Visitor {
|
|||||||
repeat = false;
|
repeat = false;
|
||||||
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
|
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
|
||||||
JCWildcard wc = (JCWildcard) enclTr;
|
JCWildcard wc = (JCWildcard) enclTr;
|
||||||
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
|
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
|
||||||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
|
wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
|
||||||
} else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
|
validateAnnotatedType(wc.getBound(), wc.getBound().type);
|
||||||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
|
|
||||||
} else {
|
} else {
|
||||||
// Nothing to do for UNBOUND
|
// Nothing to do for UNBOUND
|
||||||
}
|
}
|
||||||
repeat = false;
|
repeat = false;
|
||||||
} else if (enclTr.hasTag(TYPEARRAY)) {
|
} else if (enclTr.hasTag(TYPEARRAY)) {
|
||||||
JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
|
JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
|
||||||
validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
|
validateAnnotatedType(art.getType(), art.elemtype.type);
|
||||||
repeat = false;
|
repeat = false;
|
||||||
} else if (enclTr.hasTag(TYPEUNION)) {
|
} else if (enclTr.hasTag(TYPEUNION)) {
|
||||||
JCTypeUnion ut = (JCTypeUnion) enclTr;
|
JCTypeUnion ut = (JCTypeUnion) enclTr;
|
||||||
|
@ -843,26 +843,30 @@ public class Check {
|
|||||||
List<Type> checkDiamondDenotable(ClassType t) {
|
List<Type> checkDiamondDenotable(ClassType t) {
|
||||||
ListBuffer<Type> buf = new ListBuffer<>();
|
ListBuffer<Type> buf = new ListBuffer<>();
|
||||||
for (Type arg : t.allparams()) {
|
for (Type arg : t.allparams()) {
|
||||||
if (!diamondTypeChecker.visit(arg, null)) {
|
if (!checkDenotable(arg)) {
|
||||||
buf.append(arg);
|
buf.append(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buf.toList();
|
return buf.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean checkDenotable(Type t) {
|
||||||
|
return denotableChecker.visit(t, null);
|
||||||
|
}
|
||||||
// where
|
// where
|
||||||
|
|
||||||
/** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
|
/** 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
|
* types. The visit methods return false as soon as a non-denotable type is encountered and true
|
||||||
* otherwise.
|
* 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
|
@Override
|
||||||
public Boolean visitType(Type t, Void s) {
|
public Boolean visitType(Type t, Void s) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Boolean visitClassType(ClassType t, Void s) {
|
public Boolean visitClassType(ClassType t, Void s) {
|
||||||
if (t.isCompound()) {
|
if (t.isUnion() || t.isIntersection()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (Type targ : t.allparams()) {
|
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
|
/* 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))
|
(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
|
@Override
|
||||||
@ -941,6 +945,17 @@ public class Check {
|
|||||||
(allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
|
(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,
|
Type checkMethod(final Type mtype,
|
||||||
final Symbol sym,
|
final Symbol sym,
|
||||||
final Env<AttrContext> env,
|
final Env<AttrContext> env,
|
||||||
@ -3159,7 +3174,10 @@ public class Check {
|
|||||||
if (s.kind == PCK)
|
if (s.kind == PCK)
|
||||||
return true;
|
return true;
|
||||||
} else if (target == names.TYPE_USE) {
|
} 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.kind == MTH && !s.isConstructor() &&
|
||||||
!s.type.getReturnType().hasTag(VOID)) ||
|
!s.type.getReturnType().hasTag(VOID)) ||
|
||||||
(s.kind == MTH && s.isConstructor())) {
|
(s.kind == MTH && s.isConstructor())) {
|
||||||
|
@ -529,7 +529,7 @@ public class Infer {
|
|||||||
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
|
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
|
||||||
if (Type.containsAny(upperBounds, vars)) {
|
if (Type.containsAny(upperBounds, vars)) {
|
||||||
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
|
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);
|
todo.append(uv);
|
||||||
uv.setInst(fresh_tvar.type);
|
uv.setInst(fresh_tvar.type);
|
||||||
} else if (upperBounds.nonEmpty()) {
|
} else if (upperBounds.nonEmpty()) {
|
||||||
|
@ -259,7 +259,7 @@ public class MemberEnter extends JCTree.Visitor {
|
|||||||
try {
|
try {
|
||||||
if (TreeInfo.isEnumInit(tree)) {
|
if (TreeInfo.isEnumInit(tree)) {
|
||||||
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
|
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
|
||||||
} else {
|
} else if (!tree.isImplicitlyTyped()) {
|
||||||
attr.attribType(tree.vartype, localEnv);
|
attr.attribType(tree.vartype, localEnv);
|
||||||
if (TreeInfo.isReceiverParam(tree))
|
if (TreeInfo.isReceiverParam(tree))
|
||||||
checkReceiver(tree, localEnv);
|
checkReceiver(tree, localEnv);
|
||||||
@ -279,8 +279,8 @@ public class MemberEnter extends JCTree.Visitor {
|
|||||||
tree.vartype.type = atype.makeVarargs();
|
tree.vartype.type = atype.makeVarargs();
|
||||||
}
|
}
|
||||||
WriteableScope enclScope = enter.enterScope(env);
|
WriteableScope enclScope = enter.enterScope(env);
|
||||||
VarSymbol v =
|
Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
|
||||||
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
|
VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
|
||||||
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
|
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
|
||||||
tree.sym = v;
|
tree.sym = v;
|
||||||
if (tree.init != null) {
|
if (tree.init != null) {
|
||||||
@ -298,7 +298,9 @@ public class MemberEnter extends JCTree.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
|
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
|
||||||
|
if (!tree.isImplicitlyTyped()) {
|
||||||
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
|
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
|
||||||
|
}
|
||||||
|
|
||||||
v.pos = tree.pos;
|
v.pos = tree.pos;
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,7 @@ public class Resolve {
|
|||||||
public final boolean allowModules;
|
public final boolean allowModules;
|
||||||
public final boolean checkVarargsAccessAfterResolution;
|
public final boolean checkVarargsAccessAfterResolution;
|
||||||
private final boolean compactMethodDiags;
|
private final boolean compactMethodDiags;
|
||||||
|
private final boolean allowLocalVariableTypeInference;
|
||||||
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
|
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
|
||||||
|
|
||||||
WriteableScope polymorphicSignatureScope;
|
WriteableScope polymorphicSignatureScope;
|
||||||
@ -136,6 +137,7 @@ public class Resolve {
|
|||||||
Target target = Target.instance(context);
|
Target target = Target.instance(context);
|
||||||
allowMethodHandles = target.hasMethodHandles();
|
allowMethodHandles = target.hasMethodHandles();
|
||||||
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
|
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
|
||||||
|
allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
|
||||||
checkVarargsAccessAfterResolution =
|
checkVarargsAccessAfterResolution =
|
||||||
source.allowPostApplicabilityVarargsAccessCheck();
|
source.allowPostApplicabilityVarargsAccessCheck();
|
||||||
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
|
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
|
||||||
@ -2325,6 +2327,10 @@ public class Resolve {
|
|||||||
* (a subset of VAL, TYP, PCK).
|
* (a subset of VAL, TYP, PCK).
|
||||||
*/
|
*/
|
||||||
Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
|
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 bestSoFar = typeNotFound;
|
||||||
Symbol sym;
|
Symbol sym;
|
||||||
|
|
||||||
@ -2354,6 +2360,11 @@ public class Resolve {
|
|||||||
*/
|
*/
|
||||||
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
|
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
|
||||||
Name name, KindSelector kind) {
|
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);
|
Name fullname = TypeSymbol.formFullName(name, pck);
|
||||||
Symbol bestSoFar = typeNotFound;
|
Symbol bestSoFar = typeNotFound;
|
||||||
if (kind.contains(KindSelector.TYP)) {
|
if (kind.contains(KindSelector.TYP)) {
|
||||||
@ -2383,6 +2394,11 @@ public class Resolve {
|
|||||||
*/
|
*/
|
||||||
Symbol findIdentInType(Env<AttrContext> env, Type site,
|
Symbol findIdentInType(Env<AttrContext> env, Type site,
|
||||||
Name name, KindSelector kind) {
|
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 bestSoFar = typeNotFound;
|
||||||
Symbol sym;
|
Symbol sym;
|
||||||
if (kind.contains(KindSelector.VAL)) {
|
if (kind.contains(KindSelector.VAL)) {
|
||||||
@ -2399,6 +2415,14 @@ public class Resolve {
|
|||||||
return bestSoFar;
|
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
|
* Access checking
|
||||||
* The following methods convert ResolveErrors to ErrorSymbols, issuing
|
* 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
|
* InvalidSymbolError error class indicating that a symbol matching a
|
||||||
* given name does not exists in a given site.
|
* given name does not exists in a given site.
|
||||||
|
@ -179,6 +179,7 @@ public class JavacParser implements Parser {
|
|||||||
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
|
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
|
||||||
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
|
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
|
||||||
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
|
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
|
||||||
|
this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
|
||||||
this.keepDocComments = keepDocComments;
|
this.keepDocComments = keepDocComments;
|
||||||
this.parseModuleInfo = parseModuleInfo;
|
this.parseModuleInfo = parseModuleInfo;
|
||||||
docComments = newDocCommentTable(keepDocComments, fac);
|
docComments = newDocCommentTable(keepDocComments, fac);
|
||||||
@ -270,11 +271,14 @@ public class JavacParser implements Parser {
|
|||||||
*/
|
*/
|
||||||
boolean allowThisIdent;
|
boolean allowThisIdent;
|
||||||
|
|
||||||
|
/** Switch: is local variable inference allowed?
|
||||||
|
*/
|
||||||
|
boolean allowLocalVariableTypeInference;
|
||||||
|
|
||||||
/** The type of the method receiver, as specified by a first "this" parameter.
|
/** The type of the method receiver, as specified by a first "this" parameter.
|
||||||
*/
|
*/
|
||||||
JCVariableDecl receiverParam;
|
JCVariableDecl receiverParam;
|
||||||
|
|
||||||
|
|
||||||
/** When terms are parsed, the mode determines which is expected:
|
/** When terms are parsed, the mode determines which is expected:
|
||||||
* mode = EXPR : an expression
|
* mode = EXPR : an expression
|
||||||
* mode = TYPE : a type
|
* mode = TYPE : a type
|
||||||
@ -808,12 +812,16 @@ public class JavacParser implements Parser {
|
|||||||
* parsing annotations.
|
* parsing annotations.
|
||||||
*/
|
*/
|
||||||
public JCExpression parseType() {
|
public JCExpression parseType() {
|
||||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
return parseType(false);
|
||||||
return parseType(annotations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public JCExpression parseType(List<JCAnnotation> annotations) {
|
public JCExpression parseType(boolean allowVar) {
|
||||||
JCExpression result = unannotatedType();
|
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||||
|
return parseType(allowVar, annotations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
|
||||||
|
JCExpression result = unannotatedType(allowVar);
|
||||||
|
|
||||||
if (annotations.nonEmpty()) {
|
if (annotations.nonEmpty()) {
|
||||||
result = insertAnnotationsToMostInner(result, annotations, false);
|
result = insertAnnotationsToMostInner(result, annotations, false);
|
||||||
@ -822,10 +830,18 @@ public class JavacParser implements Parser {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JCExpression unannotatedType() {
|
public JCExpression unannotatedType(boolean allowVar) {
|
||||||
return term(TYPE);
|
JCExpression result = term(TYPE);
|
||||||
|
|
||||||
|
if (!allowVar && isRestrictedLocalVarTypeName(result)) {
|
||||||
|
syntaxError(result.pos, "var.not.allowed.here");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected JCExpression term(int newmode) {
|
protected JCExpression term(int newmode) {
|
||||||
int prevmode = mode;
|
int prevmode = mode;
|
||||||
mode = newmode;
|
mode = newmode;
|
||||||
@ -1152,11 +1168,11 @@ public class JavacParser implements Parser {
|
|||||||
accept(LPAREN);
|
accept(LPAREN);
|
||||||
mode = TYPE;
|
mode = TYPE;
|
||||||
int pos1 = pos;
|
int pos1 = pos;
|
||||||
List<JCExpression> targets = List.of(t = term3());
|
List<JCExpression> targets = List.of(t = parseType());
|
||||||
while (token.kind == AMP) {
|
while (token.kind == AMP) {
|
||||||
checkIntersectionTypesInCast();
|
checkIntersectionTypesInCast();
|
||||||
accept(AMP);
|
accept(AMP);
|
||||||
targets = targets.prepend(term3());
|
targets = targets.prepend(parseType());
|
||||||
}
|
}
|
||||||
if (targets.length() > 1) {
|
if (targets.length() > 1) {
|
||||||
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
|
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
|
||||||
@ -1912,7 +1928,7 @@ public class JavacParser implements Parser {
|
|||||||
*/
|
*/
|
||||||
JCExpression typeArgument() {
|
JCExpression typeArgument() {
|
||||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||||
if (token.kind != QUES) return parseType(annotations);
|
if (token.kind != QUES) return parseType(false, annotations);
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
nextToken();
|
nextToken();
|
||||||
JCExpression result;
|
JCExpression result;
|
||||||
@ -2425,13 +2441,8 @@ public class JavacParser implements Parser {
|
|||||||
token.kind == ENUM) {
|
token.kind == ENUM) {
|
||||||
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
|
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
|
||||||
} else {
|
} else {
|
||||||
JCExpression t = parseType();
|
JCExpression t = parseType(true);
|
||||||
ListBuffer<JCStatement> stats =
|
return localVariableDeclarations(mods, t);
|
||||||
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
|
|
||||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
|
||||||
accept(SEMI);
|
|
||||||
storeEnd(stats.last(), S.prevToken().endPos);
|
|
||||||
return stats.toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ABSTRACT: case STRICTFP: {
|
case ABSTRACT: case STRICTFP: {
|
||||||
@ -2458,12 +2469,7 @@ public class JavacParser implements Parser {
|
|||||||
pos = token.pos;
|
pos = token.pos;
|
||||||
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
|
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
|
||||||
F.at(pos);
|
F.at(pos);
|
||||||
ListBuffer<JCStatement> stats =
|
return localVariableDeclarations(mods, t);
|
||||||
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
|
|
||||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
|
||||||
accept(SEMI);
|
|
||||||
storeEnd(stats.last(), S.prevToken().endPos);
|
|
||||||
return stats.toList();
|
|
||||||
} else {
|
} else {
|
||||||
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
|
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
|
||||||
t = checkExprStat(t);
|
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 =
|
/** Statement =
|
||||||
* Block
|
* Block
|
||||||
@ -2766,11 +2781,11 @@ public class JavacParser implements Parser {
|
|||||||
ListBuffer<JCStatement> stats = new ListBuffer<>();
|
ListBuffer<JCStatement> stats = new ListBuffer<>();
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
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 {
|
} else {
|
||||||
JCExpression t = term(EXPR | TYPE);
|
JCExpression t = term(EXPR | TYPE);
|
||||||
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
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) {
|
} else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
|
||||||
error(pos, "bad.initializer", "for-loop");
|
error(pos, "bad.initializer", "for-loop");
|
||||||
return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
|
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,
|
public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
|
||||||
JCExpression type,
|
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 }
|
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
|
||||||
@ -3006,14 +3022,20 @@ public class JavacParser implements Parser {
|
|||||||
Name name,
|
Name name,
|
||||||
boolean reqInit,
|
boolean reqInit,
|
||||||
Comment dc,
|
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) {
|
while (token.kind == COMMA) {
|
||||||
|
if (implicit) {
|
||||||
|
reportSyntaxError(pos, "var.not.allowed.compound");
|
||||||
|
}
|
||||||
// All but last of multiple declarators subsume a comma
|
// All but last of multiple declarators subsume a comma
|
||||||
storeEnd((JCTree)vdefs.last(), token.endPos);
|
storeEnd((JCTree)vdefs.last(), token.endPos);
|
||||||
nextToken();
|
nextToken();
|
||||||
vdefs.append(variableDeclarator(mods, type, reqInit, dc));
|
vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
|
||||||
}
|
}
|
||||||
return vdefs;
|
return vdefs;
|
||||||
}
|
}
|
||||||
@ -3021,8 +3043,8 @@ public class JavacParser implements Parser {
|
|||||||
/** VariableDeclarator = Ident VariableDeclaratorRest
|
/** VariableDeclarator = Ident VariableDeclaratorRest
|
||||||
* ConstantDeclarator = Ident ConstantDeclaratorRest
|
* ConstantDeclarator = Ident ConstantDeclaratorRest
|
||||||
*/
|
*/
|
||||||
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
|
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
|
||||||
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
|
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
|
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
|
||||||
@ -3032,7 +3054,7 @@ public class JavacParser implements Parser {
|
|||||||
* @param dc The documentation comment for the variable declarations, or null.
|
* @param dc The documentation comment for the variable declarations, or null.
|
||||||
*/
|
*/
|
||||||
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
|
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
|
||||||
boolean reqInit, Comment dc) {
|
boolean reqInit, Comment dc, boolean localDecl) {
|
||||||
type = bracketsOpt(type);
|
type = bracketsOpt(type);
|
||||||
JCExpression init = null;
|
JCExpression init = null;
|
||||||
if (token.kind == EQ) {
|
if (token.kind == EQ) {
|
||||||
@ -3040,12 +3062,40 @@ public class JavacParser implements Parser {
|
|||||||
init = variableInitializer();
|
init = variableInitializer();
|
||||||
}
|
}
|
||||||
else if (reqInit) syntaxError(token.pos, "expected", EQ);
|
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 =
|
JCVariableDecl result =
|
||||||
toP(F.at(pos).VarDef(mods, name, type, init));
|
toP(F.at(pos).VarDef(mods, name, type, init));
|
||||||
attach(result, dc);
|
attach(result, dc);
|
||||||
return result;
|
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
|
/** VariableDeclaratorId = Ident BracketsOpt
|
||||||
*/
|
*/
|
||||||
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
|
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
|
||||||
@ -3111,13 +3161,13 @@ public class JavacParser implements Parser {
|
|||||||
int startPos = token.pos;
|
int startPos = token.pos;
|
||||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
||||||
JCModifiers mods = optFinal(Flags.FINAL);
|
JCModifiers mods = optFinal(Flags.FINAL);
|
||||||
JCExpression t = parseType();
|
JCExpression t = parseType(true);
|
||||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
|
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
|
||||||
}
|
}
|
||||||
JCExpression t = term(EXPR | TYPE);
|
JCExpression t = term(EXPR | TYPE);
|
||||||
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
||||||
JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
|
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 {
|
} else {
|
||||||
checkVariableInTryWithResources(startPos);
|
checkVariableInTryWithResources(startPos);
|
||||||
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
|
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
|
||||||
@ -3397,7 +3447,7 @@ public class JavacParser implements Parser {
|
|||||||
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
|
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
accept(CLASS);
|
accept(CLASS);
|
||||||
Name name = ident();
|
Name name = typeName();
|
||||||
|
|
||||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||||
|
|
||||||
@ -3418,6 +3468,15 @@ public class JavacParser implements Parser {
|
|||||||
return result;
|
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
|
/** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
|
||||||
* [EXTENDS TypeList] InterfaceBody
|
* [EXTENDS TypeList] InterfaceBody
|
||||||
* @param mods The modifiers starting the interface declaration
|
* @param mods The modifiers starting the interface declaration
|
||||||
@ -3426,7 +3485,8 @@ public class JavacParser implements Parser {
|
|||||||
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
|
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
accept(INTERFACE);
|
accept(INTERFACE);
|
||||||
Name name = ident();
|
|
||||||
|
Name name = typeName();
|
||||||
|
|
||||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||||
|
|
||||||
@ -3449,7 +3509,8 @@ public class JavacParser implements Parser {
|
|||||||
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
|
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
accept(ENUM);
|
accept(ENUM);
|
||||||
Name name = ident();
|
|
||||||
|
Name name = typeName();
|
||||||
|
|
||||||
List<JCExpression> implementing = List.nil();
|
List<JCExpression> implementing = List.nil();
|
||||||
if (token.kind == IMPLEMENTS) {
|
if (token.kind == IMPLEMENTS) {
|
||||||
@ -3647,7 +3708,7 @@ public class JavacParser implements Parser {
|
|||||||
nextToken();
|
nextToken();
|
||||||
} else {
|
} else {
|
||||||
// method returns types are un-annotated types
|
// method returns types are un-annotated types
|
||||||
type = unannotatedType();
|
type = unannotatedType(false);
|
||||||
}
|
}
|
||||||
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
|
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
|
||||||
if (isInterface || tk.name() != className)
|
if (isInterface || tk.name() != className)
|
||||||
@ -3667,7 +3728,7 @@ public class JavacParser implements Parser {
|
|||||||
} else if (!isVoid && typarams.isEmpty()) {
|
} else if (!isVoid && typarams.isEmpty()) {
|
||||||
List<JCTree> defs =
|
List<JCTree> defs =
|
||||||
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
|
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
|
||||||
new ListBuffer<JCTree>()).toList();
|
new ListBuffer<JCTree>(), false).toList();
|
||||||
accept(SEMI);
|
accept(SEMI);
|
||||||
storeEnd(defs.last(), S.prevToken().endPos);
|
storeEnd(defs.last(), S.prevToken().endPos);
|
||||||
return defs;
|
return defs;
|
||||||
@ -3809,7 +3870,7 @@ public class JavacParser implements Parser {
|
|||||||
JCTypeParameter typeParameter() {
|
JCTypeParameter typeParameter() {
|
||||||
int pos = token.pos;
|
int pos = token.pos;
|
||||||
List<JCAnnotation> annos = typeAnnotationsOpt();
|
List<JCAnnotation> annos = typeAnnotationsOpt();
|
||||||
Name name = ident();
|
Name name = typeName();
|
||||||
ListBuffer<JCExpression> bounds = new ListBuffer<>();
|
ListBuffer<JCExpression> bounds = new ListBuffer<>();
|
||||||
if (token.kind == EXTENDS) {
|
if (token.kind == EXTENDS) {
|
||||||
nextToken();
|
nextToken();
|
||||||
|
@ -1190,6 +1190,47 @@ compiler.err.io.exception=\
|
|||||||
compiler.err.undef.label=\
|
compiler.err.undef.label=\
|
||||||
undefined label: {0}
|
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
|
# 0: message segment, 1: unused
|
||||||
compiler.err.cant.apply.diamond=\
|
compiler.err.cant.apply.diamond=\
|
||||||
cannot infer type arguments for {0}
|
cannot infer type arguments for {0}
|
||||||
@ -1873,6 +1914,9 @@ compiler.warn.raw.class.use=\
|
|||||||
compiler.warn.diamond.redundant.args=\
|
compiler.warn.diamond.redundant.args=\
|
||||||
Redundant type arguments in new expression (use diamond operator instead).
|
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=\
|
compiler.warn.potential.lambda.found=\
|
||||||
This anonymous inner class creation can be turned into a lambda expression.
|
This anonymous inner class creation can be turned into a lambda expression.
|
||||||
|
|
||||||
|
@ -946,6 +946,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isImplicitlyTyped() {
|
||||||
|
return vartype == null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(Visitor v) { v.visitVarDef(this); }
|
public void accept(Visitor v) { v.visitVarDef(this); }
|
||||||
|
|
||||||
|
@ -1359,7 +1359,7 @@ public class Pretty extends JCTree.Visitor {
|
|||||||
|
|
||||||
// Prints the inner element type of a nested array
|
// Prints the inner element type of a nested array
|
||||||
private void printBaseElementType(JCTree tree) throws IOException {
|
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
|
// prints the brackets of a nested array in reverse order
|
||||||
|
@ -1136,7 +1136,7 @@ public class TreeInfo {
|
|||||||
* For an array that contains an annotated type, return that annotated type.
|
* For an array that contains an annotated type, return that annotated type.
|
||||||
* TODO: currently only used by Pretty. Describe behavior better.
|
* 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 lastAnnotatedType = null;
|
||||||
JCTree cur = type;
|
JCTree cur = type;
|
||||||
loop: while (true) {
|
loop: while (true) {
|
||||||
@ -1157,7 +1157,7 @@ public class TreeInfo {
|
|||||||
break loop;
|
break loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastAnnotatedType!=null) {
|
if (!skipAnnos && lastAnnotatedType!=null) {
|
||||||
return lastAnnotatedType;
|
return lastAnnotatedType;
|
||||||
} else {
|
} else {
|
||||||
return cur;
|
return cur;
|
||||||
|
@ -63,6 +63,7 @@ public class Names {
|
|||||||
public final Name _default;
|
public final Name _default;
|
||||||
public final Name _super;
|
public final Name _super;
|
||||||
public final Name _this;
|
public final Name _this;
|
||||||
|
public final Name var;
|
||||||
public final Name exports;
|
public final Name exports;
|
||||||
public final Name opens;
|
public final Name opens;
|
||||||
public final Name module;
|
public final Name module;
|
||||||
@ -224,6 +225,7 @@ public class Names {
|
|||||||
_default = fromString("default");
|
_default = fromString("default");
|
||||||
_super = fromString("super");
|
_super = fromString("super");
|
||||||
_this = fromString("this");
|
_this = fromString("this");
|
||||||
|
var = fromString("var");
|
||||||
exports = fromString("exports");
|
exports = fromString("exports");
|
||||||
opens = fromString("opens");
|
opens = fromString("opens");
|
||||||
module = fromString("module");
|
module = fromString("module");
|
||||||
|
@ -106,7 +106,8 @@ module jdk.compiler {
|
|||||||
exports com.sun.tools.javac.jvm to
|
exports com.sun.tools.javac.jvm to
|
||||||
jdk.javadoc;
|
jdk.javadoc;
|
||||||
exports com.sun.tools.javac.main to
|
exports com.sun.tools.javac.main to
|
||||||
jdk.javadoc;
|
jdk.javadoc,
|
||||||
|
jdk.jshell;
|
||||||
exports com.sun.tools.javac.model to
|
exports com.sun.tools.javac.model to
|
||||||
jdk.javadoc;
|
jdk.javadoc;
|
||||||
exports com.sun.tools.javac.parser to
|
exports com.sun.tools.javac.parser to
|
||||||
|
@ -40,6 +40,7 @@ import com.sun.source.tree.ExpressionTree;
|
|||||||
import com.sun.source.tree.IdentifierTree;
|
import com.sun.source.tree.IdentifierTree;
|
||||||
import com.sun.source.tree.MethodTree;
|
import com.sun.source.tree.MethodTree;
|
||||||
import com.sun.source.tree.ModifiersTree;
|
import com.sun.source.tree.ModifiersTree;
|
||||||
|
import com.sun.source.tree.NewClassTree;
|
||||||
import com.sun.source.tree.Tree;
|
import com.sun.source.tree.Tree;
|
||||||
import com.sun.source.tree.VariableTree;
|
import com.sun.source.tree.VariableTree;
|
||||||
import com.sun.tools.javac.tree.JCTree;
|
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.BaseTask;
|
||||||
import jdk.jshell.TaskFactory.CompileTask;
|
import jdk.jshell.TaskFactory.CompileTask;
|
||||||
import jdk.jshell.TaskFactory.ParseTask;
|
import jdk.jshell.TaskFactory.ParseTask;
|
||||||
|
import jdk.jshell.Wrap.CompoundWrap;
|
||||||
import jdk.jshell.Wrap.Range;
|
import jdk.jshell.Wrap.Range;
|
||||||
import jdk.jshell.Snippet.Status;
|
import jdk.jshell.Snippet.Status;
|
||||||
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
|
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
|
||||||
@ -274,26 +276,119 @@ class Eval {
|
|||||||
for (Tree unitTree : units) {
|
for (Tree unitTree : units) {
|
||||||
VariableTree vt = (VariableTree) unitTree;
|
VariableTree vt = (VariableTree) unitTree;
|
||||||
String name = vt.getName().toString();
|
String name = vt.getName().toString();
|
||||||
String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
|
String typeName;
|
||||||
Tree baseType = vt.getType();
|
String fullTypeName;
|
||||||
TreeDependencyScanner tds = new TreeDependencyScanner();
|
TreeDependencyScanner tds = new TreeDependencyScanner();
|
||||||
tds.scan(baseType); // Not dependent on initializer
|
Wrap typeWrap;
|
||||||
|
Wrap anonDeclareWrap = null;
|
||||||
|
Wrap winit = null;
|
||||||
StringBuilder sbBrackets = new StringBuilder();
|
StringBuilder sbBrackets = new StringBuilder();
|
||||||
|
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) {
|
while (baseType instanceof ArrayTypeTree) {
|
||||||
//TODO handle annotations too
|
//TODO handle annotations too
|
||||||
baseType = ((ArrayTypeTree) baseType).getType();
|
baseType = ((ArrayTypeTree) baseType).getType();
|
||||||
sbBrackets.append("[]");
|
sbBrackets.append("[]");
|
||||||
}
|
}
|
||||||
Range rtype = dis.treeToRange(baseType);
|
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 runit = dis.treeToRange(vt);
|
Range runit = dis.treeToRange(vt);
|
||||||
runit = new Range(runit.begin, runit.end - 1);
|
runit = new Range(runit.begin, runit.end - 1);
|
||||||
ExpressionTree it = vt.getInitializer();
|
ExpressionTree it = vt.getInitializer();
|
||||||
Range rinit = null;
|
|
||||||
int nameMax = runit.end - 1;
|
int nameMax = runit.end - 1;
|
||||||
SubKind subkind;
|
SubKind subkind;
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
|
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;
|
nameMax = rinit.begin - 1;
|
||||||
} else {
|
} else {
|
||||||
subkind = SubKind.VAR_DECLARATION_SUBKIND;
|
subkind = SubKind.VAR_DECLARATION_SUBKIND;
|
||||||
@ -304,10 +399,11 @@ class Eval {
|
|||||||
}
|
}
|
||||||
int nameEnd = nameStart + name.length();
|
int nameEnd = nameStart + name.length();
|
||||||
Range rname = new Range(nameStart, nameEnd);
|
Range rname = new Range(nameStart, nameEnd);
|
||||||
Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
|
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
|
||||||
|
winit, anonDeclareWrap);
|
||||||
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
||||||
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
|
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
|
||||||
name, subkind, typeName,
|
name, subkind, fullTypeName,
|
||||||
tds.declareReferences(), modDiag);
|
tds.declareReferences(), modDiag);
|
||||||
snippets.add(snip);
|
snippets.add(snip);
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,20 @@ import com.sun.source.tree.ReturnTree;
|
|||||||
import com.sun.source.tree.ClassTree;
|
import com.sun.source.tree.ClassTree;
|
||||||
import com.sun.source.tree.CompilationUnitTree;
|
import com.sun.source.tree.CompilationUnitTree;
|
||||||
import com.sun.source.tree.ConditionalExpressionTree;
|
import com.sun.source.tree.ConditionalExpressionTree;
|
||||||
|
import com.sun.source.tree.ExpressionStatementTree;
|
||||||
import com.sun.source.tree.ExpressionTree;
|
import com.sun.source.tree.ExpressionTree;
|
||||||
|
import com.sun.source.tree.MethodInvocationTree;
|
||||||
import com.sun.source.tree.MethodTree;
|
import com.sun.source.tree.MethodTree;
|
||||||
|
import com.sun.source.tree.NewClassTree;
|
||||||
import com.sun.source.tree.Tree;
|
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.TreePath;
|
||||||
import com.sun.source.util.TreePathScanner;
|
import com.sun.source.util.TreePathScanner;
|
||||||
import com.sun.tools.javac.code.Symtab;
|
import com.sun.tools.javac.code.Symtab;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.code.Types;
|
import com.sun.tools.javac.code.Types;
|
||||||
|
import com.sun.tools.javac.util.List;
|
||||||
import jdk.jshell.TaskFactory.AnalyzeTask;
|
import jdk.jshell.TaskFactory.AnalyzeTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,6 +69,10 @@ class ExpressionToTypeInfo {
|
|||||||
public static class ExpressionInfo {
|
public static class ExpressionInfo {
|
||||||
ExpressionTree tree;
|
ExpressionTree tree;
|
||||||
String typeName;
|
String typeName;
|
||||||
|
String fullTypeName;
|
||||||
|
List<String> parameterTypes;
|
||||||
|
String enclosingInstanceType;
|
||||||
|
boolean isClass;
|
||||||
boolean isNonVoid;
|
boolean isNonVoid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +121,16 @@ class ExpressionToTypeInfo {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
|
||||||
|
if (isTargetContext) {
|
||||||
|
throw new Result(getCurrentPath());
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type pathToType(TreePath tp) {
|
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() {
|
private ExpressionInfo typeOfExpression() {
|
||||||
return treeToInfo(findExpressionPath());
|
return treeToInfo(findExpressionPath());
|
||||||
}
|
}
|
||||||
@ -172,8 +216,10 @@ class ExpressionToTypeInfo {
|
|||||||
private ExpressionInfo treeToInfo(TreePath tp) {
|
private ExpressionInfo treeToInfo(TreePath tp) {
|
||||||
if (tp != null) {
|
if (tp != null) {
|
||||||
Tree tree = tp.getLeaf();
|
Tree tree = tp.getLeaf();
|
||||||
if (tree instanceof ExpressionTree) {
|
boolean isExpression = tree instanceof ExpressionTree;
|
||||||
|
if (isExpression || tree.getKind() == Kind.VARIABLE) {
|
||||||
ExpressionInfo ei = new ExpressionInfo();
|
ExpressionInfo ei = new ExpressionInfo();
|
||||||
|
if (isExpression)
|
||||||
ei.tree = (ExpressionTree) tree;
|
ei.tree = (ExpressionTree) tree;
|
||||||
Type type = pathToType(tp, tree);
|
Type type = pathToType(tp, tree);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
@ -189,27 +235,56 @@ class ExpressionToTypeInfo {
|
|||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
ei.isNonVoid = true;
|
ei.isNonVoid = true;
|
||||||
ei.typeName = varTypeName(type);
|
ei.typeName = varTypeName(type, false);
|
||||||
if (ei.typeName == null) {
|
ei.fullTypeName = varTypeName(type, true);
|
||||||
ei.typeName = OBJECT_TYPE_NAME;
|
|
||||||
}
|
|
||||||
break;
|
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 ei;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String varTypeName(Type type) {
|
private String varTypeName(Type type, boolean printIntersectionTypes) {
|
||||||
try {
|
try {
|
||||||
TypePrinter tp = new VarTypePrinter(at.messages(),
|
TypePrinter tp = new TypePrinter(at.messages(),
|
||||||
state.maps::fullClassNameAndPackageToClass, syms, types);
|
state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
|
||||||
return tp.toString(type);
|
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) {
|
} catch (Exception ex) {
|
||||||
return null;
|
return OBJECT_TYPE_NAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ class ReplParser extends JavacParser {
|
|||||||
//mods.flags |= Flags.STATIC;
|
//mods.flags |= Flags.STATIC;
|
||||||
List<JCTree> defs
|
List<JCTree> defs
|
||||||
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
||||||
new ListBuffer<JCTree>()).toList();
|
new ListBuffer<JCTree>(), true).toList();
|
||||||
accept(SEMI);
|
accept(SEMI);
|
||||||
storeEnd(defs.last(), S.prevToken().endPos);
|
storeEnd(defs.last(), S.prevToken().endPos);
|
||||||
return defs;
|
return defs;
|
||||||
|
@ -134,6 +134,8 @@ import static jdk.jshell.TreeDissector.printType;
|
|||||||
|
|
||||||
import static java.util.stream.Collectors.joining;
|
import static java.util.stream.Collectors.joining;
|
||||||
|
|
||||||
|
import javax.lang.model.type.IntersectionType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The concrete implementation of SourceCodeAnalysis.
|
* The concrete implementation of SourceCodeAnalysis.
|
||||||
* @author Robert Field
|
* @author Robert Field
|
||||||
@ -715,6 +717,13 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
||||||
switch (site.getKind()) {
|
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: {
|
case DECLARED: {
|
||||||
TypeElement element = (TypeElement) at.getTypes().asElement(site);
|
TypeElement element = (TypeElement) at.getTypes().asElement(site);
|
||||||
List<Element> result = new ArrayList<>();
|
List<Element> result = new ArrayList<>();
|
||||||
|
@ -61,7 +61,20 @@ import javax.lang.model.util.Elements;
|
|||||||
import javax.tools.FileObject;
|
import javax.tools.FileObject;
|
||||||
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
|
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
|
||||||
import java.lang.Runtime.Version;
|
import java.lang.Runtime.Version;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
import com.sun.source.tree.Tree.Kind;
|
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
|
* The primary interface to the compiler API. Parsing, analysis, and
|
||||||
@ -355,6 +368,7 @@ class TaskFactory {
|
|||||||
Iterable<? extends JavaFileObject> compilationUnits = inputs
|
Iterable<? extends JavaFileObject> compilationUnits = inputs
|
||||||
.map(in -> sh.sourceToFileObject(fileManager, in))
|
.map(in -> sh.sourceToFileObject(fileManager, in))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
JShellJavaCompiler.preRegister(context, state);
|
||||||
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
|
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
|
||||||
fileManager, diagnostics, options, null,
|
fileManager, diagnostics, options, null,
|
||||||
compilationUnits, context);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ class TreeDissector {
|
|||||||
Type typeImpl = (Type) type;
|
Type typeImpl = (Type) type;
|
||||||
try {
|
try {
|
||||||
TypePrinter tp = new TypePrinter(at.messages(),
|
TypePrinter tp = new TypePrinter(at.messages(),
|
||||||
state.maps::fullClassNameAndPackageToClass);
|
state.maps::fullClassNameAndPackageToClass, true);
|
||||||
return tp.toString(typeImpl);
|
return tp.toString(typeImpl);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -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.Symbol.PackageSymbol;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.code.Type.ClassType;
|
import com.sun.tools.javac.code.Type.ClassType;
|
||||||
|
import com.sun.tools.javac.code.Type.IntersectionClassType;
|
||||||
import com.sun.tools.javac.util.JavacMessages;
|
import com.sun.tools.javac.util.JavacMessages;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.BinaryOperator;
|
import java.util.function.BinaryOperator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print types in source form.
|
* Print types in source form.
|
||||||
@ -45,10 +47,14 @@ class TypePrinter extends Printer {
|
|||||||
|
|
||||||
private final JavacMessages messages;
|
private final JavacMessages messages;
|
||||||
private final BinaryOperator<String> fullClassNameAndPackageToClass;
|
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.messages = messages;
|
||||||
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
|
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
|
||||||
|
this.printEnhancedTypes = printEnhancedTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
String toString(Type t) {
|
String toString(Type t) {
|
||||||
@ -92,8 +98,18 @@ class TypePrinter extends Printer {
|
|||||||
protected String className(ClassType t, boolean longform, Locale locale) {
|
protected String className(ClassType t, boolean longform, Locale locale) {
|
||||||
Symbol sym = t.tsym;
|
Symbol sym = t.tsym;
|
||||||
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
|
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
|
||||||
|
if (printEnhancedTypes) {
|
||||||
|
return ((IntersectionClassType) t).getExplicitComponents()
|
||||||
|
.stream()
|
||||||
|
.map(i -> visit(i, locale))
|
||||||
|
.collect(Collectors.joining("&"));
|
||||||
|
} else {
|
||||||
return OBJECT;
|
return OBJECT;
|
||||||
|
}
|
||||||
} else if (sym.name.length() == 0) {
|
} else if (sym.name.length() == 0) {
|
||||||
|
if (printEnhancedTypes) {
|
||||||
|
return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
|
||||||
|
}
|
||||||
// Anonymous
|
// Anonymous
|
||||||
String s;
|
String s;
|
||||||
ClassType norm = (ClassType) t.tsym.type;
|
ClassType norm = (ClassType) t.tsym.type;
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -74,16 +74,15 @@ abstract class Wrap implements GeneralWrap {
|
|||||||
* @param rdecl Type name and name
|
* @param rdecl Type name and name
|
||||||
* @return
|
* @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 wname = new RangeWrap(source, rname);
|
||||||
RangeWrap wtype = new RangeWrap(source, rtype);
|
|
||||||
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
|
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
|
||||||
Wrap wmeth;
|
Wrap wmeth;
|
||||||
|
|
||||||
if (rinit == null) {
|
if (winit == null) {
|
||||||
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
|
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
|
||||||
} else {
|
} else {
|
||||||
RangeWrap winit = new RangeWrap(source, rinit);
|
|
||||||
// int x = y
|
// int x = y
|
||||||
// int x_ = y; return x = x_;
|
// int x_ = y; return x = x_;
|
||||||
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
|
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
|
||||||
@ -93,7 +92,8 @@ abstract class Wrap implements GeneralWrap {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Wrap wInitMeth = new DoitMethodWrap(wmeth);
|
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) {
|
public static Wrap tempVarWrap(String source, String typename, String name) {
|
||||||
@ -112,6 +112,14 @@ abstract class Wrap implements GeneralWrap {
|
|||||||
return new NoWrap(source);
|
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) {
|
public static Wrap classMemberWrap(String source) {
|
||||||
Wrap w = new NoWrap(source);
|
Wrap w = new NoWrap(source);
|
||||||
return new CompoundWrap(" public static\n ", w);
|
return new CompoundWrap(" public static\n ", w);
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @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
|
* @summary Test Completion and Documentation
|
||||||
* @library /tools/lib
|
* @library /tools/lib
|
||||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||||
@ -645,6 +645,22 @@ public class CompletionSuggestionTest extends KullaTesting {
|
|||||||
assertCompletion("Foo.m(new Baz<>(|", true, "str");
|
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
|
@BeforeMethod
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @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
|
* @summary Simple jshell tool tests
|
||||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||||
* jdk.compiler/com.sun.tools.javac.main
|
* jdk.compiler/com.sun.tools.javac.main
|
||||||
@ -740,4 +740,26 @@ public class ToolSimpleTest extends ReplToolTesting {
|
|||||||
(a) -> assertCommandOutputContains(a, "1234", "==> 1234")
|
(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 = ")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8144903
|
* @bug 8144903 8177466
|
||||||
* @summary Tests for EvaluationState.variables
|
* @summary Tests for EvaluationState.variables
|
||||||
* @build KullaTesting TestingInputStream ExpectedDiagnostic
|
* @build KullaTesting TestingInputStream ExpectedDiagnostic
|
||||||
* @run testng VariablesTest
|
* @run testng VariablesTest
|
||||||
@ -337,4 +337,30 @@ public class VariablesTest extends KullaTesting {
|
|||||||
assertEquals(unr.get(0), "class undefined");
|
assertEquals(unr.get(0), "class undefined");
|
||||||
assertVariables(variable("undefined", "d"));
|
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\"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
||||||
|
}
|
@ -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 };
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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 = () -> { };
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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 = "";
|
||||||
|
}
|
||||||
|
}
|
35
test/langtools/tools/javac/diags/examples/LocalSelfRef.java
Normal file
35
test/langtools/tools/javac/diags/examples/LocalSelfRef.java
Normal 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; }
|
||||||
|
}
|
28
test/langtools/tools/javac/diags/examples/VarNotAllowed.java
Normal file
28
test/langtools/tools/javac/diags/examples/VarNotAllowed.java
Normal 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 { }
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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 = "";
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
10
test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.out
Normal file
10
test/langtools/tools/javac/lvti/BadLocalVarInferenceTest.out
Normal 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
|
47
test/langtools/tools/javac/lvti/FoldingTest.java
Normal file
47
test/langtools/tools/javac/lvti/FoldingTest.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
6
test/langtools/tools/javac/lvti/FoldingTest.out
Normal file
6
test/langtools/tools/javac/lvti/FoldingTest.out
Normal 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
|
71
test/langtools/tools/javac/lvti/ParserTest.java
Normal file
71
test/langtools/tools/javac/lvti/ParserTest.java
Normal 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
|
||||||
|
}
|
||||||
|
}
|
25
test/langtools/tools/javac/lvti/ParserTest.out
Normal file
25
test/langtools/tools/javac/lvti/ParserTest.out
Normal 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
|
23
test/langtools/tools/javac/lvti/SelfRefTest.java
Normal file
23
test/langtools/tools/javac/lvti/SelfRefTest.java
Normal 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
|
||||||
|
}
|
||||||
|
}
|
4
test/langtools/tools/javac/lvti/SelfRefTest.out
Normal file
4
test/langtools/tools/javac/lvti/SelfRefTest.out
Normal 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
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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 {
|
||||||
|
}
|
@ -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 = "";
|
||||||
|
}
|
28
test/langtools/tools/javac/lvti/harness/InferredType.java
Normal file
28
test/langtools/tools/javac/lvti/harness/InferredType.java
Normal 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();
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
test/langtools/tools/javac/lvti/harness/NonDenotableTest.java
Normal file
148
test/langtools/tools/javac/lvti/harness/NonDenotableTest.java
Normal 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; }
|
||||||
|
}
|
@ -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; }
|
||||||
|
}
|
||||||
|
}
|
@ -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() { }
|
||||||
|
}
|
||||||
|
}
|
@ -224,7 +224,7 @@ class TrialParser extends JavacParser {
|
|||||||
//mods.flags |= Flags.STATIC;
|
//mods.flags |= Flags.STATIC;
|
||||||
List<JCTree> defs
|
List<JCTree> defs
|
||||||
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
||||||
new ListBuffer<JCTree>()).toList();
|
new ListBuffer<JCTree>(), true).toList();
|
||||||
accept(SEMI);
|
accept(SEMI);
|
||||||
storeEnd(defs.last(), S.prevToken().endPos);
|
storeEnd(defs.last(), S.prevToken().endPos);
|
||||||
return defs;
|
return defs;
|
||||||
|
@ -354,7 +354,7 @@ public class TypeHarness {
|
|||||||
|
|
||||||
public TypeVar TypeVariable(Type bound) {
|
public TypeVar TypeVariable(Type bound) {
|
||||||
TypeSymbol tvsym = new TypeVariableSymbol(0, syntheticName(), null, predef.noSymbol);
|
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;
|
return (TypeVar)tvsym.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user