This commit is contained in:
Lana Steuck 2015-11-12 14:13:17 -08:00
commit d67f9dacf5
41 changed files with 1585 additions and 139 deletions

View file

@ -126,10 +126,9 @@ public class Flags {
*/ */
public static final int BLOCK = 1<<20; public static final int BLOCK = 1<<20;
/** Flag is set for compiler-generated abstract methods that implement /** Flag bit 21 is available. (used earlier to tag compiler-generated abstract methods that implement
* an interface method (Miranda methods). * an interface method (Miranda methods)).
*/ */
public static final int IPROXY = 1<<21;
/** Flag is set for nested classes that do not access instance members /** Flag is set for nested classes that do not access instance members
* or `this' of an outer class and therefore don't need to be passed * or `this' of an outer class and therefore don't need to be passed
@ -362,7 +361,6 @@ public class Flags {
BLOCK(Flags.BLOCK), BLOCK(Flags.BLOCK),
ENUM(Flags.ENUM), ENUM(Flags.ENUM),
MANDATED(Flags.MANDATED), MANDATED(Flags.MANDATED),
IPROXY(Flags.IPROXY),
NOOUTERTHIS(Flags.NOOUTERTHIS), NOOUTERTHIS(Flags.NOOUTERTHIS),
EXISTS(Flags.EXISTS), EXISTS(Flags.EXISTS),
COMPOUND(Flags.COMPOUND), COMPOUND(Flags.COMPOUND),

View file

@ -180,6 +180,14 @@ public abstract class Symbol extends AnnoConstruct implements Element {
: metadata.getInitTypeAttributes(); : metadata.getInitTypeAttributes();
} }
public void setInitTypeAttributes(List<Attribute.TypeCompound> l) {
initedMetadata().setInitTypeAttributes(l);
}
public void setClassInitTypeAttributes(List<Attribute.TypeCompound> l) {
initedMetadata().setClassInitTypeAttributes(l);
}
public List<Attribute.Compound> getDeclarationAttributes() { public List<Attribute.Compound> getDeclarationAttributes() {
return (metadata == null) return (metadata == null)
? List.<Attribute.Compound>nil() ? List.<Attribute.Compound>nil()

View file

@ -32,6 +32,7 @@ import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Attribute.Array; import com.sun.tools.javac.code.Attribute.Array;
import com.sun.tools.javac.code.Attribute.TypeCompound; import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol;
import com.sun.tools.javac.code.Type.ArrayType; import com.sun.tools.javac.code.Type.ArrayType;
import com.sun.tools.javac.code.Type.CapturedType; import com.sun.tools.javac.code.Type.CapturedType;
@ -388,8 +389,21 @@ public class TypeAnnotations {
sym.getKind() == ElementKind.RESOURCE_VARIABLE || sym.getKind() == ElementKind.RESOURCE_VARIABLE ||
sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
// Make sure all type annotations from the symbol are also // Make sure all type annotations from the symbol are also
// on the owner. // on the owner. If the owner is an initializer block, propagate
sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes()); // to the type.
final long ownerFlags = sym.owner.flags();
if ((ownerFlags & Flags.BLOCK) != 0) {
// Store init and clinit type annotations with the ClassSymbol
// to allow output in Gen.normalizeDefs.
ClassSymbol cs = (ClassSymbol) sym.owner.owner;
if ((ownerFlags & Flags.STATIC) != 0) {
cs.appendClassInitTypeAttributes(typeAnnotations);
} else {
cs.appendInitTypeAttributes(typeAnnotations);
}
} else {
sym.owner.appendUniqueTypeAttributes(sym.getRawTypeAttributes());
}
} }
} }

View file

@ -2763,7 +2763,7 @@ public class Types {
Scope s = c.members(); Scope s = c.members();
for (Symbol sym : s.getSymbols(NON_RECURSIVE)) { for (Symbol sym : s.getSymbols(NON_RECURSIVE)) {
if (sym.kind == MTH && if (sym.kind == MTH &&
(sym.flags() & (ABSTRACT|IPROXY|DEFAULT|PRIVATE)) == ABSTRACT) { (sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
MethodSymbol absmeth = (MethodSymbol)sym; MethodSymbol absmeth = (MethodSymbol)sym;
MethodSymbol implmeth = absmeth.implementation(impl, this, true); MethodSymbol implmeth = absmeth.implementation(impl, this, true);
if (implmeth == null || implmeth == absmeth) { if (implmeth == null || implmeth == absmeth) {

View file

@ -1890,7 +1890,8 @@ public class Attr extends JCTree.Visitor {
// Check that value of resulting type is admissible in the // Check that value of resulting type is admissible in the
// current context. Also, capture the return type // current context. Also, capture the return type
result = check(tree, capture(restype), KindSelector.VAL, resultInfo); Type capturedRes = resultInfo.checkContext.inferenceContext().cachedCapture(tree, restype, true);
result = check(tree, capturedRes, KindSelector.VAL, resultInfo);
} }
chk.validate(tree.typeargs, localEnv); chk.validate(tree.typeargs, localEnv);
} }

View file

@ -1730,11 +1730,18 @@ public class Check {
boolean resultTypesOK = boolean resultTypesOK =
types.returnTypeSubstitutable(mt, ot, otres, overrideWarner); types.returnTypeSubstitutable(mt, ot, otres, overrideWarner);
if (!resultTypesOK) { if (!resultTypesOK) {
log.error(TreeInfo.diagnosticPositionFor(m, tree), if ((m.flags() & STATIC) != 0 && (other.flags() & STATIC) != 0) {
"override.incompatible.ret", log.error(TreeInfo.diagnosticPositionFor(m, tree),
cannotOverride(m, other), Errors.OverrideIncompatibleRet(Fragments.CantHide(m, m.location(), other,
mtres, otres); other.location()), mtres, otres));
m.flags_field |= BAD_OVERRIDE; m.flags_field |= BAD_OVERRIDE;
} else {
log.error(TreeInfo.diagnosticPositionFor(m, tree),
"override.incompatible.ret",
cannotOverride(m, other),
mtres, otres);
m.flags_field |= BAD_OVERRIDE;
}
return; return;
} else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) { } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) {
warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree), warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
@ -2371,7 +2378,6 @@ public class Check {
types.isSameType(types.erasure(sym.type), types.erasure(sym2.type)) && types.isSameType(types.erasure(sym.type), types.erasure(sym2.type)) &&
sym != sym2 && sym != sym2 &&
(sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) && (sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) &&
(sym.flags() & IPROXY) == 0 && (sym2.flags() & IPROXY) == 0 &&
(sym.flags() & BRIDGE) == 0 && (sym2.flags() & BRIDGE) == 0) { (sym.flags() & BRIDGE) == 0 && (sym2.flags() & BRIDGE) == 0) {
syntheticError(pos, (sym2.flags() & SYNTHETIC) == 0 ? sym2 : sym); syntheticError(pos, (sym2.flags() & SYNTHETIC) == 0 ? sym2 : sym);
return; return;

View file

@ -372,6 +372,9 @@ public class Infer {
resultInfo, inferenceContext); resultInfo, inferenceContext);
} }
} }
} else if (rsInfoInfContext.free(resultInfo.pt)) {
//propagation - cache captured vars
qtype = inferenceContext.asUndetVar(rsInfoInfContext.cachedCapture(tree, from, false));
} }
Assert.check(allowGraphInference || !rsInfoInfContext.free(to), Assert.check(allowGraphInference || !rsInfoInfContext.free(to),
"legacy inference engine cannot handle constraints on both sides of a subtyping assertion"); "legacy inference engine cannot handle constraints on both sides of a subtyping assertion");

View file

@ -55,12 +55,16 @@ import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*;
import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
/** /**
@ -268,21 +272,34 @@ public class LambdaToMethod extends TreeTranslator {
MethodSymbol sym = localContext.translatedSym; MethodSymbol sym = localContext.translatedSym;
MethodType lambdaType = (MethodType) sym.type; MethodType lambdaType = (MethodType) sym.type;
{ { /* Type annotation management: Based on where the lambda features, type annotations that
Symbol owner = localContext.owner; are interior to it, may at this point be attached to the enclosing method, or the first
ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>(); constructor in the class, or in the enclosing class symbol or in the field whose
ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>(); initializer is the lambda. In any event, gather up the annotations that belong to the
lambda and attach it to the implementation method.
*/
for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) { Symbol owner = localContext.owner;
if (tc.position.onLambda == tree) { apportionTypeAnnotations(tree,
lambdaTypeAnnos.append(tc); owner::getRawTypeAttributes,
} else { owner::setTypeAttributes,
ownerTypeAnnos.append(tc); sym::setTypeAttributes);
}
boolean init;
if ((init = (owner.name == names.init)) || owner.name == names.clinit) {
owner = owner.owner;
apportionTypeAnnotations(tree,
init ? owner::getInitTypeAttributes : owner::getClassInitTypeAttributes,
init ? owner::setInitTypeAttributes : owner::setClassInitTypeAttributes,
sym::appendUniqueTypeAttributes);
} }
if (lambdaTypeAnnos.nonEmpty()) { if (localContext.self != null && localContext.self.getKind() == ElementKind.FIELD) {
owner.setTypeAttributes(ownerTypeAnnos.toList()); owner = localContext.self;
sym.setTypeAttributes(lambdaTypeAnnos.toList()); apportionTypeAnnotations(tree,
owner::getRawTypeAttributes,
owner::setTypeAttributes,
sym::appendUniqueTypeAttributes);
} }
} }
@ -338,6 +355,11 @@ public class LambdaToMethod extends TreeTranslator {
syntheticInits.append((JCExpression) captured_local); syntheticInits.append((JCExpression) captured_local);
} }
} }
// add captured outer this instances (used only when `this' capture itself is illegal)
for (Symbol fv : localContext.getSymbolMap(CAPTURED_OUTER_THIS).keySet()) {
JCTree captured_local = make.QualThis(fv.type);
syntheticInits.append((JCExpression) captured_local);
}
//then, determine the arguments to the indy call //then, determine the arguments to the indy call
List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev);
@ -349,6 +371,29 @@ public class LambdaToMethod extends TreeTranslator {
result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); result = makeMetafactoryIndyCall(context, refKind, sym, indy_args);
} }
// where
// Reassign type annotations from the source that should really belong to the lambda
private void apportionTypeAnnotations(JCLambda tree,
Supplier<List<Attribute.TypeCompound>> source,
Consumer<List<Attribute.TypeCompound>> owner,
Consumer<List<Attribute.TypeCompound>> lambda) {
ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>();
ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>();
for (Attribute.TypeCompound tc : source.get()) {
if (tc.position.onLambda == tree) {
lambdaTypeAnnos.append(tc);
} else {
ownerTypeAnnos.append(tc);
}
}
if (lambdaTypeAnnos.nonEmpty()) {
owner.accept(ownerTypeAnnos.toList());
lambda.accept(lambdaTypeAnnos.toList());
}
}
private JCIdent makeThis(Type type, Symbol owner) { private JCIdent makeThis(Type type, Symbol owner) {
VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
names._this, names._this,
@ -434,6 +479,32 @@ public class LambdaToMethod extends TreeTranslator {
} }
} }
/**
* Translate qualified `this' references within a lambda to the mapped identifier
* @param tree
*/
@Override
public void visitSelect(JCFieldAccess tree) {
if (context == null || !analyzer.lambdaFieldAccessFilter(tree)) {
super.visitSelect(tree);
} else {
int prevPos = make.pos;
try {
make.at(tree);
LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context;
JCTree ltree = lambdaContext.translate(tree);
if (ltree != null) {
result = ltree;
} else {
super.visitSelect(tree);
}
} finally {
make.at(prevPos);
}
}
}
@Override @Override
public void visitVarDef(JCVariableDecl tree) { public void visitVarDef(JCVariableDecl tree) {
LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context;
@ -1127,6 +1198,11 @@ public class LambdaToMethod extends TreeTranslator {
*/ */
private int lambdaCount = 0; private int lambdaCount = 0;
/**
* List of types undergoing construction via explicit constructor chaining.
*/
private List<ClassSymbol> typesUnderConstruction;
/** /**
* keep the count of lambda expression defined in given context (used to * keep the count of lambda expression defined in given context (used to
* generate unambiguous names for serializable lambdas) * generate unambiguous names for serializable lambdas)
@ -1157,10 +1233,35 @@ public class LambdaToMethod extends TreeTranslator {
private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
frameStack = List.nil(); frameStack = List.nil();
typesUnderConstruction = List.nil();
localClassDefs = new HashMap<>(); localClassDefs = new HashMap<>();
return translate(tree); return translate(tree);
} }
@Override
public void visitApply(JCMethodInvocation tree) {
List<ClassSymbol> previousNascentTypes = typesUnderConstruction;
try {
Name methName = TreeInfo.name(tree.meth);
if (methName == names._this || methName == names._super) {
typesUnderConstruction = typesUnderConstruction.prepend(currentClass());
}
super.visitApply(tree);
} finally {
typesUnderConstruction = previousNascentTypes;
}
}
// where
private ClassSymbol currentClass() {
for (Frame frame : frameStack) {
if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) {
JCClassDecl cdef = (JCClassDecl) frame.tree;
return cdef.sym;
}
}
return null;
}
@Override @Override
public void visitBlock(JCBlock tree) { public void visitBlock(JCBlock tree) {
List<Frame> prevStack = frameStack; List<Frame> prevStack = frameStack;
@ -1632,6 +1733,22 @@ public class LambdaToMethod extends TreeTranslator {
&& sym.name != names.init; && sym.name != names.init;
} }
/**
* This is used to filter out those select nodes that need to be adjusted
* when translating away lambda expressions - at the moment, this is the
* set of nodes that select `this' (qualified this)
*/
private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
LambdaTranslationContext lambdaContext =
context instanceof LambdaTranslationContext ?
(LambdaTranslationContext) context : null;
return lambdaContext != null
&& !fAccess.sym.isStatic()
&& fAccess.name == names._this
&& (fAccess.sym.owner.kind == TYP)
&& !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
}
/** /**
* This is used to filter out those new class expressions that need to * This is used to filter out those new class expressions that need to
* be qualified with an enclosing tree * be qualified with an enclosing tree
@ -1806,6 +1923,7 @@ public class LambdaToMethod extends TreeTranslator {
translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>());
translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>());
translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>());
translatedSymbols.put(CAPTURED_OUTER_THIS, new LinkedHashMap<Symbol, Symbol>());
translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>()); translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>());
freeVarProcessedLocalClasses = new HashSet<>(); freeVarProcessedLocalClasses = new HashSet<>();
@ -1918,6 +2036,16 @@ public class LambdaToMethod extends TreeTranslator {
} }
}; };
break; break;
case CAPTURED_OUTER_THIS:
Name name = names.fromString(new String(sym.flatName().toString() + names.dollarThis));
ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) {
@Override
public Symbol baseSymbol() {
//keep mapping with original captured symbol
return sym;
}
};
break;
case LOCAL_VAR: case LOCAL_VAR:
ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym); ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym);
((VarSymbol) ret).pos = ((VarSymbol) sym).pos; ((VarSymbol) ret).pos = ((VarSymbol) sym).pos;
@ -1938,6 +2066,14 @@ public class LambdaToMethod extends TreeTranslator {
} }
void addSymbol(Symbol sym, LambdaSymbolKind skind) { void addSymbol(Symbol sym, LambdaSymbolKind skind) {
if (skind == CAPTURED_THIS && sym != null && sym.kind == TYP && !typesUnderConstruction.isEmpty()) {
ClassSymbol currentClass = currentClass();
if (currentClass != null && typesUnderConstruction.contains(currentClass)) {
// reference must be to enclosing outer instance, mutate capture kind.
Assert.check(sym != currentClass); // should have been caught right in Attr
skind = CAPTURED_OUTER_THIS;
}
}
Map<Symbol, Symbol> transMap = getSymbolMap(skind); Map<Symbol, Symbol> transMap = getSymbolMap(skind);
if (!transMap.containsKey(sym)) { if (!transMap.containsKey(sym)) {
transMap.put(sym, translate(sym, skind)); transMap.put(sym, translate(sym, skind));
@ -1951,17 +2087,49 @@ public class LambdaToMethod extends TreeTranslator {
} }
JCTree translate(JCIdent lambdaIdent) { JCTree translate(JCIdent lambdaIdent) {
for (Map<Symbol, Symbol> m : translatedSymbols.values()) { for (LambdaSymbolKind kind : LambdaSymbolKind.values()) {
if (m.containsKey(lambdaIdent.sym)) { Map<Symbol, Symbol> m = getSymbolMap(kind);
Symbol tSym = m.get(lambdaIdent.sym); switch(kind) {
JCTree t = make.Ident(tSym).setType(lambdaIdent.type); default:
tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); if (m.containsKey(lambdaIdent.sym)) {
return t; Symbol tSym = m.get(lambdaIdent.sym);
JCTree t = make.Ident(tSym).setType(lambdaIdent.type);
tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes());
return t;
}
break;
case CAPTURED_OUTER_THIS:
if (lambdaIdent.sym.owner.kind == TYP && m.containsKey(lambdaIdent.sym.owner)) {
// Transform outer instance variable references anchoring them to the captured synthetic.
Symbol tSym = m.get(lambdaIdent.sym.owner);
JCExpression t = make.Ident(tSym).setType(lambdaIdent.sym.owner.type);
tSym.setTypeAttributes(lambdaIdent.sym.owner.getRawTypeAttributes());
t = make.Select(t, lambdaIdent.name);
t.setType(lambdaIdent.type);
TreeInfo.setSymbol(t, lambdaIdent.sym);
return t;
}
break;
} }
} }
return null; return null;
} }
/* Translate away qualified this expressions, anchoring them to synthetic parameters that
capture the qualified this handle. `fieldAccess' is guaranteed to one such.
*/
public JCTree translate(JCFieldAccess fieldAccess) {
Assert.check(fieldAccess.name == names._this);
Map<Symbol, Symbol> m = translatedSymbols.get(LambdaSymbolKind.CAPTURED_OUTER_THIS);
if (m.containsKey(fieldAccess.sym.owner)) {
Symbol tSym = m.get(fieldAccess.sym.owner);
JCExpression t = make.Ident(tSym).setType(fieldAccess.sym.owner.type);
tSym.setTypeAttributes(fieldAccess.sym.owner.getRawTypeAttributes());
return t;
}
return null;
}
/** /**
* The translatedSym is not complete/accurate until the analysis is * The translatedSym is not complete/accurate until the analysis is
* finished. Once the analysis is finished, the translatedSym is * finished. Once the analysis is finished, the translatedSym is
@ -1999,6 +2167,10 @@ public class LambdaToMethod extends TreeTranslator {
params.append(make.VarDef((VarSymbol) thisSym, null)); params.append(make.VarDef((VarSymbol) thisSym, null));
parameterSymbols.append((VarSymbol) thisSym); parameterSymbols.append((VarSymbol) thisSym);
} }
for (Symbol thisSym : getSymbolMap(CAPTURED_OUTER_THIS).values()) {
params.append(make.VarDef((VarSymbol) thisSym, null));
parameterSymbols.append((VarSymbol) thisSym);
}
for (Symbol thisSym : getSymbolMap(PARAM).values()) { for (Symbol thisSym : getSymbolMap(PARAM).values()) {
params.append(make.VarDef((VarSymbol) thisSym, null)); params.append(make.VarDef((VarSymbol) thisSym, null));
parameterSymbols.append((VarSymbol) thisSym); parameterSymbols.append((VarSymbol) thisSym);
@ -2096,9 +2268,6 @@ public class LambdaToMethod extends TreeTranslator {
*/ */
boolean interfaceParameterIsIntersectionType() { boolean interfaceParameterIsIntersectionType() {
List<Type> tl = tree.getDescriptorType(types).getParameterTypes(); List<Type> tl = tree.getDescriptorType(types).getParameterTypes();
if (tree.kind == ReferenceKind.UNBOUND) {
tl = tl.tail;
}
for (; tl.nonEmpty(); tl = tl.tail) { for (; tl.nonEmpty(); tl = tl.tail) {
Type pt = tl.head; Type pt = tl.head;
if (pt.getKind() == TypeKind.TYPEVAR) { if (pt.getKind() == TypeKind.TYPEVAR) {
@ -2147,6 +2316,7 @@ public class LambdaToMethod extends TreeTranslator {
LOCAL_VAR, // original to translated lambda locals LOCAL_VAR, // original to translated lambda locals
CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters
CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access)
CAPTURED_OUTER_THIS, // used when `this' capture is illegal, but outer this capture is legit (JDK-8129740)
TYPE_VAR // original to translated lambda type variables TYPE_VAR // original to translated lambda type variables
} }

View file

@ -1740,7 +1740,7 @@ public class Lower extends TreeTranslator {
private JCStatement makeResourceCloseInvocation(JCExpression resource) { private JCStatement makeResourceCloseInvocation(JCExpression resource) {
// convert to AutoCloseable if needed // convert to AutoCloseable if needed
if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) { if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
resource = (JCExpression) convert(resource, syms.autoCloseableType); resource = convert(resource, syms.autoCloseableType);
} }
// create resource.close() method invocation // create resource.close() method invocation
@ -2179,7 +2179,7 @@ public class Lower extends TreeTranslator {
*************************************************************************/ *************************************************************************/
interface TreeBuilder { interface TreeBuilder {
JCTree build(JCTree arg); JCExpression build(JCExpression arg);
} }
/** Construct an expression using the builder, with the given rval /** Construct an expression using the builder, with the given rval
@ -2197,7 +2197,7 @@ public class Lower extends TreeTranslator {
* where <code><b>TEMP</b></code> is a newly declared variable * where <code><b>TEMP</b></code> is a newly declared variable
* in the let expression. * in the let expression.
*/ */
JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) { JCExpression abstractRval(JCExpression rval, Type type, TreeBuilder builder) {
rval = TreeInfo.skipParens(rval); rval = TreeInfo.skipParens(rval);
switch (rval.getTag()) { switch (rval.getTag()) {
case LITERAL: case LITERAL:
@ -2215,15 +2215,15 @@ public class Lower extends TreeTranslator {
type, type,
currentMethodSym); currentMethodSym);
rval = convert(rval,type); rval = convert(rval,type);
JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast JCVariableDecl def = make.VarDef(var, rval); // XXX cast
JCTree built = builder.build(make.Ident(var)); JCExpression built = builder.build(make.Ident(var));
JCTree res = make.LetExpr(def, built); JCExpression res = make.LetExpr(def, built);
res.type = built.type; res.type = built.type;
return res; return res;
} }
// same as above, with the type of the temporary variable computed // same as above, with the type of the temporary variable computed
JCTree abstractRval(JCTree rval, TreeBuilder builder) { JCExpression abstractRval(JCExpression rval, TreeBuilder builder) {
return abstractRval(rval, rval.type, builder); return abstractRval(rval, rval.type, builder);
} }
@ -2232,30 +2232,28 @@ public class Lower extends TreeTranslator {
// Select expressions, where we place the left-hand-side of the // Select expressions, where we place the left-hand-side of the
// select in a temporary, and for Indexed expressions, where we // select in a temporary, and for Indexed expressions, where we
// place both the indexed expression and the index value in temps. // place both the indexed expression and the index value in temps.
JCTree abstractLval(JCTree lval, final TreeBuilder builder) { JCExpression abstractLval(JCExpression lval, final TreeBuilder builder) {
lval = TreeInfo.skipParens(lval); lval = TreeInfo.skipParens(lval);
switch (lval.getTag()) { switch (lval.getTag()) {
case IDENT: case IDENT:
return builder.build(lval); return builder.build(lval);
case SELECT: { case SELECT: {
final JCFieldAccess s = (JCFieldAccess)lval; final JCFieldAccess s = (JCFieldAccess)lval;
JCTree selected = TreeInfo.skipParens(s.selected);
Symbol lid = TreeInfo.symbol(s.selected); Symbol lid = TreeInfo.symbol(s.selected);
if (lid != null && lid.kind == TYP) return builder.build(lval); if (lid != null && lid.kind == TYP) return builder.build(lval);
return abstractRval(s.selected, new TreeBuilder() { return abstractRval(s.selected, new TreeBuilder() {
public JCTree build(final JCTree selected) { public JCExpression build(final JCExpression selected) {
return builder.build(make.Select((JCExpression)selected, s.sym)); return builder.build(make.Select(selected, s.sym));
} }
}); });
} }
case INDEXED: { case INDEXED: {
final JCArrayAccess i = (JCArrayAccess)lval; final JCArrayAccess i = (JCArrayAccess)lval;
return abstractRval(i.indexed, new TreeBuilder() { return abstractRval(i.indexed, new TreeBuilder() {
public JCTree build(final JCTree indexed) { public JCExpression build(final JCExpression indexed) {
return abstractRval(i.index, syms.intType, new TreeBuilder() { return abstractRval(i.index, syms.intType, new TreeBuilder() {
public JCTree build(final JCTree index) { public JCExpression build(final JCExpression index) {
JCTree newLval = make.Indexed((JCExpression)indexed, JCExpression newLval = make.Indexed(indexed, index);
(JCExpression)index);
newLval.setType(i.type); newLval.setType(i.type);
return builder.build(newLval); return builder.build(newLval);
} }
@ -2271,9 +2269,9 @@ public class Lower extends TreeTranslator {
} }
// evaluate and discard the first expression, then evaluate the second. // evaluate and discard the first expression, then evaluate the second.
JCTree makeComma(final JCTree expr1, final JCTree expr2) { JCExpression makeComma(final JCExpression expr1, final JCExpression expr2) {
return abstractRval(expr1, new TreeBuilder() { return abstractRval(expr1, new TreeBuilder() {
public JCTree build(final JCTree discarded) { public JCExpression build(final JCExpression discarded) {
return expr2; return expr2;
} }
}); });
@ -2306,7 +2304,7 @@ public class Lower extends TreeTranslator {
/** Visitor method: Translate a single node, boxing or unboxing if needed. /** Visitor method: Translate a single node, boxing or unboxing if needed.
*/ */
public <T extends JCTree> T translate(T tree, Type type) { public <T extends JCExpression> T translate(T tree, Type type) {
return (tree == null) ? null : boxIfNeeded(translate(tree), type); return (tree == null) ? null : boxIfNeeded(translate(tree), type);
} }
@ -2332,7 +2330,7 @@ public class Lower extends TreeTranslator {
/** Visitor method: Translate list of trees. /** Visitor method: Translate list of trees.
*/ */
public <T extends JCTree> List<T> translate(List<T> trees, Type type) { public <T extends JCExpression> List<T> translate(List<T> trees, Type type) {
if (trees == null) return null; if (trees == null) return null;
for (List<T> l = trees; l.nonEmpty(); l = l.tail) for (List<T> l = trees; l.nonEmpty(); l = l.tail)
l.head = translate(l.head, type); l.head = translate(l.head, type);
@ -2907,10 +2905,10 @@ public class Lower extends TreeTranslator {
} }
} }
//where //where
private JCTree convert(JCTree tree, Type pt) { private JCExpression convert(JCExpression tree, Type pt) {
if (tree.type == pt || tree.type.hasTag(BOT)) if (tree.type == pt || tree.type.hasTag(BOT))
return tree; return tree;
JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree); JCExpression result = make_at(tree.pos()).TypeCast(make.Type(pt), tree);
result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt) result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
: pt; : pt;
return result; return result;
@ -3075,7 +3073,7 @@ public class Lower extends TreeTranslator {
/** Expand a boxing or unboxing conversion if needed. */ /** Expand a boxing or unboxing conversion if needed. */
@SuppressWarnings("unchecked") // XXX unchecked @SuppressWarnings("unchecked") // XXX unchecked
<T extends JCTree> T boxIfNeeded(T tree, Type type) { <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
boolean havePrimitive = tree.type.isPrimitive(); boolean havePrimitive = tree.type.isPrimitive();
if (havePrimitive == type.isPrimitive()) if (havePrimitive == type.isPrimitive())
return tree; return tree;
@ -3084,12 +3082,12 @@ public class Lower extends TreeTranslator {
if (!unboxedTarget.hasTag(NONE)) { if (!unboxedTarget.hasTag(NONE)) {
if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89; if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
tree.type = unboxedTarget.constType(tree.type.constValue()); tree.type = unboxedTarget.constType(tree.type.constValue());
return (T)boxPrimitive((JCExpression)tree, types.erasure(type)); return (T)boxPrimitive(tree, types.erasure(type));
} else { } else {
tree = (T)boxPrimitive((JCExpression)tree); tree = (T)boxPrimitive(tree);
} }
} else { } else {
tree = (T)unbox((JCExpression)tree, type); tree = (T)unbox(tree, type);
} }
return tree; return tree;
} }
@ -3172,7 +3170,7 @@ public class Lower extends TreeTranslator {
// or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y) // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
// (but without recomputing x) // (but without recomputing x)
JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() { JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
public JCTree build(final JCTree lhs) { public JCExpression build(final JCExpression lhs) {
JCTree.Tag newTag = tree.getTag().noAssignOp(); JCTree.Tag newTag = tree.getTag().noAssignOp();
// Erasure (TransTypes) can change the type of // Erasure (TransTypes) can change the type of
// tree.lhs. However, we can still get the // tree.lhs. However, we can still get the
@ -3182,7 +3180,7 @@ public class Lower extends TreeTranslator {
newTag, newTag,
tree.type, tree.type,
tree.rhs.type); tree.rhs.type);
JCExpression expr = (JCExpression)lhs; JCExpression expr = lhs;
if (expr.type != tree.type) if (expr.type != tree.type)
expr = make.TypeCast(tree.type, expr); expr = make.TypeCast(tree.type, expr);
JCBinary opResult = make.Binary(newTag, expr, tree.rhs); JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
@ -3191,7 +3189,7 @@ public class Lower extends TreeTranslator {
JCExpression newRhs = boxingReq ? JCExpression newRhs = boxingReq ?
make.TypeCast(types.unboxedType(tree.type), opResult) : make.TypeCast(types.unboxedType(tree.type), opResult) :
opResult; opResult;
return make.Assign((JCExpression)lhs, newRhs).setType(tree.type); return make.Assign(lhs, newRhs).setType(tree.type);
} }
}); });
result = translate(newTree); result = translate(newTree);
@ -3218,22 +3216,22 @@ public class Lower extends TreeTranslator {
} }
/** Lower a tree of the form e++ or e-- where e is an object type */ /** Lower a tree of the form e++ or e-- where e is an object type */
JCTree lowerBoxedPostop(final JCUnary tree) { JCExpression lowerBoxedPostop(final JCUnary tree) {
// translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2 // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
// or // or
// translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2 // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
// where OP is += or -= // where OP is += or -=
final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST); final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
return abstractLval(tree.arg, new TreeBuilder() { return abstractLval(tree.arg, new TreeBuilder() {
public JCTree build(final JCTree tmp1) { public JCExpression build(final JCExpression tmp1) {
return abstractRval(tmp1, tree.arg.type, new TreeBuilder() { return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
public JCTree build(final JCTree tmp2) { public JCExpression build(final JCExpression tmp2) {
JCTree.Tag opcode = (tree.hasTag(POSTINC)) JCTree.Tag opcode = (tree.hasTag(POSTINC))
? PLUS_ASG : MINUS_ASG; ? PLUS_ASG : MINUS_ASG;
JCTree lhs = cast JCTree lhs = cast
? make.TypeCast(tree.arg.type, (JCExpression)tmp1) ? make.TypeCast(tree.arg.type, tmp1)
: tmp1; : tmp1;
JCTree update = makeAssignop(opcode, JCExpression update = makeAssignop(opcode,
lhs, lhs,
make.Literal(1)); make.Literal(1));
return makeComma(update, tmp2); return makeComma(update, tmp2);

View file

@ -32,6 +32,7 @@ import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind;
import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.List;
@ -834,10 +835,6 @@ public class TransTypes extends TreeTranslator {
public void visitSelect(JCFieldAccess tree) { public void visitSelect(JCFieldAccess tree) {
Type t = types.skipTypeVars(tree.selected.type, false); Type t = types.skipTypeVars(tree.selected.type, false);
if (t.isCompound()) { if (t.isCompound()) {
if ((tree.sym.flags() & IPROXY) != 0) {
tree.sym = ((MethodSymbol)tree.sym).
implemented((TypeSymbol)tree.sym.owner, types);
}
tree.selected = coerce( tree.selected = coerce(
translate(tree.selected, erasure(tree.selected.type)), translate(tree.selected, erasure(tree.selected.type)),
erasure(tree.sym.owner.type)); erasure(tree.sym.owner.type));
@ -859,7 +856,14 @@ public class TransTypes extends TreeTranslator {
} }
public void visitReference(JCMemberReference tree) { public void visitReference(JCMemberReference tree) {
tree.expr = translate(tree.expr, erasure(tree.expr.type)); Type t = types.skipTypeVars(tree.expr.type, false);
Type receiverTarget = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t);
if (tree.kind == ReferenceKind.UNBOUND) {
tree.expr = make.Type(receiverTarget);
} else {
tree.expr = translate(tree.expr, receiverTarget);
}
tree.type = erasure(tree.type); tree.type = erasure(tree.type);
if (tree.varargsElement != null) if (tree.varargsElement != null)
tree.varargsElement = erasure(tree.varargsElement); tree.varargsElement = erasure(tree.varargsElement);

View file

@ -1112,7 +1112,8 @@ public class ClassWriter extends ClassFile {
acount += writeMethodParametersAttr(m); acount += writeMethodParametersAttr(m);
} }
acount += writeMemberAttrs(m); acount += writeMemberAttrs(m);
acount += writeParameterAttrs(m); if (!m.isLambdaMethod())
acount += writeParameterAttrs(m);
endAttrs(acountIdx, acount); endAttrs(acountIdx, acount);
} }

View file

@ -2283,6 +2283,10 @@ compiler.warn.override.equals.but.not.hashcode=\
compiler.misc.cant.override=\ compiler.misc.cant.override=\
{0} in {1} cannot override {2} in {3} {0} in {1} cannot override {2} in {3}
# 0: symbol, 1: symbol, 2: symbol, 3: symbol
compiler.misc.cant.hide=\
{0} in {1} cannot hide {2} in {3}
# 0: symbol, 1: symbol, 2: symbol, 3: symbol # 0: symbol, 1: symbol, 2: symbol, 3: symbol
compiler.misc.cant.implement=\ compiler.misc.cant.implement=\
{0} in {1} cannot implement {2} in {3} {0} in {1} cannot implement {2} in {3}

View file

@ -2623,8 +2623,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
/** (let int x = 3; in x+2) */ /** (let int x = 3; in x+2) */
public static class LetExpr extends JCExpression { public static class LetExpr extends JCExpression {
public List<JCVariableDecl> defs; public List<JCVariableDecl> defs;
public JCTree expr; public JCExpression expr;
protected LetExpr(List<JCVariableDecl> defs, JCTree expr) { protected LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
this.defs = defs; this.defs = defs;
this.expr = expr; this.expr = expr;
} }
@ -2731,7 +2731,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args); JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args);
JCModifiers Modifiers(long flags, List<JCAnnotation> annotations); JCModifiers Modifiers(long flags, List<JCAnnotation> annotations);
JCErroneous Erroneous(List<? extends JCTree> errs); JCErroneous Erroneous(List<? extends JCTree> errs);
LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr); LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr);
} }
/** A generic visitor class for trees. /** A generic visitor class for trees.

View file

@ -512,7 +512,7 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
case LETEXPR: { case LETEXPR: {
LetExpr t = (LetExpr) node; LetExpr t = (LetExpr) node;
List<JCVariableDecl> defs = copy(t.defs, p); List<JCVariableDecl> defs = copy(t.defs, p);
JCTree expr = copy(t.expr, p); JCExpression expr = copy(t.expr, p);
return M.at(t.pos).LetExpr(defs, expr); return M.at(t.pos).LetExpr(defs, expr);
} }
default: default:

View file

@ -552,7 +552,7 @@ public class TreeMaker implements JCTree.Factory {
return tree; return tree;
} }
public LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr) { public LetExpr LetExpr(List<JCVariableDecl> defs, JCExpression expr) {
LetExpr tree = new LetExpr(defs, expr); LetExpr tree = new LetExpr(defs, expr);
tree.pos = pos; tree.pos = pos;
return tree; return tree;
@ -573,7 +573,7 @@ public class TreeMaker implements JCTree.Factory {
defs); defs);
} }
public LetExpr LetExpr(JCVariableDecl def, JCTree expr) { public LetExpr LetExpr(JCVariableDecl def, JCExpression expr) {
LetExpr tree = new LetExpr(List.of(def), expr); LetExpr tree = new LetExpr(List.of(def), expr);
tree.pos = pos; tree.pos = pos;
return tree; return tree;
@ -628,6 +628,12 @@ public class TreeMaker implements JCTree.Factory {
return Ident(new VarSymbol(FINAL, names._this, t, t.tsym)); return Ident(new VarSymbol(FINAL, names._this, t, t.tsym));
} }
/** Create a tree representing qualified `this' given its type
*/
public JCExpression QualThis(Type t) {
return Select(Type(t), new VarSymbol(FINAL, names._this, t, t.tsym));
}
/** Create a tree representing a class literal. /** Create a tree representing a class literal.
*/ */
public JCExpression ClassLiteral(ClassSymbol clazz) { public JCExpression ClassLiteral(ClassSymbol clazz) {

View file

@ -177,6 +177,7 @@ public class Names {
public final Name lambda; public final Name lambda;
public final Name metafactory; public final Name metafactory;
public final Name altMetafactory; public final Name altMetafactory;
public final Name dollarThis;
public final Name.Table table; public final Name.Table table;
@ -235,6 +236,7 @@ public class Names {
value = fromString("value"); value = fromString("value");
valueOf = fromString("valueOf"); valueOf = fromString("valueOf");
values = fromString("values"); values = fromString("values");
dollarThis = fromString("$this");
// class names // class names
java_io_Serializable = fromString("java.io.Serializable"); java_io_Serializable = fromString("java.io.Serializable");

View file

@ -675,6 +675,9 @@ public class JShellTool {
registerCommand(new Command("/classes", "/c", null, "list the declared classes", registerCommand(new Command("/classes", "/c", null, "list the declared classes",
arg -> cmdClasses(), arg -> cmdClasses(),
EMPTY_COMPLETION_PROVIDER)); EMPTY_COMPLETION_PROVIDER));
registerCommand(new Command("/imports", "/i", null, "list the imported items",
arg -> cmdImports(),
EMPTY_COMPLETION_PROVIDER));
registerCommand(new Command("/exit", "/x", null, "exit the REPL", registerCommand(new Command("/exit", "/x", null, "exit the REPL",
arg -> cmdExit(), arg -> cmdExit(),
EMPTY_COMPLETION_PROVIDER)); EMPTY_COMPLETION_PROVIDER));
@ -1256,6 +1259,12 @@ public class JShellTool {
} }
} }
private void cmdImports() {
state.imports().forEach(ik -> {
hard(" import %s%s", ik.isStatic() ? "static " : "", ik.fullname());
});
}
private void cmdUseHistoryEntry(int index) { private void cmdUseHistoryEntry(int index) {
List<Snippet> keys = state.snippets(); List<Snippet> keys = state.snippets();
if (index < 0) if (index < 0)

View file

@ -68,6 +68,29 @@ public class ImportSnippet extends PersistentSnippet {
return key().name(); return key().name();
} }
/**
*
* The qualified name of the import. For any imports
* ({@link jdk.jshell.Snippet.SubKind#TYPE_IMPORT_ON_DEMAND_SUBKIND},
* ({@link jdk.jshell.Snippet.SubKind#STATIC_IMPORT_ON_DEMAND_SUBKIND}),
* ({@link jdk.jshell.Snippet.SubKind#SINGLE_TYPE_IMPORT_SUBKIND} or
* ({@link jdk.jshell.Snippet.SubKind#SINGLE_STATIC_IMPORT_SUBKIND})
* that is the full specifier including any
* qualifiers and the asterisks.
* @return the fullname of the import
*/
public String fullname() {
return fullname;
}
/**
* When this snippet represent static import, this method returns true.
* @return true when this snippet represent static import, otherwise false
*/
public boolean isStatic() {
return isStatic;
}
/**** internal access ****/ /**** internal access ****/
@Override @Override
@ -75,10 +98,6 @@ public class ImportSnippet extends PersistentSnippet {
return (ImportKey) super.key(); return (ImportKey) super.key();
} }
boolean isStatic() {
return isStatic;
}
@Override @Override
String importLine(JShell state) { String importLine(JShell state) {
return source(); return source();

View file

@ -93,7 +93,7 @@ public class JShell implements AutoCloseable {
private ExecutionControl executionControl = null; private ExecutionControl executionControl = null;
private SourceCodeAnalysis sourceCodeAnalysis = null; private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
JShell(Builder b) { JShell(Builder b) {
@ -378,6 +378,9 @@ public class JShell implements AutoCloseable {
public void addToClasspath(String path) { public void addToClasspath(String path) {
taskFactory.addToClasspath(path); // Compiler taskFactory.addToClasspath(path); // Compiler
executionControl().commandAddToClasspath(path); // Runtime executionControl().commandAddToClasspath(path); // Runtime
if (sourceCodeAnalysis != null) {
sourceCodeAnalysis.classpathChanged();
}
} }
/** /**
@ -468,6 +471,22 @@ public class JShell implements AutoCloseable {
.collect(collectingAndThen(toList(), Collections::unmodifiableList)); .collect(collectingAndThen(toList(), Collections::unmodifiableList));
} }
/**
* Returns the active import snippets.
* This convenience method is equivalent to <code>snippets()</code> filtered for
* {@link jdk.jshell.Snippet.Status#isActive status(snippet).isActive}
* <code>&amp;&amp; snippet.kind() == Kind.IMPORT</code>
* and cast to ImportSnippet.
* @return the active declared import declarations.
* @throws IllegalStateException if this JShell instance is closed.
*/
public List<ImportSnippet> imports() throws IllegalStateException {
return snippets().stream()
.filter(sn -> status(sn).isActive && sn.kind() == Snippet.Kind.IMPORT)
.map(sn -> (ImportSnippet) sn)
.collect(collectingAndThen(toList(), Collections::unmodifiableList));
}
/** /**
* Return the status of the snippet. * Return the status of the snippet.
* This is updated either because of an explicit <code>eval()</code> call or * This is updated either because of an explicit <code>eval()</code> call or

View file

@ -42,6 +42,7 @@ import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import javax.tools.JavaFileObject.Kind; import javax.tools.JavaFileObject.Kind;
import static javax.tools.StandardLocation.CLASS_PATH; import static javax.tools.StandardLocation.CLASS_PATH;
import javax.tools.FileObject; import javax.tools.FileObject;
@ -49,6 +50,7 @@ import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject; import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager; import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy;
import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.DefinedBy.Api;
@ -77,6 +79,10 @@ class MemoryFileManager implements JavaFileManager {
private Method inferModuleNameMethod = null; private Method inferModuleNameMethod = null;
private Method listModuleLocationsMethod = null; private Method listModuleLocationsMethod = null;
Iterable<? extends Path> getLocationAsPaths(Location loc) {
return this.stdFileManager.getLocationAsPaths(loc);
}
static abstract class MemoryJavaFileObject extends SimpleJavaFileObject { static abstract class MemoryJavaFileObject extends SimpleJavaFileObject {
public MemoryJavaFileObject(String name, JavaFileObject.Kind kind) { public MemoryJavaFileObject(String name, JavaFileObject.Kind kind) {

View file

@ -75,8 +75,14 @@ import javax.lang.model.type.TypeMirror;
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA; import static jdk.internal.jshell.debug.InternalDebugControl.DBG_COMPA;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator; import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
@ -92,6 +98,7 @@ import static java.util.stream.Collectors.toSet;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement; import javax.lang.model.element.PackageElement;
import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.QualifiedNameable;
@ -100,10 +107,8 @@ import javax.lang.model.type.ArrayType;
import javax.lang.model.type.ExecutableType; import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.util.ElementFilter; import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileManager.Location;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation; import javax.tools.StandardLocation;
import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME; import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
@ -584,42 +589,114 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
.collect(toList()); .collect(toList());
} }
private Set<PackageElement> listPackages(AnalyzeTask at, String enclosingPackage) { private Set<String> emptyContextPackages = null;
Set<PackageElement> packs = new HashSet<>();
listPackages(at, StandardLocation.PLATFORM_CLASS_PATH, enclosingPackage, packs); void classpathChanged() {
listPackages(at, StandardLocation.CLASS_PATH, enclosingPackage, packs); emptyContextPackages = null;
listPackages(at, StandardLocation.SOURCE_PATH, enclosingPackage, packs);
return packs;
} }
private void listPackages(AnalyzeTask at, Location loc, String currentPackage, Set<PackageElement> packs) { private Set<PackageElement> listPackages(AnalyzeTask at, String enclosingPackage) {
try { Set<String> packs;
MemoryFileManager fm = proc.taskFactory.fileManager();
for (JavaFileObject file : fm.list(loc, currentPackage, fileKinds, true)) { if (enclosingPackage.isEmpty() && emptyContextPackages != null) {
String binaryName = fm.inferBinaryName(loc, file); packs = emptyContextPackages;
if (!currentPackage.isEmpty() && !binaryName.startsWith(currentPackage + ".")) } else {
continue; packs = new HashSet<>();
int nextDot = binaryName.indexOf('.', !currentPackage.isEmpty() ? currentPackage.length() + 1 : 0);
if (nextDot == (-1)) listPackages(StandardLocation.PLATFORM_CLASS_PATH, enclosingPackage, packs);
continue; listPackages(StandardLocation.CLASS_PATH, enclosingPackage, packs);
Elements elements = at.getElements(); listPackages(StandardLocation.SOURCE_PATH, enclosingPackage, packs);
PackageElement pack =
elements.getPackageElement(binaryName.substring(0, nextDot)); if (enclosingPackage.isEmpty()) {
if (pack == null) { emptyContextPackages = packs;
//if no types in the package have ever been seen, the package will be unknown
//try to load a type, and then try to recognize the package again:
elements.getTypeElement(binaryName);
pack = elements.getPackageElement(binaryName.substring(0, nextDot));
}
if (pack != null)
packs.add(pack);
} }
} catch (IOException ex) { }
//TODO: should log?
return packs.stream()
.map(pkg -> createPackageElement(at, pkg))
.collect(Collectors.toSet());
}
private PackageElement createPackageElement(AnalyzeTask at, String packageName) {
Names names = Names.instance(at.getContext());
Symtab syms = Symtab.instance(at.getContext());
PackageElement existing = syms.enterPackage(names.fromString(packageName));
return existing;
}
private void listPackages(Location loc, String enclosing, Set<String> packs) {
Iterable<? extends Path> paths = proc.taskFactory.fileManager().getLocationAsPaths(loc);
if (paths == null)
return ;
for (Path p : paths) {
listPackages(p, enclosing, packs);
} }
} }
//where:
private final Set<JavaFileObject.Kind> fileKinds = EnumSet.of(JavaFileObject.Kind.CLASS); private void listPackages(Path path, String enclosing, Set<String> packages) {
try {
if (path.equals(Paths.get("JRT_MARKER_FILE"))) {
FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
Path modules = jrtfs.getPath("modules");
try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules)) {
for (Path c : stream) {
listDirectory(c, enclosing, packages);
}
}
} else if (!Files.isDirectory(path)) {
if (Files.exists(path)) {
ClassLoader cl = SourceCodeAnalysisImpl.class.getClassLoader();
try (FileSystem zip = FileSystems.newFileSystem(path, cl)) {
listDirectory(zip.getRootDirectories().iterator().next(), enclosing, packages);
}
}
} else {
listDirectory(path, enclosing, packages);
}
} catch (IOException ex) {
proc.debug(ex, "SourceCodeAnalysisImpl.listPackages(" + path.toString() + ", " + enclosing + ", " + packages + ")");
}
}
private void listDirectory(Path path, String enclosing, Set<String> packages) throws IOException {
String separator = path.getFileSystem().getSeparator();
Path resolved = path.resolve(enclosing.replace(".", separator));
if (Files.isDirectory(resolved)) {
try (DirectoryStream<Path> ds = Files.newDirectoryStream(resolved)) {
for (Path entry : ds) {
String name = pathName(entry);
if (SourceVersion.isIdentifier(name) &&
Files.isDirectory(entry) &&
validPackageCandidate(entry)) {
packages.add(enclosing + (enclosing.isEmpty() ? "" : ".") + name);
}
}
}
}
}
private boolean validPackageCandidate(Path p) throws IOException {
try (Stream<Path> dir = Files.list(p)) {
return dir.anyMatch(e -> Files.isDirectory(e) && SourceVersion.isIdentifier(pathName(e)) ||
e.getFileName().toString().endsWith(".class"));
}
}
private String pathName(Path p) {
String separator = p.getFileSystem().getSeparator();
String name = p.getFileName().toString();
if (name.endsWith(separator)) //jars have '/' appended
name = name.substring(0, name.length() - separator.length());
return name;
}
private Element createArrayLengthSymbol(AnalyzeTask at, TypeMirror site) { private Element createArrayLengthSymbol(AnalyzeTask at, TypeMirror site) {
Name length = Names.instance(at.getContext()).length; Name length = Names.instance(at.getContext()).length;

View file

@ -23,6 +23,7 @@
/* /*
* @test * @test
* @bug 8141092
* @summary Test Completion * @summary Test Completion
* @library /tools/lib * @library /tools/lib
* @build KullaTesting TestingInputStream ToolBox Compiler * @build KullaTesting TestingInputStream ToolBox Compiler
@ -45,6 +46,9 @@ import static jdk.jshell.Snippet.Status.OVERWRITTEN;
@Test @Test
public class CompletionSuggestionTest extends KullaTesting { public class CompletionSuggestionTest extends KullaTesting {
private final Compiler compiler = new Compiler();
private final Path outDir = Paths.get("completion_suggestion_test");
public void testMemberExpr() { public void testMemberExpr() {
assertEval("class Test { static void test() { } }"); assertEval("class Test { static void test() { } }");
assertCompletion("Test.t|", "test()"); assertCompletion("Test.t|", "test()");
@ -232,6 +236,23 @@ public class CompletionSuggestionTest extends KullaTesting {
assertCompletion("Object.notElement.|"); assertCompletion("Object.notElement.|");
assertCompletion("Object o = com.su|", "sun"); assertCompletion("Object o = com.su|", "sun");
Path p1 = outDir.resolve("dir1");
compiler.compile(p1,
"package p1.p2;\n" +
"public class Test {\n" +
"}",
"package p1.p3;\n" +
"public class Test {\n" +
"}");
String jarName = "test.jar";
compiler.jar(p1, jarName, "p1/p2/Test.class", "p1/p3/Test.class");
addToClasspath(compiler.getPath(p1.resolve(jarName)));
assertCompletionIncludesExcludes("|", new HashSet<>(Collections.singletonList("p1")), Collections.emptySet());
assertCompletion("p1.|", "p2", "p3");
assertCompletion("p1.p2.|", "Test");
assertCompletion("p1.p3.|", "Test");
} }
public void testCheckAccessibility() { public void testCheckAccessibility() {

View file

@ -27,11 +27,10 @@ import java.io.PrintStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -62,6 +61,7 @@ public class ReplToolTesting {
private Map<String, VariableInfo> variables; private Map<String, VariableInfo> variables;
private Map<String, MethodInfo> methods; private Map<String, MethodInfo> methods;
private Map<String, ClassInfo> classes; private Map<String, ClassInfo> classes;
private Map<String, ImportInfo> imports;
private boolean isDefaultStartUp = true; private boolean isDefaultStartUp = true;
public JShellTool repl = null; public JShellTool repl = null;
@ -127,6 +127,10 @@ public class ReplToolTesting {
return assertMembers("Classes", classes); return assertMembers("Classes", classes);
} }
public Consumer<String> assertImports() {
return assertMembers("Imports", imports);
}
public String getCommandOutput() { public String getCommandOutput() {
String s = cmdout.toString(); String s = cmdout.toString();
cmdout.reset(); cmdout.reset();
@ -184,9 +188,21 @@ public class ReplToolTesting {
variables = new HashMap<>(); variables = new HashMap<>();
methods = new HashMap<>(); methods = new HashMap<>();
classes = new HashMap<>(); classes = new HashMap<>();
imports = new HashMap<>();
if (isDefaultStartUp) { if (isDefaultStartUp) {
methods.put("printf (String,Object...)void", methods.put("printf (String,Object...)void",
new MethodInfo("", "(String,Object...)void", "printf")); new MethodInfo("", "(String,Object...)void", "printf"));
imports.putAll(
Stream.of(
"java.util.*",
"java.io.*",
"java.math.*",
"java.net.*",
"java.util.concurrent.*",
"java.util.prefs.*",
"java.util.regex.*")
.map(s -> new ImportInfo("", "", s))
.collect(Collectors.toMap(Object::toString, Function.identity())));
} }
} }
@ -300,6 +316,19 @@ public class ReplToolTesting {
addKey(after, clazz); addKey(after, clazz);
} }
public void loadImport(boolean after, String src, String type, String name) {
ImportInfo i = new ImportInfo(src, type, name);
addKey(after, i, imports);
addKey(after, i);
}
public void assertImport(boolean after, String src, String type, String name) {
ImportInfo i = new ImportInfo(src, type, name);
assertCommandCheckOutput(after, src, i.checkOutput());
addKey(after, i, imports);
addKey(after, i);
}
private <T extends MemberInfo> void addKey(boolean after, T memberInfo, Map<String, T> map) { private <T extends MemberInfo> void addKey(boolean after, T memberInfo, Map<String, T> map) {
if (after) { if (after) {
map.entrySet().removeIf(e -> e.getValue().equals(memberInfo)); map.entrySet().removeIf(e -> e.getValue().equals(memberInfo));
@ -347,6 +376,10 @@ public class ReplToolTesting {
dropKey(after, cmd, name, classes); dropKey(after, cmd, name, classes);
} }
public void dropImport(boolean after, String cmd, String name) {
dropKey(after, cmd, name, imports);
}
public void assertCommand(boolean after, String cmd, String out) { public void assertCommand(boolean after, String cmd, String out) {
assertCommand(after, cmd, out, "", null, "", ""); assertCommand(after, cmd, out, "", null, "", "");
} }
@ -580,6 +613,31 @@ public class ReplToolTesting {
} }
} }
public static class ImportInfo extends MemberInfo {
public ImportInfo(String source, String type, String fullname) {
super(source, type, fullname);
}
@Override
public Consumer<String> checkOutput() {
return s -> assertTrue("".equals(s), "Expected: '', actual: " + s);
}
@Override
public boolean equals(Object o) {
if (o instanceof ImportInfo) {
ImportInfo i = (ImportInfo) o;
return name.equals(i.name) && type.equals(i.type);
}
return false;
}
@Override
public String toString() {
return String.format("import %s%s", type.equals("static") ? "static " : "", name);
}
}
class WaitingTestingInputStream extends TestingInputStream { class WaitingTestingInputStream extends TestingInputStream {
@Override @Override

View file

@ -24,7 +24,6 @@
/* /*
* @test * @test
* @summary Tests for Basic tests for REPL tool * @summary Tests for Basic tests for REPL tool
* @ignore 8139873
* @library /tools/lib * @library /tools/lib
* @build KullaTesting TestingInputStream ToolBox Compiler * @build KullaTesting TestingInputStream ToolBox Compiler
* @run testng ToolBasicTest * @run testng ToolBasicTest
@ -139,7 +138,13 @@ public class ToolBasicTest extends ReplToolTesting {
(a) -> assertCommand(a, "class A {}\u0003", ""), (a) -> assertCommand(a, "class A {}\u0003", ""),
(a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
(a) -> assertClass(a, "interface A {}", "interface", "A"), (a) -> assertClass(a, "interface A {}", "interface", "A"),
(a) -> assertCommandCheckOutput(a, "/c", assertClasses()) (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
(a) -> assertCommand(a, "import java.util.stream." + s, ""),
interrupt,
(a) -> assertCommand(a, "import java.util.stream.\u0003", ""),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertImport(a, "import java.util.stream.Stream", "", "java.util.stream.Stream"),
(a) -> assertCommandCheckOutput(a, "/i", assertImports())
); );
} }
} }
@ -364,6 +369,35 @@ public class ToolBasicTest extends ReplToolTesting {
); );
} }
public void defineImports() {
test(
(a) -> assertCommandCheckOutput(a, "/l", assertList()),
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
(a) -> assertImport(a, "import java.util.stream.Stream;", "", "java.util.stream.Stream"),
(a) -> assertCommandCheckOutput(a, "/l", assertList()),
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
(a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
(a) -> assertCommandCheckOutput(a, "/l", assertList()),
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
(a) -> assertImport(a, "import static java.lang.Math.PI;", "static", "java.lang.Math.PI"),
(a) -> assertCommandCheckOutput(a, "/l", assertList()),
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertCommandCheckOutput(a, "/imports", assertImports()),
(a) -> assertImport(a, "import static java.lang.Math.*;", "static", "java.lang.Math.*"),
(a) -> assertCommandCheckOutput(a, "/l", assertList()),
(a) -> assertCommandCheckOutput(a, "/list", assertList()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertCommandCheckOutput(a, "/imports", assertImports())
);
}
public void testClasspathDirectory() { public void testClasspathDirectory() {
Compiler compiler = new Compiler(); Compiler compiler = new Compiler();
Path outDir = Paths.get("testClasspathDirectory"); Path outDir = Paths.get("testClasspathDirectory");
@ -443,10 +477,13 @@ public class ToolBasicTest extends ReplToolTesting {
(a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
(a) -> assertClass(a, "class A { }", "class", "A"), (a) -> assertClass(a, "class A { }", "class", "A"),
(a) -> assertCommandCheckOutput(a, "/c", assertClasses()), (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
(a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
(a) -> assertCommandCheckOutput(a, "/i", assertImports()),
(a) -> assertReset(a, "/reset"), (a) -> assertReset(a, "/reset"),
(a) -> assertCommandCheckOutput(a, "/v", assertVariables()), (a) -> assertCommandCheckOutput(a, "/v", assertVariables()),
(a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
(a) -> assertCommandCheckOutput(a, "/c", assertClasses()) (a) -> assertCommandCheckOutput(a, "/c", assertClasses()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports())
); );
} }
@ -455,22 +492,26 @@ public class ToolBasicTest extends ReplToolTesting {
Path path = compiler.getPath("testOpen.repl"); Path path = compiler.getPath("testOpen.repl");
compiler.writeToFile(path, compiler.writeToFile(path,
"int a = 10;\ndouble x = 20;\ndouble a = 10;\n" + "int a = 10;\ndouble x = 20;\ndouble a = 10;\n" +
"class A { public String toString() { return \"A\"; } }"); "class A { public String toString() { return \"A\"; } }\nimport java.util.stream.*;");
for (String s : new String[]{"/o", "/open"}) { for (String s : new String[]{"/o", "/open"}) {
test( test(
(a) -> assertCommand(a, s + " " + path.toString(), ""), (a) -> assertCommand(a, s + " " + path.toString(), ""),
(a) -> assertCommand(a, "a", "| Variable a of type double has value 10.0\n"), (a) -> assertCommand(a, "a", "| Variable a of type double has value 10.0\n"),
(a) -> evaluateExpression(a, "A", "new A();", "\"A\""), (a) -> evaluateExpression(a, "A", "new A();", "\"A\""),
(a) -> evaluateExpression(a, "long", "Stream.of(\"A\").count();", "1"),
(a) -> { (a) -> {
loadVariable(a, "double", "x", "20.0", "20.0"); loadVariable(a, "double", "x", "20.0", "20.0");
loadVariable(a, "double", "a", "10.0", "10.0"); loadVariable(a, "double", "a", "10.0", "10.0");
loadVariable(a, "A", "$6", "new A();", "A"); loadVariable(a, "A", "$7", "new A();", "A");
loadVariable(a, "long", "$8", "Stream.of(\"A\").count();", "1");
loadClass(a, "class A { public String toString() { return \"A\"; } }", loadClass(a, "class A { public String toString() { return \"A\"; } }",
"class", "A"); "class", "A");
loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*");
assertCommandCheckOutput(a, "/c", assertClasses()); assertCommandCheckOutput(a, "/c", assertClasses());
}, },
(a) -> assertCommandCheckOutput(a, "/m", assertMethods()), (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
(a) -> assertCommandCheckOutput(a, "/v", assertVariables()) (a) -> assertCommandCheckOutput(a, "/v", assertVariables()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports())
); );
Path unknown = compiler.getPath("UNKNOWN.repl"); Path unknown = compiler.getPath("UNKNOWN.repl");
test( test(
@ -536,6 +577,7 @@ public class ToolBasicTest extends ReplToolTesting {
(a) -> assertVariable(a, "int", "a"), (a) -> assertVariable(a, "int", "a"),
(a) -> assertVariable(a, "double", "b", "10", "10.0"), (a) -> assertVariable(a, "double", "b", "10", "10.0"),
(a) -> assertMethod(a, "void f() {}", "()V", "f"), (a) -> assertMethod(a, "void f() {}", "()V", "f"),
(a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
(a) -> assertCommand(a, "/s " + startUpFile.toString(), null), (a) -> assertCommand(a, "/s " + startUpFile.toString(), null),
(a) -> assertCommand(a, "/setstart " + startUpFile.toString(), null) (a) -> assertCommand(a, "/setstart " + startUpFile.toString(), null)
); );
@ -549,10 +591,12 @@ public class ToolBasicTest extends ReplToolTesting {
loadVariable(a, "int", "a"); loadVariable(a, "int", "a");
loadVariable(a, "double", "b", "10.0", "10.0"); loadVariable(a, "double", "b", "10.0", "10.0");
loadMethod(a, "void f() {}", "()void", "f"); loadMethod(a, "void f() {}", "()void", "f");
loadImport(a, "import java.util.stream.*;", "", "java.util.stream.*");
assertCommandCheckOutput(a, "/c", assertClasses()); assertCommandCheckOutput(a, "/c", assertClasses());
}, },
(a) -> assertCommandCheckOutput(a, "/v", assertVariables()), (a) -> assertCommandCheckOutput(a, "/v", assertVariables()),
(a) -> assertCommandCheckOutput(a, "/m", assertMethods()) (a) -> assertCommandCheckOutput(a, "/m", assertMethods()),
(a) -> assertCommandCheckOutput(a, "/i", assertImports())
); );
} finally { } finally {
removeStartup(); removeStartup();
@ -768,9 +812,12 @@ public class ToolBasicTest extends ReplToolTesting {
a -> dropMethod(a, drop + " 2", "b ()I"), a -> dropMethod(a, drop + " 2", "b ()I"),
a -> assertClass(a, "class A {}", "class", "A"), a -> assertClass(a, "class A {}", "class", "A"),
a -> dropClass(a, drop + " 3", "class A"), a -> dropClass(a, drop + " 3", "class A"),
a -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"),
a -> dropImport(a, drop + " 4", "import java.util.stream.*"),
a -> assertCommandCheckOutput(a, "/v", assertVariables()), a -> assertCommandCheckOutput(a, "/v", assertVariables()),
a -> assertCommandCheckOutput(a, "/m", assertMethods()), a -> assertCommandCheckOutput(a, "/m", assertMethods()),
a -> assertCommandCheckOutput(a, "/c", assertClasses()) a -> assertCommandCheckOutput(a, "/c", assertClasses()),
a -> assertCommandCheckOutput(a, "/i", assertImports())
); );
test(false, new String[]{"-nostartup"}, test(false, new String[]{"-nostartup"},
a -> assertVariable(a, "int", "a"), a -> assertVariable(a, "int", "a"),
@ -781,7 +828,8 @@ public class ToolBasicTest extends ReplToolTesting {
a -> dropClass(a, drop + " A", "class A"), a -> dropClass(a, drop + " A", "class A"),
a -> assertCommandCheckOutput(a, "/v", assertVariables()), a -> assertCommandCheckOutput(a, "/v", assertVariables()),
a -> assertCommandCheckOutput(a, "/m", assertMethods()), a -> assertCommandCheckOutput(a, "/m", assertMethods()),
a -> assertCommandCheckOutput(a, "/c", assertClasses()) a -> assertCommandCheckOutput(a, "/c", assertClasses()),
a -> assertCommandCheckOutput(a, "/i", assertImports())
); );
} }
} }
@ -814,7 +862,8 @@ public class ToolBasicTest extends ReplToolTesting {
a -> assertCommandCheckOutput(a, drop + " a", check), a -> assertCommandCheckOutput(a, drop + " a", check),
a -> assertCommandCheckOutput(a, "/v", assertVariables()), a -> assertCommandCheckOutput(a, "/v", assertVariables()),
a -> assertCommandCheckOutput(a, "/m", assertMethods()), a -> assertCommandCheckOutput(a, "/m", assertMethods()),
a -> assertCommandCheckOutput(a, "/c", assertClasses()) a -> assertCommandCheckOutput(a, "/c", assertClasses()),
a -> assertCommandCheckOutput(a, "/i", assertImports())
); );
test( test(
a -> assertMethod(a, "int a() { return 0; }", "()int", "a"), a -> assertMethod(a, "int a() { return 0; }", "()int", "a"),

View file

@ -1,2 +1,2 @@
T4720359a.java:16:23: compiler.err.override.incompatible.ret: (compiler.misc.cant.override: m(), p1.T4720359c, m(), p1.T4720359a), int, void T4720359a.java:16:23: compiler.err.override.incompatible.ret: (compiler.misc.cant.hide: m(), p1.T4720359c, m(), p1.T4720359a), int, void
1 error 1 error

View file

@ -0,0 +1,14 @@
/*
* @test /nodynamiccopyright/
* @bug 8139255
* @summary javac emits diagnostic message as overriding instead of hiding for class methods.
* @compile/fail/ref=T8139255.out -XDrawDiagnostics T8139255.java
*/
public class T8139255 {
static void func() { }
}
class T8139255_1 extends T8139255 {
static int func() { return 0; }
}

View file

@ -0,0 +1,2 @@
T8139255.java:13:15: compiler.err.override.incompatible.ret: (compiler.misc.cant.hide: func(), T8139255_1, func(), T8139255), int, void
1 error

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2015, 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.
*/
import java.lang.annotation.*;
import java.util.ArrayList;
import com.sun.tools.classfile.*;
/*
* @test
* @bug 8136419
* @summary test that type annotations on entities in initializers are emitted to classfile
* @modules jdk.jdeps/com.sun.tools.classfile
*/
public class InstanceInitializer extends ClassfileTestHelper {
public static void main(String[] args) throws Exception {
new InstanceInitializer().run();
}
public void run() throws Exception {
expected_tinvisibles = 4;
expected_tvisibles = 0;
ClassFile cf = getClassFile("InstanceInitializer$Test.class");
test(cf);
for (Field f : cf.fields) {
test(cf, f);
}
for (Method m: cf.methods) {
test(cf, m, true);
}
countAnnotations();
if (errors > 0)
throw new Exception(errors + " errors found");
System.out.println("PASSED");
}
/*********************** Test class *************************/
static class Test {
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface T {}
{
@T String s = null;
Runnable r = () -> new ArrayList<@T String>();
}
@T String s = null;
Runnable r = () -> new ArrayList<@T String>();
}
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (c) 2015, 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.
*/
import java.lang.annotation.*;
import java.util.ArrayList;
import com.sun.tools.classfile.*;
/*
* @test
* @bug 8136419
* @summary test that type annotations on entities in static initializers are emitted to classfile
* @modules jdk.jdeps/com.sun.tools.classfile
*/
public class StaticInitializer extends ClassfileTestHelper {
public static void main(String[] args) throws Exception {
new StaticInitializer().run();
}
public void run() throws Exception {
expected_tinvisibles = 4;
expected_tvisibles = 0;
ClassFile cf = getClassFile("StaticInitializer$Test.class");
test(cf);
for (Field f : cf.fields) {
test(cf, f);
}
for (Method m: cf.methods) {
test(cf, m, true);
}
countAnnotations();
if (errors > 0)
throw new Exception(errors + " errors found");
System.out.println("PASSED");
}
/*********************** Test class *************************/
static class Test {
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface T {}
static {
@T String s = null;
Runnable r = () -> new ArrayList<@T String>();
}
@T static String s = null;
static Runnable r = () -> new ArrayList<@T String>();
}
}

View file

@ -23,10 +23,9 @@
/* /*
* @test * @test
* @bug 8044411 8079060 * @bug 8044411 8079060 8138612
* @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute. * @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib * @library /tools/lib /tools/javac/lib ../lib
* @ignore 8079060 javac does not generate RuntimeParameterAnnotation attributes for lambda expressions
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox * @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo * @build TestCase ClassType TestAnnotationInfo
* @build RuntimeParameterAnnotationsForLambdaTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase * @build RuntimeParameterAnnotationsForLambdaTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
@ -36,12 +35,11 @@
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.*;
import com.sun.tools.classfile.Method;
/** /**
* RuntimeParameterAnnotationsForLambdaTest is a test which checks that RuntimeVisibleParameterAnnotationsAttribute * RuntimeParameterAnnotationsForLambdaTest is a test which checks that RuntimeVisibleParameterAnnotationsAttribute
* and RuntimeInvisibleParameterAnnotationsAttribute are generated properly for lambda expressions. * and RuntimeInvisibleParameterAnnotationsAttribute are not generated at all for lambda expressions.
* The test checks both single and repeatable annotations. * The test checks both single and repeatable annotations.
* All possible combinations of retention policies are tested. * All possible combinations of retention policies are tested.
* *
@ -74,8 +72,8 @@ public class RuntimeParameterAnnotationsForLambdaTest extends RuntimeParameterAn
TestCase.TestParameterInfo p3 = testMethodInfo.addParameter("String", "c"); TestCase.TestParameterInfo p3 = testMethodInfo.addParameter("String", "c");
annotations.annotate(p3); annotations.annotate(p3);
String source = SOURCE_TEMPLATE.replace("%SOURCE%", generateLambdaSource(testMethodInfo)); String source = SOURCE_TEMPLATE.replace("%SOURCE%", generateLambdaSource(testMethodInfo));
echo("Testing:\n" + source);
addTestCase(source); addTestCase(source);
echo("Testing:\n" + source);
ClassFile classFile = readClassFile(compile(source).getClasses().get(CLASS_NAME)); ClassFile classFile = readClassFile(compile(source).getClasses().get(CLASS_NAME));
boolean isFoundLambda = false; boolean isFoundLambda = false;
for (Method method : classFile.methods) { for (Method method : classFile.methods) {
@ -94,6 +92,17 @@ public class RuntimeParameterAnnotationsForLambdaTest extends RuntimeParameterAn
} }
} }
protected void testAttributes(
TestCase.TestMethodInfo testMethod,
ClassFile classFile,
Method method) throws ConstantPoolException {
Attributes attributes = method.attributes;
RuntimeParameterAnnotations_attribute attr = (RuntimeParameterAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleParameterAnnotations);
checkNull(attr, String.format("%s should be null", Attribute.RuntimeInvisibleParameterAnnotations));
attr = (RuntimeParameterAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleParameterAnnotations);
checkNull(attr, String.format("%s should be null", Attribute.RuntimeVisibleParameterAnnotations));
}
public String generateLambdaSource(TestCase.TestMethodInfo method) { public String generateLambdaSource(TestCase.TestMethodInfo method) {
return method.parameters.stream() return method.parameters.stream()
.map(TestCase.TestParameterInfo::generateSource) .map(TestCase.TestParameterInfo::generateSource)

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2015, 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.override.incompatible.ret
// key: compiler.misc.cant.hide
class Base {
static void func() { }
}
class HideStatic extends Base {
static int func() { return 0; }
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2015, 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 8141613
* @summary Compiler fails to infer generic type
* @compile T8141613.java
*/
class T8141613 {
static class Sub<V, L> implements Sup<V, L> {
Sub(Bar<V> barv) { }
}
interface Bar<V> { }
interface Sup<V, L> { }
<L> void test() {
Sup<?, L> res1 = makeSub(makeBar());
Sup<?, L> res2 = new Sub<>(makeBar());
}
<S, U> Sub<S, U> makeSub(Bar<S> bars) { return null; }
<B> Bar<?> makeBar() {
return null;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8138612
* @summary Do not retain declaration annotations on lambda formal parameters
* @run main SE5AnnotationsOnLambdaParameters
*/
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class SE5AnnotationsOnLambdaParameters {
@Retention(RetentionPolicy.RUNTIME)
@interface Annot {}
interface Runnable {
void run(int x);
}
public void run(Runnable r) {}
public static void main(@Annot String [] args) throws ClassNotFoundException {
new SE5AnnotationsOnLambdaParameters().run((@Annot int x) -> { System.out.println(x + args.length); });
Class<?> clazz = Class.forName("SE5AnnotationsOnLambdaParameters");
for (Method m : clazz.getDeclaredMethods()) {
if (m.getName().startsWith("lambda$")) {
for (Annotation[] annots : m.getParameterAnnotations()) {
if (annots.length > 0) {
throw new AssertionError("Unexpected annotations on lambda parameters");
}
}
}
}
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8129740 8133111
* @summary Incorrect class file created when passing lambda in inner class constructor
* @run main AllowEnclosingVarCaptureTest
*/
public class AllowEnclosingVarCaptureTest {
int var = 0;
void foo() {
var *= 2;
}
public static void main(String[] args) {
new AllowEnclosingVarCaptureTest().new Inner(9764);
}
public class Inner {
public Inner(Runnable r) {
r.run();
if (var != 66704)
throw new AssertionError("Unexpected output: " + var);
}
public Inner(int x) {
this(() -> {
var = x + 1234;
AllowEnclosingVarCaptureTest.this.var += 5678;
foo();
AllowEnclosingVarCaptureTest.this.foo();
});
}
}
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8129740 8133111
* @summary Incorrect class file created when passing lambda in inner class constructor
* @run main CaptureInCtorChainingTest
*/
import java.util.function.Consumer;
import java.util.function.Function;
public class CaptureInCtorChainingTest {
CaptureInCtorChainingTest(Function<Function<Function<Consumer<Void>, Void>, Void>, Void> innerClass) {
new InnerClass(innerClass);
}
void foo(Void v) { }
class InnerClass {
InnerClass(Function<Function<Function<Consumer<Void>, Void>, Void>, Void> factory) {
this(factory.apply(o -> o.apply(CaptureInCtorChainingTest.this::foo)));
}
InnerClass(Void unused) { }
}
public static void main(String[] args) {
new CaptureInCtorChainingTest(o -> null);
}
}

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8129740 8133111
* @summary Incorrect class file created when passing lambda in inner class constructor
* @run main QualifiedThisAccessTest
*/
public class QualifiedThisAccessTest { // Not referenced by lambda, so should not be captured.
public class Universe { // Not referenced by lambda, so should not be captured.
public String name;
public int galaxiesCount;
public Universe(String name, int galaxiesCount) {
this.name = name;
this.galaxiesCount = galaxiesCount;
}
public String toString() {
return "Universe" + name + " of " + galaxiesCount + " galaxies";
}
class Galaxy {
String name;
private int starsCount;
Galaxy(String name, int starsCount) {
this.name = name;
this.starsCount = starsCount;
}
public String toString() {
return "galaxy " + name + " of " + starsCount + " solar systems";
}
int starsCount() {
return starsCount;
}
private String name() {
return name;
}
class SolarSystem {
String name;
int planetsCount;
SolarSystem(String name, int planetsCount) {
this.name = name;
this.planetsCount = planetsCount;
}
public String toString() {
return "Solar System of " + name + " with " + planetsCount + " planets";
}
int planetsCount() {
return planetsCount;
}
SolarSystem copy(SolarSystem s) {
return s;
}
class Planet {
String name;
int moonsCount;
Planet(String name, int moonsCount, Runnable r) {
this.name = name;
this.moonsCount = moonsCount;
r.run();
}
Planet (String name, int moonsCount) {
this(name, moonsCount, ()-> {
StringBuffer buf = new StringBuffer();
buf.append("This planet belongs to the galaxy "
+ Galaxy.this.name + " with " + starsCount + " stars\n");
buf.append("This planet belongs to the galaxy "
+ Universe.Galaxy.this.name + " with " + starsCount() + " stars\n");
buf.append("This planet belongs to the galaxy "
+ Galaxy.this.name() + " with " + starsCount() + " stars\n");
buf.append("This planet belongs to the galaxy "
+ Universe.Galaxy.this.name() + " with "
+ (Universe.Galaxy.this).starsCount() + " stars\n");
buf.append("This planet belongs to the solar system "
+ SolarSystem.this.name + " with " + planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ Galaxy.SolarSystem.this.name + " with " + planetsCount() + " planets\n");
buf.append("This planet belongs to the solar system "
+ (SolarSystem.this).name + " with " + planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ Universe.Galaxy.SolarSystem.this.name + " with "
+ Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ Universe.Galaxy.SolarSystem.this.name.toLowerCase().toUpperCase()
+ " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ copy(Universe.Galaxy.SolarSystem.this).name.toLowerCase().toUpperCase()
+ " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n");
if (!buf.toString().equals(output))
throw new AssertionError("Unexpected value\n" + buf);
});
}
static final String output =
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system SUN with 9 planets\n" +
"This planet belongs to the solar system SUN with 9 planets\n";
public String toString() {
return "Planet " + name + " with " + moonsCount + " moon(s)";
}
}
}
}
}
public static void main(String[] args) {
new QualifiedThisAccessTest().new Universe("Universe", 12345678).new Galaxy("Mily way", 23456789).new SolarSystem("Sun", 9).new Planet("Earth", 1);
}
}

View file

@ -0,0 +1,122 @@
class Universe { // Not referenced by lambda, so should not be captured.
public String name;
public int galaxiesCount;
public Universe(String name, int galaxiesCount) {
this.name = name;
this.galaxiesCount = galaxiesCount;
}
public String toString() {
return "Universe" + name + " of " + galaxiesCount + " galaxies";
}
class Galaxy {
String name;
private int starsCount;
Galaxy(String name, int starsCount) {
this.name = name;
this.starsCount = starsCount;
}
public String toString() {
return "galaxy " + name + " of " + starsCount + " solar systems";
}
int starsCount() {
return starsCount;
}
private String name() {
return name;
}
class SolarSystem {
String name;
int planetsCount;
SolarSystem(String name, int planetsCount) {
this.name = name;
this.planetsCount = planetsCount;
}
public String toString() {
return "Solar System of " + name + " with " + planetsCount + " planets";
}
int planetsCount() {
return planetsCount;
}
SolarSystem copy(SolarSystem s) {
return s;
}
class Planet {
String name;
int moonsCount;
Planet(String name, int moonsCount, Runnable r) {
this.name = name;
this.moonsCount = moonsCount;
r.run();
}
Planet (String name, int moonsCount) {
this(name, moonsCount, ()-> {
String n = name;
StringBuffer buf = new StringBuffer();
buf.append("This planet belongs to the galaxy "
+ Galaxy.this.name + " with " + starsCount + " stars\n");
buf.append("This planet belongs to the galaxy "
+ Universe.Galaxy.this.name + " with " + starsCount() + " stars\n");
buf.append("This planet belongs to the galaxy "
+ Galaxy.this.name() + " with " + starsCount() + " stars\n");
buf.append("This planet belongs to the galaxy "
+ Universe.Galaxy.this.name() + " with "
+ (Universe.Galaxy.this).starsCount() + " stars\n");
buf.append("This planet belongs to the solar system "
+ SolarSystem.this.name + " with " + planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ Galaxy.SolarSystem.this.name + " with " + planetsCount() + " planets\n");
buf.append("This planet belongs to the solar system "
+ (SolarSystem.this).name + " with " + planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ Universe.Galaxy.SolarSystem.this.name + " with "
+ Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ Universe.Galaxy.SolarSystem.this.name.toLowerCase().toUpperCase()
+ " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system "
+ copy(Universe.Galaxy.SolarSystem.this).name.toLowerCase().toUpperCase()
+ " with " + Universe.Galaxy.SolarSystem.this.planetsCount + " planets\n");
if (!buf.toString().equals(output))
throw new AssertionError("Unexpected value\n" + buf);
});
}
static final String output =
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the galaxy Mily way with 23456789 stars\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system Sun with 9 planets\n" +
"This planet belongs to the solar system SUN with 9 planets\n" +
"This planet belongs to the solar system SUN with 9 planets\n";
public String toString() {
return "Planet " + name + " with " + moonsCount + " moon(s)";
}
}
}
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8129740 8133111
* @summary Incorrect class file created when passing lambda in inner class constructor
* @library /tools/lib
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.file
* jdk.compiler/com.sun.tools.javac.main
* @build ToolBox
* @run compile -XD-printsource SourceForTranslation.java
* @run main SourceToSourceTranslationTest
*/
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class SourceToSourceTranslationTest {
public static void main(String[] args) throws Exception {
ToolBox tb = new ToolBox();
Path path1 = Paths.get(ToolBox.testClasses, "Universe.java");
List<String> file1 = tb.readAllLines(path1);
Path path2 = Paths.get(ToolBox.testSrc, "Universe.java.out");
List<String> file2 = tb.readAllLines(path2);
tb.checkEqual(file1, file2);
}
}

View file

@ -0,0 +1,98 @@
class Universe {
public String name;
public int galaxiesCount;
public Universe(String name, int galaxiesCount) {
super();
this.name = name;
this.galaxiesCount = galaxiesCount;
}
public String toString() {
return "Universe" + name + " of " + galaxiesCount + " galaxies";
}
class Galaxy {
String name;
private int starsCount;
Galaxy(String name, int starsCount) {
super();
this.name = name;
this.starsCount = starsCount;
}
public String toString() {
return "galaxy " + name + " of " + starsCount + " solar systems";
}
int starsCount() {
return starsCount;
}
private String name() {
return name;
}
class SolarSystem {
String name;
int planetsCount;
SolarSystem(String name, int planetsCount) {
super();
this.name = name;
this.planetsCount = planetsCount;
}
public String toString() {
return "Solar System of " + name + " with " + planetsCount + " planets";
}
int planetsCount() {
return planetsCount;
}
SolarSystem copy(SolarSystem s) {
return s;
}
class Planet {
String name;
int moonsCount;
Planet(String name, int moonsCount, Runnable r) {
super();
this.name = name;
this.moonsCount = moonsCount;
r.run();
}
Planet(String name, int moonsCount) {
this(name, moonsCount, java.lang.invoke.LambdaMetafactory.metafactory(name, Universe.Galaxy.this, Universe.Galaxy.SolarSystem.this));
}
static final String output = "This planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the galaxy Mily way with 23456789 stars\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system Sun with 9 planets\nThis planet belongs to the solar system SUN with 9 planets\nThis planet belongs to the solar system SUN with 9 planets\n";
public String toString() {
return "Planet " + name + " with " + moonsCount + " moon(s)";
}
/*synthetic*/ private static void lambda$new$0(/*synthetic*/ final String name, /*synthetic*/ final Universe.Galaxy Universe$Galaxy$this, /*synthetic*/ final Universe.Galaxy.SolarSystem Universe$Galaxy$SolarSystem$this) {
String n = name;
StringBuffer buf = new StringBuffer();
buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name + " with " + Universe$Galaxy$this.starsCount + " stars\n");
buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name + " with " + Universe$Galaxy$this.starsCount() + " stars\n");
buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name() + " with " + Universe$Galaxy$this.starsCount() + " stars\n");
buf.append("This planet belongs to the galaxy " + Universe$Galaxy$this.name() + " with " + (Universe$Galaxy$this).starsCount() + " stars\n");
buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount() + " planets\n");
buf.append("This planet belongs to the solar system " + (Universe$Galaxy$SolarSystem$this).name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.name.toLowerCase().toUpperCase() + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n");
buf.append("This planet belongs to the solar system " + Universe$Galaxy$SolarSystem$this.copy(Universe$Galaxy$SolarSystem$this).name.toLowerCase().toUpperCase() + " with " + Universe$Galaxy$SolarSystem$this.planetsCount + " planets\n");
if (!buf.toString().equals(output)) throw new AssertionError("Unexpected value\n" + buf);
}
}
}
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8141508
* @summary Test that Call site initialization exception is not thrown when the method
reference receiver is of intersection type.
* @run main IntersectionTypeReceiverTest
*/
import java.time.LocalDate;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
public class IntersectionTypeReceiverTest {
public static void main(String[] args) {
String output = valueOfKey(Size.class, LocalDate.now()).toString();
if (!"Optional[S]".equals(output))
throw new AssertionError("Unexpected output: " + output);
}
enum Size implements Supplier<LocalDate> {
S, M, L;
@Override
public LocalDate get() {
return LocalDate.now();
}
}
public static <K, T extends Enum<T> & Supplier<K>> Optional<T> valueOfKey(Class<T> enumType, K key) {
return valueOf(enumType, key, T::get);
}
public static <K, T extends Enum<T>> Optional<T> valueOf(Class<T> enumType, K key, Function<T, K> keyExtractor) {
return EnumSet.allOf(enumType).stream().filter(t -> Objects.equals(keyExtractor.apply(t), key)).findFirst();
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8142476
* @summary Test that Call site initialization exception is not thrown when the method
reference receiver is of intersection type.
* @run main IntersectionTypeReceiverTest2
*/
public class IntersectionTypeReceiverTest2 {
interface I {
}
interface J {
void foo();
}
static <T extends I & J> void bar(T t) {
Runnable r = t::foo;
}
public static void main(String[] args) {
class A implements I, J {
public void foo() {
}
}
bar(new A());
}
}