mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 02:54:35 +02:00
7177385: Add attribution support for lambda expressions
Add support for function descriptor lookup, functional interface inference and lambda expression type-checking Reviewed-by: jjg, dlsmith
This commit is contained in:
parent
c0e2ed86c1
commit
72f39bf20c
41 changed files with 1847 additions and 189 deletions
|
@ -54,11 +54,8 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
|
||||||
|
|
||||||
List<Type> seenCaptured = List.nil();
|
List<Type> seenCaptured = List.nil();
|
||||||
static final int PRIME = 997; // largest prime less than 1000
|
static final int PRIME = 997; // largest prime less than 1000
|
||||||
boolean raw;
|
|
||||||
|
|
||||||
protected Printer(boolean raw) {
|
protected Printer() { }
|
||||||
this.raw = raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method should be overriden in order to provide proper i18n support.
|
* 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
|
* @return printer visitor instance
|
||||||
*/
|
*/
|
||||||
public static Printer createStandardPrinter(final Messages messages) {
|
public static Printer createStandardPrinter(final Messages messages) {
|
||||||
return new Printer(false) {
|
return new Printer() {
|
||||||
@Override
|
@Override
|
||||||
protected String localize(Locale locale, String key, Object... args) {
|
protected String localize(Locale locale, String key, Object... args) {
|
||||||
return messages.getLocalizedString(locale, key, 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);
|
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
|
@Override
|
||||||
public String visitUndetVar(UndetVar t, Locale locale) {
|
public String visitUndetVar(UndetVar t, Locale locale) {
|
||||||
if (t.inst != null) {
|
if (t.inst != null) {
|
||||||
|
@ -265,15 +234,11 @@ public abstract class Printer implements Type.Visitor<String, Locale>, Symbol.Vi
|
||||||
}
|
}
|
||||||
|
|
||||||
public String visitType(Type t, Locale locale) {
|
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)
|
String s = (t.tsym == null || t.tsym.name == null)
|
||||||
? localize(locale, "compiler.misc.type.none")
|
? localize(locale, "compiler.misc.type.none")
|
||||||
: t.tsym.name.toString();
|
: t.tsym.name.toString();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a class name into a (possibly localized) string. Anonymous
|
* Converts a class name into a (possibly localized) string. Anonymous
|
||||||
|
|
|
@ -1220,9 +1220,13 @@ public class Type implements PrimitiveType {
|
||||||
}
|
}
|
||||||
|
|
||||||
public UndetVar(TypeVar origin, Types types) {
|
public UndetVar(TypeVar origin, Types types) {
|
||||||
|
this(origin, types, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UndetVar(TypeVar origin, Types types, boolean includeBounds) {
|
||||||
super(UNDETVAR, origin);
|
super(UNDETVAR, origin);
|
||||||
bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class);
|
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.LOWER, List.<Type>nil());
|
||||||
bounds.put(InferenceBound.EQ, List.<Type>nil());
|
bounds.put(InferenceBound.EQ, List.<Type>nil());
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,10 @@ public class Types {
|
||||||
final boolean allowObjectToPrimitiveCast;
|
final boolean allowObjectToPrimitiveCast;
|
||||||
final ClassReader reader;
|
final ClassReader reader;
|
||||||
final Check chk;
|
final Check chk;
|
||||||
|
JCDiagnostic.Factory diags;
|
||||||
List<Warner> warnStack = List.nil();
|
List<Warner> warnStack = List.nil();
|
||||||
final Name capturedName;
|
final Name capturedName;
|
||||||
|
private final FunctionDescriptorLookupError functionDescriptorLookupError;
|
||||||
|
|
||||||
// <editor-fold defaultstate="collapsed" desc="Instantiating">
|
// <editor-fold defaultstate="collapsed" desc="Instantiating">
|
||||||
public static Types instance(Context context) {
|
public static Types instance(Context context) {
|
||||||
|
@ -102,6 +104,8 @@ public class Types {
|
||||||
chk = Check.instance(context);
|
chk = Check.instance(context);
|
||||||
capturedName = names.fromString("<captured wildcard>");
|
capturedName = names.fromString("<captured wildcard>");
|
||||||
messages = JavacMessages.instance(context);
|
messages = JavacMessages.instance(context);
|
||||||
|
diags = JCDiagnostic.Factory.instance(context);
|
||||||
|
functionDescriptorLookupError = new FunctionDescriptorLookupError();
|
||||||
}
|
}
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
|
|
||||||
|
@ -296,6 +300,294 @@ public class Types {
|
||||||
}
|
}
|
||||||
// </editor-fold>
|
// </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">
|
// <editor-fold defaultstate="collapsed" desc="isSubtype">
|
||||||
/**
|
/**
|
||||||
* Is t an unchecked subtype of s?
|
* Is t an unchecked subtype of s?
|
||||||
|
@ -1215,7 +1507,10 @@ public class Types {
|
||||||
* Returns the lower bounds of the formals of a method.
|
* Returns the lower bounds of the formals of a method.
|
||||||
*/
|
*/
|
||||||
public List<Type> lowerBoundArgtypes(Type t) {
|
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") {
|
private final Mapping lowerBoundMapping = new Mapping("lowerBound") {
|
||||||
public Type apply(Type t) {
|
public Type apply(Type t) {
|
||||||
|
@ -2007,6 +2302,15 @@ public class Types {
|
||||||
hasSameArgs(t, erasure(s)) || hasSameArgs(erasure(t), s);
|
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">
|
// <editor-fold defaultstate="collapsed" desc="Determining method implementation in given site">
|
||||||
class ImplementationCache {
|
class ImplementationCache {
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ import com.sun.tools.javac.code.Type.*;
|
||||||
import com.sun.tools.javac.comp.Check.CheckContext;
|
import com.sun.tools.javac.comp.Check.CheckContext;
|
||||||
|
|
||||||
import com.sun.source.tree.IdentifierTree;
|
import com.sun.source.tree.IdentifierTree;
|
||||||
|
import com.sun.source.tree.LambdaExpressionTree;
|
||||||
import com.sun.source.tree.MemberSelectTree;
|
import com.sun.source.tree.MemberSelectTree;
|
||||||
import com.sun.source.tree.TreeVisitor;
|
import com.sun.source.tree.TreeVisitor;
|
||||||
import com.sun.source.util.SimpleTreeVisitor;
|
import com.sun.source.util.SimpleTreeVisitor;
|
||||||
|
@ -85,6 +86,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
final Infer infer;
|
final Infer infer;
|
||||||
final DeferredAttr deferredAttr;
|
final DeferredAttr deferredAttr;
|
||||||
final Check chk;
|
final Check chk;
|
||||||
|
final Flow flow;
|
||||||
final MemberEnter memberEnter;
|
final MemberEnter memberEnter;
|
||||||
final TreeMaker make;
|
final TreeMaker make;
|
||||||
final ConstFold cfolder;
|
final ConstFold cfolder;
|
||||||
|
@ -110,6 +112,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
syms = Symtab.instance(context);
|
syms = Symtab.instance(context);
|
||||||
rs = Resolve.instance(context);
|
rs = Resolve.instance(context);
|
||||||
chk = Check.instance(context);
|
chk = Check.instance(context);
|
||||||
|
flow = Flow.instance(context);
|
||||||
memberEnter = MemberEnter.instance(context);
|
memberEnter = MemberEnter.instance(context);
|
||||||
make = TreeMaker.instance(context);
|
make = TreeMaker.instance(context);
|
||||||
enter = Enter.instance(context);
|
enter = Enter.instance(context);
|
||||||
|
@ -133,17 +136,20 @@ public class Attr extends JCTree.Visitor {
|
||||||
allowAnonOuterThis = source.allowAnonOuterThis();
|
allowAnonOuterThis = source.allowAnonOuterThis();
|
||||||
allowStringsInSwitch = source.allowStringsInSwitch();
|
allowStringsInSwitch = source.allowStringsInSwitch();
|
||||||
allowPoly = source.allowPoly() && options.isSet("allowPoly");
|
allowPoly = source.allowPoly() && options.isSet("allowPoly");
|
||||||
|
allowLambda = source.allowLambda();
|
||||||
sourceName = source.name;
|
sourceName = source.name;
|
||||||
relax = (options.isSet("-retrofit") ||
|
relax = (options.isSet("-retrofit") ||
|
||||||
options.isSet("-relax"));
|
options.isSet("-relax"));
|
||||||
findDiamonds = options.get("findDiamond") != null &&
|
findDiamonds = options.get("findDiamond") != null &&
|
||||||
source.allowDiamond();
|
source.allowDiamond();
|
||||||
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
||||||
|
identifyLambdaCandidate = options.getBoolean("identifyLambdaCandidate", false);
|
||||||
|
|
||||||
statInfo = new ResultInfo(NIL, Type.noType);
|
statInfo = new ResultInfo(NIL, Type.noType);
|
||||||
varInfo = new ResultInfo(VAR, Type.noType);
|
varInfo = new ResultInfo(VAR, Type.noType);
|
||||||
unknownExprInfo = new ResultInfo(VAL, Type.noType);
|
unknownExprInfo = new ResultInfo(VAL, Type.noType);
|
||||||
unknownTypeInfo = new ResultInfo(TYP, Type.noType);
|
unknownTypeInfo = new ResultInfo(TYP, Type.noType);
|
||||||
|
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Switch: relax some constraints for retrofit mode.
|
/** Switch: relax some constraints for retrofit mode.
|
||||||
|
@ -174,6 +180,10 @@ public class Attr extends JCTree.Visitor {
|
||||||
*/
|
*/
|
||||||
boolean allowCovariantReturns;
|
boolean allowCovariantReturns;
|
||||||
|
|
||||||
|
/** Switch: support lambda expressions ?
|
||||||
|
*/
|
||||||
|
boolean allowLambda;
|
||||||
|
|
||||||
/** Switch: allow references to surrounding object from anonymous
|
/** Switch: allow references to surrounding object from anonymous
|
||||||
* objects during constructor call?
|
* objects during constructor call?
|
||||||
*/
|
*/
|
||||||
|
@ -195,6 +205,12 @@ public class Attr extends JCTree.Visitor {
|
||||||
*/
|
*/
|
||||||
boolean useBeforeDeclarationWarning;
|
boolean useBeforeDeclarationWarning;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch: generate warnings whenever an anonymous inner class that is convertible
|
||||||
|
* to a lambda expression is found
|
||||||
|
*/
|
||||||
|
boolean identifyLambdaCandidate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch: allow strings in switch?
|
* Switch: allow strings in switch?
|
||||||
*/
|
*/
|
||||||
|
@ -286,6 +302,9 @@ public class Attr extends JCTree.Visitor {
|
||||||
case CLASSDEF:
|
case CLASSDEF:
|
||||||
//class def is always an owner
|
//class def is always an owner
|
||||||
return ((JCClassDecl)env.tree).sym;
|
return ((JCClassDecl)env.tree).sym;
|
||||||
|
case LAMBDA:
|
||||||
|
//a lambda is an owner - return a fresh synthetic method symbol
|
||||||
|
return new MethodSymbol(0, names.empty, null, syms.methodClass);
|
||||||
case BLOCK:
|
case BLOCK:
|
||||||
//static/instance init blocks are owner
|
//static/instance init blocks are owner
|
||||||
Symbol blockSym = env.info.scope.owner;
|
Symbol blockSym = env.info.scope.owner;
|
||||||
|
@ -505,10 +524,36 @@ public class Attr extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RecoveryInfo extends ResultInfo {
|
||||||
|
|
||||||
|
public RecoveryInfo(final DeferredAttr.DeferredAttrContext deferredAttrContext) {
|
||||||
|
super(Kinds.VAL, Type.recoveryType, new Check.NestedCheckContext(chk.basicHandler) {
|
||||||
|
@Override
|
||||||
|
public DeferredAttr.DeferredAttrContext deferredAttrContext() {
|
||||||
|
return deferredAttrContext;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Type check(DiagnosticPosition pos, Type found) {
|
||||||
|
return chk.checkNonVoid(pos, super.check(pos, found));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final ResultInfo statInfo;
|
final ResultInfo statInfo;
|
||||||
final ResultInfo varInfo;
|
final ResultInfo varInfo;
|
||||||
final ResultInfo unknownExprInfo;
|
final ResultInfo unknownExprInfo;
|
||||||
final ResultInfo unknownTypeInfo;
|
final ResultInfo unknownTypeInfo;
|
||||||
|
final ResultInfo recoveryInfo;
|
||||||
|
|
||||||
Type pt() {
|
Type pt() {
|
||||||
return resultInfo.pt;
|
return resultInfo.pt;
|
||||||
|
@ -987,7 +1032,9 @@ public class Attr extends JCTree.Visitor {
|
||||||
chk.checkDeprecatedAnnotation(tree.pos(), v);
|
chk.checkDeprecatedAnnotation(tree.pos(), v);
|
||||||
|
|
||||||
if (tree.init != null) {
|
if (tree.init != null) {
|
||||||
if ((v.flags_field & FINAL) != 0 && !tree.init.hasTag(NEWCLASS)) {
|
if ((v.flags_field & FINAL) != 0 &&
|
||||||
|
!tree.init.hasTag(NEWCLASS) &&
|
||||||
|
!tree.init.hasTag(LAMBDA)) {
|
||||||
// In this case, `v' is final. Ensure that it's initializer is
|
// In this case, `v' is final. Ensure that it's initializer is
|
||||||
// evaluated.
|
// evaluated.
|
||||||
v.getConstValue(); // ensure initializer is evaluated
|
v.getConstValue(); // ensure initializer is evaluated
|
||||||
|
@ -1528,6 +1575,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
case SWITCH:
|
case SWITCH:
|
||||||
if (label == null && tag == BREAK) return env1.tree;
|
if (label == null && tag == BREAK) return env1.tree;
|
||||||
break;
|
break;
|
||||||
|
case LAMBDA:
|
||||||
case METHODDEF:
|
case METHODDEF:
|
||||||
case CLASSDEF:
|
case CLASSDEF:
|
||||||
break LOOP;
|
break LOOP;
|
||||||
|
@ -1961,6 +2009,8 @@ public class Attr extends JCTree.Visitor {
|
||||||
|
|
||||||
attribStat(cdef, localEnv);
|
attribStat(cdef, localEnv);
|
||||||
|
|
||||||
|
checkLambdaCandidate(tree, cdef.sym, clazztype);
|
||||||
|
|
||||||
// If an outer instance is given,
|
// If an outer instance is given,
|
||||||
// prefix it to the constructor arguments
|
// prefix it to the constructor arguments
|
||||||
// and delete it from the new expression
|
// and delete it from the new expression
|
||||||
|
@ -2016,6 +2066,32 @@ public class Attr extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkLambdaCandidate(JCNewClass tree, ClassSymbol csym, Type clazztype) {
|
||||||
|
if (allowLambda &&
|
||||||
|
identifyLambdaCandidate &&
|
||||||
|
clazztype.tag == CLASS &&
|
||||||
|
pt().tag != NONE &&
|
||||||
|
types.isFunctionalInterface(clazztype.tsym)) {
|
||||||
|
Symbol descriptor = types.findDescriptorSymbol(clazztype.tsym);
|
||||||
|
int count = 0;
|
||||||
|
boolean found = false;
|
||||||
|
for (Symbol sym : csym.members().getElements()) {
|
||||||
|
if ((sym.flags() & SYNTHETIC) != 0 ||
|
||||||
|
sym.isConstructor()) continue;
|
||||||
|
count++;
|
||||||
|
if (sym.kind != MTH ||
|
||||||
|
!sym.name.equals(descriptor.name)) continue;
|
||||||
|
Type mtype = types.memberType(clazztype, sym);
|
||||||
|
if (types.overrideEquivalent(mtype, types.memberType(clazztype, descriptor))) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found && count == 1) {
|
||||||
|
log.note(tree.def, "potential.lambda.found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Make an attributed null check tree.
|
/** Make an attributed null check tree.
|
||||||
*/
|
*/
|
||||||
public JCExpression makeNullCheck(JCExpression arg) {
|
public JCExpression makeNullCheck(JCExpression arg) {
|
||||||
|
@ -2064,14 +2140,221 @@ public class Attr extends JCTree.Visitor {
|
||||||
result = check(tree, owntype, VAL, resultInfo);
|
result = check(tree, owntype, VAL, resultInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A lambda expression can only be attributed when a target-type is available.
|
||||||
|
* In addition, if the target-type is that of a functional interface whose
|
||||||
|
* descriptor contains inference variables in argument position the lambda expression
|
||||||
|
* is 'stuck' (see DeferredAttr).
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void visitLambda(JCLambda that) {
|
public void visitLambda(final JCLambda that) {
|
||||||
throw new UnsupportedOperationException("Lambda expression not supported yet");
|
if (pt().isErroneous() || (pt().tag == NONE && pt() != Type.recoveryType)) {
|
||||||
|
if (pt().tag == NONE) {
|
||||||
|
//lambda only allowed in assignment or method invocation/cast context
|
||||||
|
log.error(that.pos(), "unexpected.lambda");
|
||||||
|
}
|
||||||
|
result = that.type = types.createErrorType(pt());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//create an environment for attribution of the lambda expression
|
||||||
|
final Env<AttrContext> localEnv = lambdaEnv(that, env);
|
||||||
|
boolean needsRecovery = resultInfo.checkContext.deferredAttrContext() == deferredAttr.emptyDeferredAttrContext ||
|
||||||
|
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK;
|
||||||
|
try {
|
||||||
|
List<Type> explicitParamTypes = null;
|
||||||
|
if (TreeInfo.isExplicitLambda(that)) {
|
||||||
|
//attribute lambda parameters
|
||||||
|
attribStats(that.params, localEnv);
|
||||||
|
explicitParamTypes = TreeInfo.types(that.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type target = infer.instantiateFunctionalInterface(that, pt(), explicitParamTypes, resultInfo.checkContext);
|
||||||
|
Type lambdaType = (target == Type.recoveryType) ?
|
||||||
|
fallbackDescriptorType(that) :
|
||||||
|
types.findDescriptorType(target);
|
||||||
|
|
||||||
|
if (!TreeInfo.isExplicitLambda(that)) {
|
||||||
|
//add param type info in the AST
|
||||||
|
List<Type> actuals = lambdaType.getParameterTypes();
|
||||||
|
List<JCVariableDecl> params = that.params;
|
||||||
|
|
||||||
|
boolean arityMismatch = false;
|
||||||
|
|
||||||
|
while (params.nonEmpty()) {
|
||||||
|
if (actuals.isEmpty()) {
|
||||||
|
//not enough actuals to perform lambda parameter inference
|
||||||
|
arityMismatch = true;
|
||||||
|
}
|
||||||
|
//reset previously set info
|
||||||
|
Type argType = arityMismatch ?
|
||||||
|
syms.errType :
|
||||||
|
actuals.head;
|
||||||
|
params.head.vartype = make.Type(argType);
|
||||||
|
params.head.sym = null;
|
||||||
|
actuals = actuals.isEmpty() ?
|
||||||
|
actuals :
|
||||||
|
actuals.tail;
|
||||||
|
params = params.tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//attribute lambda parameters
|
||||||
|
attribStats(that.params, localEnv);
|
||||||
|
|
||||||
|
if (arityMismatch) {
|
||||||
|
resultInfo.checkContext.report(that, diags.fragment("incompatible.arg.types.in.lambda"));
|
||||||
|
result = that.type = types.createErrorType(target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//from this point on, no recovery is needed; if we are in assignment context
|
||||||
|
//we will be able to attribute the whole lambda body, regardless of errors;
|
||||||
|
//if we are in a 'check' method context, and the lambda is not compatible
|
||||||
|
//with the target-type, it will be recovered anyway in Attr.checkId
|
||||||
|
needsRecovery = false;
|
||||||
|
|
||||||
|
ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ?
|
||||||
|
recoveryInfo :
|
||||||
|
new ResultInfo(VAL, lambdaType.getReturnType(), new LambdaReturnContext(resultInfo.checkContext));
|
||||||
|
localEnv.info.returnResult = bodyResultInfo;
|
||||||
|
|
||||||
|
if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
|
||||||
|
attribTree(that.getBody(), localEnv, bodyResultInfo);
|
||||||
|
} else {
|
||||||
|
JCBlock body = (JCBlock)that.body;
|
||||||
|
attribStats(body.stats, localEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = check(that, target, VAL, resultInfo);
|
||||||
|
|
||||||
|
boolean isSpeculativeRound =
|
||||||
|
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
|
||||||
|
|
||||||
|
postAttr(that);
|
||||||
|
flow.analyzeLambda(env, that, make, isSpeculativeRound);
|
||||||
|
|
||||||
|
checkLambdaCompatible(that, lambdaType, resultInfo.checkContext, isSpeculativeRound);
|
||||||
|
|
||||||
|
if (!isSpeculativeRound) {
|
||||||
|
checkAccessibleFunctionalDescriptor(that, localEnv, resultInfo.checkContext.inferenceContext(), lambdaType);
|
||||||
|
}
|
||||||
|
result = check(that, target, VAL, resultInfo);
|
||||||
|
} catch (Types.FunctionDescriptorLookupError ex) {
|
||||||
|
JCDiagnostic cause = ex.getDiagnostic();
|
||||||
|
resultInfo.checkContext.report(that, cause);
|
||||||
|
result = that.type = types.createErrorType(pt());
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
localEnv.info.scope.leave();
|
||||||
|
if (needsRecovery) {
|
||||||
|
attribTree(that, env, recoveryInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//where
|
||||||
|
private Type fallbackDescriptorType(JCExpression tree) {
|
||||||
|
switch (tree.getTag()) {
|
||||||
|
case LAMBDA:
|
||||||
|
JCLambda lambda = (JCLambda)tree;
|
||||||
|
List<Type> argtypes = List.nil();
|
||||||
|
for (JCVariableDecl param : lambda.params) {
|
||||||
|
argtypes = param.vartype != null ?
|
||||||
|
argtypes.append(param.vartype.type) :
|
||||||
|
argtypes.append(syms.errType);
|
||||||
|
}
|
||||||
|
return new MethodType(argtypes, Type.recoveryType, List.<Type>nil(), syms.methodClass);
|
||||||
|
case REFERENCE:
|
||||||
|
return new MethodType(List.<Type>nil(), Type.recoveryType, List.<Type>nil(), syms.methodClass);
|
||||||
|
default:
|
||||||
|
Assert.error("Cannot get here!");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAccessibleFunctionalDescriptor(final DiagnosticPosition pos,
|
||||||
|
final Env<AttrContext> env, final InferenceContext inferenceContext, final Type desc) {
|
||||||
|
if (inferenceContext.free(desc)) {
|
||||||
|
inferenceContext.addFreeTypeListener(List.of(desc), new FreeTypeListener() {
|
||||||
|
@Override
|
||||||
|
public void typesInferred(InferenceContext inferenceContext) {
|
||||||
|
checkAccessibleFunctionalDescriptor(pos, env, inferenceContext, inferenceContext.asInstType(desc, types));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
chk.checkAccessibleFunctionalDescriptor(pos, env, desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lambda/method reference have a special check context that ensures
|
||||||
|
* that i.e. a lambda return type is compatible with the expected
|
||||||
|
* type according to both the inherited context and the assignment
|
||||||
|
* context.
|
||||||
|
*/
|
||||||
|
class LambdaReturnContext extends Check.NestedCheckContext {
|
||||||
|
public LambdaReturnContext(CheckContext enclosingContext) {
|
||||||
|
super(enclosingContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitReference(JCMemberReference that) {
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
throw new UnsupportedOperationException("Member references not supported yet");
|
//return type must be compatible in both current context and assignment context
|
||||||
|
return types.isAssignable(found, inferenceContext().asFree(req, types), warn) &&
|
||||||
|
super.compatible(found, req, warn);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
||||||
|
enclosingContext.report(pos, diags.fragment("incompatible.ret.type.in.lambda", details));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lambda compatibility. Check that given return types, thrown types, parameter types
|
||||||
|
* are compatible with the expected functional interface descriptor. This means that:
|
||||||
|
* (i) parameter types must be identical to those of the target descriptor; (ii) return
|
||||||
|
* types must be compatible with the return type of the expected descriptor;
|
||||||
|
* (iii) thrown types must be 'included' in the thrown types list of the expected
|
||||||
|
* descriptor.
|
||||||
|
*/
|
||||||
|
private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) {
|
||||||
|
Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types);
|
||||||
|
|
||||||
|
//return values have already been checked - but if lambda has no return
|
||||||
|
//values, we must ensure that void/value compatibility is correct;
|
||||||
|
//this amounts at checking that, if a lambda body can complete normally,
|
||||||
|
//the descriptor's return type must be void
|
||||||
|
if (tree.getBodyKind() == JCLambda.BodyKind.STATEMENT && tree.canCompleteNormally &&
|
||||||
|
returnType.tag != VOID && returnType != Type.recoveryType) {
|
||||||
|
checkContext.report(tree, diags.fragment("incompatible.ret.type.in.lambda",
|
||||||
|
diags.fragment("missing.ret.val", returnType)));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes(), types);
|
||||||
|
if (!types.isSameTypes(argTypes, TreeInfo.types(tree.params))) {
|
||||||
|
checkContext.report(tree, diags.fragment("incompatible.arg.types.in.lambda"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!speculativeAttr) {
|
||||||
|
List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes(), types);
|
||||||
|
if (chk.unhandled(tree.inferredThrownTypes == null ? List.<Type>nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) {
|
||||||
|
log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Env<AttrContext> lambdaEnv(JCLambda that, Env<AttrContext> env) {
|
||||||
|
Env<AttrContext> lambdaEnv;
|
||||||
|
Symbol owner = env.info.scope.owner;
|
||||||
|
if (owner.kind == VAR && owner.owner.kind == TYP) {
|
||||||
|
//field initializer
|
||||||
|
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dupUnshared()));
|
||||||
|
lambdaEnv.info.scope.owner =
|
||||||
|
new MethodSymbol(0, names.empty, null,
|
||||||
|
env.info.scope.owner);
|
||||||
|
} else {
|
||||||
|
lambdaEnv = env.dup(that, env.info.dup(env.info.scope.dup()));
|
||||||
|
}
|
||||||
|
return lambdaEnv;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void visitParens(JCParens tree) {
|
public void visitParens(JCParens tree) {
|
||||||
|
@ -3355,8 +3638,8 @@ public class Attr extends JCTree.Visitor {
|
||||||
* mode (e.g. by an IDE) and the AST contains semantic errors, this routine
|
* mode (e.g. by an IDE) and the AST contains semantic errors, this routine
|
||||||
* prevents NPE to be progagated during subsequent compilation steps.
|
* prevents NPE to be progagated during subsequent compilation steps.
|
||||||
*/
|
*/
|
||||||
public void postAttr(Env<AttrContext> env) {
|
public void postAttr(JCTree tree) {
|
||||||
new PostAttrAnalyzer().scan(env.tree);
|
new PostAttrAnalyzer().scan(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
class PostAttrAnalyzer extends TreeScanner {
|
class PostAttrAnalyzer extends TreeScanner {
|
||||||
|
|
|
@ -421,7 +421,7 @@ public class Check {
|
||||||
* checks - depending on the check context, meaning of 'compatibility' might
|
* checks - depending on the check context, meaning of 'compatibility' might
|
||||||
* vary significantly.
|
* vary significantly.
|
||||||
*/
|
*/
|
||||||
interface CheckContext {
|
public interface CheckContext {
|
||||||
/**
|
/**
|
||||||
* Is type 'found' compatible with type 'req' in given context
|
* Is type 'found' compatible with type 'req' in given context
|
||||||
*/
|
*/
|
||||||
|
@ -438,6 +438,8 @@ public class Check {
|
||||||
public Infer.InferenceContext inferenceContext();
|
public Infer.InferenceContext inferenceContext();
|
||||||
|
|
||||||
public DeferredAttr.DeferredAttrContext deferredAttrContext();
|
public DeferredAttr.DeferredAttrContext deferredAttrContext();
|
||||||
|
|
||||||
|
public boolean allowBoxing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -472,6 +474,10 @@ public class Check {
|
||||||
public DeferredAttrContext deferredAttrContext() {
|
public DeferredAttrContext deferredAttrContext() {
|
||||||
return enclosingContext.deferredAttrContext();
|
return enclosingContext.deferredAttrContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean allowBoxing() {
|
||||||
|
return enclosingContext.allowBoxing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -496,6 +502,10 @@ public class Check {
|
||||||
public DeferredAttrContext deferredAttrContext() {
|
public DeferredAttrContext deferredAttrContext() {
|
||||||
return deferredAttr.emptyDeferredAttrContext;
|
return deferredAttr.emptyDeferredAttrContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean allowBoxing() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Check that a given type is assignable to a given proto-type.
|
/** Check that a given type is assignable to a given proto-type.
|
||||||
|
@ -906,6 +916,65 @@ public class Check {
|
||||||
return;
|
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
|
* Check that type 't' is a valid instantiation of a generic class
|
||||||
* (see JLS 4.5)
|
* (see JLS 4.5)
|
||||||
|
|
|
@ -497,7 +497,7 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
* a default expected type (j.l.Object).
|
* a default expected type (j.l.Object).
|
||||||
*/
|
*/
|
||||||
private Type recover(DeferredType dt) {
|
private Type recover(DeferredType dt) {
|
||||||
dt.check(new RecoveryInfo());
|
dt.check(attr.new RecoveryInfo(deferredAttrContext));
|
||||||
switch (TreeInfo.skipParens(dt.tree).getTag()) {
|
switch (TreeInfo.skipParens(dt.tree).getTag()) {
|
||||||
case LAMBDA:
|
case LAMBDA:
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
|
@ -509,31 +509,6 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
return super.apply(dt);
|
return super.apply(dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecoveryInfo extends ResultInfo {
|
|
||||||
|
|
||||||
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) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void report(DiagnosticPosition pos, JCDiagnostic details) {
|
|
||||||
//do nothing
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Type check(DiagnosticPosition pos, Type found) {
|
|
||||||
return chk.checkNonVoid(pos, super.check(pos, found));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -541,13 +516,125 @@ public class DeferredAttr extends JCTree.Visitor {
|
||||||
* an AST node can be type-checked
|
* an AST node can be type-checked
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("fallthrough")
|
@SuppressWarnings("fallthrough")
|
||||||
List<Type> stuckVars(JCExpression tree, ResultInfo resultInfo) {
|
List<Type> stuckVars(JCTree tree, ResultInfo resultInfo) {
|
||||||
switch (tree.getTag()) {
|
if (resultInfo.pt.tag == NONE || resultInfo.pt.isErroneous()) {
|
||||||
case LAMBDA:
|
|
||||||
case REFERENCE:
|
|
||||||
Assert.error("not supported yet");
|
|
||||||
default:
|
|
||||||
return List.nil();
|
return List.nil();
|
||||||
|
} else {
|
||||||
|
StuckChecker sc = new StuckChecker(resultInfo);
|
||||||
|
sc.scan(tree);
|
||||||
|
return List.from(sc.stuckVars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
* (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
|
||||||
* unassignment analysis (see AssignAnalyzer) in ensures that no final variable
|
* unassignment analysis (see AssignAnalyzer) in ensures that no final variable
|
||||||
* is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
|
* 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
|
* determines that local variables accessed within the scope of an inner class/lambda
|
||||||
* either final or effectively-final.
|
* are either final or effectively-final.
|
||||||
*
|
*
|
||||||
* <p>The JLS has a number of problems in the
|
* <p>The JLS has a number of problems in the
|
||||||
* specification of these flow analysis problems. This implementation
|
* specification of these flow analysis problems. This implementation
|
||||||
|
@ -211,6 +211,29 @@ public class Flow {
|
||||||
new CaptureAnalyzer().analyzeTree(env, make);
|
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
|
* 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) {
|
public void visitTopLevel(JCCompilationUnit tree) {
|
||||||
// Do nothing for TopLevel since each class is visited individually
|
// 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.
|
/** Perform definite assignment/unassignment analysis on a tree.
|
||||||
*/
|
*/
|
||||||
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
|
||||||
|
analyzeTree(env, env.tree, make);
|
||||||
|
}
|
||||||
|
public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
|
||||||
try {
|
try {
|
||||||
attrEnv = env;
|
attrEnv = env;
|
||||||
Flow.this.make = make;
|
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) {
|
public void visitTopLevel(JCCompilationUnit tree) {
|
||||||
// Do nothing for TopLevel since each class is visited individually
|
// Do nothing for TopLevel since each class is visited individually
|
||||||
}
|
}
|
||||||
|
@ -1267,6 +1337,10 @@ public class Flow {
|
||||||
*/
|
*/
|
||||||
int nextadr;
|
int nextadr;
|
||||||
|
|
||||||
|
/** The first variable sequence number in a block that can return.
|
||||||
|
*/
|
||||||
|
int returnadr;
|
||||||
|
|
||||||
/** The list of unreferenced automatic resources.
|
/** The list of unreferenced automatic resources.
|
||||||
*/
|
*/
|
||||||
Scope unrefdResources;
|
Scope unrefdResources;
|
||||||
|
@ -1296,8 +1370,8 @@ public class Flow {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void markDead() {
|
void markDead() {
|
||||||
inits.inclRange(firstadr, nextadr);
|
inits.inclRange(returnadr, nextadr);
|
||||||
uninits.inclRange(firstadr, nextadr);
|
uninits.inclRange(returnadr, nextadr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------- Processing variables ----------------------*/
|
/*-------------- Processing variables ----------------------*/
|
||||||
|
@ -1552,6 +1626,7 @@ public class Flow {
|
||||||
Bits uninitsPrev = uninits.dup();
|
Bits uninitsPrev = uninits.dup();
|
||||||
int nextadrPrev = nextadr;
|
int nextadrPrev = nextadr;
|
||||||
int firstadrPrev = firstadr;
|
int firstadrPrev = firstadr;
|
||||||
|
int returnadrPrev = returnadr;
|
||||||
Lint lintPrev = lint;
|
Lint lintPrev = lint;
|
||||||
|
|
||||||
lint = lint.augment(tree.sym.annotations);
|
lint = lint.augment(tree.sym.annotations);
|
||||||
|
@ -1596,6 +1671,7 @@ public class Flow {
|
||||||
uninits = uninitsPrev;
|
uninits = uninitsPrev;
|
||||||
nextadr = nextadrPrev;
|
nextadr = nextadrPrev;
|
||||||
firstadr = firstadrPrev;
|
firstadr = firstadrPrev;
|
||||||
|
returnadr = returnadrPrev;
|
||||||
lint = lintPrev;
|
lint = lintPrev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1980,6 +2056,35 @@ public class Flow {
|
||||||
scan(tree.def);
|
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) {
|
public void visitNewArray(JCNewArray tree) {
|
||||||
scanExprs(tree.dims);
|
scanExprs(tree.dims);
|
||||||
scanExprs(tree.elems);
|
scanExprs(tree.elems);
|
||||||
|
|
|
@ -274,7 +274,7 @@ public class Infer {
|
||||||
Resolve.MethodResolutionContext resolveContext,
|
Resolve.MethodResolutionContext resolveContext,
|
||||||
Warner warn) throws InferenceException {
|
Warner warn) throws InferenceException {
|
||||||
//-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG
|
//-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();
|
inferenceException.clear();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -467,6 +467,75 @@ public class Infer {
|
||||||
throw bk.setMessage(inferenceException, uv);
|
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
|
* Compute a synthetic method type corresponding to the requested polymorphic
|
||||||
* method signature. The target return type is computed from the immediately
|
* 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
|
* Mapping that turns inference variables into undet vars
|
||||||
* (used by inference context)
|
* (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) {
|
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);
|
else return t.map(this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -573,8 +650,8 @@ public class Infer {
|
||||||
|
|
||||||
List<FreeTypeListener> freetypeListeners = List.nil();
|
List<FreeTypeListener> freetypeListeners = List.nil();
|
||||||
|
|
||||||
public InferenceContext(List<Type> inferencevars, Infer infer) {
|
public InferenceContext(List<Type> inferencevars, Infer infer, boolean includeBounds) {
|
||||||
this.undetvars = Type.map(inferencevars, infer.fromTypeVarFun);
|
this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds));
|
||||||
this.inferencevars = inferencevars;
|
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;
|
tree.sym = v;
|
||||||
if (tree.init != null) {
|
if (tree.init != null) {
|
||||||
v.flags_field |= HASINIT;
|
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);
|
Env<AttrContext> initEnv = getInitEnv(tree, env);
|
||||||
initEnv.info.enclVar = v;
|
initEnv.info.enclVar = v;
|
||||||
v.setLazyConstValue(initEnv(tree, initEnv), attr, tree.init);
|
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> initEnv(JCVariableDecl tree, Env<AttrContext> env) {
|
||||||
Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
|
Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
|
||||||
if (tree.sym.owner.kind == TYP) {
|
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;
|
localEnv.info.scope.owner = tree.sym;
|
||||||
}
|
}
|
||||||
if ((tree.mods.flags & STATIC) != 0 ||
|
if ((tree.mods.flags & STATIC) != 0 ||
|
||||||
|
|
|
@ -753,6 +753,10 @@ public class Resolve {
|
||||||
public boolean compatible(Type found, Type req, Warner warn) {
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), 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) {
|
public boolean compatible(Type found, Type req, Warner warn) {
|
||||||
return types.isConvertible(found, inferenceContext.asFree(req, types), 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)
|
return (bestSoFar.kind > AMBIGUOUS)
|
||||||
? sym
|
? sym
|
||||||
: mostSpecific(sym, bestSoFar, env, site,
|
: mostSpecific(argtypes, sym, bestSoFar, env, site,
|
||||||
allowBoxing && operator, useVarargs);
|
allowBoxing && operator, useVarargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1050,7 +1058,7 @@ public class Resolve {
|
||||||
* @param allowBoxing Allow boxing conversions of arguments.
|
* @param allowBoxing Allow boxing conversions of arguments.
|
||||||
* @param useVarargs Box trailing arguments into an array for varargs.
|
* @param useVarargs Box trailing arguments into an array for varargs.
|
||||||
*/
|
*/
|
||||||
Symbol mostSpecific(Symbol m1,
|
Symbol mostSpecific(List<Type> argtypes, Symbol m1,
|
||||||
Symbol m2,
|
Symbol m2,
|
||||||
Env<AttrContext> env,
|
Env<AttrContext> env,
|
||||||
final Type site,
|
final Type site,
|
||||||
|
@ -1059,8 +1067,10 @@ public class Resolve {
|
||||||
switch (m2.kind) {
|
switch (m2.kind) {
|
||||||
case MTH:
|
case MTH:
|
||||||
if (m1 == m2) return m1;
|
if (m1 == m2) return m1;
|
||||||
boolean m1SignatureMoreSpecific = signatureMoreSpecific(env, site, m1, m2, allowBoxing, useVarargs);
|
boolean m1SignatureMoreSpecific =
|
||||||
boolean m2SignatureMoreSpecific = signatureMoreSpecific(env, site, m2, m1, allowBoxing, useVarargs);
|
signatureMoreSpecific(argtypes, env, site, m1, m2, allowBoxing, useVarargs);
|
||||||
|
boolean m2SignatureMoreSpecific =
|
||||||
|
signatureMoreSpecific(argtypes, env, site, m2, m1, allowBoxing, useVarargs);
|
||||||
if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) {
|
if (m1SignatureMoreSpecific && m2SignatureMoreSpecific) {
|
||||||
Type mt1 = types.memberType(site, m1);
|
Type mt1 = types.memberType(site, m1);
|
||||||
Type mt2 = types.memberType(site, m2);
|
Type mt2 = types.memberType(site, m2);
|
||||||
|
@ -1127,8 +1137,8 @@ public class Resolve {
|
||||||
return ambiguityError(m1, m2);
|
return ambiguityError(m1, m2);
|
||||||
case AMBIGUOUS:
|
case AMBIGUOUS:
|
||||||
AmbiguityError e = (AmbiguityError)m2;
|
AmbiguityError e = (AmbiguityError)m2;
|
||||||
Symbol err1 = mostSpecific(m1, e.sym, env, site, allowBoxing, useVarargs);
|
Symbol err1 = mostSpecific(argtypes, m1, e.sym, env, site, allowBoxing, useVarargs);
|
||||||
Symbol err2 = mostSpecific(m1, e.sym2, env, site, allowBoxing, useVarargs);
|
Symbol err2 = mostSpecific(argtypes, m1, e.sym2, env, site, allowBoxing, useVarargs);
|
||||||
if (err1 == err2) return err1;
|
if (err1 == err2) return err1;
|
||||||
if (err1 == e.sym && err2 == e.sym2) return m2;
|
if (err1 == e.sym && err2 == e.sym2) return m2;
|
||||||
if (err1 instanceof AmbiguityError &&
|
if (err1 instanceof AmbiguityError &&
|
||||||
|
@ -1142,13 +1152,82 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//where
|
//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();
|
noteWarner.clear();
|
||||||
Type mtype1 = types.memberType(site, adjustVarargs(m1, m2, useVarargs));
|
Type mst = instantiate(env, site, m2, null,
|
||||||
Type mtype2 = instantiate(env, site, adjustVarargs(m2, m1, useVarargs), null,
|
types.lowerBounds(argtypes1), null,
|
||||||
types.lowerBoundArgtypes(mtype1), null,
|
|
||||||
allowBoxing, false, noteWarner);
|
allowBoxing, false, noteWarner);
|
||||||
return mtype2 != null &&
|
return mst != null &&
|
||||||
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
|
!noteWarner.hasLint(Lint.LintCategory.UNCHECKED);
|
||||||
}
|
}
|
||||||
//where
|
//where
|
||||||
|
@ -1187,6 +1266,32 @@ public class Resolve {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//where
|
//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 mostSpecificReturnType(Type mt1, Type mt2) {
|
||||||
Type rt1 = mt1.getReturnType();
|
Type rt1 = mt1.getReturnType();
|
||||||
Type rt2 = mt2.getReturnType();
|
Type rt2 = mt2.getReturnType();
|
||||||
|
@ -2388,7 +2493,19 @@ public class Resolve {
|
||||||
private final LocalizedString noArgs = new LocalizedString("compiler.misc.no.args");
|
private final LocalizedString noArgs = new LocalizedString("compiler.misc.no.args");
|
||||||
|
|
||||||
public Object methodArguments(List<Type> argtypes) {
|
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;
|
result = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitLambda(JCLambda tree) {
|
||||||
|
Assert.error("Translation of lambda expression not supported yet");
|
||||||
|
}
|
||||||
|
|
||||||
public void visitParens(JCParens tree) {
|
public void visitParens(JCParens tree) {
|
||||||
tree.expr = translate(tree.expr, pt);
|
tree.expr = translate(tree.expr, pt);
|
||||||
tree.type = erasure(tree.type);
|
tree.type = erasure(tree.type);
|
||||||
|
|
|
@ -1227,7 +1227,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter {
|
||||||
if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
|
if (errorCount() > 0 && !shouldStop(CompileState.ATTR)) {
|
||||||
//if in fail-over mode, ensure that AST expression nodes
|
//if in fail-over mode, ensure that AST expression nodes
|
||||||
//are correctly initialized (e.g. they have a type/symbol)
|
//are correctly initialized (e.g. they have a type/symbol)
|
||||||
attr.postAttr(env);
|
attr.postAttr(env.tree);
|
||||||
}
|
}
|
||||||
compileStates.put(env, CompileState.ATTR);
|
compileStates.put(env, CompileState.ATTR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -950,12 +950,13 @@ public class JavacParser implements Parser {
|
||||||
break;
|
break;
|
||||||
case LPAREN:
|
case LPAREN:
|
||||||
if (typeArgs == null && (mode & EXPR) != 0) {
|
if (typeArgs == null && (mode & EXPR) != 0) {
|
||||||
if (peekToken(FINAL) ||
|
if (peekToken(MONKEYS_AT) ||
|
||||||
|
peekToken(FINAL) ||
|
||||||
peekToken(RPAREN) ||
|
peekToken(RPAREN) ||
|
||||||
peekToken(IDENTIFIER, COMMA) ||
|
peekToken(IDENTIFIER, COMMA) ||
|
||||||
peekToken(IDENTIFIER, RPAREN, ARROW)) {
|
peekToken(IDENTIFIER, RPAREN, ARROW)) {
|
||||||
//implicit n-ary lambda
|
//implicit n-ary lambda
|
||||||
t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
|
t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
nextToken();
|
nextToken();
|
||||||
|
@ -1343,11 +1344,6 @@ public class JavacParser implements Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
|
JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
|
||||||
if (token.kind != ARROW) {
|
|
||||||
//better error recovery
|
|
||||||
return F.at(pos).Erroneous(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkLambda();
|
checkLambda();
|
||||||
accept(ARROW);
|
accept(ARROW);
|
||||||
|
|
||||||
|
|
|
@ -164,6 +164,54 @@ compiler.err.cant.apply.symbol.1=\
|
||||||
compiler.err.cant.apply.symbols=\
|
compiler.err.cant.apply.symbols=\
|
||||||
no suitable {0} found for {1}({2})
|
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
|
# 0: symbol
|
||||||
compiler.err.cant.assign.val.to.final.var=\
|
compiler.err.cant.assign.val.to.final.var=\
|
||||||
cannot assign a value to final variable {0}
|
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
|
local variables referenced from {1} must be final or effectively final
|
||||||
|
|
||||||
|
|
||||||
|
compiler.misc.lambda=\
|
||||||
|
a lambda expression
|
||||||
|
|
||||||
compiler.misc.inner.cls=\
|
compiler.misc.inner.cls=\
|
||||||
an inner class
|
an inner class
|
||||||
|
|
||||||
|
@ -592,6 +643,9 @@ compiler.err.missing.meth.body.or.decl.abstract=\
|
||||||
compiler.err.missing.ret.stmt=\
|
compiler.err.missing.ret.stmt=\
|
||||||
missing return statement
|
missing return statement
|
||||||
|
|
||||||
|
compiler.misc.missing.ret.val=\
|
||||||
|
missing return value
|
||||||
|
|
||||||
compiler.err.missing.ret.val=\
|
compiler.err.missing.ret.val=\
|
||||||
missing return value
|
missing return value
|
||||||
|
|
||||||
|
@ -639,6 +693,18 @@ compiler.err.neither.conditional.subtype=\
|
||||||
compiler.misc.incompatible.type.in.conditional=\
|
compiler.misc.incompatible.type.in.conditional=\
|
||||||
bad type in conditional expression; {0}
|
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=\
|
compiler.err.new.not.allowed.in.annotation=\
|
||||||
''new'' not allowed in an 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:
|
## The following string will appear before all messages keyed as:
|
||||||
## "compiler.note".
|
## "compiler.note".
|
||||||
|
|
||||||
|
compiler.note.potential.lambda.found=\
|
||||||
|
This anonymous inner class creation can be turned into a lambda expression.
|
||||||
|
|
||||||
compiler.note.note=\
|
compiler.note.note=\
|
||||||
Note:\u0020
|
Note:\u0020
|
||||||
|
|
||||||
|
@ -1755,6 +1825,9 @@ compiler.err.unexpected.type=\
|
||||||
required: {0}\n\
|
required: {0}\n\
|
||||||
found: {1}
|
found: {1}
|
||||||
|
|
||||||
|
compiler.err.unexpected.lambda=\
|
||||||
|
lambda expression not expected here
|
||||||
|
|
||||||
## The first argument {0} is a "kindname" (e.g. 'constructor', 'field', etc.)
|
## The first argument {0} is a "kindname" (e.g. 'constructor', 'field', etc.)
|
||||||
## The second argument {1} is the non-resolved symbol
|
## 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)
|
## 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=\
|
compiler.misc.type.null=\
|
||||||
<null>
|
<null>
|
||||||
|
|
||||||
compiler.misc.type.conditional=\
|
|
||||||
conditional expression
|
|
||||||
|
|
||||||
# X#n (where n is an int id) is disambiguated tvar name
|
# X#n (where n is an int id) is disambiguated tvar name
|
||||||
# 0: name, 1: number
|
# 0: name, 1: number
|
||||||
compiler.misc.type.var=\
|
compiler.misc.type.var=\
|
||||||
|
|
|
@ -87,6 +87,11 @@ public class Pretty extends JCTree.Visitor {
|
||||||
*/
|
*/
|
||||||
private final static String trimSequence = "[...]";
|
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.
|
/** Align code to be indented to left margin.
|
||||||
*/
|
*/
|
||||||
void align() throws IOException {
|
void align() throws IOException {
|
||||||
|
@ -135,6 +140,10 @@ public class Pretty extends JCTree.Visitor {
|
||||||
out.write(lineSep);
|
out.write(lineSep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toSimpleString(JCTree tree) {
|
||||||
|
return toSimpleString(tree, PREFERRED_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
public static String toSimpleString(JCTree tree, int maxLength) {
|
public static String toSimpleString(JCTree tree, int maxLength) {
|
||||||
StringWriter s = new StringWriter();
|
StringWriter s = new StringWriter();
|
||||||
try {
|
try {
|
||||||
|
@ -938,7 +947,16 @@ public class Pretty extends JCTree.Visitor {
|
||||||
public void visitLambda(JCLambda tree) {
|
public void visitLambda(JCLambda tree) {
|
||||||
try {
|
try {
|
||||||
print("(");
|
print("(");
|
||||||
|
if (TreeInfo.isExplicitLambda(tree)) {
|
||||||
printExprs(tree.params);
|
printExprs(tree.params);
|
||||||
|
} else {
|
||||||
|
String sep = "";
|
||||||
|
for (JCVariableDecl param : tree.params) {
|
||||||
|
print(sep);
|
||||||
|
print(param.name);
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
print(")->");
|
print(")->");
|
||||||
printExpr(tree.body);
|
printExpr(tree.body);
|
||||||
} catch (IOException e) {
|
} 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
|
* 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;
|
JCVariableDecl node = (JCVariableDecl)tree;
|
||||||
if (node.mods.pos != Position.NOPOS) {
|
if (node.mods.pos != Position.NOPOS) {
|
||||||
return node.mods.pos;
|
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 {
|
} else {
|
||||||
return getStartPos(node.vartype);
|
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.Symbol;
|
||||||
import com.sun.tools.javac.code.Type;
|
import com.sun.tools.javac.code.Type;
|
||||||
import com.sun.tools.javac.code.Type.CapturedType;
|
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.file.BaseFileObject;
|
||||||
|
import com.sun.tools.javac.tree.Pretty;
|
||||||
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
|
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,6 +182,9 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
else if (arg instanceof JCExpression) {
|
||||||
|
return expr2String((JCExpression)arg);
|
||||||
|
}
|
||||||
else if (arg instanceof Iterable<?>) {
|
else if (arg instanceof Iterable<?>) {
|
||||||
return formatIterable(d, (Iterable<?>)arg, l);
|
return formatIterable(d, (Iterable<?>)arg, l);
|
||||||
}
|
}
|
||||||
|
@ -199,6 +204,19 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
|
||||||
return String.valueOf(arg);
|
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.
|
* 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
|
* type referred by a given captured type C contains C itself) which might
|
||||||
* lead to infinite loops.
|
* lead to infinite loops.
|
||||||
*/
|
*/
|
||||||
protected Printer printer = new Printer(isRaw()) {
|
protected Printer printer = new Printer() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String localize(Locale locale, String key, Object... args) {
|
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.DiagnosticFormatter.Configuration.*;
|
||||||
import com.sun.tools.javac.api.Formattable;
|
import com.sun.tools.javac.api.Formattable;
|
||||||
import com.sun.tools.javac.file.BaseFileObject;
|
import com.sun.tools.javac.file.BaseFileObject;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.*;
|
||||||
import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
|
import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
|
||||||
|
|
||||||
import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*;
|
import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*;
|
||||||
|
@ -117,16 +118,17 @@ public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter {
|
||||||
@Override
|
@Override
|
||||||
protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) {
|
protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) {
|
||||||
String s;
|
String s;
|
||||||
if (arg instanceof Formattable)
|
if (arg instanceof Formattable) {
|
||||||
s = arg.toString();
|
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();
|
s = ((BaseFileObject) arg).getShortName();
|
||||||
else
|
} else {
|
||||||
s = super.formatArgument(diag, arg, null);
|
s = super.formatArgument(diag, arg, null);
|
||||||
if (arg instanceof JCDiagnostic)
|
}
|
||||||
return "(" + s + ")";
|
return (arg instanceof JCDiagnostic) ? "(" + s + ")" : s;
|
||||||
else
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -325,10 +325,6 @@ public class RichDiagnosticFormatter extends
|
||||||
*/
|
*/
|
||||||
protected class RichPrinter extends Printer {
|
protected class RichPrinter extends Printer {
|
||||||
|
|
||||||
public RichPrinter() {
|
|
||||||
super(formatter.isRaw());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String localize(Locale locale, String key, Object... args) {
|
public String localize(Locale locale, String key, Object... args) {
|
||||||
return formatter.localize(locale, key, args);
|
return formatter.localize(locale, key, args);
|
||||||
|
|
|
@ -43,9 +43,9 @@ class Test {
|
||||||
|
|
||||||
boolean b = new Object() {
|
boolean b = new Object() {
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
String p = "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 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 r = "r, q, p, other, super, this; -, super, this; List, Test2, Test; java.io.*, java.lang.*";
|
||||||
return (this == other);
|
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.fatal.err.cant.close # JavaCompiler
|
||||||
compiler.misc.file.does.not.contain.package
|
compiler.misc.file.does.not.contain.package
|
||||||
compiler.misc.illegal.start.of.class.file
|
compiler.misc.illegal.start.of.class.file
|
||||||
compiler.misc.cyclic.inference # Cannot happen w/o lambdas
|
|
||||||
compiler.misc.kindname.annotation
|
compiler.misc.kindname.annotation
|
||||||
compiler.misc.kindname.enum
|
compiler.misc.kindname.enum
|
||||||
compiler.misc.kindname.package
|
compiler.misc.kindname.package
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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-> { };
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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.err.cant.ref.non.effectively.final.var
|
||||||
// key: compiler.misc.inner.cls
|
// key: compiler.misc.inner.cls
|
||||||
// options: -XDallowEffectivelyFinalInInnerClasses
|
// key: compiler.misc.lambda
|
||||||
|
// options: -XDallowLambda -XDallowEffectivelyFinalInInnerClasses
|
||||||
|
|
||||||
class CantRefNonEffectivelyFinalVar {
|
class CantRefNonEffectivelyFinalVar {
|
||||||
void test() {
|
void test() {
|
||||||
|
@ -31,4 +32,14 @@ class CantRefNonEffectivelyFinalVar {
|
||||||
new Object() { int j = i; };
|
new Object() { int j = i; };
|
||||||
i = 2;
|
i = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SAM {
|
||||||
|
void m();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test2() {
|
||||||
|
int i = 0;
|
||||||
|
SAM s = ()-> { int j = i; };
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.catch.without.try
|
||||||
// key: compiler.err.expected
|
// key: compiler.err.expected
|
||||||
|
// key: compiler.err.not.stmt
|
||||||
|
// key: compiler.err.lambda.not.supported.in.source
|
||||||
|
|
||||||
class CatchWithoutTry {
|
class CatchWithoutTry {
|
||||||
void m() {
|
void m() {
|
||||||
|
|
|
@ -22,17 +22,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.err.cant.apply.symbol.1
|
// key: compiler.err.cant.apply.symbol.1
|
||||||
// key: compiler.misc.type.conditional
|
// key: compiler.misc.cyclic.inference
|
||||||
// key: compiler.misc.no.args
|
// options: -XDallowLambda -XDallowPoly
|
||||||
// key: compiler.misc.arg.length.mismatch
|
|
||||||
// options: -XDallowPoly
|
|
||||||
// run: simple
|
|
||||||
|
|
||||||
class TypeConditional {
|
class CyclicInference {
|
||||||
|
interface SAM<X> {
|
||||||
|
void m(X x);
|
||||||
|
}
|
||||||
|
|
||||||
void m() { }
|
<Z> void g(SAM<Z> sz) { }
|
||||||
|
|
||||||
void test() {
|
void test() {
|
||||||
m(true ? 1 : 2);
|
g(x-> {});
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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-> { };
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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)-> {};
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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-> { };
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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 = ()-> "";
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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(); };
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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-> { };
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 = ()->{};
|
||||||
|
}
|
||||||
|
}
|
34
langtools/test/tools/javac/diags/examples/NoAbstracts.java
Normal file
34
langtools/test/tools/javac/diags/examples/NoAbstracts.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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-> { };
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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)-> { };
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* 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-> { };
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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() { } };
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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);
|
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) {
|
void check(boolean ok, String label, Info self) {
|
||||||
if (!ok) {
|
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:22: compiler.err.illegal.start.of.expr
|
||||||
BasicTest.java:52:31: compiler.err.expected: ';'
|
BasicTest.java:52:31: compiler.err.expected: ';'
|
||||||
BasicTest.java:52:37: compiler.err.expected: token.identifier
|
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:30: compiler.err.expected: token.identifier
|
||||||
BasicTest.java:53:32: compiler.err.illegal.start.of.type
|
BasicTest.java:53:32: compiler.err.lambda.not.supported.in.source: 1.8
|
||||||
BasicTest.java:53:37: compiler.err.expected: token.identifier
|
BasicTest.java:53:31: compiler.err.expected: ->
|
||||||
BasicTest.java:53:38: compiler.err.expected: ';'
|
|
||||||
BasicTest.java:56:17: compiler.err.expected: token.identifier
|
|
||||||
BasicTest.java:56:23: compiler.err.expected: token.identifier
|
BasicTest.java:56:23: compiler.err.expected: token.identifier
|
||||||
BasicTest.java:56:24: compiler.err.expected2: '(', '['
|
BasicTest.java:56:24: compiler.err.expected2: '(', '['
|
||||||
BasicTest.java:56:25: compiler.err.expected: ';'
|
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:25: compiler.err.illegal.start.of.type
|
||||||
BasicTest.java:74:33: compiler.err.expected: ';'
|
BasicTest.java:74:33: compiler.err.expected: ';'
|
||||||
BasicTest.java:77:2: compiler.err.premature.eof
|
BasicTest.java:77:2: compiler.err.premature.eof
|
||||||
65 errors
|
61 errors
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue