提交 21333f41 编写于 作者: M mcimadamore

7177385: Add attribution support for lambda expressions

Summary: Add support for function descriptor lookup, functional interface inference and lambda expression type-checking
Reviewed-by: jjg, dlsmith
上级 b2ca49a5
......@@ -54,11 +54,8 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
List<Type> seenCaptured = List.nil();
static final int PRIME = 997; // largest prime less than 1000
boolean raw;
protected Printer(boolean raw) {
this.raw = raw;
}
protected Printer() { }
/**
* This method should be overriden in order to provide proper i18n support.
......@@ -87,7 +84,7 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
* @return printer visitor instance
*/
public static Printer createStandardPrinter(final Messages messages) {
return new Printer(false) {
return new Printer() {
@Override
protected String localize(Locale locale, String key, Object... args) {
return messages.getLocalizedString(locale, key, args);
......@@ -174,34 +171,6 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
return "<" + visitTypes(t.tvars, locale) + ">" + visit(t.qtype, locale);
}
public String visitDeferredType(DeferredType t, Locale locale) {
return raw ? localize(locale, getDeferredKey(t.tree)) :
deferredTypeTree2String(t.tree);
}
//where
private String deferredTypeTree2String(JCTree tree) {
switch(tree.getTag()) {
case PARENS:
return deferredTypeTree2String(((JCTree.JCParens)tree).expr);
case CONDEXPR:
return Pretty.toSimpleString(tree, 15);
default:
Assert.error("unexpected tree kind " + tree.getKind());
return null;
}
}
private String getDeferredKey (JCTree tree) {
switch (tree.getTag()) {
case PARENS:
return getDeferredKey(((JCTree.JCParens)tree).expr);
case CONDEXPR:
return "compiler.misc.type.conditional";
default:
Assert.error("unexpected tree kind " + tree.getKind());
return null;
}
}
@Override
public String visitUndetVar(UndetVar t, Locale locale) {
if (t.inst != null) {
......@@ -265,14 +234,10 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
}
public String visitType(Type t, Locale locale) {
if (t.tag == DEFERRED) {
return visitDeferredType((DeferredType)t, locale);
} else {
String s = (t.tsym == null || t.tsym.name == null)
? localize(locale, "compiler.misc.type.none")
: t.tsym.name.toString();
return s;
}
String s = (t.tsym == null || t.tsym.name == null)
? localize(locale, "compiler.misc.type.none")
: t.tsym.name.toString();
return s;
}
/**
......
......@@ -1220,9 +1220,13 @@ public class Type implements PrimitiveType {
}
public UndetVar(TypeVar origin, Types types) {
this(origin, types, true);
}
public UndetVar(TypeVar origin, Types types, boolean includeBounds) {
super(UNDETVAR, origin);
bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class);
bounds.put(InferenceBound.UPPER, types.getBounds(origin));
bounds.put(InferenceBound.UPPER, includeBounds ? types.getBounds(origin) : List.<Type>nil());
bounds.put(InferenceBound.LOWER, List.<Type>nil());
bounds.put(InferenceBound.EQ, List.<Type>nil());
}
......
......@@ -79,8 +79,10 @@ public class Types {
final boolean allowObjectToPrimitiveCast;
final ClassReader reader;
final Check chk;
JCDiagnostic.Factory diags;
List<Warner> warnStack = List.nil();
final Name capturedName;
private final FunctionDescriptorLookupError functionDescriptorLookupError;
// <editor-fold defaultstate="collapsed" desc="Instantiating">
public static Types instance(Context context) {
......@@ -102,6 +104,8 @@ public class Types {
chk = Check.instance(context);
capturedName = names.fromString("<captured wildcard>");
messages = JavacMessages.instance(context);
diags = JCDiagnostic.Factory.instance(context);
functionDescriptorLookupError = new FunctionDescriptorLookupError();
}
// </editor-fold>
......@@ -296,6 +300,294 @@ public class Types {
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="findSam">
/**
* Exception used to report a function descriptor lookup failure. The exception
* wraps a diagnostic that can be used to generate more details error
* messages.
*/
public static class FunctionDescriptorLookupError extends RuntimeException {
private static final long serialVersionUID = 0;
JCDiagnostic diagnostic;
FunctionDescriptorLookupError() {
this.diagnostic = null;
}
FunctionDescriptorLookupError setMessage(JCDiagnostic diag) {
this.diagnostic = diag;
return this;
}
public JCDiagnostic getDiagnostic() {
return diagnostic;
}
}
/**
* A cache that keeps track of function descriptors associated with given
* functional interfaces.
*/
class DescriptorCache {
private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<TypeSymbol, Entry>();
class FunctionDescriptor {
Symbol descSym;
FunctionDescriptor(Symbol descSym) {
this.descSym = descSym;
}
public Symbol getSymbol() {
return descSym;
}
public Type getType(Type origin) {
return memberType(origin, descSym);
}
}
class Entry {
final FunctionDescriptor cachedDescRes;
final int prevMark;
public Entry(FunctionDescriptor cachedDescRes,
int prevMark) {
this.cachedDescRes = cachedDescRes;
this.prevMark = prevMark;
}
boolean matches(int mark) {
return this.prevMark == mark;
}
}
FunctionDescriptor get(TypeSymbol origin) throws FunctionDescriptorLookupError {
Entry e = _map.get(origin);
CompoundScope members = membersClosure(origin.type, false);
if (e == null ||
!e.matches(members.getMark())) {
FunctionDescriptor descRes = findDescriptorInternal(origin, members);
_map.put(origin, new Entry(descRes, members.getMark()));
return descRes;
}
else {
return e.cachedDescRes;
}
}
/**
* Scope filter used to skip methods that should be ignored during
* function interface conversion (such as methods overridden by
* j.l.Object)
*/
class DescriptorFilter implements Filter<Symbol> {
TypeSymbol origin;
DescriptorFilter(TypeSymbol origin) {
this.origin = origin;
}
@Override
public boolean accepts(Symbol sym) {
return sym.kind == Kinds.MTH &&
(sym.flags() & ABSTRACT) != 0 &&
!overridesObjectMethod(origin, sym) &&
notOverridden(sym);
}
private boolean notOverridden(Symbol msym) {
Symbol impl = ((MethodSymbol)msym).implementation(origin, Types.this, false);
return impl == null || (impl.flags() & ABSTRACT) != 0;
}
};
/**
* Compute the function descriptor associated with a given functional interface
*/
public FunctionDescriptor findDescriptorInternal(TypeSymbol origin, CompoundScope membersCache) throws FunctionDescriptorLookupError {
if (!origin.isInterface()) {
//t must be an interface
throw failure("not.a.functional.intf");
}
final ListBuffer<Symbol> abstracts = ListBuffer.lb();
for (Symbol sym : membersCache.getElements(new DescriptorFilter(origin))) {
Type mtype = memberType(origin.type, sym);
if (abstracts.isEmpty() ||
(sym.name == abstracts.first().name &&
overrideEquivalent(mtype, memberType(origin.type, abstracts.first())))) {
abstracts.append(sym);
} else {
//the target method(s) should be the only abstract members of t
throw failure("not.a.functional.intf.1",
diags.fragment("incompatible.abstracts", Kinds.kindName(origin), origin));
}
}
if (abstracts.isEmpty()) {
//t must define a suitable non-generic method
throw failure("not.a.functional.intf.1",
diags.fragment("no.abstracts", Kinds.kindName(origin), origin));
} else if (abstracts.size() == 1) {
if (abstracts.first().type.tag == FORALL) {
throw failure("invalid.generic.desc.in.functional.intf",
abstracts.first(),
Kinds.kindName(origin),
origin);
} else {
return new FunctionDescriptor(abstracts.first());
}
} else { // size > 1
for (Symbol msym : abstracts) {
if (msym.type.tag == FORALL) {
throw failure("invalid.generic.desc.in.functional.intf",
abstracts.first(),
Kinds.kindName(origin),
origin);
}
}
FunctionDescriptor descRes = mergeDescriptors(origin, abstracts.toList());
if (descRes == null) {
//we can get here if the functional interface is ill-formed
ListBuffer<JCDiagnostic> descriptors = ListBuffer.lb();
for (Symbol desc : abstracts) {
String key = desc.type.getThrownTypes().nonEmpty() ?
"descriptor.throws" : "descriptor";
descriptors.append(diags.fragment(key, desc.name,
desc.type.getParameterTypes(),
desc.type.getReturnType(),
desc.type.getThrownTypes()));
}
JCDiagnostic.MultilineDiagnostic incompatibleDescriptors =
new JCDiagnostic.MultilineDiagnostic(diags.fragment("incompatible.descs.in.functional.intf",
Kinds.kindName(origin), origin), descriptors.toList());
throw failure(incompatibleDescriptors);
}
return descRes;
}
}
/**
* Compute a synthetic type for the target descriptor given a list
* of override-equivalent methods in the functional interface type.
* The resulting method type is a method type that is override-equivalent
* and return-type substitutable with each method in the original list.
*/
private FunctionDescriptor mergeDescriptors(TypeSymbol origin, List<Symbol> methodSyms) {
//pick argument types - simply take the signature that is a
//subsignature of all other signatures in the list (as per JLS 8.4.2)
List<Symbol> mostSpecific = List.nil();
outer: for (Symbol msym1 : methodSyms) {
Type mt1 = memberType(origin.type, msym1);
for (Symbol msym2 : methodSyms) {
Type mt2 = memberType(origin.type, msym2);
if (!isSubSignature(mt1, mt2)) {
continue outer;
}
}
mostSpecific = mostSpecific.prepend(msym1);
}
if (mostSpecific.isEmpty()) {
return null;
}
//pick return types - this is done in two phases: (i) first, the most
//specific return type is chosen using strict subtyping; if this fails,
//a second attempt is made using return type substitutability (see JLS 8.4.5)
boolean phase2 = false;
Symbol bestSoFar = null;
while (bestSoFar == null) {
outer: for (Symbol msym1 : mostSpecific) {
Type mt1 = memberType(origin.type, msym1);
for (Symbol msym2 : methodSyms) {
Type mt2 = memberType(origin.type, msym2);
if (phase2 ?
!returnTypeSubstitutable(mt1, mt2) :
!isSubtypeInternal(mt1.getReturnType(), mt2.getReturnType())) {
continue outer;
}
}
bestSoFar = msym1;
}
if (phase2) {
break;
} else {
phase2 = true;
}
}
if (bestSoFar == null) return null;
//merge thrown types - form the intersection of all the thrown types in
//all the signatures in the list
List<Type> thrown = null;
for (Symbol msym1 : methodSyms) {
Type mt1 = memberType(origin.type, msym1);
thrown = (thrown == null) ?
mt1.getThrownTypes() :
chk.intersect(mt1.getThrownTypes(), thrown);
}
final List<Type> thrown1 = thrown;
return new FunctionDescriptor(bestSoFar) {
@Override
public Type getType(Type origin) {
Type mt = memberType(origin, getSymbol());
return new MethodType(mt.getParameterTypes(), mt.getReturnType(), thrown1, syms.methodClass);
}
};
}
boolean isSubtypeInternal(Type s, Type t) {
return (s.isPrimitive() && t.isPrimitive()) ?
isSameType(t, s) :
isSubtype(s, t);
}
FunctionDescriptorLookupError failure(String msg, Object... args) {
return failure(diags.fragment(msg, args));
}
FunctionDescriptorLookupError failure(JCDiagnostic diag) {
return functionDescriptorLookupError.setMessage(diag);
}
}
private DescriptorCache descCache = new DescriptorCache();
/**
* Find the method descriptor associated to this class symbol - if the
* symbol 'origin' is not a functional interface, an exception is thrown.
*/
public Symbol findDescriptorSymbol(TypeSymbol origin) throws FunctionDescriptorLookupError {
return descCache.get(origin).getSymbol();
}
/**
* Find the type of the method descriptor associated to this class symbol -
* if the symbol 'origin' is not a functional interface, an exception is thrown.
*/
public Type findDescriptorType(Type origin) throws FunctionDescriptorLookupError {
return descCache.get(origin.tsym).getType(origin);
}
/**
* Is given type a functional interface?
*/
public boolean isFunctionalInterface(TypeSymbol tsym) {
try {
findDescriptorSymbol(tsym);
return true;
} catch (FunctionDescriptorLookupError ex) {
return false;
}
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="isSubtype">
/**
* Is t an unchecked subtype of s?
......@@ -1215,7 +1507,10 @@ public class Types {
* Returns the lower bounds of the formals of a method.
*/
public List<Type> lowerBoundArgtypes(Type t) {
return map(t.getParameterTypes(), lowerBoundMapping);
return lowerBounds(t.getParameterTypes());
}
public List<Type> lowerBounds(List<Type> ts) {
return map(ts, lowerBoundMapping);
}
private final Mapping lowerBoundMapping = new Mapping("lowerBound") {
public Type apply(Type t) {
......@@ -2007,6 +2302,15 @@ public class Types {
hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s);
}
public boolean overridesObjectMethod(TypeSymbol origin, Symbol msym) {
for (Scope.Entry e = syms.objectType.tsym.members().lookup(msym.name) ; e.scope != null ; e = e.next()) {
if (msym.overrides(e.sym, origin, Types.this, true)) {
return true;
}
}
return false;
}
// <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site">
class ImplementationCache {
......
......@@ -421,7 +421,7 @@ public class Check {
* checks - depending on the check context, meaning of 'compatibility' might
* vary significantly.
*/
interface CheckContext {
public interface CheckContext {
/**
* Is type 'found' compatible with type 'req' in given context
*/
......@@ -438,6 +438,8 @@ public class Check {
public Infer.InferenceContext inferenceContext();
public DeferredAttr.DeferredAttrContext deferredAttrContext();
public boolean allowBoxing();
}
/**
......@@ -472,6 +474,10 @@ public class Check {
public DeferredAttrContext deferredAttrContext() {
return enclosingContext.deferredAttrContext();
}
public boolean allowBoxing() {
return enclosingContext.allowBoxing();
}
}
/**
......@@ -496,6 +502,10 @@ public class Check {
public DeferredAttrContext deferredAttrContext() {
return deferredAttr.emptyDeferredAttrContext;
}
public boolean allowBoxing() {
return true;
}
};
/** Check that a given type is assignable to a given proto-type.
......@@ -557,9 +567,9 @@ public class Check {
*/
public void checkRedundantCast(Env<AttrContext> env, JCTypeCast tree) {
if (!tree.type.isErroneous() &&
(env.info.lint == null || env.info.lint.isEnabled(Lint.LintCategory.CAST))
&& types.isSameType(tree.expr.type, tree.clazz.type)
&& !is292targetTypeCast(tree)) {
(env.info.lint == null || env.info.lint.isEnabled(Lint.LintCategory.CAST))
&& types.isSameType(tree.expr.type, tree.clazz.type)
&& !is292targetTypeCast(tree)) {
log.warning(Lint.LintCategory.CAST,
tree.pos(), "redundant.cast", tree.expr.type);
}
......@@ -906,6 +916,65 @@ public class Check {
return;
}
void checkAccessibleFunctionalDescriptor(DiagnosticPosition pos, Env<AttrContext> env, Type desc) {
AccessChecker accessChecker = new AccessChecker(env);
//check args accessibility (only if implicit parameter types)
for (Type arg : desc.getParameterTypes()) {
if (!accessChecker.visit(arg)) {
log.error(pos, "cant.access.arg.type.in.functional.desc", arg);
return;
}
}
//check return type accessibility
if (!accessChecker.visit(desc.getReturnType())) {
log.error(pos, "cant.access.return.in.functional.desc", desc.getReturnType());
return;
}
//check thrown types accessibility
for (Type thrown : desc.getThrownTypes()) {
if (!accessChecker.visit(thrown)) {
log.error(pos, "cant.access.thrown.in.functional.desc", thrown);
return;
}
}
}
class AccessChecker extends Types.UnaryVisitor<Boolean> {
Env<AttrContext> env;
AccessChecker(Env<AttrContext> env) {
this.env = env;
}
Boolean visit(List<Type> ts) {
for (Type t : ts) {
if (!visit(t))
return false;
}
return true;
}
public Boolean visitType(Type t, Void s) {
return true;
}
@Override
public Boolean visitArrayType(ArrayType t, Void s) {
return visit(t.elemtype);
}
@Override
public Boolean visitClassType(ClassType t, Void s) {
return rs.isAccessible(env, t, true) &&
visit(t.getTypeArguments());
}
@Override
public Boolean visitWildcardType(WildcardType t, Void s) {
return visit(t.type);
}
};
/**
* Check that type 't' is a valid instantiation of a generic class
* (see JLS 4.5)
......
......@@ -497,7 +497,7 @@ public class DeferredAttr extends JCTree.Visitor {
* a default expected type (j.l.Object).
*/
private Type recover(DeferredType dt) {
dt.check(new RecoveryInfo());
dt.check(attr.new RecoveryInfo(deferredAttrContext));
switch (TreeInfo.skipParens(dt.tree).getTag()) {
case LAMBDA:
case REFERENCE:
......@@ -509,45 +509,132 @@ public class DeferredAttr extends JCTree.Visitor {
return super.apply(dt);
}
}
}
class RecoveryInfo extends ResultInfo {
/**
* Retrieves the list of inference variables that need to be inferred before
* an AST node can be type-checked
*/
@SuppressWarnings("fallthrough")
List<Type> stuckVars(JCTree tree, ResultInfo resultInfo) {
if (resultInfo.pt.tag == NONE || resultInfo.pt.isErroneous()) {
return List.nil();
} else {
StuckChecker sc = new StuckChecker(resultInfo);
sc.scan(tree);
return List.from(sc.stuckVars);
}
}
public RecoveryInfo() {
attr.super(Kinds.VAL, Type.recoveryType, new Check.NestedCheckContext(chk.basicHandler) {
@Override
public DeferredAttrContext deferredAttrContext() {
return deferredAttrContext;
}
@Override
public boolean compatible(Type found, Type req, Warner warn) {
/**
* This visitor is used to check that structural expressions conform
* to their target - this step is required as inference could end up
* inferring types that make some of the nested expressions incompatible
* with their corresponding instantiated target
*/
class StuckChecker extends TreeScanner {
Type pt;
Filter<JCTree> treeFilter;
Infer.InferenceContext inferenceContext;
Set<Type> stuckVars = new HashSet<Type>();
final Filter<JCTree> argsFilter = new Filter<JCTree>() {
public boolean accepts(JCTree t) {
switch (t.getTag()) {
case CONDEXPR:
case LAMBDA:
case PARENS:
case REFERENCE:
return true;
}
@Override
public void report(DiagnosticPosition pos, JCDiagnostic details) {
//do nothing
}
});
default:
return false;
}
}
};
@Override
protected Type check(DiagnosticPosition pos, Type found) {
return chk.checkNonVoid(pos, super.check(pos, found));
final Filter<JCTree> lambdaBodyFilter = new Filter<JCTree>() {
public boolean accepts(JCTree t) {
switch (t.getTag()) {
case BLOCK: case CASE: case CATCH: case DOLOOP:
case FOREACHLOOP: case FORLOOP: case RETURN:
case SYNCHRONIZED: case SWITCH: case TRY: case WHILELOOP:
return true;
default:
return false;
}
}
};
StuckChecker(ResultInfo resultInfo) {
this.pt = resultInfo.pt;
this.inferenceContext = resultInfo.checkContext.inferenceContext();
this.treeFilter = argsFilter;
}
}
/**
* Retrieves the list of inference variables that need to be inferred before
* an AST node can be type-checked
*/
@SuppressWarnings("fallthrough")
List<Type> stuckVars(JCExpression tree, ResultInfo resultInfo) {
switch (tree.getTag()) {
case LAMBDA:
case REFERENCE:
Assert.error("not supported yet");
default:
return List.nil();
@Override
public void scan(JCTree tree) {
if (tree != null && treeFilter.accepts(tree)) {
super.scan(tree);
}
}
@Override
public void visitLambda(JCLambda tree) {
Type prevPt = pt;
Filter<JCTree> prevFilter = treeFilter;
try {
if (inferenceContext.inferenceVars().contains(pt)) {
stuckVars.add(pt);
}
if (!types.isFunctionalInterface(pt.tsym)) {
return;
}
Type descType = types.findDescriptorType(pt);
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
if (!TreeInfo.isExplicitLambda(tree) &&
freeArgVars.nonEmpty()) {
stuckVars.addAll(freeArgVars);
}
pt = descType.getReturnType();
if (tree.getBodyKind() == JCTree.JCLambda.BodyKind.EXPRESSION) {
scan(tree.getBody());
} else {
treeFilter = lambdaBodyFilter;
super.visitLambda(tree);
}
} finally {
pt = prevPt;
treeFilter = prevFilter;
}
}
@Override
public void visitReference(JCMemberReference tree) {
scan(tree.expr);
if (inferenceContext.inferenceVars().contains(pt)) {
stuckVars.add(pt);
return;
}
if (!types.isFunctionalInterface(pt.tsym)) {
return;
}
Type descType = types.findDescriptorType(pt);
List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes());
stuckVars.addAll(freeArgVars);
}
@Override
public void visitReturn(JCReturn tree) {
Filter<JCTree> prevFilter = treeFilter;
try {
treeFilter = argsFilter;
if (tree.expr != null) {
scan(tree.expr);
}
} finally {
treeFilter = prevFilter;
}
}
}
}
......@@ -50,8 +50,8 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*;
* (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
* unassignment analysis (see AssignAnalyzer) in ensures that no final variable
* is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
* determines that local variables accessed within the scope of an inner class are
* either final or effectively-final.
* determines that local variables accessed within the scope of an inner class/lambda
* are either final or effectively-final.
*
* <p>The JLS has a number of problems in the
* specification of these flow analysis problems. This implementation
......@@ -211,6 +211,29 @@ public class Flow {
new CaptureAnalyzer().analyzeTree(env, make);
}
public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
java.util.Queue<JCDiagnostic> prevDeferredDiagnostics = log.deferredDiagnostics;
Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
//we need to disable diagnostics temporarily; the problem is that if
//a lambda expression contains e.g. an unreachable statement, an error
//message will be reported and will cause compilation to skip the flow analyis
//step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
//related errors, which will allow for more errors to be detected
if (!speculative) {
log.deferAll();
log.deferredDiagnostics = ListBuffer.lb();
}
try {
new AliveAnalyzer().analyzeTree(env, that, make);
new FlowAnalyzer().analyzeTree(env, that, make);
} finally {
if (!speculative) {
log.deferredDiagFilter = prevDeferDiagsFilter;
log.deferredDiagnostics = prevDeferredDiagnostics;
}
}
}
/**
* Definite assignment scan mode
*/
......@@ -659,6 +682,27 @@ public class Flow {
}
}
@Override
public void visitLambda(JCLambda tree) {
if (tree.type != null &&
tree.type.isErroneous()) {
return;
}
ListBuffer<PendingExit> prevPending = pendingExits;
boolean prevAlive = alive;
try {
pendingExits = ListBuffer.lb();
alive = true;
scanStat(tree.body);
tree.canCompleteNormally = alive;
}
finally {
pendingExits = prevPending;
alive = prevAlive;
}
}
public void visitTopLevel(JCCompilationUnit tree) {
// Do nothing for TopLevel since each class is visited individually
}
......@@ -670,6 +714,9 @@ public class Flow {
/** Perform definite assignment/unassignment analysis on a tree.
*/
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
analyzeTree(env, env.tree, make);
}
public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
try {
attrEnv = env;
Flow.this.make = make;
......@@ -1185,6 +1232,29 @@ public class Flow {
}
}
@Override
public void visitLambda(JCLambda tree) {
if (tree.type != null &&
tree.type.isErroneous()) {
return;
}
List<Type> prevCaught = caught;
List<Type> prevThrown = thrown;
ListBuffer<FlowPendingExit> prevPending = pendingExits;
try {
pendingExits = ListBuffer.lb();
caught = List.of(syms.throwableType); //inhibit exception checking
thrown = List.nil();
scan(tree.body);
tree.inferredThrownTypes = thrown;
}
finally {
pendingExits = prevPending;
caught = prevCaught;
thrown = prevThrown;
}
}
public void visitTopLevel(JCCompilationUnit tree) {
// Do nothing for TopLevel since each class is visited individually
}
......@@ -1267,6 +1337,10 @@ public class Flow {
*/
int nextadr;
/** The first variable sequence number in a block that can return.
*/
int returnadr;
/** The list of unreferenced automatic resources.
*/
Scope unrefdResources;
......@@ -1296,8 +1370,8 @@ public class Flow {
@Override
void markDead() {
inits.inclRange(firstadr, nextadr);
uninits.inclRange(firstadr, nextadr);
inits.inclRange(returnadr, nextadr);
uninits.inclRange(returnadr, nextadr);
}
/*-------------- Processing variables ----------------------*/
......@@ -1552,6 +1626,7 @@ public class Flow {
Bits uninitsPrev = uninits.dup();
int nextadrPrev = nextadr;
int firstadrPrev = firstadr;
int returnadrPrev = returnadr;
Lint lintPrev = lint;
lint = lint.augment(tree.sym.annotations);
......@@ -1596,6 +1671,7 @@ public class Flow {
uninits = uninitsPrev;
nextadr = nextadrPrev;
firstadr = firstadrPrev;
returnadr = returnadrPrev;
lint = lintPrev;
}
}
......@@ -1980,6 +2056,35 @@ public class Flow {
scan(tree.def);
}
@Override
public void visitLambda(JCLambda tree) {
Bits prevUninits = uninits;
Bits prevInits = inits;
int returnadrPrev = returnadr;
ListBuffer<AssignPendingExit> prevPending = pendingExits;
try {
returnadr = nextadr;
pendingExits = new ListBuffer<AssignPendingExit>();
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
inits.incl(def.sym.adr);
uninits.excl(def.sym.adr);
}
if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
scanExpr(tree.body);
} else {
scan(tree.body);
}
}
finally {
returnadr = returnadrPrev;
uninits = prevUninits;
inits = prevInits;
pendingExits = prevPending;
}
}
public void visitNewArray(JCNewArray tree) {
scanExprs(tree.dims);
scanExprs(tree.elems);
......
......@@ -274,7 +274,7 @@ public class Infer {
Resolve.MethodResolutionContext resolveContext,
Warner warn) throws InferenceException {
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
final InferenceContext inferenceContext = new InferenceContext(tvars, this);
final InferenceContext inferenceContext = new InferenceContext(tvars, this, true);
inferenceException.clear();
try {
......@@ -467,6 +467,75 @@ public class Infer {
throw bk.setMessage(inferenceException, uv);
}
// <editor-fold desc="functional interface instantiation">
/**
* This method is used to infer a suitable target functional interface in case
* the original parameterized interface contains wildcards. An inference process
* is applied so that wildcard bounds, as well as explicit lambda/method ref parameters
* (where applicable) are used to constraint the solution.
*/
public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface,
List<Type> paramTypes, Check.CheckContext checkContext) {
if (types.capture(funcInterface) == funcInterface) {
//if capture doesn't change the type then return the target unchanged
//(this means the target contains no wildcards!)
return funcInterface;
} else {
Type formalInterface = funcInterface.tsym.type;
InferenceContext funcInterfaceContext =
new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false);
if (paramTypes != null) {
//get constraints from explicit params (this is done by
//checking that explicit param types are equal to the ones
//in the functional interface descriptors)
List<Type> descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes();
if (descParameterTypes.size() != paramTypes.size()) {
checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda"));
return types.createErrorType(funcInterface);
}
for (Type p : descParameterTypes) {
if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) {
checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
return types.createErrorType(funcInterface);
}
paramTypes = paramTypes.tail;
}
for (Type t : funcInterfaceContext.undetvars) {
UndetVar uv = (UndetVar)t;
minimizeInst(uv, Warner.noWarnings);
if (uv.inst == null &&
Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) {
maximizeInst(uv, Warner.noWarnings);
}
}
formalInterface = funcInterfaceContext.asInstType(formalInterface, types);
}
ListBuffer<Type> typeargs = ListBuffer.lb();
List<Type> actualTypeargs = funcInterface.getTypeArguments();
//for remaining uninferred type-vars in the functional interface type,
//simply replace the wildcards with its bound
for (Type t : formalInterface.getTypeArguments()) {
if (actualTypeargs.head.tag == WILDCARD) {
WildcardType wt = (WildcardType)actualTypeargs.head;
typeargs.append(wt.type);
} else {
typeargs.append(actualTypeargs.head);
}
actualTypeargs = actualTypeargs.tail;
}
Type owntype = types.subst(formalInterface, funcInterfaceContext.inferenceVars(), typeargs.toList());
if (!chk.checkValidGenericType(owntype)) {
//if the inferred functional interface type is not well-formed,
//or if it's not a subtype of the original target, issue an error
checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface));
return types.createErrorType(funcInterface);
}
return owntype;
}
}
// </editor-fold>
/**
* Compute a synthetic method type corresponding to the requested polymorphic
* method signature. The target return type is computed from the immediately
......@@ -536,9 +605,17 @@ public class Infer {
* Mapping that turns inference variables into undet vars
* (used by inference context)
*/
Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") {
class FromTypeVarFun extends Mapping {
boolean includeBounds;
FromTypeVarFun(boolean includeBounds) {
super("fromTypeVarFunWithBounds");
this.includeBounds = includeBounds;
}
public Type apply(Type t) {
if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types);
if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types, includeBounds);
else return t.map(this);
}
};
......@@ -573,8 +650,8 @@ public class Infer {
List<FreeTypeListener> freetypeListeners = List.nil();
public InferenceContext(List<Type> inferencevars, Infer infer) {
this.undetvars = Type.map(inferencevars, infer.fromTypeVarFun);
public InferenceContext(List<Type> inferencevars, Infer infer, boolean includeBounds) {
this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds));
this.inferencevars = inferencevars;
}
......@@ -737,5 +814,5 @@ public class Infer {
}
}
final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this);
final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), this, false);
}
......@@ -646,7 +646,9 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
tree.sym = v;
if (tree.init != null) {
v.flags_field |= HASINIT;
if ((v.flags_field & FINAL) != 0 && !tree.init.hasTag(NEWCLASS)) {
if ((v.flags_field & FINAL) != 0 &&
!tree.init.hasTag(NEWCLASS) &&
!tree.init.hasTag(LAMBDA)) {
Env<AttrContext> initEnv = getInitEnv(tree, env);
initEnv.info.enclVar = v;
v.setLazyConstValue(initEnv(tree, initEnv), attr, tree.init);
......@@ -671,7 +673,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer {
Env<AttrContext> initEnv(JCVariableDecl tree, Env<AttrContext> env) {
Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
if (tree.sym.owner.kind == TYP) {
localEnv.info.scope = new Scope.DelegatedScope(env.info.scope);
localEnv.info.scope = env.info.scope.dupUnshared();
localEnv.info.scope.owner = tree.sym;
}
if ((tree.mods.flags & STATIC) != 0 ||
......
......@@ -753,6 +753,10 @@ public class Resolve {
public boolean compatible(Type found, Type req, Warner warn) {
return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn);
}
public boolean allowBoxing() {
return false;
}
}
/**
......@@ -769,6 +773,10 @@ public class Resolve {
public boolean compatible(Type found, Type req, Warner warn) {
return types.isConvertible(found, inferenceContext.asFree(req, types), warn);
}
public boolean allowBoxing() {
return true;
}
}
/**
......@@ -1036,7 +1044,7 @@ public class Resolve {
}
return (bestSoFar.kind > AMBIGUOUS)
? sym
: mostSpecific(sym, bestSoFar, env, site,
: mostSpecific(argtypes, sym, bestSoFar, env, site,
allowBoxing && operator, useVarargs);
}
......@@ -1050,7 +1058,7 @@ public class Resolve {
* @param allowBoxing Allow boxing conversions of arguments.
* @param useVarargs Box trailing arguments into an array for varargs.
*/
Symbol mostSpecific(Symbol m1,
Symbol mostSpecific(List<Type> argtypes, Symbol m1,
Symbol m2,
Env<AttrContext> env,
final Type site,
......@@ -1059,8 +1067,10 @@ public class Resolve {
switch (m2.kind) {
case MTH:
if (m1 == m2) return m1;
boolean m1SignatureMoreSpecific = signatureMoreSpecific(env, site, m1, m2, allowBoxing, useVarargs);
boolean m2SignatureMoreSpecific = signatureMoreSpecific(env, site, m2, m1, allowBoxing, useVarargs);
boolean m1SignatureMoreSpecific =
signatureMoreSpecific(argtypes, env, site, m1, m2, allowBoxing, useVarargs);
boolean m2SignatureMoreSpecific =
signatureMoreSpecific(argtypes, env, site, m2, m1, allowBoxing, useVarargs);
if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) {
Type mt1 = types.memberType(site, m1);
Type mt2 = types.memberType(site, m2);
......@@ -1127,8 +1137,8 @@ public class Resolve {
return ambiguityError(m1, m2);
case AMBIGUOUS:
AmbiguityError e = (AmbiguityError)m2;
Symbol err1 = mostSpecific(m1, e.sym, env, site, allowBoxing, useVarargs);
Symbol err2 = mostSpecific(m1, e.sym2, env, site, allowBoxing, useVarargs);
Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs);
Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs);
if (err1 == err2) return err1;
if (err1 == e.sym && err2 == e.sym2) return m2;
if (err1 instanceof AmbiguityError &&
......@@ -1142,13 +1152,82 @@ public class Resolve {
}
}
//where
private boolean signatureMoreSpecific(Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
private boolean signatureMoreSpecific(List<Type> actuals, Env<AttrContext> env, Type site, Symbol m1, Symbol m2, boolean allowBoxing, boolean useVarargs) {
Symbol m12 = adjustVarargs(m1, m2, useVarargs);
Symbol m22 = adjustVarargs(m2, m1, useVarargs);
Type mtype1 = types.memberType(site, m12);
Type mtype2 = types.memberType(site, m22);
//check if invocation is more specific
if (invocationMoreSpecific(env, site, m22, mtype1.getParameterTypes(), allowBoxing, useVarargs)) {
return true;
}
//perform structural check
List<Type> formals1 = mtype1.getParameterTypes();
Type lastFormal1 = formals1.last();
List<Type> formals2 = mtype2.getParameterTypes();
Type lastFormal2 = formals2.last();
ListBuffer<Type> newFormals = ListBuffer.lb();
boolean hasStructuralPoly = false;
for (Type actual : actuals) {
//perform formal argument adaptation in case actuals > formals (varargs)
Type f1 = formals1.isEmpty() ?
lastFormal1 : formals1.head;
Type f2 = formals2.isEmpty() ?
lastFormal2 : formals2.head;
//is this a structural actual argument?
boolean isStructuralPoly = actual.tag == DEFERRED &&
((DeferredType)actual).tree.hasTag(LAMBDA);
Type newFormal = f1;
if (isStructuralPoly) {
//for structural arguments only - check that corresponding formals
//are related - if so replace formal with <null>
hasStructuralPoly = true;
DeferredType dt = (DeferredType)actual;
Type t1 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m1, currentResolutionContext.step).apply(dt);
Type t2 = deferredAttr.new DeferredTypeMap(AttrMode.SPECULATIVE, m2, currentResolutionContext.step).apply(dt);
if (t1.isErroneous() || t2.isErroneous() || !isStructuralSubtype(t1, t2)) {
//not structural subtypes - simply fail
return false;
} else {
newFormal = syms.botType;
}
}
newFormals.append(newFormal);
if (newFormals.length() > mtype2.getParameterTypes().length()) {
//expand m2's type so as to fit the new formal arity (varargs)
m22.type = types.createMethodTypeWithParameters(m22.type, m22.type.getParameterTypes().append(f2));
}
formals1 = formals1.isEmpty() ? formals1 : formals1.tail;
formals2 = formals2.isEmpty() ? formals2 : formals2.tail;
}
if (!hasStructuralPoly) {
//if no structural actual was found, we're done
return false;
}
//perform additional adaptation if actuals < formals (varargs)
for (Type t : formals1) {
newFormals.append(t);
}
//check if invocation (with tweaked args) is more specific
return invocationMoreSpecific(env, site, m22, newFormals.toList(), allowBoxing, useVarargs);
}
//where
private boolean invocationMoreSpecific(Env<AttrContext> env, Type site, Symbol m2, List<Type> argtypes1, boolean allowBoxing, boolean useVarargs) {
noteWarner.clear();
Type mtype1 = types.memberType(site, adjustVarargs(m1, m2, useVarargs));
Type mtype2 = instantiate(env, site, adjustVarargs(m2, m1, useVarargs), null,
types.lowerBoundArgtypes(mtype1), null,
Type mst = instantiate(env, site, m2, null,
types.lowerBounds(argtypes1), null,
allowBoxing, false, noteWarner);
return mtype2 != null &&
return mst != null &&
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
}
//where
......@@ -1187,6 +1266,32 @@ public class Resolve {
}
}
//where
boolean isStructuralSubtype(Type s, Type t) {
Type ret_s = types.findDescriptorType(s).getReturnType();
Type ret_t = types.findDescriptorType(t).getReturnType();
//covariant most specific check for function descriptor return type
if (!types.isSubtype(ret_s, ret_t)) {
return false;
}
List<Type> args_s = types.findDescriptorType(s).getParameterTypes();
List<Type> args_t = types.findDescriptorType(t).getParameterTypes();
//arity must be identical
if (args_s.length() != args_t.length()) {
return false;
}
//invariant most specific check for function descriptor parameter types
if (!types.isSameTypes(args_t, args_s)) {
return false;
}
return true;
}
//where
Type mostSpecificReturnType(Type mt1, Type mt2) {
Type rt1 = mt1.getReturnType();
Type rt2 = mt2.getReturnType();
......@@ -2388,7 +2493,19 @@ public class Resolve {
private final LocalizedString noArgs = new LocalizedString("compiler.misc.no.args");
public Object methodArguments(List<Type> argtypes) {
return argtypes == null || argtypes.isEmpty() ? noArgs : argtypes;
if (argtypes == null || argtypes.isEmpty()) {
return noArgs;
} else {
ListBuffer<Object> diagArgs = ListBuffer.lb();
for (Type t : argtypes) {
if (t.tag == DEFERRED) {
diagArgs.append(((DeferredAttr.DeferredType)t).tree);
} else {
diagArgs.append(t);
}
}
return diagArgs;
}
}
/**
......
......@@ -627,6 +627,11 @@ public class TransTypes extends TreeTranslator {
result = tree;
}
@Override
public void visitLambda(JCLambda tree) {
Assert.error("Translation of lambda expression not supported yet");
}
public void visitParens(JCParens tree) {
tree.expr = translate(tree.expr, pt);
tree.type = erasure(tree.type);
......
......@@ -1227,7 +1227,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
//if in fail-over mode, ensure that AST expression nodes
//are correctly initialized (e.g. they have a type/symbol)
attr.postAttr(env);
attr.postAttr(env.tree);
}
compileStates.put(env, CompileState.ATTR);
}
......
......@@ -950,12 +950,13 @@ public class JavacParser implements Parser {
break;
case LPAREN:
if (typeArgs == null && (mode & EXPR) != 0) {
if (peekToken(FINAL) ||
if (peekToken(MONKEYS_AT) ||
peekToken(FINAL) ||
peekToken(RPAREN) ||
peekToken(IDENTIFIER, COMMA) ||
peekToken(IDENTIFIER, RPAREN, ARROW)) {
//implicit n-ary lambda
t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos);
break;
} else {
nextToken();
......@@ -1343,11 +1344,6 @@ public class JavacParser implements Parser {
}
JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
if (token.kind != ARROW) {
//better error recovery
return F.at(pos).Erroneous(args);
}
checkLambda();
accept(ARROW);
......
......@@ -164,6 +164,54 @@ compiler.err.cant.apply.symbol.1=\
compiler.err.cant.apply.symbols=\
no suitable {0} found for {1}({2})
# 0: type
compiler.err.cant.access.arg.type.in.functional.desc=\
cannot access parameter type {0} in target functional descriptor
# 0: type
compiler.err.cant.access.return.in.functional.desc=\
cannot access return type {0} in target functional descriptor
# 0: type
compiler.err.cant.access.thrown.in.functional.desc=\
cannot access thrown type {0} in target functional descriptor
# 0: symbol kind, 1: symbol
compiler.misc.no.abstracts=\
no abstract method found in {0} {1}
# 0: symbol kind, 1: symbol
compiler.misc.incompatible.abstracts=\
multiple non-overriding abstract methods found in {0} {1}
compiler.misc.not.a.functional.intf=\
the target type must be a functional interface
# 0: message segment
compiler.misc.not.a.functional.intf.1=\
the target type must be a functional interface\n\
{0}
# 0: symbol, 1: symbol kind, 2: symbol
compiler.misc.invalid.generic.desc.in.functional.intf=\
invalid functional descriptor: method {0} in {1} {2} is generic
# 0: symbol kind, 1: symbol
compiler.misc.incompatible.descs.in.functional.intf=\
incompatible function descriptors found in {0} {1}
# 0: name, 1: list of type, 2: type, 3: list of type
compiler.misc.descriptor=\
descriptor: {2} {0}({1})
# 0: name, 1: list of type, 2: type, 3: list of type
compiler.misc.descriptor.throws=\
descriptor: {2} {0}({1}) throws {3}
# 0: type
compiler.misc.no.suitable.functional.intf.inst=\
cannot infer functional interface descriptor for {0}
# 0: symbol
compiler.err.cant.assign.val.to.final.var=\
cannot assign a value to final variable {0}
......@@ -173,6 +221,9 @@ compiler.err.cant.ref.non.effectively.final.var=\
local variables referenced from {1} must be final or effectively final
compiler.misc.lambda=\
a lambda expression
compiler.misc.inner.cls=\
an inner class
......@@ -592,6 +643,9 @@ compiler.err.missing.meth.body.or.decl.abstract=\
compiler.err.missing.ret.stmt=\
missing return statement
compiler.misc.missing.ret.val=\
missing return value
compiler.err.missing.ret.val=\
missing return value
......@@ -639,6 +693,18 @@ compiler.err.neither.conditional.subtype=\
compiler.misc.incompatible.type.in.conditional=\
bad type in conditional expression; {0}
# 0: type
compiler.misc.incompatible.ret.type.in.lambda=\
bad return type in lambda expression\n\
{0}
# 0: list of type
compiler.err.incompatible.thrown.types.in.lambda=\
incompatible thrown types {0} in lambda expression
compiler.misc.incompatible.arg.types.in.lambda=\
incompatible parameter types in lambda expression
compiler.err.new.not.allowed.in.annotation=\
''new'' not allowed in an annotation
......@@ -995,6 +1061,10 @@ compiler.misc.x.print.rounds=\
## The following string will appear before all messages keyed as:
## "compiler.note".
compiler.note.potential.lambda.found=\
This anonymous inner class creation can be turned into a lambda expression.
compiler.note.note=\
Note:\u0020
......@@ -1755,6 +1825,9 @@ compiler.err.unexpected.type=\
required: {0}\n\
found: {1}
compiler.err.unexpected.lambda=\
lambda expression not expected here
## The first argument {0} is a "kindname" (e.g. 'constructor', 'field', etc.)
## The second argument {1} is the non-resolved symbol
## The third argument {2} is a list of type parameters (non-empty if {1} is a method)
......@@ -2094,9 +2167,6 @@ compiler.note.deferred.method.inst=\
compiler.misc.type.null=\
<null>
compiler.misc.type.conditional=\
conditional expression
# X#n (where n is an int id) is disambiguated tvar name
# 0: name, 1: number
compiler.misc.type.var=\
......
......@@ -87,6 +87,11 @@ public class Pretty extends JCTree.Visitor {
*/
private final static String trimSequence = "[...]";
/**
* Max number of chars to be generated when output should fit into a single line
*/
private final static int PREFERRED_LENGTH = 20;
/** Align code to be indented to left margin.
*/
void align() throws IOException {
......@@ -135,6 +140,10 @@ public class Pretty extends JCTree.Visitor {
out.write(lineSep);
}
public static String toSimpleString(JCTree tree) {
return toSimpleString(tree, PREFERRED_LENGTH);
}
public static String toSimpleString(JCTree tree, int maxLength) {
StringWriter s = new StringWriter();
try {
......@@ -938,7 +947,16 @@ public class Pretty extends JCTree.Visitor {
public void visitLambda(JCLambda tree) {
try {
print("(");
printExprs(tree.params);
if (TreeInfo.isExplicitLambda(tree)) {
printExprs(tree.params);
} else {
String sep = "";
for (JCVariableDecl param : tree.params) {
print(sep);
print(param.name);
sep = ",";
}
}
print(")->");
printExpr(tree.body);
} catch (IOException e) {
......
......@@ -262,6 +262,10 @@ public class TreeInfo {
}
}
public static boolean isExplicitLambda(JCLambda lambda) {
return lambda.params.isEmpty() ||
lambda.params.head.vartype != null;
}
/**
* Return true if the AST corresponds to a static select of the kind A.B
*/
......@@ -400,6 +404,10 @@ public class TreeInfo {
JCVariableDecl node = (JCVariableDecl)tree;
if (node.mods.pos != Position.NOPOS) {
return node.mods.pos;
} else if (node.vartype == null) {
//if there's no type (partially typed lambda parameter)
//simply return node position
return node.pos;
} else {
return getStartPos(node.vartype);
}
......
......@@ -43,8 +43,10 @@ import com.sun.tools.javac.code.Printer;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.CapturedType;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.tree.Pretty;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
/**
......@@ -180,6 +182,9 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
}
return s;
}
else if (arg instanceof JCExpression) {
return expr2String((JCExpression)arg);
}
else if (arg instanceof Iterable<?>) {
return formatIterable(d, (Iterable<?>)arg, l);
}
......@@ -199,6 +204,19 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
return String.valueOf(arg);
}
}
//where
private String expr2String(JCExpression tree) {
switch(tree.getTag()) {
case PARENS:
return expr2String(((JCParens)tree).expr);
case LAMBDA:
case CONDEXPR:
return Pretty.toSimpleString(tree);
default:
Assert.error("unexpected tree kind " + tree.getKind());
return null;
}
}
/**
* Format an iterable argument of a given diagnostic.
......@@ -489,7 +507,7 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
* type referred by a given captured type C contains C itself) which might
* lead to infinite loops.
*/
protected Printer printer = new Printer(isRaw()) {
protected Printer printer = new Printer() {
@Override
protected String localize(Locale locale, String key, Object... args) {
......
......@@ -32,6 +32,7 @@ import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*;
import com.sun.tools.javac.api.Formattable;
import com.sun.tools.javac.file.BaseFileObject;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*;
......@@ -117,16 +118,17 @@ public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter {
@Override
protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) {
String s;
if (arg instanceof Formattable)
if (arg instanceof Formattable) {
s = arg.toString();
else if (arg instanceof BaseFileObject)
} else if (arg instanceof JCExpression) {
JCExpression tree = (JCExpression)arg;
s = "@" + tree.getStartPosition();
} else if (arg instanceof BaseFileObject) {
s = ((BaseFileObject) arg).getShortName();
else
} else {
s = super.formatArgument(diag, arg, null);
if (arg instanceof JCDiagnostic)
return "(" + s + ")";
else
return s;
}
return (arg instanceof JCDiagnostic) ? "(" + s + ")" : s;
}
@Override
......
......@@ -325,10 +325,6 @@ public class RichDiagnosticFormatter extends
*/
protected class RichPrinter extends Printer {
public RichPrinter() {
super(formatter.isRaw());
}
@Override
public String localize(Locale locale, String key, Object... args) {
return formatter.localize(locale, key, args);
......
......@@ -43,9 +43,9 @@ class Test {
boolean b = new Object() {
public boolean equals(Object other) {
String p = "p, other, super, this; super, this; List, Test2, Test; java.io.*, java.lang.*";
String q = "q, p, other, super, this; super, this; List, Test2, Test; java.io.*, java.lang.*";
String r = "r, q, p, other, super, this; super, this; List, Test2, Test; java.io.*, java.lang.*";
String p = "p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
String q = "q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
String r = "r, q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
return (this == other);
}
......
......@@ -58,7 +58,6 @@ compiler.misc.fatal.err.cant.locate.meth # Resolve, from Lower
compiler.misc.fatal.err.cant.close # JavaCompiler
compiler.misc.file.does.not.contain.package
compiler.misc.illegal.start.of.class.file
compiler.misc.cyclic.inference # Cannot happen w/o lambdas
compiler.misc.kindname.annotation
compiler.misc.kindname.enum
compiler.misc.kindname.package
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.cant.access.arg.type.in.functional.desc
// key: compiler.err.report.access
// options: -XDallowLambda
interface SAM_InaccessibleArg {
void m(Foo.Bar bar);
static class Foo { private class Bar { } }
}
class CantAccessArgTypeInFunctionalDesc {
SAM_InaccessibleArg s = x-> { };
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.cant.access.return.in.functional.desc
// options: -XDallowLambda
interface SAM_InaccessibleRet {
Foo.Bar m();
static class Foo { private class Bar { } }
}
class CantAccessReturnTypeInFunctionalDesc {
SAM_InaccessibleRet s = ()->null;
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// key: compiler.err.cant.access.thrown.in.functional.desc
// options: -XDallowLambda
interface SAM_InaccessibleThrown {
void m() throws Foo.Bar;
static class Foo { private class Bar extends Exception { } }
}
class CantAccessThrownTypesInFunctionalDesc {
SAM_InaccessibleThrown s = ()-> { };
}
......@@ -23,7 +23,8 @@
// key: compiler.err.cant.ref.non.effectively.final.var
// key: compiler.misc.inner.cls
// options: -XDallowEffectivelyFinalInInnerClasses
// key: compiler.misc.lambda
// options: -XDallowLambda -XDallowEffectivelyFinalInInnerClasses
class CantRefNonEffectivelyFinalVar {
void test() {
......@@ -31,4 +32,14 @@ class CantRefNonEffectivelyFinalVar {
new Object() { int j = i; };
i = 2;
}
interface SAM {
void m();
}
void test2() {
int i = 0;
SAM s = ()-> { int j = i; };
i++;
}
}
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2012, 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
......@@ -23,6 +23,8 @@
// key: compiler.err.catch.without.try
// key: compiler.err.expected
// key: compiler.err.not.stmt
// key: compiler.err.lambda.not.supported.in.source
class CatchWithoutTry {
void m() {
......
......@@ -22,17 +22,17 @@
*/
// key: compiler.err.cant.apply.symbol.1
// key: compiler.misc.type.conditional
// key: compiler.misc.no.args
// key: compiler.misc.arg.length.mismatch
// options: -XDallowPoly
// run: simple
// key: compiler.misc.cyclic.inference
// options: -XDallowLambda -XDallowPoly
class TypeConditional {
class CyclicInference {
interface SAM<X> {
void m(X x);
}
void m() { }
<Z> void g(SAM<Z> sz) { }
void test() {
m(true ? 1 : 2);
g(x-> {});
}
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.not.a.functional.intf.1
// key: compiler.misc.incompatible.abstracts
// options: -XDallowLambda
class IncompatibleAbstracts {
interface SAM {
void m(String s);
void m(Integer i);
}
SAM s = x-> { };
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.incompatible.arg.types.in.lambda
// options: -XDallowLambda -XDallowPoly
class IncompatibleArgTypesInLambda {
interface SAM {
void m(Integer x);
}
SAM s = (String x)-> {};
}
/*
* Copyright (c) 2012, 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.types.incompatible.diff.ret
// key: compiler.err.prob.found.req
// key: compiler.misc.incompatible.descs.in.functional.intf
// key: compiler.misc.descriptor
// key: compiler.misc.descriptor.throws
// options: -XDallowLambda
class IncompatibleDescsInFunctionalIntf {
interface A {
Integer m(String i) throws Exception;
}
interface B {
String m(String i);
}
interface SAM extends A,B { }
SAM s = x-> { };
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.inconvertible.types
// key: compiler.misc.incompatible.ret.type.in.lambda
// options: -XDallowLambda -XDallowPoly
class IncompatibleRetTypeInLambda {
interface SAM {
Integer m();
}
SAM s = ()-> "";
}
/*
* Copyright (c) 2012, 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.incompatible.thrown.types.in.lambda
// options: -XDallowLambda
class IncompatibleThrownTypesInLambda {
interface SAM {
void m();
}
SAM s = ()-> { throw new Exception(); };
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.invalid.generic.desc.in.functional.intf
// options: -XDallowLambda
class InvalidGenericDescInFunctionalIntf {
interface SAM {
<Z> void m();
}
SAM s = x-> { };
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.incompatible.ret.type.in.lambda
// key: compiler.misc.missing.ret.val
// options: -XDallowLambda
class MissingReturnValueFragment {
interface SAM {
String m();
}
void test() {
SAM s = ()->{};
}
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.not.a.functional.intf.1
// key: compiler.misc.no.abstracts
// options: -XDallowLambda
class NoAbstracts {
interface SAM { }
SAM s = x-> { };
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.no.suitable.functional.intf.inst
// options: -XDallowLambda
class NoSuitableFunctionalIntfInst {
interface SAM<X extends Number> {
void m(X x);
}
SAM<?> ss = (String s)-> { };
}
/*
* Copyright (c) 2012, 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.prob.found.req
// key: compiler.misc.not.a.functional.intf
// options: -XDallowLambda
class NotAFunctionalIntf {
abstract class SAM {
abstract <Z> void m();
}
SAM s = x-> { };
}
/*
* Copyright (c) 2012, 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.note.potential.lambda.found
// options: -XDallowLambda -XDidentifyLambdaCandidate=true
class PotentialLambdaFound {
interface SAM {
void m();
}
SAM s = new SAM() { public void m() { } };
}
/*
* Copyright (c) 2012, 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.unexpected.lambda
// options: -XDallowLambda
class UnexpectedLambda {
{ (()-> { })++; }
}
......@@ -376,7 +376,7 @@ public class CheckAttributedTree {
that.hasTag(CLASSDEF);
}
private final List<String> excludedFields = Arrays.asList("varargsElement");
private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType");
void check(boolean ok, String label, Info self) {
if (!ok) {
......
......@@ -9,13 +9,9 @@ BasicTest.java:47:84: compiler.err.expected: token.identifier
BasicTest.java:52:22: compiler.err.illegal.start.of.expr
BasicTest.java:52:31: compiler.err.expected: ';'
BasicTest.java:52:37: compiler.err.expected: token.identifier
BasicTest.java:53:21: compiler.err.illegal.start.of.expr
BasicTest.java:53:23: compiler.err.expected: ';'
BasicTest.java:53:30: compiler.err.expected: token.identifier
BasicTest.java:53:32: compiler.err.illegal.start.of.type
BasicTest.java:53:37: compiler.err.expected: token.identifier
BasicTest.java:53:38: compiler.err.expected: ';'
BasicTest.java:56:17: compiler.err.expected: token.identifier
BasicTest.java:53:32: compiler.err.lambda.not.supported.in.source: 1.8
BasicTest.java:53:31: compiler.err.expected: ->
BasicTest.java:56:23: compiler.err.expected: token.identifier
BasicTest.java:56:24: compiler.err.expected2: '(', '['
BasicTest.java:56:25: compiler.err.expected: ';'
......@@ -63,4 +59,4 @@ BasicTest.java:74:24: compiler.err.expected: ';'
BasicTest.java:74:25: compiler.err.illegal.start.of.type
BasicTest.java:74:33: compiler.err.expected: ';'
BasicTest.java:77:2: compiler.err.premature.eof
65 errors
61 errors
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册