The following issues have been addressed:
authormcimadamore
Fri Jun 04 12:34:09 2010 +0100 (2 years ago)
changeset 557d74a4b240764
parent 55681966684ef23
child 5581f2a6005435d
The following issues have been addressed:
*) fixed type-inference issues w.r.t. wildcard types
*) fixed SAM conversion issues (now Object members are ignored as per strawman)
*) fixed minor parser issues (wrong start position of lambdas)/ambiguities
*) improved translation of nested lambda expression/lambda expression nested in inner classes/inner classes nested in lambda
*) minor attribution fixes: added check for lambda method call, improved check for return expression in lambda context
*) better diagnostic support
src/share/classes/com/sun/tools/javac/code/Flags.java
src/share/classes/com/sun/tools/javac/code/Types.java
src/share/classes/com/sun/tools/javac/comp/Attr.java
src/share/classes/com/sun/tools/javac/comp/Enter.java
src/share/classes/com/sun/tools/javac/comp/Lower.java
src/share/classes/com/sun/tools/javac/comp/Resolve.java
src/share/classes/com/sun/tools/javac/parser/JavacParser.java
src/share/classes/com/sun/tools/javac/resources/compiler.properties
test/tools/javac/lambda/BadAccess.java
test/tools/javac/lambda/BadAccess.out
test/tools/javac/lambda/BadLambdaCall.java
test/tools/javac/lambda/BadLambdaCall.out
test/tools/javac/lambda/BadReturn.java
test/tools/javac/lambda/BadReturn.out
test/tools/javac/lambda/LambdaCapture02.java
test/tools/javac/lambda/LambdaCapture03.java
test/tools/javac/lambda/LambdaCapture04.java
test/tools/javac/lambda/LambdaCapture05.java
test/tools/javac/lambda/LambdaConv05.java
test/tools/javac/lambda/LambdaScope02.java
test/tools/javac/lambda/NakedThis.out
--- a/src/share/classes/com/sun/tools/javac/code/Flags.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Flags.java Fri Jun 04 12:34:09 2010 +0100
@@ -240,6 +240,11 @@ public class Flags {
*/
public static final long LAMBDA = 1L<<40;
+ /**
+ * Flag that marks a lambda expression symbol that requires access to enclosing class
+ */
+ public static final long OUTER_ACCESS = 1L<<41;
+
/** Modifier masks.
*/
public static final int
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Jun 04 12:34:09 2010 +0100
@@ -280,7 +280,8 @@ public class Types {
isSameType(mtype.getReturnType(), syms.voidType)) :
isConvertible(t.getReturnType(), mtype.getReturnType(), warn);
boolean argsOk = t.getParameterTypes().size() == mtype.getParameterTypes().size() &&
- isSameTypes(t.getParameterTypes(), mtype.getParameterTypes());
+ containsType(mtype.getParameterTypes(), t.getParameterTypes());
+
boolean thrownOk = chk.unhandled(t.getThrownTypes(), mtype.getThrownTypes()).isEmpty();
return isReturnOk && argsOk && thrownOk;
}
@@ -331,6 +332,7 @@ public class Types {
if (e.sym != null &&
e.sym.kind == Kinds.MTH &&
(e.sym.flags() & ABSTRACT) != 0 &&
+ !overridesObjectMethod(e.sym, t.tsym) &&
(buf.isEmpty() || overrideEquivalent(e.sym.type, buf.first().type))) {
buf.append(e.sym);
}
@@ -339,6 +341,15 @@ public class Types {
for (Type i : interfaces(t)) {
findSAM(i, buf);
}
+ }
+ //where
+ private boolean overridesObjectMethod(Symbol msym, TypeSymbol tsym) {
+ for (Scope.Entry e = syms.objectType.tsym.members().lookup(msym.name) ; e.scope != null ; e = e.next()) {
+ if (msym.overrides(e.sym, tsym, this, true)) {
+ return true;
+ }
+ }
+ return false;
}
/**
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jun 04 12:34:09 2010 +0100
@@ -1036,7 +1036,7 @@ public class Attr extends JCTree.Visitor
Type condtype,
Type thentype,
Type elsetype) {
- Type ctype = condType1(pos, condtype, thentype, elsetype);
+ Type ctype = unionType(pos, condtype, thentype, elsetype, "neither.conditional.subtype");
// If condition and both arms are numeric constants,
// evaluate at compile-time.
@@ -1057,8 +1057,8 @@ public class Attr extends JCTree.Visitor
* @param thentype The type of the expression's then-part.
* @param elsetype The type of the expression's else-part.
*/
- private Type condType1(DiagnosticPosition pos, Type condtype,
- Type thentype, Type elsetype) {
+ private Type unionType(DiagnosticPosition pos, Type condtype,
+ Type thentype, Type elsetype, String diagKey) {
// If same type, that is the result
if (types.isSameType(thentype, elsetype))
return thentype.baseType();
@@ -1105,7 +1105,7 @@ public class Attr extends JCTree.Visitor
return thentype.baseType();
if (!allowBoxing || thentype.tag == VOID || elsetype.tag == VOID) {
- log.error(pos, "neither.conditional.subtype",
+ log.error(pos, diagKey,
thentype, elsetype);
return thentype.baseType();
}
@@ -1232,9 +1232,13 @@ public class Attr extends JCTree.Visitor
} else {
attribExpr(tree.expr, env, isLambda ? Type.noType : m.type.getReturnType());
if (isLambda) {
+ if (tree.getExpression().type.tag == VOID) {
+ log.error(tree.expr.pos(),
+ "cant.ret.void.expr");
+ }
((MethodType)m.type).restype = m.type.getReturnType() == Type.noType ?
(tree.expr.type == syms.botType ? syms.objectType : tree.expr.type) :
- condType1(tree.pos(), null, m.type.getReturnType(), tree.expr.type);
+ unionType(tree.pos(), null, m.type.getReturnType(), tree.expr.type, "incompatibles.ret.types.in.lambda");
}
}
}
@@ -1826,44 +1830,70 @@ public class Attr extends JCTree.Visitor
result = check(tree, owntype, VAL, pkind, pt);
}
- /** An environment in which to evaluate a lambda.
+ /**
+ * An environment in which to evaluate a lambda.
* This environment is a method environment nested into a class environment.
- * The compiler generates synthetic symbols for both envs.
- */
- Env<AttrContext> lambdaEnvironment(JCLambda tree) {
- long flags = LAMBDA | (Resolve.isStatic(env) ?
- STATIC :
- 0);
-
- ClassSymbol lambdaClassSym = new ClassSymbol(SYNTHETIC, names.empty, null, env.info.scope.owner);
- lambdaClassSym.type = new ClassType(env.enclClass.type, List.<Type>nil(), lambdaClassSym);
- Env<AttrContext> outerEnv = env.dup(breakTree).dup(tree, env.info.dup(new Scope(lambdaClassSym)));
+ * The compiler generates synthetic symbols for both envs. 'Fake' AST must
+ * also be generated as they are required during lowering (in order to find
+ * free-variables used within a lambda expression).
+ */
+ Env<AttrContext> lambdaEnvironment(JCLambda tree) {
+ long flags = lambdaFlags(env);
+ //create synthetic outer class symbol hoisting the lambda
+ ClassSymbol lambdaClassSym =
+ new ClassSymbol(flags, names.empty, null, env.info.scope.owner);
+ lambdaClassSym.type = new ClassType(env.enclClass.type,
+ List.<Type>nil(),
+ lambdaClassSym);
+ Env<AttrContext> outerEnv =
+ env.dup(tree, env.info.dup(new Scope(lambdaClassSym)));
outerEnv.outer = env;
((ClassType)lambdaClassSym.type).supertype_field = syms.methodHandleType;
- outerEnv.enclClass = make.ClassDef(make.Modifiers(SYNTHETIC), names.empty, List.<JCTypeParameter>nil(), null, null, null);
+ outerEnv.enclClass = make.ClassDef(make.Modifiers(flags),
+ names.empty,
+ List.<JCTypeParameter>nil(),
+ null, null, null);
outerEnv.enclClass.sym = lambdaClassSym;
outerEnv.enclClass.type = lambdaClassSym.type;
lambdaClassSym.members_field = outerEnv.info.scope;
lambdaEnvs.put(tree, outerEnv);
- Env<AttrContext> newEnv = outerEnv.dup(tree, outerEnv.info.dup(outerEnv.info.scope.dupUnshared()));
-
- VarSymbol thisSym =
- new VarSymbol(FINAL | HASINIT, names._this, lambdaClassSym.type, lambdaClassSym);
-
- newEnv.info.scope.enter(thisSym);
-
- newEnv.outer = outerEnv;
- MethodSymbol lambdaSym = new MethodSymbol(flags, names.lambda, null, outerEnv.info.scope.owner);
+
+ //create synthetic lambda symbol
+ MethodSymbol lambdaSym =
+ new MethodSymbol(flags, names.lambda, null, outerEnv.info.scope.owner);
lambdaSym.type = new MethodType(null, Type.noType, null, syms.methodClass);
- newEnv.info.scope.owner = lambdaSym;
JCBlock body = tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body))) :
(JCBlock)tree.body;
- newEnv.enclMethod = make.MethodDef(make.Modifiers(SYNTHETIC), lambdaSym.name, null, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
- newEnv.enclMethod.sym = lambdaSym;
+ JCMethodDecl lambda = make.MethodDef(make.Modifiers(flags),
+ lambdaSym.name,
+ null, // missing restype
+ List.<JCTypeParameter>nil(),
+ List.<JCVariableDecl>nil(),
+ List.<JCExpression>nil(),
+ body,
+ null); // missing defaultValue
+ tree.sym = lambdaSym;
+ Env<AttrContext> newEnv = memberEnter.methodEnv(lambda, outerEnv);
+ newEnv.info.scope.owner = lambda.sym = lambdaSym;
newEnv.enclClass.defs = List.<JCTree>of(newEnv.enclMethod);
- tree.sym = lambdaSym;
+ //add 'this'
+ VarSymbol thisSym = new VarSymbol(FINAL | HASINIT,
+ names._this,
+ lambdaClassSym.type,
+ lambdaClassSym);
+ newEnv.info.scope.enter(thisSym);
return newEnv;
+ }
+ //where
+ private long lambdaFlags(Env<AttrContext> env) {
+ Symbol owner = env.info.scope.owner;
+ //a lambda definied in a static conext is static
+ boolean needsOuterAccess = (owner.flags() & LAMBDA) != 0 ?
+ (owner.flags() & OUTER_ACCESS) != 0 :
+ !Resolve.isStatic(env);
+ return LAMBDA | SYNTHETIC |
+ (needsOuterAccess ? OUTER_ACCESS : 0);
}
@Override
@@ -2114,9 +2144,12 @@ public class Attr extends JCTree.Visitor
if (v.owner.kind == MTH &&
v.owner != env.info.scope.owner &&
(v.flags_field & FINAL) == 0) {
+ String subkey = (env.info.scope.owner.flags() & LAMBDA) != 0 ?
+ "lambda" :
+ "icls";
log.error(tree.pos(),
- "local.var.accessed.from.icls.needs.final",
- v);
+ "local.var.accessed.from.inner.ctx.needs.final",
+ v, diags.fragment(subkey));
}
// If we are expecting a variable (as opposed to a value), check
--- a/src/share/classes/com/sun/tools/javac/comp/Enter.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Enter.java Fri Jun 04 12:34:09 2010 +0100
@@ -397,8 +397,9 @@ public class Enter extends JCTree.Visito
// which contains this class in a non-static context
// (its "enclosing instance class"), provided such a class exists.
Symbol owner1 = owner;
- while ((owner1.kind & (VAR | MTH)) != 0 &&
- (owner1.flags_field & STATIC) == 0) {
+ while (((owner1.kind & (VAR | MTH)) != 0 &&
+ (owner1.flags_field & STATIC) == 0) ||
+ (owner1.flags_field & LAMBDA) != 0) {
owner1 = owner1.owner;
}
if (owner1.kind == TYP) {
--- a/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Lower.java Fri Jun 04 12:34:09 2010 +0100
@@ -112,6 +112,10 @@ public class Lower extends TreeTranslato
*/
ClassSymbol currentClass;
+ /** Stack of nested lambda expressions
+ */
+ Stack<MethodSymbol> lambdaStack;
+
/** A queue of all translated classes.
*/
ListBuffer<JCTree> translated;
@@ -124,9 +128,9 @@ public class Lower extends TreeTranslato
*/
Map<JCTree, Integer> endPositions;
- /** A hash table mapping class trees to a ist of translated lambda defs.
- */
- Map<ClassSymbol, List<JCMethodDecl>> translatedLambdas = new HashMap<ClassSymbol, List<JCMethodDecl>>();
+ /** A list of translated lambda expressions
+ */
+ List<JCMethodDecl> translatedLambdas;
/**************************************************************************
* Global mappings
@@ -332,7 +336,12 @@ public class Lower extends TreeTranslato
fvs = collector.fvs;
freevarCache.put(c, fvs);
}
- return fvs;
+ //if the enclosing class is a synthetic lambda symbol
+ //append enclosing freevars to current freevars
+ //(nested lambdas cannot refer each other scopes)
+ return (c.owner.flags() & LAMBDA) != 0 ?
+ fvs.appendList(freevars(c.owner.enclClass())) :
+ fvs;
} else {
return List.nil();
}
@@ -999,7 +1008,8 @@ public class Lower extends TreeTranslato
JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
// Access a free variable via its proxy, or its proxy's proxy
while (sym.kind == VAR && sym.owner.kind == MTH &&
- sym.owner.enclClass() != currentClass) {
+ ((!lambdaStack.isEmpty() && lambdaStack.peek() != sym.owner) ||
+ sym.owner.enclClass() != currentClass)) {
// A constant is replaced by its constant value.
Object cv = ((VarSymbol)sym).getConstValue();
if (cv != null) {
@@ -1049,11 +1059,12 @@ public class Lower extends TreeTranslato
boolean accReq = protAccess || needsPrivateAccess(sym);
// A base has to be supplied for
- // - simple identifiers accessing variables in outer classes.
+ // - simple identifiers accessing variables in outer classes OR
+ // in current class when we are translating a lambda expr
boolean baseReq =
base == null &&
sym.owner != syms.predefClass &&
- !sym.isMemberOf(currentClass, types);
+ (!sym.isMemberOf(currentClass, types) || !lambdaStack.isEmpty());
if (accReq || baseReq) {
make.at(tree.pos);
@@ -1323,6 +1334,25 @@ public class Lower extends TreeTranslato
return result;
}
+ /** The name of a this$n field
+ * @param type The class referenced by the this$n field
+ */
+ Name outerThisLambda(Symbol lambdaSym, LambdaThisKind kind) {
+ Name result = names.fromString(kind.kindName + target.syntheticNameChar() + lambdaStack.indexOf(lambdaSym));
+ return result;
+ }
+
+ enum LambdaThisKind {
+ CURRENT_LAMBDA("lambda"),
+ ENCLOSING_CLASS("encl");
+
+ String kindName;
+
+ LambdaThisKind(String kindName) {
+ this.kindName = kindName;
+ }
+ }
+
/** Definition for this$n field.
* @param pos The source code position of the definition.
* @param owner The class in which the definition goes.
@@ -1362,7 +1392,8 @@ public class Lower extends TreeTranslato
* @param c The qualifier class.
*/
JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
- if (currentClass == c) {
+ //during lambda translation always call makeOutherThis
+ if (currentClass == c && lambdaStack.isEmpty()) {
// in this case, `this' works fine
return make.at(pos).This(c.erasure(types));
} else {
@@ -1420,12 +1451,18 @@ public class Lower extends TreeTranslato
*/
JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
Symbol c = sym.owner;
- if (preciseMatch ? sym.isMemberOf(currentClass, types)
- : currentClass.isSubClass(sym.owner, types)) {
+ if ((preciseMatch ? sym.isMemberOf(currentClass, types)
+ : currentClass.isSubClass(sym.owner, types)) &&
+ lambdaStack.isEmpty()) {
// in this case, `this' works fine
return make.at(pos).This(c.erasure(types));
+ } else if ((sym.owner.type == syms.objectType ||
+ sym.owner.type == syms.methodHandleType) &&
+ !lambdaStack.isEmpty()) {
+ // when in lambda translation resolve Object symbols to 'fake' MethodHandle param
+ return make.at(pos).Ident(proxies.lookup(outerThisLambda(lambdaStack.peek(), LambdaThisKind.CURRENT_LAMBDA)).sym);
} else {
- // need to go via this$n
+ // need to go via this$n (also applies when in lambda translation)
return makeOwnerThisN(pos, sym, preciseMatch);
}
}
@@ -2026,10 +2063,13 @@ public class Lower extends TreeTranslato
public void visitClassDef(JCClassDecl tree) {
ClassSymbol currentClassPrev = currentClass;
MethodSymbol currentMethodSymPrev = currentMethodSym;
+ Stack<MethodSymbol> prevLambdaStack = lambdaStack;
+ List<JCMethodDecl> prevTranslatedLambdas = translatedLambdas;
currentClass = tree.sym;
currentMethodSym = null;
+ lambdaStack = new Stack<MethodSymbol>();
+ translatedLambdas = List.nil();
classdefs.put(currentClass, tree);
- translatedLambdas.put(currentClass, List.<JCMethodDecl>nil());
proxies = proxies.dup(currentClass);
List<VarSymbol> prevOuterThisStack = outerThisStack;
@@ -2084,8 +2124,9 @@ public class Lower extends TreeTranslato
enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
}
- if (translatedLambdas.get(currentClass).nonEmpty()) {
- for (JCMethodDecl lambda : translatedLambdas.get(currentClass)) {
+ //append translated lambdas to lowered defs
+ if (translatedLambdas.nonEmpty()) {
+ for (JCMethodDecl lambda : translatedLambdas) {
tree.defs = tree.defs.prepend(lambda);
enterSynthetic(tree.pos(), lambda.sym, currentClass.members());
}
@@ -2099,6 +2140,8 @@ public class Lower extends TreeTranslato
currentClass = currentClassPrev;
currentMethodSym = currentMethodSymPrev;
+ lambdaStack = prevLambdaStack;
+ translatedLambdas = prevTranslatedLambdas;
// Return empty block {} as a placeholder for an inner class.
result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
@@ -3110,7 +3153,7 @@ public class Lower extends TreeTranslato
new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
names.empty, null,
currentClass);
- }
+ }
if (tree.init != null) tree.init = translate(tree.init, tree.type);
result = tree;
currentMethodSym = oldMethodSym;
@@ -3397,123 +3440,182 @@ public class Lower extends TreeTranslato
}
Name lambdaName() {
- return names.lambda.append(names.fromString("$" + translatedLambdas.get(currentClass).size()));
+ return names.lambda.append(names.fromString("$" + translatedLambdas.size()));
+ }
+
+ Name lambdaThisName(LambdaThisKind thisKind) {
+ return names.fromString(thisKind.kindName + target.syntheticNameChar() + lambdaStack.size());
}
public void visitLambda(JCLambda tree) {
- MethodSymbol lambdaSym = new MethodSymbol(SYNTHETIC | STATIC, lambdaName(), null, currentClass);
+ MethodSymbol lambdaSym = new MethodSymbol(LAMBDA | SYNTHETIC | STATIC, lambdaName(), null, currentClass);
MethodType lambdaType = (MethodType)types.erasure(tree.sym.type);
lambdaSym.type = lambdaType;
- //compute synthetic params
- ListBuffer<JCVariableDecl> syntheticParams = ListBuffer.lb();
- List<VarSymbol> freevars = List.nil();
- //add MethodHandle param
- syntheticParams.append(make.Param(names._this, syms.methodHandleType, lambdaSym));
- if (!tree.sym.isStatic()) {
- //add this$0
- syntheticParams.append(make.Param(outerThisName(currentClass.type, lambdaSym), currentClass.type, lambdaSym));
- }
- //add freevars
- freevars = freevars((ClassSymbol)tree.sym.owner);
- for (VarSymbol fv : freevars) {
- JCVariableDecl proxy = make.Param(proxyName(fv.name), fv.type, lambdaSym);
- proxy.sym.flags_field |= FINAL | SYNTHETIC;
- syntheticParams.append(proxy);
- }
-
- //prepend synthetic args to translated lambda method signature
- lambdaType.argtypes = lambdaType.argtypes.prependList(TreeInfo.types(syntheticParams.toList()));
-
- //create method declaration hoisting the lambda body
- JCBlock body = tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ?
- make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body))) :
- (JCBlock)tree.body;
- JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC),
- lambdaSym.name,
- make.QualIdent(lambdaType.getReturnType().tsym),
- List.<JCTypeParameter>nil(),
- tree.params.prependList(syntheticParams.toList()),
- tree.sym.type.getThrownTypes() == null ?
- List.<JCExpression>nil() :
- make.Types(tree.sym.type.getThrownTypes()),
- body,
- null);
- lambdaDecl.sym = lambdaSym;
- lambdaDecl.type = lambdaType;
-
+ ListBuffer<VarSymbol> freevars = ListBuffer.lb();
+
//save current translation context
-
List<VarSymbol> prevOuterThisStack = outerThisStack;
- ClassSymbol prevClass = currentClass;
- Scope prevProxies = proxies;
-
- //lower translated lambda method
+
+ boolean needsOuterAccess = (tree.sym.flags() & OUTER_ACCESS) != 0;
+
try {
- ListBuffer<JCVariableDecl> syntheticTransParams = ListBuffer.lb();
- currentClass = (ClassSymbol)tree.sym.owner;
- proxies = proxies.dupUnshared();
- if (!tree.sym.isStatic()) {
- JCVariableDecl _this$0 = outerThisDef(tree.pos, tree.sym.owner);
- outerThisStack =
- outerThisStack.prepend(_this$0.sym);
- syntheticTransParams.append(_this$0);
- }
- List<JCVariableDecl> fvdefs = freevarDefs(tree.pos,
- freevars((ClassSymbol)tree.sym.owner),
- tree.sym.owner);
- syntheticTransParams.appendList(fvdefs);
- JCMethodDecl transLambda = translate(lambdaDecl);
- patchLambda(transLambda, syntheticTransParams.toList(), syntheticParams.toList().tail);
- translatedLambdas.put(prevClass, translatedLambdas.get(prevClass).prepend(transLambda));
+ proxies = proxies.dup();
+ //compute synthetic params
+ ListBuffer<JCVariableDecl> syntheticParams = ListBuffer.lb();
+
+ //add MethodHandle param
+ VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+ lambdaThisName(LambdaThisKind.CURRENT_LAMBDA),
+ syms.methodHandleType, lambdaSym);
+ syntheticParams.append(make.VarDef(_this, null));
+ proxies.enter(_this); //make MethodHandle 'this' available as proxy
+
+ //add encl$n if needed
+ if (needsOuterAccess) {
+ VarSymbol _this$0 = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+ lambdaThisName(LambdaThisKind.ENCLOSING_CLASS),
+ currentClass.type, lambdaSym);
+ outerThisStack = outerThisStack.prepend(_this$0);
+ syntheticParams.append(make.VarDef(_this$0, null));
+ }
+
+ //add freevars
+ for (VarSymbol fv : freevars((ClassSymbol)tree.sym.owner)) {
+ freevars.append(fv);
+ VarSymbol arg = new VarSymbol(PARAMETER | FINAL | SYNTHETIC,
+ proxyName(fv.name),
+ fv.type,
+ lambdaSym);
+ proxies.enter(arg); //make freevars available as proxies
+ syntheticParams.append(make.at(tree.pos).VarDef(arg, null));
+ }
+
+ //add other arguments
+ for (JCVariableDecl param : tree.params) {
+ syntheticParams.append(make.at(tree.pos).VarDef(param.sym, null));
+ }
+
+ //prepend synthetic args to translated lambda method signature
+ lambdaType.argtypes = TreeInfo.types(syntheticParams.toList());
+
+ //replace synthetic symbol occurrences
+ patchLambda(tree, tree.sym, lambdaSym, _this);
+
+ //create method declaration hoisting the lambda body
+ JCBlock body = makeLambdaBody(tree);
+ JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(STATIC | SYNTHETIC),
+ lambdaSym.name,
+ make.QualIdent(lambdaType.getReturnType().tsym),
+ List.<JCTypeParameter>nil(),
+ syntheticParams.toList(),
+ tree.sym.type.getThrownTypes() == null ?
+ List.<JCExpression>nil() :
+ make.Types(tree.sym.type.getThrownTypes()),
+ body,
+ null);
+ lambdaDecl.sym = lambdaSym;
+ lambdaDecl.type = lambdaType;
+
+ //translate lambda body
+ lambdaStack.push(lambdaSym);
+ translatedLambdas = translatedLambdas.prepend(lambdaDecl);
+ translate(lambdaDecl);
}
finally {
- currentClass = prevClass;
+ proxies = proxies.leave();
+ lambdaStack.pop();
outerThisStack = prevOuterThisStack;
- proxies = prevProxies;
}
//generate method handle and pre-initialize synthetic arguments
- VarSymbol handleSym =
- new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()), syms.methodHandleType, lambdaSym);
+ VarSymbol handleSym = new VarSymbol(SYNTHETIC,
+ names.fromString("i" + target.syntheticNameChar()),
+ syms.methodHandleType,
+ lambdaStack.isEmpty() ?
+ currentMethodSym :
+ lambdaStack.peek());
JCVariableDecl handleDecl = make.VarDef(handleSym, makeMethodHandle(lambdaSym));
JCExpression handleRef = make.Ident(handleSym);
ListBuffer<JCExpression> syntheticInits = ListBuffer.lb();
+
+ //append MethodHandle reference
syntheticInits.append(handleRef);
- if (!tree.sym.isStatic()) {
+
+ //append reference to outer class (if needed)
+ if (needsOuterAccess) {
syntheticInits.append(makeThis(tree.pos(), currentClass));
}
+
+ //add free variables
for (VarSymbol fv : freevars) {
- syntheticInits.append(make.Ident(fv));
- }
+ syntheticInits.append(boxIfNeeded(loadFreevar(tree.pos(), fv),syms.objectType));
+ }
+
+ //generate insertArguments() call
JCExpression insertArgumentsArgs = makeArray(syms.objectType, syntheticInits.toList());
JCExpression insertArgumentsCall =
makeCall(make.QualIdent(syms.methodHandlesType.tsym), names.insertArguments, List.of(handleRef, makeLit(syms.intType, 0), insertArgumentsArgs));
result = make.LetExpr(handleDecl, insertArgumentsCall).setType(syms.methodHandleType);
}
- void patchLambda(JCTree tree, final List<JCVariableDecl> from, final List<JCVariableDecl> to) {
+ JCBlock makeLambdaBody(JCLambda tree) {
+ if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION &&
+ tree.body.type != syms.voidType) {
+ return make.Block(0, List.<JCStatement>of(make.Return((JCExpression)tree.body)));
+ } else {
+ switch (tree.body.getTag()) {
+ case JCTree.BLOCK: return (JCBlock)tree.body;
+ default:
+ JCStatement stat = make.Exec((JCExpression)tree.body);
+ return make.Block(0, List.<JCStatement>of(stat));
+ }
+ }
+ }
+
+ /*
+ * Patch a lambda expression; this is done by replacing all instances of
+ * synthetic symbols for lowered ones. Reference to 'fake' lambda this are
+ * also handled accordingly.
+ */
+ void patchLambda(JCTree tree, final Symbol oldOwner, final Symbol newOwner, final Symbol _this) {
class LambdaPatcher extends TreeScanner {
- HashMap<Symbol, Symbol> map = new HashMap<Symbol, Symbol>();
- LambdaPatcher() {
- List<JCVariableDecl> to2 = to;
- for (JCVariableDecl v : from) {
- map.put(v.sym, to2.head.sym);
- to2 = to2.tail;
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ if (tree.sym.owner == oldOwner) {
+ tree.sym.owner = newOwner;
}
+ super.visitClassDef(tree);
}
@Override
- public void visitIdent(JCIdent ident) {
- if (map.containsKey(ident.sym)) {
- ident.sym = map.get(ident.sym);
- ident.type = ident.sym.type;
- ident.name = ident.sym.name;
+ public void visitVarDef(JCVariableDecl tree) {
+ if (tree.sym.owner == oldOwner) {
+ tree.sym.owner = newOwner;
}
+ super.visitVarDef(tree);
+ }
+ @Override
+ public void visitLambda(JCLambda tree) {
+ if (tree.sym.owner.owner == oldOwner) {
+ tree.sym.owner.owner = newOwner;
+ }
+ super.visitLambda(tree);
+ }
+ @Override
+ public void visitIdent(JCIdent tree) {
+ //replace occurrences of synthetic 'this'
+ //with the special lambda MethodHandle parameter
+ if (tree.sym.name == names._this &&
+ tree.sym.owner == oldOwner.owner) {
+ tree.name = _this.name;
+ tree.sym = _this;
+ tree.type = _this.type;
+ }
}
}
new LambdaPatcher().scan(tree);
}
-
+
JCExpression makeMethodHandle(MethodSymbol msym) {
String sig = writer.typeSig(msym.type).toString();
ListBuffer<JCExpression> args1 = ListBuffer.lb();
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Jun 04 12:34:09 2010 +0100
@@ -911,11 +911,14 @@ public class Resolve {
}
Type restype;
List<Type> thrown = List.nil();
+ List<Type> paramtypes;
if (types.isFunctionType(site)) {
+ paramtypes = site.getParameterTypes();
restype = site.getReturnType();
thrown = site.getThrownTypes();
}
else {
+ paramtypes = Type.map(argtypes, implicitArgType);
if (typeargtypes.isEmpty()) {
restype = syms.objectType;
} else {
@@ -924,7 +927,7 @@ public class Resolve {
return methodNotFound;
}
}
- List<Type> paramtypes = Type.map(argtypes, implicitArgType);
+
MethodType mtype = new MethodType(paramtypes,
restype,
thrown,
@@ -951,8 +954,12 @@ public class Resolve {
m = new MethodSymbol(flags, name, mtype, c);
implicit.enter(m);
}
+ boolean argsOk = argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
+ true, false, Warner.noWarnings);
+ if (types.isFunctionType(site) && !argsOk)
+ return wrongMethod.setWrongSym(m);
assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
- false, false, Warner.noWarnings);
+ true, false, Warner.noWarnings);
assert null != instantiate(env, site, m, argtypes, typeargtypes, false, false, Warner.noWarnings);
return m;
}
@@ -1353,9 +1360,12 @@ public class Resolve {
needsImplicitResolution(site, name)) {
// lookup failed; supply an exactly-typed implicit method
sym = findImplicitMethod(env, site, name, argtypes, typeargtypes);
+ if (sym.kind >= AMBIGUOUS) {
+ sym = access(sym, pos, site, name, true, argtypes, typeargtypes);
+ }
env.info.varArgs = false;
}
- if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
+ else if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
MethodResolutionPhase errPhase =
firstErroneousResolutionPhase();
sym = access(methodResolutionCache.get(errPhase),
@@ -1889,6 +1899,13 @@ public class Resolve {
return diags.create(dkind, false, log.currentSource(),
pos, "operator.cant.be.applied", name, argtypes);
}
+ else if (types.isFunctionType(site) &&
+ name == names.empty) {
+ return diags.create(dkind, false, log.currentSource(), pos,
+ "cant.apply.lambda",
+ methodArguments(site.getParameterTypes()),
+ methodArguments(argtypes));
+ }
else {
Symbol ws = sym.asMemberOf(site, types);
return diags.create(dkind, false, log.currentSource(), pos,
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Jun 04 12:34:09 2010 +0100
@@ -952,8 +952,9 @@ public class JavacParser implements Pars
} else return illegal();
break;
case HASH:
- S.nextToken();
- t = lambdaOrFunctionType();
+ int prevPos = S.pos();
+ S.nextToken();
+ t = lambdaOrFunctionType(prevPos);
break;
case LPAREN:
if (typeArgs == null && (mode & EXPR) != 0) {
@@ -1288,16 +1289,15 @@ public class JavacParser implements Pars
return toP(t);
}
- JCExpression lambdaOrFunctionType() {
+ JCExpression lambdaOrFunctionType(int pos) {
return S.token() == LPAREN ?
- lambdaExpressionOrStatement() :
+ lambdaExpressionOrStatement(pos) :
functionType();
}
- JCExpression lambdaExpressionOrStatement() {
+ JCExpression lambdaExpressionOrStatement(int pos) {
mode = EXPR;
checkLambda();
- int pos = S.pos();
List<JCVariableDecl> args = formalParameters();
return S.token() == LBRACE ?
lambdaExpression(args, pos) :
@@ -1328,7 +1328,8 @@ public class JavacParser implements Pars
typeList();
accept(RPAREN);
List<JCExpression> thrown = List.nil();
- if (S.token() == LPAREN) {
+ if (S.token() == LPAREN &&
+ S.peekToken() == THROWS) {
S.nextToken();
accept(THROWS);
thrown = qualidentList();
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri May 28 17:19:22 2010 +0100
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Jun 04 12:34:09 2010 +0100
@@ -89,6 +89,10 @@ compiler.err.cant.apply.symbol.1=\
required: {2}\n\
found: {3}\n\
reason: {6}
+compiler.err.cant.apply.lambda=\
+ lambda expression cannot be applied to given types\n\
+ required: {0}\n\
+ found: {1}
compiler.err.cant.assign.val.to.final.var=\
cannot assign a value to final variable {0}
compiler.err.cant.deref=\
@@ -101,6 +105,8 @@ compiler.err.cant.ref.before.ctor.called
cannot reference {0} before supertype constructor has been called
compiler.err.cant.ret.val.from.meth.decl.void=\
cannot return a value from method whose result type is void
+compiler.err.cant.ret.void.expr=\
+ cannot return an expression whose type is void
compiler.err.cant.select.static.class.from.param.type=\
cannot select a static class from a parameterized type
compiler.err.cant.inherit.diff.arg=\
@@ -265,8 +271,15 @@ compiler.err.invalid.meth.decl.ret.type.
compiler.err.label.already.in.use=\
label {0} already in use
-compiler.err.local.var.accessed.from.icls.needs.final=\
- local variable {0} is accessed from within inner class; needs to be declared final
+
+compiler.err.local.var.accessed.from.inner.ctx.needs.final=\
+ local variable {0} is accessed from within {1}; needs to be declared final
+#where {1} is either
+compiler.misc.icls=\
+ an inner class
+compiler.misc.lambda=\
+ a lambda expression
+
compiler.err.local.enum=\
enum types must not be local
compiler.err.cannot.create.array.with.type.arguments=\
@@ -327,6 +340,10 @@ incompatible types for ?: neither is a s
incompatible types for ?: neither is a subtype of the other\n\
second operand: {0}\n\
third operand : {1}
+compiler.err.incompatibles.ret.types.in.lambda=\
+incompatible return types in lambda expression: neither is a subtype of the other\n\
+expected type: {0}\n\
+found : {1}
compiler.err.new.not.allowed.in.annotation=\
''new'' not allowed in an annotation
compiler.err.no.annotation.member=\
--- a/test/tools/javac/lambda/NakedThis.out Fri May 28 17:19:22 2010 +0100
+++ b/test/tools/javac/lambda/NakedThis.out Fri Jun 04 12:34:09 2010 +0100
@@ -1,2 +1,2 @@ NakedThis.java:33:16: compiler.err.canno
-NakedThis.java:33:16: compiler.err.cannot.infer.lambda.return.type
+NakedThis.java:33:15: compiler.err.cannot.infer.lambda.return.type
1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadAccess.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary check that non-static variables are not accessible from static lambdas
+ * and that lambda can access only final locals
+ * @author Maurizio Cimadamore
+ * @compile/fail/ref=BadAccess.out -XDrawDiagnostics BadAccess.java
+ */
+
+public class BadAccess {
+
+ int i;
+ static int I;
+
+ static void test1() {
+ int l = 0;
+ final int L = 0;
+ Object o = #()(i + I + l + L);
+ }
+
+ void test2() {
+ int l = 0;
+ final int L = 0;
+ Object o = #()(i + I + l + L);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadAccess.out Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,4 @@
+BadAccess.java:40:24: compiler.err.non-static.cant.be.ref: kindname.variable, i
+BadAccess.java:40:32: compiler.err.local.var.accessed.from.inner.ctx.needs.final: l, (compiler.misc.lambda)
+BadAccess.java:46:32: compiler.err.local.var.accessed.from.inner.ctx.needs.final: l, (compiler.misc.lambda)
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadLambdaCall.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary test for capture in nested lambda expressions
+ * @author Maurizio Cimadamore
+ * @compile/fail/ref=BadLambdaCall.out -XDrawDiagnostics BadLambdaCall.java
+ */
+
+class BadLambdaCall {
+ void test(final int a0) {
+ #(){ }.(1); //too many args
+ #(int x){ }.(); //not enough args
+ #(int x){ }.(1,2); //not enough args
+ #(int x){ }.(""); //type mismatch
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadLambdaCall.out Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,5 @@
+BadLambdaCall.java:33:16: compiler.err.cant.apply.lambda: compiler.misc.no.args, int
+BadLambdaCall.java:34:21: compiler.err.cant.apply.lambda: int, compiler.misc.no.args
+BadLambdaCall.java:35:21: compiler.err.cant.apply.lambda: int, int,int
+BadLambdaCall.java:36:21: compiler.err.cant.apply.lambda: int, java.lang.String
+4 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadReturn.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary check that incompatible return types in lambdas are flagged with error
+ * @author Maurizio Cimadamore
+ * @compile/fail/ref=BadReturn.out -XDrawDiagnostics BadReturn.java
+ */
+
+class BadReturn {
+
+ static void testNeg1() {
+ Object o = #(){
+ if (true) {
+ return "";
+ } else {
+ return System.out.println("");
+ }};
+ }
+
+ static void testNeg2() {
+ Object o = #(){ return System.out.println(""); };
+ }
+
+ static void testPos() {
+ Comparable<?> o = #() {
+ if (false) {
+ return 10;
+ }
+ else {
+ return true;
+ }}.();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/BadReturn.out Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,4 @@
+BadReturn.java:38:42: compiler.err.cant.ret.void.expr
+BadReturn.java:38:17: compiler.err.incompatibles.ret.types.in.lambda: java.lang.String, void
+BadReturn.java:43:50: compiler.err.cant.ret.void.expr
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture02.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary basic test for capture of non-mutable locals
+ * @author Brian Goetz
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture02
+ */
+
+public class LambdaCapture02 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ interface Tester {
+ void test();
+ }
+
+ interface TU<T, U> {
+ public T foo(U u);
+ }
+
+ public static <T, U> T exec(TU<T, U> lambda, U x) {
+ return lambda.foo(x);
+ }
+
+ public Integer n = 5;
+
+ //Simple local capture
+ void test1() {
+ final Integer N = 1;
+ int x = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + N), 3);
+ assertTrue(4 == x);
+ }
+
+ //Local capture with multiple scopes (anon class)
+ void test2() {
+ final Integer N = 1;
+ new Tester() {
+ public void test() {
+ final Integer M = 2;
+ int x = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + N + M), 3);
+ assertTrue(6 == x);
+ }
+ }.test();
+ }
+
+ //Local capture with multiple scopes (local class)
+ void test3() {
+ final Integer N = 1;
+ class MyTester implements Tester {
+ public void test() {
+ final Integer M = 2;
+ int x = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + N + M), 3);
+ assertTrue(6 == x);
+ }
+ }
+ new MyTester().test();
+ }
+
+ //access to field from enclosing scope
+ void test4() {
+ final Integer N = 4;
+ int x1 = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + n + N), 3);
+ assertTrue(12 == x1);
+ int x2 = LambdaCapture02.<Integer,Integer>exec(#(Integer x)(x + LambdaCapture02.this.n + N), 3);
+ assertTrue(12 == x2);
+ }
+
+ public static void main(String[] args) {
+ LambdaCapture02 t = new LambdaCapture02();
+ t.test1();
+ t.test2();
+ t.test3();
+ t.test4();
+ assertTrue(assertionCount == 5);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture03.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary test for capture of non-mutable locals/outer fields in multiple scopes
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture03
+ */
+
+public class LambdaCapture03 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ interface Tester {
+ void test();
+ }
+
+ interface TU<T, U> {
+ public T foo(U u);
+ }
+
+ public static <T, U> T exec(TU<T, U> lambda, U x) {
+ return lambda.foo(x);
+ }
+
+ Integer n1 = 10;
+
+ void test1() {
+ final Integer N1 = 1;
+ class A {
+ Integer n2 = 20;
+ void test() {
+ final Integer N2 = 2;
+ class B {
+ void test() {
+ final Integer N3 = 3;
+ int x = LambdaCapture03.exec(#(Integer x)(x + n1 + n2 + N1 + N2 + N3), 30);
+ assertTrue(x == 66);
+ }
+ }
+ new B().test();
+ }
+ }
+ new A().test();
+ }
+
+ void test2() {
+ final Integer N1 = 1;
+ new Tester() {
+ Integer n2 = 20;
+ public void test() {
+ final Integer N2 = 2;
+ new Tester() {
+ public void test() {
+ final Integer N3 = 3;
+ int x = LambdaCapture03.exec(#(Integer x)(x + n1 + n2 + N1 + N2 + N3), 30);
+ assertTrue(x == 66);
+ }
+ }.test();
+ }
+ }.test();
+ }
+
+ public static void main(String[] args) {
+ LambdaCapture03 t = new LambdaCapture03();
+ t.test1();
+ t.test2();
+ assertTrue(assertionCount == 2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture04.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary test for capture of non-mutable locals/outer fields in multiple scopes
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture04
+ */
+
+public class LambdaCapture04 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ interface Tester {
+ void test();
+ }
+
+ interface TU<T, U> {
+ public T foo(U u);
+ }
+
+ public static <T, U> T exec(TU<T, U> lambda, U x) {
+ return lambda.foo(x);
+ }
+
+ Integer n1 = 10;
+
+ void test1() {
+ final Integer N1 = 1;
+ class A {
+ Integer n2 = 20;
+ void test() {
+ final Integer N2 = 2;
+ class B {
+ void test() {
+ final Integer N3 = 3;
+ #(final Integer x)(new Tester() { public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); } }.test()).(30);
+ }
+ }
+ new B().test();
+ }
+ }
+ new A().test();
+ }
+
+ void test2() {
+ final Integer N1 = 1;
+ class A {
+ Integer n2 = 20;
+ void test() {
+ final Integer N2 = 2;
+ class B {
+ void test() {
+ final Integer N3 = 3;
+ #(final Integer x){
+ class LocTester implements Tester {
+ public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); }
+ };
+ new LocTester().test();}.(30);
+ }
+ }
+ new B().test();
+ }
+ }
+ new A().test();
+ }
+
+ void test3() {
+ final Integer N1 = 1;
+ new Tester() {
+ Integer n2 = 20;
+ public void test() {
+ final Integer N2 = 2;
+ new Tester() {
+ public void test() {
+ final Integer N3 = 3;
+ #(final Integer x)(new Tester() { public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); } }.test()).(30);
+ }
+ }.test();
+ }
+ }.test();
+ }
+
+ void test4() {
+ final Integer N1 = 1;
+ new Tester() {
+ Integer n2 = 20;
+ public void test() {
+ final Integer N2 = 2;
+ new Tester() {
+ public void test() {
+ final Integer N3 = 3;
+ #(final Integer x){
+ class LocTester implements Tester {
+ public void test() { assertTrue(x + n1 + n2 + N1 + N2 + N3 == 66); }
+ };
+ new LocTester().test();}.(30);
+ }
+ }.test();
+ }
+ }.test();
+ }
+
+ public static void main(String[] args) {
+ LambdaCapture04 t = new LambdaCapture04();
+ t.test1();
+ t.test2();
+ t.test3();
+ t.test4();
+ assertTrue(assertionCount == 4);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaCapture05.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary test for capture in nested lambda expressions
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaCapture05
+ */
+
+public class LambdaCapture05 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ int i = 40;
+
+ void test1(final int a0) {
+ #(final int a1){
+ final Integer x2 = 10; #(final int a2) {
+ final Integer x3 = 20;
+ #(final int a3)(assertTrue(106 == (a0 + a1 + a2 + a3 + x2 + x3 + i))).(3);
+ }.(2);
+ }.(1);
+ }
+
+ static void test2(final int a0) {
+ #(final int a1){
+ final Integer x2 = 10; #(final int a2) {
+ final Integer x3 = 20;
+ #(final int a3)(assertTrue(66 == (a0 + a1 + a2 + a3 + x2 + x3))).(3);
+ }.(2);
+ }.(1);
+ }
+
+ public static void main(String[] args) {
+ LambdaCapture05 t = new LambdaCapture05();
+ t.test1(30);
+ test2(30);
+ assertTrue(assertionCount == 2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaConv05.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary function type and method type inference
+ * @author Alex Buckley
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaConv05
+ */
+
+import java.util.*;
+
+public class LambdaConv05 {
+
+ static void assertTrue(boolean cond) {
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ int count = 0;
+
+ void sort(List<String> data) {
+ Collections.sort(data,
+ #(String a, String b) { LambdaConv05.this.count++; return a.length()-b.length(); });
+ }
+
+ public static void main(String[] args) {
+ ArrayList<String> arr = new ArrayList<>();
+ arr.add("Three");
+ arr.add("Four");
+ arr.add("One");
+ LambdaConv05 sorter = new LambdaConv05();
+ sorter.sort(arr);
+ assertTrue(arr.get(0).equals("One"));
+ assertTrue(arr.get(1).equals("Four"));
+ assertTrue(arr.get(2).equals("Three"));
+ assertTrue(sorter.count == 2);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/lambda/LambdaScope02.java Fri Jun 04 12:34:09 2010 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @summary check that MethodHandle members are accessible as expected
+ * @author Maurizio Cimadamore
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles LambdaScope02
+ */
+
+public class LambdaScope02 {
+
+ static int assertionCount = 0;
+
+ static void assertTrue(boolean cond) {
+ assertionCount++;
+ if (!cond)
+ throw new AssertionError();
+ }
+
+ static void test1() {
+ final String sig = "(java.dyn.MethodHandle)void";
+ #() {assertTrue(this.type().toString().equals(sig));}.();
+ #() {assertTrue(type().toString().equals(sig));}.();
+ }
+
+ void test2() {
+ final String sig = "(java.dyn.MethodHandle,LambdaScope02)void";
+ #() {assertTrue(this.type().toString().equals(sig));}.();
+ #() {assertTrue(type().toString().equals(sig));}.();
+ }
+
+ public static void main(String[] args) {
+ test1();
+ new LambdaScope02().test2();
+ assertTrue(assertionCount == 4);
+ }
+}