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
|
||||
STATICERR(Category.RESOLUTION_TARGET), // overloaded? target
|
||||
MISSING_ENCL(Category.RESOLUTION), // not overloaded non-target
|
||||
BAD_VAR(Category.RESOLUTION), // not overloaded non-target
|
||||
ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR), // not overloaded non-target
|
||||
WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD), // overloaded target
|
||||
WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD), // not overloaded target
|
||||
|
@ -227,6 +227,7 @@ public enum Source {
|
||||
return compareTo(JDK1_8) <= 0;
|
||||
}
|
||||
public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
|
||||
public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
|
||||
public static SourceVersion toSourceVersion(Source source) {
|
||||
switch(source) {
|
||||
case JDK1_2:
|
||||
|
@ -1616,6 +1616,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
|
||||
public TypeVar(Name name, Symbol owner, Type lower) {
|
||||
super(null, TypeMetadata.EMPTY);
|
||||
Assert.checkNonNull(lower);
|
||||
tsym = new TypeVariableSymbol(0, name, this, owner);
|
||||
this.bound = null;
|
||||
this.lower = lower;
|
||||
@ -1628,6 +1629,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
|
||||
public TypeVar(TypeSymbol tsym, Type bound, Type lower,
|
||||
TypeMetadata metadata) {
|
||||
super(tsym, metadata);
|
||||
Assert.checkNonNull(lower);
|
||||
this.bound = bound;
|
||||
this.lower = lower;
|
||||
}
|
||||
|
@ -1247,7 +1247,9 @@ public class TypeAnnotations {
|
||||
final TypeAnnotationPosition pos =
|
||||
TypeAnnotationPosition.localVariable(currentLambda,
|
||||
tree.pos);
|
||||
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
|
||||
if (!tree.isImplicitlyTyped()) {
|
||||
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
|
||||
}
|
||||
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
|
||||
final TypeAnnotationPosition pos =
|
||||
TypeAnnotationPosition.exceptionParameter(currentLambda,
|
||||
|
@ -190,6 +190,245 @@ public class Types {
|
||||
}
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="projections">
|
||||
|
||||
/**
|
||||
* A projection kind. See {@link TypeProjection}
|
||||
*/
|
||||
enum ProjectionKind {
|
||||
UPWARDS() {
|
||||
@Override
|
||||
ProjectionKind complement() {
|
||||
return DOWNWARDS;
|
||||
}
|
||||
},
|
||||
DOWNWARDS() {
|
||||
@Override
|
||||
ProjectionKind complement() {
|
||||
return UPWARDS;
|
||||
}
|
||||
};
|
||||
|
||||
abstract ProjectionKind complement();
|
||||
}
|
||||
|
||||
/**
|
||||
* This visitor performs upwards and downwards projections on types.
|
||||
*
|
||||
* A projection is defined as a function that takes a type T, a set of type variables V and that
|
||||
* produces another type S.
|
||||
*
|
||||
* An upwards projection maps a type T into a type S such that (i) T has no variables in V,
|
||||
* and (ii) S is an upper bound of T.
|
||||
*
|
||||
* A downwards projection maps a type T into a type S such that (i) T has no variables in V,
|
||||
* and (ii) S is a lower bound of T.
|
||||
*
|
||||
* Note that projections are only allowed to touch variables in V. Theferore it is possible for
|
||||
* a projection to leave its input type unchanged if it does not contain any variables in V.
|
||||
*
|
||||
* Moreover, note that while an upwards projection is always defined (every type as an upper bound),
|
||||
* a downwards projection is not always defined.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
|
||||
* {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
|
||||
* {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
|
||||
* {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
|
||||
*/
|
||||
class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
|
||||
|
||||
List<Type> vars;
|
||||
Set<Type> seen = new HashSet<>();
|
||||
|
||||
public TypeProjection(List<Type> vars) {
|
||||
this.vars = vars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitClassType(ClassType t, ProjectionKind pkind) {
|
||||
if (t.isCompound()) {
|
||||
List<Type> components = directSupertypes(t);
|
||||
List<Type> components1 = components.map(c -> c.map(this, pkind));
|
||||
if (components == components1) return t;
|
||||
else return makeIntersectionType(components1);
|
||||
} else {
|
||||
Type outer = t.getEnclosingType();
|
||||
Type outer1 = visit(outer, pkind);
|
||||
List<Type> typarams = t.getTypeArguments();
|
||||
List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
|
||||
if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
|
||||
//not defined
|
||||
return syms.botType;
|
||||
}
|
||||
if (outer1 == outer && typarams1 == typarams) return t;
|
||||
else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
|
||||
@Override
|
||||
protected boolean needsStripping() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
protected Type makeWildcard(Type upper, Type lower) {
|
||||
BoundKind bk;
|
||||
Type bound;
|
||||
if (upper.hasTag(BOT)) {
|
||||
upper = syms.objectType;
|
||||
}
|
||||
boolean isUpperObject = isSameType(upper, syms.objectType);
|
||||
if (!lower.hasTag(BOT) && isUpperObject) {
|
||||
bound = lower;
|
||||
bk = SUPER;
|
||||
} else {
|
||||
bound = upper;
|
||||
bk = isUpperObject ? UNBOUND : EXTENDS;
|
||||
}
|
||||
return new WildcardType(bound, bk, syms.boundClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
|
||||
if (vars.contains(t)) {
|
||||
try {
|
||||
if (seen.add(t)) {
|
||||
final Type bound;
|
||||
switch (pkind) {
|
||||
case UPWARDS:
|
||||
bound = t.getUpperBound();
|
||||
break;
|
||||
case DOWNWARDS:
|
||||
bound = (t.getLowerBound() == null) ?
|
||||
syms.botType :
|
||||
t.getLowerBound();
|
||||
break;
|
||||
default:
|
||||
Assert.error();
|
||||
return null;
|
||||
}
|
||||
return bound.map(this, pkind);
|
||||
} else {
|
||||
//cycle
|
||||
return syms.objectType;
|
||||
}
|
||||
} finally {
|
||||
seen.remove(t);
|
||||
}
|
||||
} else {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
|
||||
switch (pkind) {
|
||||
case UPWARDS:
|
||||
return wt.isExtendsBound() ?
|
||||
wt.type.map(this, pkind) :
|
||||
syms.objectType;
|
||||
case DOWNWARDS:
|
||||
return wt.isSuperBound() ?
|
||||
wt.type.map(this, pkind) :
|
||||
syms.botType;
|
||||
default:
|
||||
Assert.error();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Type mapTypeArgument(Type t, ProjectionKind pkind) {
|
||||
if (!t.containsAny(vars)) {
|
||||
return t;
|
||||
} else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
|
||||
//not defined
|
||||
return syms.botType;
|
||||
} else {
|
||||
Type upper = t.map(this, pkind);
|
||||
Type lower = t.map(this, pkind.complement());
|
||||
return makeWildcard(upper, lower);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes an upward projection of given type, and vars. See {@link TypeProjection}.
|
||||
*
|
||||
* @param t the type to be projected
|
||||
* @param vars the set of type variables to be mapped
|
||||
* @return the type obtained as result of the projection
|
||||
*/
|
||||
public Type upward(Type t, List<Type> vars) {
|
||||
return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
|
||||
* This routine is typically used to computed the input set of variables to be used during
|
||||
* an upwards projection (see {@link Types#upward(Type, List)}).
|
||||
*
|
||||
* @param t the type where occurrences of captured variables have to be found
|
||||
* @return the set of captured variables found in t
|
||||
*/
|
||||
public List<Type> captures(Type t) {
|
||||
CaptureScanner cs = new CaptureScanner();
|
||||
Set<Type> captures = new HashSet<>();
|
||||
cs.visit(t, captures);
|
||||
return List.from(captures);
|
||||
}
|
||||
|
||||
/**
|
||||
* This visitor scans a type recursively looking for occurrences of captured type variables.
|
||||
*/
|
||||
class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
|
||||
|
||||
@Override
|
||||
public Void visitType(Type t, Set<Type> types) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitClassType(ClassType t, Set<Type> seen) {
|
||||
if (t.isCompound()) {
|
||||
directSupertypes(t).forEach(s -> visit(s, seen));
|
||||
} else {
|
||||
t.allparams().forEach(ta -> visit(ta, seen));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitArrayType(ArrayType t, Set<Type> seen) {
|
||||
return visit(t.elemtype, seen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitWildcardType(WildcardType t, Set<Type> seen) {
|
||||
visit(t.type, seen);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitTypeVar(TypeVar t, Set<Type> seen) {
|
||||
if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
|
||||
visit(t.getUpperBound(), seen);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitCapturedType(CapturedType t, Set<Type> seen) {
|
||||
if (seen.add(t)) {
|
||||
visit(t.getUpperBound(), seen);
|
||||
visit(t.getLowerBound(), seen);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// </editor-fold>
|
||||
|
||||
// <editor-fold defaultstate="collapsed" desc="isUnbounded">
|
||||
/**
|
||||
* Checks that all the arguments to a class are unbounded
|
||||
|
@ -83,6 +83,7 @@ import com.sun.tools.javac.util.DiagnosticSource;
|
||||
import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
|
||||
import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
|
||||
@ -139,7 +140,8 @@ public class Analyzer {
|
||||
enum AnalyzerMode {
|
||||
DIAMOND("diamond", Source::allowDiamond),
|
||||
LAMBDA("lambda", Source::allowLambda),
|
||||
METHOD("method", Source::allowGraphInference);
|
||||
METHOD("method", Source::allowGraphInference),
|
||||
LOCAL("local", Source::allowLocalVariableTypeInference);
|
||||
|
||||
final String opt;
|
||||
final Predicate<Source> sourceFilter;
|
||||
@ -341,11 +343,91 @@ public class Analyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for local variable inference analyzers.
|
||||
*/
|
||||
abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
|
||||
|
||||
RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
|
||||
super(AnalyzerMode.LOCAL, tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a variable tree into a new declaration using implicit type.
|
||||
*/
|
||||
JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
|
||||
newTree.vartype = null;
|
||||
return newTree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze results of local variable inference.
|
||||
*/
|
||||
void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
|
||||
if (!hasErrors) {
|
||||
if (types.isSameType(oldTree.type, newTree.type)) {
|
||||
log.warning(oldTree, Warnings.LocalRedundantType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if a local variable declaration has redundant type.
|
||||
*/
|
||||
class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
|
||||
|
||||
RedundantLocalVarTypeAnalyzer() {
|
||||
super(VARDEF);
|
||||
}
|
||||
|
||||
boolean match(JCVariableDecl tree){
|
||||
return tree.sym.owner.kind == Kind.MTH &&
|
||||
tree.init != null && !tree.isImplicitlyTyped() &&
|
||||
attr.canInferLocalVarType(tree) == null;
|
||||
}
|
||||
@Override
|
||||
JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
|
||||
return mapVar(oldTree, newTree);
|
||||
}
|
||||
@Override
|
||||
void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
|
||||
processVar(oldTree, newTree, hasErrors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This analyzer checks if a for each variable declaration has redundant type.
|
||||
*/
|
||||
class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
|
||||
|
||||
RedundantLocalVarTypeAnalyzerForEach() {
|
||||
super(FOREACHLOOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean match(JCEnhancedForLoop tree){
|
||||
return !tree.var.isImplicitlyTyped();
|
||||
}
|
||||
@Override
|
||||
JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
|
||||
newTree.var = mapVar(oldTree.var, newTree.var);
|
||||
newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
|
||||
return newTree;
|
||||
}
|
||||
@Override
|
||||
void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
|
||||
processVar(oldTree.var, newTree.var, hasErrors);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
|
||||
new DiamondInitializer(),
|
||||
new LambdaAnalyzer(),
|
||||
new RedundantTypeArgAnalyzer()
|
||||
new RedundantTypeArgAnalyzer(),
|
||||
new RedundantLocalVarTypeAnalyzer(),
|
||||
new RedundantLocalVarTypeAnalyzerForEach()
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -28,9 +28,11 @@ package com.sun.tools.javac.comp;
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Attribute.Compound;
|
||||
import com.sun.tools.javac.code.Attribute.TypeCompound;
|
||||
import com.sun.tools.javac.code.Kinds.KindSelector;
|
||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
|
||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||
import com.sun.tools.javac.resources.CompilerProperties.Errors;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
@ -602,7 +604,7 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
Type result = attr.attribExpr(tree, env, expectedElementType);
|
||||
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
|
||||
Symbol sym = TreeInfo.symbol(tree);
|
||||
if (sym == null ||
|
||||
TreeInfo.nonstaticSelect(tree) ||
|
||||
@ -616,7 +618,7 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
Type result = attr.attribExpr(tree, env, expectedElementType);
|
||||
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
|
||||
if (result.isErroneous()) {
|
||||
// Does it look like an unresolved class literal?
|
||||
if (TreeInfo.name(tree) == names._class &&
|
||||
@ -642,7 +644,7 @@ public class Annotate {
|
||||
}
|
||||
|
||||
private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
Type result = attr.attribExpr(tree, env, expectedElementType);
|
||||
Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
|
||||
if (result.isErroneous())
|
||||
return new Attribute.Error(result.getOriginalType());
|
||||
if (result.constValue() == null) {
|
||||
@ -653,6 +655,22 @@ public class Annotate {
|
||||
return new Attribute.Constant(expectedElementType, result.constValue());
|
||||
}
|
||||
|
||||
private Attr.ResultInfo annotationValueInfo(Type pt) {
|
||||
return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
|
||||
}
|
||||
|
||||
class AnnotationValueContext extends Check.NestedCheckContext {
|
||||
AnnotationValueContext(CheckContext enclosingContext) {
|
||||
super(enclosingContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean compatible(Type found, Type req, Warner warn) {
|
||||
//handle non-final implicitly-typed vars (will be rejected later on)
|
||||
return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
|
||||
}
|
||||
}
|
||||
|
||||
private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
|
||||
// Special case, implicit array
|
||||
if (!tree.hasTag(NEWARRAY)) {
|
||||
|
@ -36,7 +36,6 @@ import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.TreeVisitor;
|
||||
import com.sun.source.util.SimpleTreeVisitor;
|
||||
import com.sun.tools.javac.code.*;
|
||||
import com.sun.tools.javac.code.Directive.RequiresFlag;
|
||||
import com.sun.tools.javac.code.Lint.LintCategory;
|
||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
@ -46,7 +45,6 @@ import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
|
||||
import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
|
||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||
import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
|
||||
import com.sun.tools.javac.comp.Infer.FreeTypeListener;
|
||||
import com.sun.tools.javac.jvm.*;
|
||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
|
||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
|
||||
@ -830,6 +828,10 @@ public class Attr extends JCTree.Visitor {
|
||||
final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
|
||||
try {
|
||||
Type itype = attribExpr(variable.init, env, type);
|
||||
if (variable.isImplicitlyTyped()) {
|
||||
//fixup local variable type
|
||||
type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
|
||||
}
|
||||
if (itype.constValue() != null) {
|
||||
return coerce(itype, type).constValue();
|
||||
} else {
|
||||
@ -1108,6 +1110,21 @@ public class Attr extends JCTree.Visitor {
|
||||
// parameters have already been entered
|
||||
env.info.scope.enter(tree.sym);
|
||||
} else {
|
||||
if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
|
||||
if (tree.init == null) {
|
||||
//cannot use 'var' without initializer
|
||||
log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
|
||||
tree.vartype = make.Erroneous();
|
||||
} else {
|
||||
Fragment msg = canInferLocalVarType(tree);
|
||||
if (msg != null) {
|
||||
//cannot use 'var' with initializer which require an explicit target
|
||||
//(e.g. lambda, method reference, array initializer).
|
||||
log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
|
||||
tree.vartype = make.Erroneous();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
annotate.blockAnnotations();
|
||||
memberEnter.memberEnter(tree, env);
|
||||
@ -1131,7 +1148,7 @@ public class Attr extends JCTree.Visitor {
|
||||
boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
|
||||
((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
|
||||
(tree.sym.flags() & PARAMETER) != 0;
|
||||
chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
|
||||
chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
|
||||
|
||||
try {
|
||||
v.getConstValue(); // ensure compile-time constant initializer is evaluated
|
||||
@ -1152,6 +1169,10 @@ public class Attr extends JCTree.Visitor {
|
||||
// marking the variable as undefined.
|
||||
initEnv.info.enclVar = v;
|
||||
attribExpr(tree.init, initEnv, v.type);
|
||||
if (tree.isImplicitlyTyped()) {
|
||||
//fixup local variable type
|
||||
v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = tree.type = v.type;
|
||||
@ -1161,6 +1182,71 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
Fragment canInferLocalVarType(JCVariableDecl tree) {
|
||||
LocalInitScanner lis = new LocalInitScanner();
|
||||
lis.scan(tree.init);
|
||||
return lis.badInferenceMsg;
|
||||
}
|
||||
|
||||
static class LocalInitScanner extends TreeScanner {
|
||||
Fragment badInferenceMsg = null;
|
||||
boolean needsTarget = true;
|
||||
|
||||
@Override
|
||||
public void visitNewArray(JCNewArray tree) {
|
||||
if (tree.elemtype == null && needsTarget) {
|
||||
badInferenceMsg = Fragments.LocalArrayMissingTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambda(JCLambda tree) {
|
||||
if (needsTarget) {
|
||||
badInferenceMsg = Fragments.LocalLambdaMissingTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeCast(JCTypeCast tree) {
|
||||
boolean prevNeedsTarget = needsTarget;
|
||||
try {
|
||||
needsTarget = false;
|
||||
super.visitTypeCast(tree);
|
||||
} finally {
|
||||
needsTarget = prevNeedsTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReference(JCMemberReference tree) {
|
||||
if (needsTarget) {
|
||||
badInferenceMsg = Fragments.LocalMrefMissingTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNewClass(JCNewClass tree) {
|
||||
boolean prevNeedsTarget = needsTarget;
|
||||
try {
|
||||
needsTarget = false;
|
||||
super.visitNewClass(tree);
|
||||
} finally {
|
||||
needsTarget = prevNeedsTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitApply(JCMethodInvocation tree) {
|
||||
boolean prevNeedsTarget = needsTarget;
|
||||
try {
|
||||
needsTarget = false;
|
||||
super.visitApply(tree);
|
||||
} finally {
|
||||
needsTarget = prevNeedsTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void visitSkip(JCSkip tree) {
|
||||
result = null;
|
||||
}
|
||||
@ -1243,7 +1329,6 @@ public class Attr extends JCTree.Visitor {
|
||||
//attributing the for-each expression; we mimick this by attributing
|
||||
//the for-each expression first (against original scope).
|
||||
Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
|
||||
attribStat(tree.var, loopEnv);
|
||||
chk.checkNonVoid(tree.pos(), exprType);
|
||||
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
|
||||
if (elemtype == null) {
|
||||
@ -1261,6 +1346,15 @@ public class Attr extends JCTree.Visitor {
|
||||
: types.wildUpperBound(iterableParams.head);
|
||||
}
|
||||
}
|
||||
if (tree.var.isImplicitlyTyped()) {
|
||||
Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
|
||||
if (inferredType.isErroneous()) {
|
||||
tree.var.vartype = make.at(tree.var.vartype).Erroneous();
|
||||
} else {
|
||||
tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
|
||||
}
|
||||
}
|
||||
attribStat(tree.var, loopEnv);
|
||||
chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
|
||||
loopEnv.tree = tree; // before, we were not in loop!
|
||||
attribStat(tree.body, loopEnv);
|
||||
@ -2379,7 +2473,8 @@ public class Attr extends JCTree.Visitor {
|
||||
if (pt().hasTag(ARRAY)) {
|
||||
elemtype = types.elemtype(pt());
|
||||
} else {
|
||||
if (!pt().hasTag(ERROR)) {
|
||||
if (!pt().hasTag(ERROR) &&
|
||||
(env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||
log.error(tree.pos(),
|
||||
Errors.IllegalInitializerForType(pt()));
|
||||
}
|
||||
@ -2404,7 +2499,7 @@ public class Attr extends JCTree.Visitor {
|
||||
@Override
|
||||
public void visitLambda(final JCLambda that) {
|
||||
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
|
||||
if (pt().hasTag(NONE)) {
|
||||
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||
//lambda only allowed in assignment or method invocation/cast context
|
||||
log.error(that.pos(), Errors.UnexpectedLambda);
|
||||
}
|
||||
@ -2837,7 +2932,7 @@ public class Attr extends JCTree.Visitor {
|
||||
@Override
|
||||
public void visitReference(final JCMemberReference that) {
|
||||
if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
|
||||
if (pt().hasTag(NONE)) {
|
||||
if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
|
||||
//method reference only allowed in assignment or method invocation/cast context
|
||||
log.error(that.pos(), Errors.UnexpectedMref);
|
||||
}
|
||||
@ -3811,6 +3906,14 @@ public class Attr extends JCTree.Visitor {
|
||||
break;
|
||||
case VAR:
|
||||
VarSymbol v = (VarSymbol)sym;
|
||||
|
||||
if (env.info.enclVar != null
|
||||
&& v.type.hasTag(NONE)) {
|
||||
//self reference to implicitly typed variable declaration
|
||||
log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
|
||||
return v.type = types.createErrorType(v.type);
|
||||
}
|
||||
|
||||
// Test (4): if symbol is an instance field of a raw type,
|
||||
// which is being assigned to, issue an unchecked warning if
|
||||
// its type changes under erasure.
|
||||
@ -4135,6 +4238,9 @@ public class Attr extends JCTree.Visitor {
|
||||
public void visitTypeArray(JCArrayTypeTree tree) {
|
||||
Type etype = attribType(tree.elemtype, env);
|
||||
Type type = new ArrayType(etype, syms.arrayClass);
|
||||
if (etype.isErroneous()) {
|
||||
type = types.createErrorType(type);
|
||||
}
|
||||
result = check(tree, type, KindSelector.TYP, resultInfo);
|
||||
}
|
||||
|
||||
@ -4776,7 +4882,7 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
public void visitVarDef(final JCVariableDecl tree) {
|
||||
//System.err.println("validateTypeAnnotations.visitVarDef " + tree);
|
||||
if (tree.sym != null && tree.sym.type != null)
|
||||
if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
|
||||
validateAnnotatedType(tree.vartype, tree.sym.type);
|
||||
scan(tree.mods);
|
||||
scan(tree.vartype);
|
||||
@ -4904,17 +5010,16 @@ public class Attr extends JCTree.Visitor {
|
||||
repeat = false;
|
||||
} else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
|
||||
JCWildcard wc = (JCWildcard) enclTr;
|
||||
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
|
||||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
|
||||
} else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
|
||||
validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
|
||||
if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
|
||||
wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
|
||||
validateAnnotatedType(wc.getBound(), wc.getBound().type);
|
||||
} else {
|
||||
// Nothing to do for UNBOUND
|
||||
}
|
||||
repeat = false;
|
||||
} else if (enclTr.hasTag(TYPEARRAY)) {
|
||||
JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
|
||||
validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
|
||||
validateAnnotatedType(art.getType(), art.elemtype.type);
|
||||
repeat = false;
|
||||
} else if (enclTr.hasTag(TYPEUNION)) {
|
||||
JCTypeUnion ut = (JCTypeUnion) enclTr;
|
||||
|
@ -843,26 +843,30 @@ public class Check {
|
||||
List<Type> checkDiamondDenotable(ClassType t) {
|
||||
ListBuffer<Type> buf = new ListBuffer<>();
|
||||
for (Type arg : t.allparams()) {
|
||||
if (!diamondTypeChecker.visit(arg, null)) {
|
||||
if (!checkDenotable(arg)) {
|
||||
buf.append(arg);
|
||||
}
|
||||
}
|
||||
return buf.toList();
|
||||
}
|
||||
|
||||
boolean checkDenotable(Type t) {
|
||||
return denotableChecker.visit(t, null);
|
||||
}
|
||||
// where
|
||||
|
||||
/** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
|
||||
* types. The visit methods return false as soon as a non-denotable type is encountered and true
|
||||
* otherwise.
|
||||
*/
|
||||
private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
|
||||
private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
|
||||
@Override
|
||||
public Boolean visitType(Type t, Void s) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public Boolean visitClassType(ClassType t, Void s) {
|
||||
if (t.isCompound()) {
|
||||
if (t.isUnion() || t.isIntersection()) {
|
||||
return false;
|
||||
}
|
||||
for (Type targ : t.allparams()) {
|
||||
@ -878,7 +882,7 @@ public class Check {
|
||||
/* Any type variable mentioned in the inferred type must have been declared as a type parameter
|
||||
(i.e cannot have been produced by inference (18.4))
|
||||
*/
|
||||
return t.tsym.owner.type.getTypeArguments().contains(t);
|
||||
return (t.tsym.flags() & SYNTHETIC) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -941,6 +945,17 @@ public class Check {
|
||||
(allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
|
||||
}
|
||||
|
||||
Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
|
||||
//upward project the initializer type
|
||||
t = types.upward(t, types.captures(t));
|
||||
//check that resulting type is not the null type
|
||||
if (t.hasTag(BOT)) {
|
||||
log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
|
||||
return types.createErrorType(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
Type checkMethod(final Type mtype,
|
||||
final Symbol sym,
|
||||
final Env<AttrContext> env,
|
||||
@ -3159,7 +3174,10 @@ public class Check {
|
||||
if (s.kind == PCK)
|
||||
return true;
|
||||
} else if (target == names.TYPE_USE) {
|
||||
if (s.kind == TYP || s.kind == VAR ||
|
||||
if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
|
||||
//cannot type annotate implictly typed locals
|
||||
return false;
|
||||
} else if (s.kind == TYP || s.kind == VAR ||
|
||||
(s.kind == MTH && !s.isConstructor() &&
|
||||
!s.type.getReturnType().hasTag(VOID)) ||
|
||||
(s.kind == MTH && s.isConstructor())) {
|
||||
|
@ -529,7 +529,7 @@ public class Infer {
|
||||
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
|
||||
if (Type.containsAny(upperBounds, vars)) {
|
||||
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
|
||||
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
|
||||
fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
|
||||
todo.append(uv);
|
||||
uv.setInst(fresh_tvar.type);
|
||||
} else if (upperBounds.nonEmpty()) {
|
||||
|
@ -259,7 +259,7 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
try {
|
||||
if (TreeInfo.isEnumInit(tree)) {
|
||||
attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
|
||||
} else {
|
||||
} else if (!tree.isImplicitlyTyped()) {
|
||||
attr.attribType(tree.vartype, localEnv);
|
||||
if (TreeInfo.isReceiverParam(tree))
|
||||
checkReceiver(tree, localEnv);
|
||||
@ -279,8 +279,8 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
tree.vartype.type = atype.makeVarargs();
|
||||
}
|
||||
WriteableScope enclScope = enter.enterScope(env);
|
||||
VarSymbol v =
|
||||
new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
|
||||
Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
|
||||
VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
|
||||
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
|
||||
tree.sym = v;
|
||||
if (tree.init != null) {
|
||||
@ -298,7 +298,9 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
}
|
||||
|
||||
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
|
||||
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
|
||||
if (!tree.isImplicitlyTyped()) {
|
||||
annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
|
||||
}
|
||||
|
||||
v.pos = tree.pos;
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ public class Resolve {
|
||||
public final boolean allowModules;
|
||||
public final boolean checkVarargsAccessAfterResolution;
|
||||
private final boolean compactMethodDiags;
|
||||
private final boolean allowLocalVariableTypeInference;
|
||||
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
|
||||
|
||||
WriteableScope polymorphicSignatureScope;
|
||||
@ -136,6 +137,7 @@ public class Resolve {
|
||||
Target target = Target.instance(context);
|
||||
allowMethodHandles = target.hasMethodHandles();
|
||||
allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
|
||||
allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
|
||||
checkVarargsAccessAfterResolution =
|
||||
source.allowPostApplicabilityVarargsAccessCheck();
|
||||
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
|
||||
@ -2325,6 +2327,10 @@ public class Resolve {
|
||||
* (a subset of VAL, TYP, PCK).
|
||||
*/
|
||||
Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
|
||||
return checkVarType(findIdentInternal(env, name, kind), name);
|
||||
}
|
||||
|
||||
Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
|
||||
Symbol bestSoFar = typeNotFound;
|
||||
Symbol sym;
|
||||
|
||||
@ -2354,6 +2360,11 @@ public class Resolve {
|
||||
*/
|
||||
Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
|
||||
Name name, KindSelector kind) {
|
||||
return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
|
||||
}
|
||||
|
||||
Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
|
||||
Name name, KindSelector kind) {
|
||||
Name fullname = TypeSymbol.formFullName(name, pck);
|
||||
Symbol bestSoFar = typeNotFound;
|
||||
if (kind.contains(KindSelector.TYP)) {
|
||||
@ -2383,6 +2394,11 @@ public class Resolve {
|
||||
*/
|
||||
Symbol findIdentInType(Env<AttrContext> env, Type site,
|
||||
Name name, KindSelector kind) {
|
||||
return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
|
||||
}
|
||||
|
||||
Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
|
||||
Name name, KindSelector kind) {
|
||||
Symbol bestSoFar = typeNotFound;
|
||||
Symbol sym;
|
||||
if (kind.contains(KindSelector.VAL)) {
|
||||
@ -2399,6 +2415,14 @@ public class Resolve {
|
||||
return bestSoFar;
|
||||
}
|
||||
|
||||
private Symbol checkVarType(Symbol bestSoFar, Name name) {
|
||||
if (allowLocalVariableTypeInference && name.equals(names.var) &&
|
||||
(bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
|
||||
bestSoFar = new BadVarTypeError();
|
||||
}
|
||||
return bestSoFar;
|
||||
}
|
||||
|
||||
/* ***************************************************************************
|
||||
* Access checking
|
||||
* The following methods convert ResolveErrors to ErrorSymbols, issuing
|
||||
@ -3774,6 +3798,17 @@ public class Resolve {
|
||||
}
|
||||
}
|
||||
|
||||
class BadVarTypeError extends ResolveError {
|
||||
BadVarTypeError() {
|
||||
super(Kind.BAD_VAR, "bad var use");
|
||||
}
|
||||
|
||||
@Override
|
||||
JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
|
||||
return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* InvalidSymbolError error class indicating that a symbol matching a
|
||||
* given name does not exists in a given site.
|
||||
|
@ -179,6 +179,7 @@ public class JavacParser implements Parser {
|
||||
this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
|
||||
this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
|
||||
this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
|
||||
this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
|
||||
this.keepDocComments = keepDocComments;
|
||||
this.parseModuleInfo = parseModuleInfo;
|
||||
docComments = newDocCommentTable(keepDocComments, fac);
|
||||
@ -270,11 +271,14 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
boolean allowThisIdent;
|
||||
|
||||
/** Switch: is local variable inference allowed?
|
||||
*/
|
||||
boolean allowLocalVariableTypeInference;
|
||||
|
||||
/** The type of the method receiver, as specified by a first "this" parameter.
|
||||
*/
|
||||
JCVariableDecl receiverParam;
|
||||
|
||||
|
||||
/** When terms are parsed, the mode determines which is expected:
|
||||
* mode = EXPR : an expression
|
||||
* mode = TYPE : a type
|
||||
@ -808,12 +812,16 @@ public class JavacParser implements Parser {
|
||||
* parsing annotations.
|
||||
*/
|
||||
public JCExpression parseType() {
|
||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||
return parseType(annotations);
|
||||
return parseType(false);
|
||||
}
|
||||
|
||||
public JCExpression parseType(List<JCAnnotation> annotations) {
|
||||
JCExpression result = unannotatedType();
|
||||
public JCExpression parseType(boolean allowVar) {
|
||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||
return parseType(allowVar, annotations);
|
||||
}
|
||||
|
||||
public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
|
||||
JCExpression result = unannotatedType(allowVar);
|
||||
|
||||
if (annotations.nonEmpty()) {
|
||||
result = insertAnnotationsToMostInner(result, annotations, false);
|
||||
@ -822,10 +830,18 @@ public class JavacParser implements Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
public JCExpression unannotatedType() {
|
||||
return term(TYPE);
|
||||
public JCExpression unannotatedType(boolean allowVar) {
|
||||
JCExpression result = term(TYPE);
|
||||
|
||||
if (!allowVar && isRestrictedLocalVarTypeName(result)) {
|
||||
syntaxError(result.pos, "var.not.allowed.here");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected JCExpression term(int newmode) {
|
||||
int prevmode = mode;
|
||||
mode = newmode;
|
||||
@ -1152,11 +1168,11 @@ public class JavacParser implements Parser {
|
||||
accept(LPAREN);
|
||||
mode = TYPE;
|
||||
int pos1 = pos;
|
||||
List<JCExpression> targets = List.of(t = term3());
|
||||
List<JCExpression> targets = List.of(t = parseType());
|
||||
while (token.kind == AMP) {
|
||||
checkIntersectionTypesInCast();
|
||||
accept(AMP);
|
||||
targets = targets.prepend(term3());
|
||||
targets = targets.prepend(parseType());
|
||||
}
|
||||
if (targets.length() > 1) {
|
||||
t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
|
||||
@ -1912,7 +1928,7 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
JCExpression typeArgument() {
|
||||
List<JCAnnotation> annotations = typeAnnotationsOpt();
|
||||
if (token.kind != QUES) return parseType(annotations);
|
||||
if (token.kind != QUES) return parseType(false, annotations);
|
||||
int pos = token.pos;
|
||||
nextToken();
|
||||
JCExpression result;
|
||||
@ -2425,13 +2441,8 @@ public class JavacParser implements Parser {
|
||||
token.kind == ENUM) {
|
||||
return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
|
||||
} else {
|
||||
JCExpression t = parseType();
|
||||
ListBuffer<JCStatement> stats =
|
||||
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
|
||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
||||
accept(SEMI);
|
||||
storeEnd(stats.last(), S.prevToken().endPos);
|
||||
return stats.toList();
|
||||
JCExpression t = parseType(true);
|
||||
return localVariableDeclarations(mods, t);
|
||||
}
|
||||
}
|
||||
case ABSTRACT: case STRICTFP: {
|
||||
@ -2458,12 +2469,7 @@ public class JavacParser implements Parser {
|
||||
pos = token.pos;
|
||||
JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
|
||||
F.at(pos);
|
||||
ListBuffer<JCStatement> stats =
|
||||
variableDeclarators(mods, t, new ListBuffer<JCStatement>());
|
||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
||||
accept(SEMI);
|
||||
storeEnd(stats.last(), S.prevToken().endPos);
|
||||
return stats.toList();
|
||||
return localVariableDeclarations(mods, t);
|
||||
} else {
|
||||
// This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
|
||||
t = checkExprStat(t);
|
||||
@ -2473,6 +2479,15 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
}
|
||||
}
|
||||
//where
|
||||
private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
|
||||
ListBuffer<JCStatement> stats =
|
||||
variableDeclarators(mods, type, new ListBuffer<>(), true);
|
||||
// A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
|
||||
accept(SEMI);
|
||||
storeEnd(stats.last(), S.prevToken().endPos);
|
||||
return stats.toList();
|
||||
}
|
||||
|
||||
/** Statement =
|
||||
* Block
|
||||
@ -2766,11 +2781,11 @@ public class JavacParser implements Parser {
|
||||
ListBuffer<JCStatement> stats = new ListBuffer<>();
|
||||
int pos = token.pos;
|
||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
||||
return variableDeclarators(optFinal(0), parseType(), stats).toList();
|
||||
return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
|
||||
} else {
|
||||
JCExpression t = term(EXPR | TYPE);
|
||||
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
||||
return variableDeclarators(modifiersOpt(), t, stats).toList();
|
||||
return variableDeclarators(modifiersOpt(), t, stats, true).toList();
|
||||
} else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
|
||||
error(pos, "bad.initializer", "for-loop");
|
||||
return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
|
||||
@ -2989,9 +3004,10 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
|
||||
JCExpression type,
|
||||
T vdefs)
|
||||
T vdefs,
|
||||
boolean localDecl)
|
||||
{
|
||||
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
|
||||
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
|
||||
}
|
||||
|
||||
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
|
||||
@ -3006,14 +3022,20 @@ public class JavacParser implements Parser {
|
||||
Name name,
|
||||
boolean reqInit,
|
||||
Comment dc,
|
||||
T vdefs)
|
||||
T vdefs,
|
||||
boolean localDecl)
|
||||
{
|
||||
vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
|
||||
JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
|
||||
boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
|
||||
vdefs.append(head);
|
||||
while (token.kind == COMMA) {
|
||||
if (implicit) {
|
||||
reportSyntaxError(pos, "var.not.allowed.compound");
|
||||
}
|
||||
// All but last of multiple declarators subsume a comma
|
||||
storeEnd((JCTree)vdefs.last(), token.endPos);
|
||||
nextToken();
|
||||
vdefs.append(variableDeclarator(mods, type, reqInit, dc));
|
||||
vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
|
||||
}
|
||||
return vdefs;
|
||||
}
|
||||
@ -3021,8 +3043,8 @@ public class JavacParser implements Parser {
|
||||
/** VariableDeclarator = Ident VariableDeclaratorRest
|
||||
* ConstantDeclarator = Ident ConstantDeclaratorRest
|
||||
*/
|
||||
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
|
||||
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
|
||||
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
|
||||
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
|
||||
}
|
||||
|
||||
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
|
||||
@ -3032,7 +3054,7 @@ public class JavacParser implements Parser {
|
||||
* @param dc The documentation comment for the variable declarations, or null.
|
||||
*/
|
||||
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
|
||||
boolean reqInit, Comment dc) {
|
||||
boolean reqInit, Comment dc, boolean localDecl) {
|
||||
type = bracketsOpt(type);
|
||||
JCExpression init = null;
|
||||
if (token.kind == EQ) {
|
||||
@ -3040,12 +3062,40 @@ public class JavacParser implements Parser {
|
||||
init = variableInitializer();
|
||||
}
|
||||
else if (reqInit) syntaxError(token.pos, "expected", EQ);
|
||||
JCTree elemType = TreeInfo.innermostType(type, true);
|
||||
if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
|
||||
Name typeName = ((JCIdent)elemType).name;
|
||||
if (isRestrictedLocalVarTypeName(typeName)) {
|
||||
if (type.hasTag(TYPEARRAY)) {
|
||||
//error - 'var' and arrays
|
||||
reportSyntaxError(pos, "var.not.allowed.array");
|
||||
} else {
|
||||
//implicit type
|
||||
type = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
JCVariableDecl result =
|
||||
toP(F.at(pos).VarDef(mods, name, type, init));
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean isRestrictedLocalVarTypeName(JCExpression e) {
|
||||
switch (e.getTag()) {
|
||||
case IDENT:
|
||||
return isRestrictedLocalVarTypeName(((JCIdent)e).name);
|
||||
case TYPEARRAY:
|
||||
return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isRestrictedLocalVarTypeName(Name name) {
|
||||
return allowLocalVariableTypeInference && name == names.var;
|
||||
}
|
||||
|
||||
/** VariableDeclaratorId = Ident BracketsOpt
|
||||
*/
|
||||
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
|
||||
@ -3111,13 +3161,13 @@ public class JavacParser implements Parser {
|
||||
int startPos = token.pos;
|
||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
||||
JCModifiers mods = optFinal(Flags.FINAL);
|
||||
JCExpression t = parseType();
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
|
||||
JCExpression t = parseType(true);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
|
||||
}
|
||||
JCExpression t = term(EXPR | TYPE);
|
||||
if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
|
||||
JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
|
||||
} else {
|
||||
checkVariableInTryWithResources(startPos);
|
||||
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
|
||||
@ -3397,7 +3447,7 @@ public class JavacParser implements Parser {
|
||||
protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
|
||||
int pos = token.pos;
|
||||
accept(CLASS);
|
||||
Name name = ident();
|
||||
Name name = typeName();
|
||||
|
||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||
|
||||
@ -3418,6 +3468,15 @@ public class JavacParser implements Parser {
|
||||
return result;
|
||||
}
|
||||
|
||||
Name typeName() {
|
||||
int pos = token.pos;
|
||||
Name name = ident();
|
||||
if (isRestrictedLocalVarTypeName(name)) {
|
||||
reportSyntaxError(pos, "var.not.allowed", name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
|
||||
* [EXTENDS TypeList] InterfaceBody
|
||||
* @param mods The modifiers starting the interface declaration
|
||||
@ -3426,7 +3485,8 @@ public class JavacParser implements Parser {
|
||||
protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
|
||||
int pos = token.pos;
|
||||
accept(INTERFACE);
|
||||
Name name = ident();
|
||||
|
||||
Name name = typeName();
|
||||
|
||||
List<JCTypeParameter> typarams = typeParametersOpt();
|
||||
|
||||
@ -3449,7 +3509,8 @@ public class JavacParser implements Parser {
|
||||
protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
|
||||
int pos = token.pos;
|
||||
accept(ENUM);
|
||||
Name name = ident();
|
||||
|
||||
Name name = typeName();
|
||||
|
||||
List<JCExpression> implementing = List.nil();
|
||||
if (token.kind == IMPLEMENTS) {
|
||||
@ -3647,7 +3708,7 @@ public class JavacParser implements Parser {
|
||||
nextToken();
|
||||
} else {
|
||||
// method returns types are un-annotated types
|
||||
type = unannotatedType();
|
||||
type = unannotatedType(false);
|
||||
}
|
||||
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
|
||||
if (isInterface || tk.name() != className)
|
||||
@ -3667,7 +3728,7 @@ public class JavacParser implements Parser {
|
||||
} else if (!isVoid && typarams.isEmpty()) {
|
||||
List<JCTree> defs =
|
||||
variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
|
||||
new ListBuffer<JCTree>()).toList();
|
||||
new ListBuffer<JCTree>(), false).toList();
|
||||
accept(SEMI);
|
||||
storeEnd(defs.last(), S.prevToken().endPos);
|
||||
return defs;
|
||||
@ -3809,7 +3870,7 @@ public class JavacParser implements Parser {
|
||||
JCTypeParameter typeParameter() {
|
||||
int pos = token.pos;
|
||||
List<JCAnnotation> annos = typeAnnotationsOpt();
|
||||
Name name = ident();
|
||||
Name name = typeName();
|
||||
ListBuffer<JCExpression> bounds = new ListBuffer<>();
|
||||
if (token.kind == EXTENDS) {
|
||||
nextToken();
|
||||
|
@ -1190,6 +1190,47 @@ compiler.err.io.exception=\
|
||||
compiler.err.undef.label=\
|
||||
undefined label: {0}
|
||||
|
||||
# 0: name (type)
|
||||
compiler.err.illegal.ref.to.var.type=\
|
||||
illegal reference to restricted type ''{0}''
|
||||
|
||||
# 0: token
|
||||
compiler.err.var.not.allowed=\
|
||||
''{0}'' not allowed here\n\
|
||||
as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
|
||||
|
||||
# 0: name (variable), 1: message segment
|
||||
compiler.err.cant.infer.local.var.type=\
|
||||
cannot infer type for local variable {0}\n\
|
||||
({1})
|
||||
|
||||
compiler.err.var.not.allowed.here=\
|
||||
''var'' is not allowed here
|
||||
|
||||
compiler.err.var.not.allowed.array=\
|
||||
''var'' is not allowed as an element type of an array
|
||||
|
||||
compiler.err.var.not.allowed.compound=\
|
||||
''var'' is not allowed in a compound declaration
|
||||
|
||||
compiler.misc.local.cant.infer.null=\
|
||||
variable initializer is ''null''
|
||||
|
||||
compiler.misc.local.missing.init=\
|
||||
cannot use ''var'' on variable without initializer
|
||||
|
||||
compiler.misc.local.lambda.missing.target=\
|
||||
lambda expression needs an explicit target-type
|
||||
|
||||
compiler.misc.local.mref.missing.target=\
|
||||
method reference needs an explicit target-type
|
||||
|
||||
compiler.misc.local.array.missing.target=\
|
||||
array initializer needs an explicit target-type
|
||||
|
||||
compiler.misc.local.self.ref=\
|
||||
cannot use ''var'' on self-referencing variable
|
||||
|
||||
# 0: message segment, 1: unused
|
||||
compiler.err.cant.apply.diamond=\
|
||||
cannot infer type arguments for {0}
|
||||
@ -1873,6 +1914,9 @@ compiler.warn.raw.class.use=\
|
||||
compiler.warn.diamond.redundant.args=\
|
||||
Redundant type arguments in new expression (use diamond operator instead).
|
||||
|
||||
compiler.warn.local.redundant.type=\
|
||||
Redundant type for local variable (replace explicit type with ''var'').
|
||||
|
||||
compiler.warn.potential.lambda.found=\
|
||||
This anonymous inner class creation can be turned into a lambda expression.
|
||||
|
||||
|
@ -946,6 +946,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isImplicitlyTyped() {
|
||||
return vartype == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) { v.visitVarDef(this); }
|
||||
|
||||
|
@ -1359,7 +1359,7 @@ public class Pretty extends JCTree.Visitor {
|
||||
|
||||
// Prints the inner element type of a nested array
|
||||
private void printBaseElementType(JCTree tree) throws IOException {
|
||||
printExpr(TreeInfo.innermostType(tree));
|
||||
printExpr(TreeInfo.innermostType(tree, false));
|
||||
}
|
||||
|
||||
// prints the brackets of a nested array in reverse order
|
||||
|
@ -1136,7 +1136,7 @@ public class TreeInfo {
|
||||
* For an array that contains an annotated type, return that annotated type.
|
||||
* TODO: currently only used by Pretty. Describe behavior better.
|
||||
*/
|
||||
public static JCTree innermostType(JCTree type) {
|
||||
public static JCTree innermostType(JCTree type, boolean skipAnnos) {
|
||||
JCTree lastAnnotatedType = null;
|
||||
JCTree cur = type;
|
||||
loop: while (true) {
|
||||
@ -1157,7 +1157,7 @@ public class TreeInfo {
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (lastAnnotatedType!=null) {
|
||||
if (!skipAnnos && lastAnnotatedType!=null) {
|
||||
return lastAnnotatedType;
|
||||
} else {
|
||||
return cur;
|
||||
|
@ -63,6 +63,7 @@ public class Names {
|
||||
public final Name _default;
|
||||
public final Name _super;
|
||||
public final Name _this;
|
||||
public final Name var;
|
||||
public final Name exports;
|
||||
public final Name opens;
|
||||
public final Name module;
|
||||
@ -224,6 +225,7 @@ public class Names {
|
||||
_default = fromString("default");
|
||||
_super = fromString("super");
|
||||
_this = fromString("this");
|
||||
var = fromString("var");
|
||||
exports = fromString("exports");
|
||||
opens = fromString("opens");
|
||||
module = fromString("module");
|
||||
|
@ -106,7 +106,8 @@ module jdk.compiler {
|
||||
exports com.sun.tools.javac.jvm to
|
||||
jdk.javadoc;
|
||||
exports com.sun.tools.javac.main to
|
||||
jdk.javadoc;
|
||||
jdk.javadoc,
|
||||
jdk.jshell;
|
||||
exports com.sun.tools.javac.model to
|
||||
jdk.javadoc;
|
||||
exports com.sun.tools.javac.parser to
|
||||
|
@ -40,6 +40,7 @@ import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.ModifiersTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
@ -59,6 +60,7 @@ import jdk.jshell.TaskFactory.AnalyzeTask;
|
||||
import jdk.jshell.TaskFactory.BaseTask;
|
||||
import jdk.jshell.TaskFactory.CompileTask;
|
||||
import jdk.jshell.TaskFactory.ParseTask;
|
||||
import jdk.jshell.Wrap.CompoundWrap;
|
||||
import jdk.jshell.Wrap.Range;
|
||||
import jdk.jshell.Snippet.Status;
|
||||
import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
|
||||
@ -274,26 +276,119 @@ class Eval {
|
||||
for (Tree unitTree : units) {
|
||||
VariableTree vt = (VariableTree) unitTree;
|
||||
String name = vt.getName().toString();
|
||||
String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
|
||||
Tree baseType = vt.getType();
|
||||
String typeName;
|
||||
String fullTypeName;
|
||||
TreeDependencyScanner tds = new TreeDependencyScanner();
|
||||
tds.scan(baseType); // Not dependent on initializer
|
||||
Wrap typeWrap;
|
||||
Wrap anonDeclareWrap = null;
|
||||
Wrap winit = null;
|
||||
StringBuilder sbBrackets = new StringBuilder();
|
||||
while (baseType instanceof ArrayTypeTree) {
|
||||
//TODO handle annotations too
|
||||
baseType = ((ArrayTypeTree) baseType).getType();
|
||||
sbBrackets.append("[]");
|
||||
Tree baseType = vt.getType();
|
||||
if (baseType != null) {
|
||||
tds.scan(baseType); // Not dependent on initializer
|
||||
fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
|
||||
while (baseType instanceof ArrayTypeTree) {
|
||||
//TODO handle annotations too
|
||||
baseType = ((ArrayTypeTree) baseType).getType();
|
||||
sbBrackets.append("[]");
|
||||
}
|
||||
Range rtype = dis.treeToRange(baseType);
|
||||
typeWrap = Wrap.rangeWrap(compileSource, rtype);
|
||||
} else {
|
||||
Tree init = vt.getInitializer();
|
||||
if (init != null) {
|
||||
Range rinit = dis.treeToRange(init);
|
||||
String initCode = rinit.part(compileSource);
|
||||
ExpressionInfo ei =
|
||||
ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
|
||||
typeName = ei == null ? "java.lang.Object" : ei.typeName;
|
||||
fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
|
||||
if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
|
||||
((NewClassTree) init).getClassBody() != null) {
|
||||
NewClassTree nct = (NewClassTree) init;
|
||||
StringBuilder constructor = new StringBuilder();
|
||||
constructor.append(fullTypeName).append("(");
|
||||
String sep = "";
|
||||
if (ei.enclosingInstanceType != null) {
|
||||
constructor.append(ei.enclosingInstanceType);
|
||||
constructor.append(" encl");
|
||||
sep = ", ";
|
||||
}
|
||||
int idx = 0;
|
||||
for (String type : ei.parameterTypes) {
|
||||
constructor.append(sep);
|
||||
constructor.append(type);
|
||||
constructor.append(" ");
|
||||
constructor.append("arg" + idx++);
|
||||
sep = ", ";
|
||||
}
|
||||
if (ei.enclosingInstanceType != null) {
|
||||
constructor.append(") { encl.super (");
|
||||
} else {
|
||||
constructor.append(") { super (");
|
||||
}
|
||||
sep = "";
|
||||
for (int i = 0; i < idx; i++) {
|
||||
constructor.append(sep);
|
||||
constructor.append("arg" + i++);
|
||||
sep = ", ";
|
||||
}
|
||||
constructor.append("); }");
|
||||
List<? extends Tree> members = nct.getClassBody().getMembers();
|
||||
Range bodyRange = dis.treeListToRange(members);
|
||||
Wrap bodyWrap;
|
||||
|
||||
if (bodyRange != null) {
|
||||
bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
|
||||
} else {
|
||||
bodyWrap = Wrap.simpleWrap(" ");
|
||||
}
|
||||
|
||||
Range argRange = dis.treeListToRange(nct.getArguments());
|
||||
Wrap argWrap;
|
||||
|
||||
if (argRange != null) {
|
||||
argWrap = Wrap.rangeWrap(compileSource, argRange);
|
||||
} else {
|
||||
argWrap = Wrap.simpleWrap(" ");
|
||||
}
|
||||
|
||||
if (ei.enclosingInstanceType != null) {
|
||||
Range enclosingRanges =
|
||||
dis.treeToRange(nct.getEnclosingExpression());
|
||||
Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
|
||||
argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
|
||||
Wrap.simpleWrap(","),
|
||||
argWrap)
|
||||
: enclosingWrap;
|
||||
}
|
||||
Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
|
||||
(ei.isClass ? " extends " : " implements ") +
|
||||
typeName + " { " + constructor);
|
||||
anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
|
||||
winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
|
||||
|
||||
String superType = typeName;
|
||||
|
||||
typeName = fullTypeName;
|
||||
fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
|
||||
: "<anonymous class implementing " + superType + ">";
|
||||
}
|
||||
tds.scan(init);
|
||||
} else {
|
||||
fullTypeName = typeName = "java.lang.Object";
|
||||
}
|
||||
typeWrap = Wrap.identityWrap(typeName);
|
||||
}
|
||||
Range rtype = dis.treeToRange(baseType);
|
||||
Range runit = dis.treeToRange(vt);
|
||||
runit = new Range(runit.begin, runit.end - 1);
|
||||
ExpressionTree it = vt.getInitializer();
|
||||
Range rinit = null;
|
||||
int nameMax = runit.end - 1;
|
||||
SubKind subkind;
|
||||
if (it != null) {
|
||||
subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
|
||||
rinit = dis.treeToRange(it);
|
||||
Range rinit = dis.treeToRange(it);
|
||||
winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
|
||||
nameMax = rinit.begin - 1;
|
||||
} else {
|
||||
subkind = SubKind.VAR_DECLARATION_SUBKIND;
|
||||
@ -304,10 +399,11 @@ class Eval {
|
||||
}
|
||||
int nameEnd = nameStart + name.length();
|
||||
Range rname = new Range(nameStart, nameEnd);
|
||||
Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
|
||||
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
||||
Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
|
||||
winit, anonDeclareWrap);
|
||||
DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
|
||||
Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
|
||||
name, subkind, typeName,
|
||||
name, subkind, fullTypeName,
|
||||
tds.declareReferences(), modDiag);
|
||||
snippets.add(snip);
|
||||
}
|
||||
|
@ -29,14 +29,20 @@ import com.sun.source.tree.ReturnTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.tree.ConditionalExpressionTree;
|
||||
import com.sun.source.tree.ExpressionStatementTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import jdk.jshell.TaskFactory.AnalyzeTask;
|
||||
|
||||
/**
|
||||
@ -63,6 +69,10 @@ class ExpressionToTypeInfo {
|
||||
public static class ExpressionInfo {
|
||||
ExpressionTree tree;
|
||||
String typeName;
|
||||
String fullTypeName;
|
||||
List<String> parameterTypes;
|
||||
String enclosingInstanceType;
|
||||
boolean isClass;
|
||||
boolean isNonVoid;
|
||||
}
|
||||
|
||||
@ -111,6 +121,16 @@ class ExpressionToTypeInfo {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
|
||||
if (isTargetContext) {
|
||||
throw new Result(getCurrentPath());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Type pathToType(TreePath tp) {
|
||||
@ -156,6 +176,30 @@ class ExpressionToTypeInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry method: get expression info corresponding to a local variable declaration if its type
|
||||
* has been inferred automatically from the given initializer.
|
||||
* @param code the initializer as a string
|
||||
* @param state a JShell instance
|
||||
* @return type information
|
||||
*/
|
||||
public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
|
||||
if (code == null || code.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + code));
|
||||
AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
|
||||
CompilationUnitTree cu = at.firstCuTree();
|
||||
if (at.hasErrors() || cu == null) {
|
||||
return null;
|
||||
}
|
||||
return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ExpressionInfo typeOfExpression() {
|
||||
return treeToInfo(findExpressionPath());
|
||||
}
|
||||
@ -172,9 +216,11 @@ class ExpressionToTypeInfo {
|
||||
private ExpressionInfo treeToInfo(TreePath tp) {
|
||||
if (tp != null) {
|
||||
Tree tree = tp.getLeaf();
|
||||
if (tree instanceof ExpressionTree) {
|
||||
boolean isExpression = tree instanceof ExpressionTree;
|
||||
if (isExpression || tree.getKind() == Kind.VARIABLE) {
|
||||
ExpressionInfo ei = new ExpressionInfo();
|
||||
ei.tree = (ExpressionTree) tree;
|
||||
if (isExpression)
|
||||
ei.tree = (ExpressionTree) tree;
|
||||
Type type = pathToType(tp, tree);
|
||||
if (type != null) {
|
||||
switch (type.getKind()) {
|
||||
@ -189,27 +235,56 @@ class ExpressionToTypeInfo {
|
||||
break;
|
||||
default: {
|
||||
ei.isNonVoid = true;
|
||||
ei.typeName = varTypeName(type);
|
||||
if (ei.typeName == null) {
|
||||
ei.typeName = OBJECT_TYPE_NAME;
|
||||
}
|
||||
ei.typeName = varTypeName(type, false);
|
||||
ei.fullTypeName = varTypeName(type, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tree.getKind() == Tree.Kind.VARIABLE) {
|
||||
Tree init = ((VariableTree) tree).getInitializer();
|
||||
if (init.getKind() == Tree.Kind.NEW_CLASS &&
|
||||
((NewClassTree) init).getClassBody() != null) {
|
||||
NewClassTree nct = (NewClassTree) init;
|
||||
ClassTree clazz = nct.getClassBody();
|
||||
MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
|
||||
ExpressionStatementTree superCallStatement =
|
||||
(ExpressionStatementTree) constructor.getBody().getStatements().get(0);
|
||||
MethodInvocationTree superCall =
|
||||
(MethodInvocationTree) superCallStatement.getExpression();
|
||||
TreePath superCallPath =
|
||||
at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
|
||||
Type constrType = pathToType(superCallPath);
|
||||
ei.parameterTypes = constrType.getParameterTypes()
|
||||
.stream()
|
||||
.map(t -> varTypeName(t, false))
|
||||
.collect(List.collector());
|
||||
if (nct.getEnclosingExpression() != null) {
|
||||
TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
|
||||
ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
|
||||
}
|
||||
ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
|
||||
}
|
||||
}
|
||||
return ei;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String varTypeName(Type type) {
|
||||
private String varTypeName(Type type, boolean printIntersectionTypes) {
|
||||
try {
|
||||
TypePrinter tp = new VarTypePrinter(at.messages(),
|
||||
state.maps::fullClassNameAndPackageToClass, syms, types);
|
||||
return tp.toString(type);
|
||||
TypePrinter tp = new TypePrinter(at.messages(),
|
||||
state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
|
||||
List<Type> captures = types.captures(type);
|
||||
String res = tp.toString(types.upward(type, captures));
|
||||
|
||||
if (res == null)
|
||||
res = OBJECT_TYPE_NAME;
|
||||
|
||||
return res;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
return OBJECT_TYPE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ class ReplParser extends JavacParser {
|
||||
//mods.flags |= Flags.STATIC;
|
||||
List<JCTree> defs
|
||||
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
||||
new ListBuffer<JCTree>()).toList();
|
||||
new ListBuffer<JCTree>(), true).toList();
|
||||
accept(SEMI);
|
||||
storeEnd(defs.last(), S.prevToken().endPos);
|
||||
return defs;
|
||||
|
@ -134,6 +134,8 @@ import static jdk.jshell.TreeDissector.printType;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import javax.lang.model.type.IntersectionType;
|
||||
|
||||
/**
|
||||
* The concrete implementation of SourceCodeAnalysis.
|
||||
* @author Robert Field
|
||||
@ -715,6 +717,13 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
||||
return Collections.emptyList();
|
||||
|
||||
switch (site.getKind()) {
|
||||
case INTERSECTION: {
|
||||
List<Element> result = new ArrayList<>();
|
||||
for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
|
||||
result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case DECLARED: {
|
||||
TypeElement element = (TypeElement) at.getTypes().asElement(site);
|
||||
List<Element> result = new ArrayList<>();
|
||||
|
@ -61,7 +61,20 @@ import javax.lang.model.util.Elements;
|
||||
import javax.tools.FileObject;
|
||||
import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
|
||||
import java.lang.Runtime.Version;
|
||||
import java.nio.CharBuffer;
|
||||
import com.sun.source.tree.Tree.Kind;
|
||||
import com.sun.tools.javac.code.Kinds;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.VarSymbol;
|
||||
import com.sun.tools.javac.parser.Parser;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.util.Context.Factory;
|
||||
import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
|
||||
import jdk.jshell.Snippet.Status;
|
||||
|
||||
/**
|
||||
* The primary interface to the compiler API. Parsing, analysis, and
|
||||
@ -355,6 +368,7 @@ class TaskFactory {
|
||||
Iterable<? extends JavaFileObject> compilationUnits = inputs
|
||||
.map(in -> sh.sourceToFileObject(fileManager, in))
|
||||
.collect(Collectors.toList());
|
||||
JShellJavaCompiler.preRegister(context, state);
|
||||
this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
|
||||
fileManager, diagnostics, options, null,
|
||||
compilationUnits, context);
|
||||
@ -464,4 +478,57 @@ class TaskFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
|
||||
|
||||
public static void preRegister(Context c, JShell state) {
|
||||
c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
|
||||
}
|
||||
|
||||
private final JShell state;
|
||||
|
||||
public JShellJavaCompiler(Context context, JShell state) {
|
||||
super(context);
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
|
||||
super.processAnnotations(roots, classnames);
|
||||
state.maps
|
||||
.snippetList()
|
||||
.stream()
|
||||
.filter(s -> s.status() == Status.VALID)
|
||||
.filter(s -> s.kind() == Snippet.Kind.VAR)
|
||||
.filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
|
||||
.forEach(s -> setVariableType(roots, (VarSnippet) s));
|
||||
}
|
||||
|
||||
private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
|
||||
ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
|
||||
if (clazz == null || !clazz.isCompleted())
|
||||
return;
|
||||
VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
|
||||
if (field != null) {
|
||||
JavaFileObject prev = log.useSource(null);
|
||||
DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
|
||||
try {
|
||||
String typeName = s.typeName();
|
||||
CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
|
||||
Parser parser = parserFactory.newParser(buf, false, false, false);
|
||||
JCExpression expr = parser.parseExpression();
|
||||
if (expr.hasTag(Tag.TYPECAST)) {
|
||||
JCTypeCast tree = (JCTypeCast) expr;
|
||||
if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
|
||||
field.type = attr.attribType(tree.clazz,
|
||||
((JCClassDecl) roots.head.getTypeDecls().head).sym);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
log.popDiagnosticHandler(h);
|
||||
log.useSource(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ class TreeDissector {
|
||||
Type typeImpl = (Type) type;
|
||||
try {
|
||||
TypePrinter tp = new TypePrinter(at.messages(),
|
||||
state.maps::fullClassNameAndPackageToClass);
|
||||
state.maps::fullClassNameAndPackageToClass, true);
|
||||
return tp.toString(typeImpl);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
|
@ -32,9 +32,11 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.PackageSymbol;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
import com.sun.tools.javac.code.Type.IntersectionClassType;
|
||||
import com.sun.tools.javac.util.JavacMessages;
|
||||
import java.util.Locale;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Print types in source form.
|
||||
@ -45,10 +47,14 @@ class TypePrinter extends Printer {
|
||||
|
||||
private final JavacMessages messages;
|
||||
private final BinaryOperator<String> fullClassNameAndPackageToClass;
|
||||
private final boolean printEnhancedTypes;
|
||||
|
||||
TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
|
||||
TypePrinter(JavacMessages messages,
|
||||
BinaryOperator<String> fullClassNameAndPackageToClass,
|
||||
boolean printEnhancedTypes) {
|
||||
this.messages = messages;
|
||||
this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
|
||||
this.printEnhancedTypes = printEnhancedTypes;
|
||||
}
|
||||
|
||||
String toString(Type t) {
|
||||
@ -92,8 +98,18 @@ class TypePrinter extends Printer {
|
||||
protected String className(ClassType t, boolean longform, Locale locale) {
|
||||
Symbol sym = t.tsym;
|
||||
if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
|
||||
return OBJECT;
|
||||
if (printEnhancedTypes) {
|
||||
return ((IntersectionClassType) t).getExplicitComponents()
|
||||
.stream()
|
||||
.map(i -> visit(i, locale))
|
||||
.collect(Collectors.joining("&"));
|
||||
} else {
|
||||
return OBJECT;
|
||||
}
|
||||
} else if (sym.name.length() == 0) {
|
||||
if (printEnhancedTypes) {
|
||||
return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
|
||||
}
|
||||
// Anonymous
|
||||
String s;
|
||||
ClassType norm = (ClassType) t.tsym.type;
|
||||
|
@ -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
|
||||
* @return
|
||||
*/
|
||||
public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
|
||||
public static Wrap varWrap(String source, Wrap wtype, String brackets,
|
||||
Range rname, Wrap winit, Wrap anonDeclareWrap) {
|
||||
RangeWrap wname = new RangeWrap(source, rname);
|
||||
RangeWrap wtype = new RangeWrap(source, rtype);
|
||||
Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
|
||||
Wrap wmeth;
|
||||
|
||||
if (rinit == null) {
|
||||
if (winit == null) {
|
||||
wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n");
|
||||
} else {
|
||||
RangeWrap winit = new RangeWrap(source, rinit);
|
||||
// int x = y
|
||||
// int x_ = y; return x = x_;
|
||||
// decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
|
||||
@ -93,7 +92,8 @@ abstract class Wrap implements GeneralWrap {
|
||||
);
|
||||
}
|
||||
Wrap wInitMeth = new DoitMethodWrap(wmeth);
|
||||
return new CompoundWrap(wVarDecl, wInitMeth);
|
||||
return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
|
||||
: new CompoundWrap(wVarDecl, wInitMeth);
|
||||
}
|
||||
|
||||
public static Wrap tempVarWrap(String source, String typename, String name) {
|
||||
@ -112,6 +112,14 @@ abstract class Wrap implements GeneralWrap {
|
||||
return new NoWrap(source);
|
||||
}
|
||||
|
||||
public static Wrap identityWrap(String source) {
|
||||
return new NoWrap(source);
|
||||
}
|
||||
|
||||
public static Wrap rangeWrap(String source, Range range) {
|
||||
return new RangeWrap(source, range);
|
||||
}
|
||||
|
||||
public static Wrap classMemberWrap(String source) {
|
||||
Wrap w = new NoWrap(source);
|
||||
return new CompoundWrap(" public static\n ", w);
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110
|
||||
* @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466
|
||||
* @summary Test Completion and Documentation
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
@ -645,6 +645,22 @@ public class CompletionSuggestionTest extends KullaTesting {
|
||||
assertCompletion("Foo.m(new Baz<>(|", true, "str");
|
||||
}
|
||||
|
||||
public void testIntersection() {
|
||||
assertEval("<Z extends Runnable & CharSequence> Z get() { return null; }");
|
||||
assertEval("var v = get();");
|
||||
assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
|
||||
assertCompletion("Runnable r = |", true, "get()", "v");
|
||||
assertCompletion("CharSequence r = |", true, "get()", "v");
|
||||
assertCompletion("Number r = |", true);
|
||||
}
|
||||
|
||||
public void testAnonymous() {
|
||||
assertEval("var v = new Runnable() { public void run() { } public int length() { return 0; } };");
|
||||
assertCompletionIncludesExcludes("v.|", true, Set.of("run()", "length()"), Set.of());
|
||||
assertCompletion("Runnable r = |", true, "v");
|
||||
assertCompletion("CharSequence r = |", true);
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() {
|
||||
super.setUp();
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508
|
||||
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466
|
||||
* @summary Simple jshell tool tests
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
@ -740,4 +740,26 @@ public class ToolSimpleTest extends ReplToolTesting {
|
||||
(a) -> assertCommandOutputContains(a, "1234", "==> 1234")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntersection() {
|
||||
test(
|
||||
(a) -> assertCommandOutputContains(a, "<Z extends Runnable&CharSequence> Z get1() { return null; }", "get1()"),
|
||||
(a) -> assertCommandOutputContains(a, "var g1 = get1()", "g1"),
|
||||
(a) -> assertCommand(a, "/vars g1", "| CharSequence&Runnable g1 = null"),
|
||||
(a) -> assertCommandOutputContains(a, "<Z extends Number&CharSequence> Z get2() { return null; }", "get2()"),
|
||||
(a) -> assertCommandOutputContains(a, "var g2 = get2()", "g2"),
|
||||
(a) -> assertCommand(a, "/vars g2", "| Number&CharSequence g2 = null")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymous() {
|
||||
test(
|
||||
(a) -> assertCommandOutputContains(a, "var r1 = new Object() {}", "r1"),
|
||||
(a) -> assertCommandOutputContains(a, "/vars r1", "| <anonymous class extending Object> r1 = "),
|
||||
(a) -> assertCommandOutputContains(a, "var r2 = new Runnable() { public void run() { } }", "r2"),
|
||||
(a) -> assertCommandOutputContains(a, "/vars r2", "| <anonymous class implementing Runnable> r2 = ")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8144903
|
||||
* @bug 8144903 8177466
|
||||
* @summary Tests for EvaluationState.variables
|
||||
* @build KullaTesting TestingInputStream ExpectedDiagnostic
|
||||
* @run testng VariablesTest
|
||||
@ -337,4 +337,30 @@ public class VariablesTest extends KullaTesting {
|
||||
assertEquals(unr.get(0), "class undefined");
|
||||
assertVariables(variable("undefined", "d"));
|
||||
}
|
||||
|
||||
public void lvti() {
|
||||
assertEval("var d = 234;", "234");
|
||||
assertEval("class Test<T> { T[][] get() { return null; } }", added(VALID));
|
||||
assertEval("Test<? extends String> test() { return new Test<>(); }", added(VALID));
|
||||
assertEval("var t = test().get();", added(VALID));
|
||||
assertEval("<Z extends Runnable & CharSequence> Z get1() { return null; }", added(VALID));
|
||||
assertEval("var i1 = get1();", added(VALID));
|
||||
assertEval("void t1() { i1.run(); i1.length(); }", added(VALID));
|
||||
assertEval("i1 = 1;", DiagCheck.DIAG_ERROR, DiagCheck.DIAG_OK, ste(MAIN_SNIPPET, NONEXISTENT, REJECTED, false, null));
|
||||
assertEval("<Z extends Number & CharSequence> Z get2() { return null; }", added(VALID));
|
||||
assertEval("var i2 = get2();", added(VALID));
|
||||
assertEval("void t2() { i2.length(); }", added(VALID));
|
||||
assertEval("var r1 = new Runnable() { public void run() { } public String get() { return \"good\"; } };", added(VALID));
|
||||
assertEval("Runnable r2 = r1;");
|
||||
assertEval("r1.get()", "\"good\"");
|
||||
assertEval("var v = r1.get();", "\"good\"");
|
||||
assertEval("var r3 = new java.util.ArrayList<String>(42) { public String get() { return \"good\"; } };", added(VALID));
|
||||
assertEval("r3.get()", "\"good\"");
|
||||
assertEval("class O { public class Inner { public String test() { return \"good\"; } } }");
|
||||
assertEval("var r4 = new O().new Inner() { public String get() { return \"good\"; } };");
|
||||
assertEval("r4.get()", "\"good\"");
|
||||
assertEval("class O2 { public class Inner { public Inner(int i) { } public String test() { return \"good\"; } } }");
|
||||
assertEval("var r5 = new O2().new Inner(1) { public String get() { return \"good\"; } };");
|
||||
assertEval("r5.get()", "\"good\"");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
List<JCTree> defs
|
||||
= variableDeclaratorsRest(pos, mods, t, name, false, dc,
|
||||
new ListBuffer<JCTree>()).toList();
|
||||
new ListBuffer<JCTree>(), true).toList();
|
||||
accept(SEMI);
|
||||
storeEnd(defs.last(), S.prevToken().endPos);
|
||||
return defs;
|
||||
|
@ -354,7 +354,7 @@ public class TypeHarness {
|
||||
|
||||
public TypeVar TypeVariable(Type bound) {
|
||||
TypeSymbol tvsym = new TypeVariableSymbol(0, syntheticName(), null, predef.noSymbol);
|
||||
tvsym.type = new TypeVar(tvsym, bound, null);
|
||||
tvsym.type = new TypeVar(tvsym, bound, Type.noType);
|
||||
return (TypeVar)tvsym.type;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user