OpenJDK / lambda / lambda / langtools
changeset 1445:56419f06ad92
Enhancement: Add support for more aggressive type-inference
Experimental aggressive inference support can be enabled using the flag -XDuseGraphInference.
The new inferencer (disabled by default) solves a number of outstanding problems in the legacy JDK 5/6/7 type-inferencer (which means it is also slightly backwards incompatible).
Examples:
*) Foo<Number> fn = new Foo<>(1);
*) Set<String> ss = listInt.map(x->x.toString()).into(new HashSet<>);
*) <Z> void call(SAM<Z> x, SAM<Z> y) { ... }
call(() -> Collections.emptyList(), () -> new ArrayList<String>());
Misc fixes:
*) remove unused class in com/sun/runtime
*) fix build.properties to generate right amount of stubs
*) fix regression tests failures triggered when running against lambda binary snapshot
line wrap: on
line diff
--- a/make/build.properties Mon Jul 30 13:34:28 2012 -0700 +++ b/make/build.properties Fri Aug 03 12:48:20 2012 +0100 @@ -164,8 +164,7 @@ # The API can be provided by using a suitable boot.java.home # or by setting import.jdk require.latest.jdk.files = \ - com/sun/tools/javac/nio/*.java \ - com/sun/runtime/*.java + com/sun/tools/javac/nio/*.java # The following files in the import jdk source directory are required # in order to compile the files defined in ${require.latest.jdk.files} @@ -176,21 +175,14 @@ # generator were to be improved -- e.g. by removing unnecessary imports. # import.jdk.stub.files = \ - java/io/File.java \ - java/nio/file/**.java \ - java/nio/file/attribute/**.java \ - java/nio/file/spi/**.java \ - java/nio/channels/AsynchronousChannel.java \ - java/nio/channels/AsynchronousFileChannel.java \ - java/nio/channels/CompletionHandler.java \ - java/nio/channels/SeekableByteChannel.java \ - java/lang/invoke/**.java \ - java/lang/ReflectiveOperationException.java \ - java/lang/NoSuchMethodException.java \ - java/lang/IllegalAccessException.java \ - sun/invoke/**.java \ - sun/invoke/util/**.java \ - sun/invoke/empty/**.java + java/io/File.java \ + java/nio/file/**.java \ + java/nio/file/attribute/**.java \ + java/nio/file/spi/**.java \ + java/nio/channels/AsynchronousChannel.java \ + java/nio/channels/AsynchronousFileChannel.java \ + java/nio/channels/CompletionHandler.java \ + java/nio/channels/SeekableByteChannel.java # The following value is used by the main jtreg target. # An empty value means all tests
--- a/src/share/classes/com/sun/runtime/DefenderMethod.java Mon Jul 30 13:34:28 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.sun.runtime; - -import java.lang.annotation.*; - - -/** - * - * @author Maurizio Cimadamore - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -public @interface DefenderMethod { - String className(); - String methodName(); - String methodSignature(); -}
--- a/src/share/classes/com/sun/tools/javac/code/Source.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Source.java Fri Aug 03 12:48:20 2012 +0100 @@ -212,6 +212,9 @@ public boolean allowEffectivelyFinalInInnerClasses() { return compareTo(JDK1_8) >= 0; } + public boolean allowBetterInference() { + return compareTo(JDK1_8) >= 0; + } public static SourceVersion toSourceVersion(Source source) { switch(source) { case JDK1_2:
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java Fri Aug 03 12:48:20 2012 +0100 @@ -161,7 +161,6 @@ public final Type autoCloseableType; public final Type trustMeType; public final Type lambdaMetafactory; - public final Type defenderMethodType; /** The symbol representing the length field of an array. */ @@ -497,7 +496,6 @@ trustMeType = enterClass("java.lang.SafeVarargs"); nativeHeaderType = enterClass("javax.tools.annotation.GenerateNativeHeader"); lambdaMetafactory = enterClass("java.lang.invoke.LambdaMetafactory"); - defenderMethodType = enterClass("com.sun.runtime.DefenderMethod"); synthesizeEmptyTypeIfMissing(autoCloseableType, PUBLIC | INTERFACE); synthesizeEmptyTypeIfMissing(cloneableType, PUBLIC | INTERFACE);
--- a/src/share/classes/com/sun/tools/javac/code/Type.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Type.java Fri Aug 03 12:48:20 2012 +0100 @@ -30,6 +30,11 @@ import com.sun.tools.javac.util.*; import com.sun.tools.javac.code.Symbol.*; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; + import javax.lang.model.type.*; import static com.sun.tools.javac.code.Flags.*; @@ -69,6 +74,9 @@ /** Constant type: no type at all. */ public static final JCNoType noType = new JCNoType(NONE); + + /** Constant type: proto type of all poly types. */ + public static final JCNoType anyPoly = new JCNoType(NONE); /** If this switch is turned on, the names of type variables * and anonymous classes are printed with hashcodes appended. @@ -1108,11 +1116,16 @@ public boolean isErroneous() { return qtype.isErroneous(); } } + /** + * The type of a generic method type. It consists of a method type and + * a list of method type-parameters that are used within the method + * type. + */ public static class ForAll extends DelegatedType implements ExecutableType { public List<Type> tvars; public ForAll(List<Type> tvars, Type qtype) { - super(FORALL, qtype); + super(FORALL, (MethodType)qtype); this.tvars = tvars; } @@ -1163,33 +1176,112 @@ } } - /** A class for instantiatable variables, for use during type - * inference. - */ - public static class UndetVar extends DelegatedType { - public List<Type> lobounds = List.nil(); - public List<Type> hibounds = List.nil(); - public Type inst = null; - - @Override - public <R,S> R accept(Type.Visitor<R,S> v, S s) { - return v.visitUndetVar(this, s); - } - - public UndetVar(Type origin) { - super(UNDETVAR, origin); - } - - public String toString() { - if (inst != null) return inst.toString(); - else return qtype + "?"; - } - - public Type baseType() { - if (inst != null) return inst.baseType(); - else return this; - } - } + /** A class for inference variables, for use during method/diamond type + * inference. An inference variable has upper/lower bounds and a set + * of equality constraints. Such bounds are set during subtyping, type-containment, + * type-equality checks, when the types being tested contain inference variables. + * A change listener can be attached to an inference variable, to receive notifications + * whenever the bounds of an inference variable change. + */ + public static class UndetVar extends DelegatedType { + + /** Inference variable change listener. The listener method is called + * whenever a change to the inference variable's bounds occurs + */ + public interface UndetVarListener { + /** called when some inference variable bounds (of given kinds ibs) change */ + void varChanged(UndetVar uv, Set<InferenceBound> ibs); + } + + /** + * Inference variable bound kinds + */ + public enum InferenceBound { + /** upper bounds */ + UPPER, + /** lower bounds */ + LOWER, + /** equality constraints */ + EQ; + } + + /** inference variable bounds */ + private Map<InferenceBound, List<Type>> bounds; + + /** inference variable's inferred type (set from Infer.java) */ + public Type inst = null; + + /** inference variable's change listener */ + public UndetVarListener listener = null; + + @Override + public <R,S> R accept(Type.Visitor<R,S> v, S s) { + return v.visitUndetVar(this, s); + } + + public UndetVar(TypeVar origin, boolean includeBounds, Types types) { + super(UNDETVAR, origin); + bounds = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); + bounds.put(InferenceBound.UPPER, includeBounds ? types.getBounds(origin) : List.<Type>nil()); + bounds.put(InferenceBound.LOWER, List.<Type>nil()); + bounds.put(InferenceBound.EQ, List.<Type>nil()); + } + + public String toString() { + if (inst != null) return inst.toString(); + else return qtype + "?"; + } + + public Type baseType() { + if (inst != null) return inst.baseType(); + else return this; + } + + /** get all bounds of a given kind */ + public List<Type> getBounds(InferenceBound... ibs) { + ListBuffer<Type> buf = ListBuffer.lb(); + for (InferenceBound ib : ibs) { + buf.appendList(bounds.get(ib)); + } + return buf.toList(); + } + + /** add a bound of a given kind - this might trigger listener notification */ + public void addBound(InferenceBound ib, Type bound, Types types) { + List<Type> prevBounds = bounds.get(ib); + for (Type b : prevBounds) { + if (types.isSameType(b, bound)) + return; + } + bounds.put(ib, prevBounds.prepend(bound)); + notifyChange(EnumSet.of(ib)); + } + + /** replace types in all bounds - this might trigger listener notification */ + public void substBounds(List<Type> from, List<Type> to, Types types) { + EnumSet<InferenceBound> changed = EnumSet.noneOf(InferenceBound.class); + Map<InferenceBound, List<Type>> bounds2 = new EnumMap<InferenceBound, List<Type>>(InferenceBound.class); + for (Map.Entry<InferenceBound, List<Type>> _entry : bounds.entrySet()) { + InferenceBound ib = _entry.getKey(); + List<Type> prevBounds = _entry.getValue(); + List<Type> newBounds = types.subst(prevBounds, from, to); + bounds2.put(ib, newBounds); + if (prevBounds != newBounds) { + changed.add(ib); + } + } + if (!changed.isEmpty()) { + bounds = bounds2; + notifyChange(changed); + } + } + + private void notifyChange(EnumSet<InferenceBound> ibs) { + if (listener != null) { + listener.varChanged(this, ibs); + } + } + } /** Represents VOID or NONE. */
--- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Fri Aug 03 12:48:20 2012 +0100 @@ -35,6 +35,7 @@ import com.sun.tools.javac.code.Attribute.RetentionPolicy; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Scope.CompoundScope; +import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; import com.sun.tools.javac.comp.Check; import static com.sun.tools.javac.code.Type.*; @@ -575,11 +576,6 @@ else if (t.tag == TYPEVAR) { return isSubtypeUnchecked(t.getUpperBound(), s, warn); } - else if (s.tag == UNDETVAR) { - UndetVar uv = (UndetVar)s; - if (uv.inst != null) - return isSubtypeUnchecked(t, uv.inst, warn); - } else if (!s.isRaw()) { Type t2 = asSuper(t, s.tsym); if (t2 != null && t2.isRaw()) { @@ -764,10 +760,7 @@ return false; } - if (t.inst != null) - return isSubtypeNoCapture(t.inst, s); // TODO: ", warn"? - - t.hibounds = t.hibounds.prepend(s); + t.addBound(InferenceBound.UPPER, s, Types.this); return true; } @@ -835,9 +828,7 @@ undet.qtype == s || s.tag == ERROR || s.tag == BOT) return true; - if (undet.inst != null) - return isSubtype(s, undet.inst); - undet.lobounds = undet.lobounds.prepend(s); + undet.addBound(InferenceBound.LOWER, s, this); return true; } default: @@ -982,18 +973,8 @@ if (t == s || t.qtype == s || s.tag == ERROR || s.tag == UNKNOWN) return true; - if (t.inst != null) - return visit(t.inst, s); - - t.inst = fromUnknownFun.apply(s); - for (List<Type> l = t.lobounds; l.nonEmpty(); l = l.tail) { - if (!isSubtype(l.head, t.inst)) - return false; - } - for (List<Type> l = t.hibounds; l.nonEmpty(); l = l.tail) { - if (!isSubtype(t.inst, l.head)) - return false; - } + t.addBound(InferenceBound.EQ, s, Types.this); + return true; } @@ -1004,19 +985,6 @@ }; // </editor-fold> - // <editor-fold defaultstate="collapsed" desc="fromUnknownFun"> - /** - * A mapping that turns all unknown types in this type to fresh - * unknown variables. - */ - public Mapping fromUnknownFun = new Mapping("fromUnknownFun") { - public Type apply(Type t) { - if (t.tag == UNKNOWN) return new UndetVar(t); - else return t.map(this); - } - }; - // </editor-fold> - // <editor-fold defaultstate="collapsed" desc="Contains Type"> public boolean containedBy(Type t, Type s) { switch (t.tag) { @@ -1028,24 +996,12 @@ case UNBOUND: //similar to ? extends Object case EXTENDS: { Type bound = upperBound(s); - // We should check the new upper bound against any of the - // undetvar's lower bounds. - for (Type t2 : undetvar.lobounds) { - if (!isSubtype(t2, bound)) - return false; - } - undetvar.hibounds = undetvar.hibounds.prepend(bound); + undetvar.addBound(InferenceBound.UPPER, bound, this); break; } case SUPER: { Type bound = lowerBound(s); - // We should check the new lower bound against any of the - // undetvar's lower bounds. - for (Type t2 : undetvar.hibounds) { - if (!isSubtype(bound, t2)) - return false; - } - undetvar.lobounds = undetvar.lobounds.prepend(bound); + undetvar.addBound(InferenceBound.LOWER, bound, this); break; } }
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Aug 03 12:48:20 2012 +0100 @@ -25,12 +25,12 @@ package com.sun.tools.javac.comp; -import com.sun.tools.javac.comp.Infer.InferenceContext; import java.util.*; import java.util.Set; import javax.lang.model.element.ElementKind; import javax.tools.JavaFileObject; +import com.sun.tools.javac.comp.Infer.InferenceContext.PendingCheck; import com.sun.tools.javac.code.*; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.tree.*; @@ -115,7 +115,7 @@ memberEnter = MemberEnter.instance(context); make = TreeMaker.instance(context); enter = Enter.instance(context); - infer = Infer.instance(context); + infer = InferFactory.instance(context).getInfer(); cfolder = ConstFold.instance(context); target = Target.instance(context); types = Types.instance(context); @@ -247,11 +247,11 @@ Type owntype = found; if (owntype.tag != ERROR && resultInfo.pt.tag != METHOD && resultInfo.pt.tag != FORALL) { if (inferenceContext.free(found)) { - inferenceContext.addPendingCheck(new Infer.PendingCheck() { + inferenceContext.addPendingCheck(new PendingCheck() { public void eval() { ResultInfo pendingResult = - resultInfo.dup(inferenceContext.asInstType(resultInfo.pt)); - check(tree, inferenceContext.asInstType(found), ownkind, pendingResult); + resultInfo.dup(inferenceContext.asInstType(resultInfo.pt, types)); + check(tree, inferenceContext.asInstType(found, types), ownkind, pendingResult); } }); return tree.type = resultInfo.pt; @@ -619,7 +619,7 @@ for (JCExpression arg : trees) { Type argtype = allowPoly && TreeInfo.isPoly(arg) ? new DeferredAttr.DeferredType<JCExpression>(arg, env) : - attribExpr(arg, env, Infer.anyPoly); + attribExpr(arg, env, Type.anyPoly); argtypes.append(argtype); } return argtypes.toList(); @@ -1775,7 +1775,7 @@ // Check that value of resulting type is admissible in the // current context. Also, capture the return type - result = check(tree, capture(restype), VAL, resultInfo); + result = check(tree, restype, VAL, resultInfo); if (localEnv.info.varArgs) Assert.check(result.isErroneous() || tree.varargsElement != null); @@ -1946,7 +1946,7 @@ // Resolve the called constructor under the assumption // that we are referring to a superclass instance of the // current instance (JLS ???). - else { + else if (!TreeInfo.isDiamond(tree)) { //the following code alters some of the fields in the current //AttrContext - hence, the current context must be dup'ed in //order to avoid downstream failures @@ -2054,6 +2054,7 @@ interface DiamondHelper { DiagnosticPosition pos(); List<JCExpression> argumentExpressions(); + void attribTree(Symbol constrSymbol, Type constrType); } Type attribDiamond(Env<AttrContext> env, @@ -2069,6 +2070,10 @@ public List<JCExpression> argumentExpressions() { return tree.args; } + public void attribTree(Symbol constrSymbol, Type constrType) { + tree.constructor = constrSymbol; + tree.constructorType = constrType; + } }); } @@ -2085,6 +2090,9 @@ public List<JCExpression> argumentExpressions() { return null; } + public void attribTree(Symbol constrSymbol, Type constrType) { + //do nothing; + } }); } @@ -2113,14 +2121,14 @@ //if the type of the instance creation expression is a class type //apply method resolution inference (JLS 15.12.2.7). The return type //of the resolved constructor will be a partially instantiated type - Symbol constructor = rs.resolveDiamond(tree.pos(), + Pair<Symbol, Symbol> constructorPair = rs.resolveDiamond(tree.pos(), localEnv, site, argtypes, typeargtypes); Type owntype = types.createErrorType(clazztype); - if (constructor.kind == MTH) { + if (constructorPair.fst.kind == MTH) { ResultInfo diamondResult = new ResultInfo(VAL, resultInfo.pt, new Check.NestedCheckContext(resultInfo.checkContext) { @Override public void report(DiagnosticPosition pos, JCDiagnostic details) { @@ -2128,14 +2136,18 @@ diags.fragment("cant.apply.diamond.1", diags.fragment("diamond", clazztype.tsym), details)); } }); - owntype = checkMethod(site, - constructor, + Type constructorType = checkMethod(site, + constructorPair.fst, diamondResult, localEnv, diamondHelper.argumentExpressions(), argtypes, typeargtypes, - localEnv.info.varArgs).getReturnType(); + localEnv.info.varArgs); + owntype = constructorType.getReturnType(); + if (!owntype.isErroneous()) { + diamondHelper.attribTree(constructorPair.snd, types.createMethodTypeWithReturn(constructorType, syms.voidType)); + } } return chk.checkClassType(diamondHelper.pos(), owntype, true); @@ -2297,9 +2309,9 @@ //where private void checkAccessibleSAM(final DiagnosticPosition pos, final Env<AttrContext> env, final Infer.InferenceContext inferenceContext, final Type target) { if (inferenceContext.free(target)) { - inferenceContext.addPendingCheck(new Infer.PendingCheck() { + inferenceContext.addPendingCheck(new PendingCheck() { public void eval() { - checkAccessibleSAM(pos, env, inferenceContext, inferenceContext.asInstType(target)); + checkAccessibleSAM(pos, env, inferenceContext, inferenceContext.asInstType(target, types)); } }); } else { @@ -2321,7 +2333,7 @@ @Override public boolean compatible(Type found, Type req, Warner warn) { //return type must be compatible in both current context and assignment context - return types.isAssignable(found, inferenceContext().asFree(req), warn) && + return types.isAssignable(found, inferenceContext().asFree(req, types), warn) && super.compatible(found, req, warn); } @Override @@ -2783,7 +2795,7 @@ */ void checkLambdaCompatible(JCLambda tree, Type target, CheckContext checkContext, boolean speculativeAttr) { Type descriptor = types.findDescriptor(target); - Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType()); + 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; @@ -2794,14 +2806,14 @@ checkContext.report(tree, diags.fragment("infer.incompatible.ret.types.in.lambda", diags.fragment("missing.ret.val", returnType))); } - - List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes()); + + List<Type> argTypes = checkContext.inferenceContext().asFree(descriptor.getParameterTypes(), types); if (!types.isSameTypes(argTypes, TreeInfo.types(tree.params))) { checkContext.report(tree, diags.fragment("infer.incompatible.arg.types.in.lambda")); } if (!speculativeAttr) { - List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes()); + 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); } @@ -2810,7 +2822,7 @@ void checkReferenceCompatible(JCMemberReference tree, Type target, Type refType, CheckContext checkContext, boolean speculativeAttr) { Type descriptor = types.findDescriptor(target); - Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType()); + Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType(), types); Type resType = tree.getMode() == ReferenceMode.INVOKE ? refType.getReturnType() : tree.expr.type; @@ -2834,7 +2846,7 @@ } if (!speculativeAttr) { - List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes()); + List<Type> thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes(), types); if (chk.unhandled(refType.getThrownTypes(), thrownTypes).nonEmpty()) { log.error(tree, "incompatible.thrown.types.in.lambda", refType.getThrownTypes()); } @@ -2855,7 +2867,7 @@ } // Attribute the qualifier expression, and determine its symbol (if any). - Type site = attribTree(tree.selected, env, new ResultInfo(skind, Infer.anyPoly)); + Type site = attribTree(tree.selected, env, new ResultInfo(skind, Type.anyPoly)); if ((pkind() & (PCK | TYP)) == 0) site = capture(site); // Capture field access
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Fri Aug 03 12:48:20 2012 +0100 @@ -41,6 +41,7 @@ import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.comp.Infer.InferenceContext; +import com.sun.tools.javac.comp.Infer.InferenceContext.PendingCheck; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.ANNOTATION; @@ -100,7 +101,7 @@ rs = Resolve.instance(context); syms = Symtab.instance(context); enter = Enter.instance(context); - infer = Infer.instance(context); + infer = InferFactory.instance(context).getInfer(); this.types = Types.instance(context); diags = JCDiagnostic.Factory.instance(context); Options options = Options.instance(context); @@ -519,9 +520,9 @@ Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) { final Infer.InferenceContext inferenceContext = checkContext.inferenceContext(); if (inferenceContext.free(req)) { - inferenceContext.addPendingCheck(new Infer.PendingCheck() { + inferenceContext.addPendingCheck(new PendingCheck() { public void eval() { - checkType(pos, found, inferenceContext.asInstType(req), checkContext); + checkType(pos, found, inferenceContext.asInstType(req, types), checkContext); } }); }
--- a/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Aug 03 12:48:20 2012 +0100 @@ -37,6 +37,9 @@ import javax.tools.JavaFileObject; +import java.util.HashSet; +import java.util.Set; + import static com.sun.tools.javac.code.TypeTags.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; @@ -159,17 +162,31 @@ /** array of deferred attribution modes */ AttrRound[] attrRounds = { new AttrRound(AttrMode.CHECK) { - public Type doAttr(DeferredType<?> dt, ResultInfo result) { - if (isStuck(dt, result)) { - throw new StuckDeferredAttrException(result.checkContext.inferenceContext().inferenceVars()); + public Type doAttr(final DeferredType<?> dt, ResultInfo result) { + List<Type> stuckVars = stuckVars(dt, result); + if (stuckVars.nonEmpty()) { + throw new StuckDeferredAttrException(stuckVars); + } + Type owntype = attr.attribTree(dt.tree, dt.env, result); + //the computed type might contain free variables + //which means the type should be recomputed after inference + //has completed + if (result.checkContext.inferenceContext().free(owntype)) { + final Infer.InferenceContext inferenceContext = result.checkContext.inferenceContext(); + result.checkContext.inferenceContext().addPendingCheck(new Infer.InferenceContext.PendingCheck() { + public void eval() { + dt.qtype = inferenceContext.asInstType(dt.qtype, types); + } + }); } - return dt.qtype = attr.attribTree(dt.tree, dt.env, result); + return dt.qtype = owntype; } }, new AttrRound(AttrMode.SPECULATIVE) { public Type doAttr(DeferredType<?> dt, ResultInfo result) { - if (isStuck(dt, result)) { - throw new StuckDeferredAttrException(result.checkContext.inferenceContext().inferenceVars()); + List<Type> stuckVars = stuckVars(dt, result); + if (stuckVars.nonEmpty()) { + throw new StuckDeferredAttrException(stuckVars); } JCTree newTree = new TreeCopier<Object>(make).copy(dt.tree); Env<AttrContext> speculativeEnv = dt.env.dup(newTree, dt.env.info.dup(dt.env.info.scope.dupUnshared())); @@ -238,7 +255,7 @@ * given expected context */ Type attribDeferred(DeferredType<?> dt, AttrMode mode, final ResultInfo result) { - if (dt.qtype.tag != NONE) { + if (dt.qtype.tag != NONE && !result.checkContext.inferenceContext().free(dt.qtype)) { return result.check(dt.tree, dt.qtype); } else { for (AttrRound attrRound : attrRounds) { @@ -255,10 +272,10 @@ * Check as to whether a given deferred type can be type-checked using * given expected context */ - boolean isStuck(DeferredType<?> dt, ResultInfo resultInfo) { + List<Type> stuckVars(DeferredType<?> dt, ResultInfo resultInfo) { StuckChecker sc = new StuckChecker(resultInfo); sc.scan(dt.tree); - return sc.stuck; + return List.from(sc.stuckVars); } /** @@ -272,7 +289,7 @@ Type pt; Filter<JCTree> treeFilter; Infer.InferenceContext inferenceContext; - boolean stuck = false; + Set<Type> stuckVars = new HashSet<Type>(); final Filter<JCTree> argsFilter = new Filter<JCTree>() { public boolean accepts(JCTree t) { @@ -306,13 +323,18 @@ Type prevPt = pt; Filter<JCTree> prevFilter = treeFilter; try { - if ((stuck |= inferenceContext.inferenceVars().contains(pt)) || - !types.isSam(pt.tsym)) { + if (inferenceContext.inferenceVars().contains(pt)) { + stuckVars.add(pt); + } + if (!types.isSam(pt.tsym)) { return; } Type descType = types.findDescriptor(pt); - stuck |= !TreeInfo.isExplicitLambda(tree) && - Type.containsAny(descType.getParameterTypes(), inferenceContext.inferenceVars()); + 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()); @@ -329,12 +351,16 @@ @Override public void visitReference(JCMemberReference tree) { scan(tree.expr); - if ((stuck |= inferenceContext.inferenceVars().contains(pt)) || - !types.isSam(pt.tsym)) { + if (inferenceContext.inferenceVars().contains(pt)) { + stuckVars.add(pt); + return; + } + if (!types.isSam(pt.tsym)) { return; } Type descType = types.findDescriptor(pt); - stuck |= Type.containsAny(descType.getParameterTypes(), inferenceContext.inferenceVars()); + List<Type> freeArgVars = inferenceContext.freeVarsIn(descType.getParameterTypes()); + stuckVars.addAll(freeArgVars); } @Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/comp/GraphInfer.java Fri Aug 03 12:48:20 2012 +0100 @@ -0,0 +1,882 @@ +/* + * Copyright (c) 1999, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import com.sun.tools.javac.comp.GraphInfer.InferenceSolver.AcyclicInferenceGraph; +import com.sun.tools.javac.comp.GraphInfer.InferenceSolver.AcyclicInferenceGraph.Node; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.comp.Resolve.InapplicableMethodException; +import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static com.sun.tools.javac.code.TypeTags.*; + +/** Helper class for type parameter inference, used by the attribution phase. + * + * <p><b>This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class GraphInfer extends Infer { + + Check chk; + Resolve rs; + DeferredAttr deferredAttr; + Log log; + + protected GraphInfer(Context context) { + super(context); + rs = Resolve.instance(context); + deferredAttr = DeferredAttr.instance(context); + log = Log.instance(context); + chk = Check.instance(context); + diags = JCDiagnostic.Factory.instance(context); + } + + @Override + public Type instantiateMethod(Env<AttrContext> env, + List<Type> tvars, + MethodType mt, + Symbol msym, + Attr.ResultInfo resultInfo, + List<Type> argtypes, + boolean allowBoxing, + boolean useVarargs, + Resolve.MethodResolutionContext resolveContext, + Warner warn) throws InferenceException { + //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG + final GraphInferenceContext inferenceContext = new GraphInferenceContext(tvars); + + rs.checkRawArgumentsAcceptable(env, resolveContext.attrMode(), inferenceContext, argtypes, mt.getParameterTypes(), + allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext)); + + if (resultInfo != null && + !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { + Type to = resultInfo.pt.tag == NONE ? mt.getReturnType() : resultInfo.pt; + Type qtype1 = inferenceContext.asFree(mt.getReturnType(), types); + if (!types.isSubtypeNoCapture(qtype1, + qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to) && + !types.isSubtypeNoCapture(mt.getReturnType(), resultInfo.checkContext.inferenceContext().asFree(to, types))) { + throw inferenceException + .setMessage("infer.no.conforming.instance.exists", + inferenceContext.restvars(), mt.getReturnType(), to); + } + + if (resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { + //propagate inference context outwards and exit + inferenceContext.dupTo(resultInfo.checkContext.inferenceContext()); + return mt; + } + } + + // minimize as yet undetermined type variables + inferenceContext.solve(); + + mt = (MethodType)inferenceContext.asInstType(mt, types); + + inferenceContext.finish(); + + if (resultInfo != null && rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { + log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt); + } + + // return instantiated version of method type + return mt; + } + + private void instantiateAsUninferredVars(List<Type> vars, InferenceContext inferenceContext) { + ListBuffer<Type> todo = ListBuffer.lb(); + //step 1 - create fresh tvars + for (Type t : vars) { + UndetVar uv = (UndetVar)inferenceContext.asFree(t, types); + List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER); + if (Type.containsAny(upperBounds, vars)) { + TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); + fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null); + todo.append(uv); + uv.inst = fresh_tvar.type; + } else if (upperBounds.nonEmpty()) { + uv.inst = types.glb(upperBounds); + } else { + uv.inst = syms.objectType; + } + } + //step 2 - replace fresh tvars in their bounds + List<Type> formals = vars; + for (Type t : todo) { + UndetVar uv = (UndetVar)t; + TypeVar ct = (TypeVar)uv.inst; + ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types)); + if (ct.bound.isErroneous()) { + //report inference error if glb fails + reportBoundError(uv, BoundErrorKind.BAD_UPPER); + } + formals = formals.tail; + } + } + + /** + * Check bounds and perform incorporation + */ + void checkWithinBounds(InferenceContext inferenceContext, Warner warn) throws InferenceException { + super.checkWithinBounds(inferenceContext, warn, incorporationSteps); + } + //where + IncorporationStep[] incorporationSteps = { + //cross pollination of bounds --- if an undet-variable contains i.e. bounds + //of the kind alpha <: List<gamma> && alpha :> ArrayList<beta>, we + //do ArrayList<gamma> <: List<beta> and derive gamma == beta. + new IncorporationStep() { + public void apply(UndetVar uv, InferenceContext inferenceContext) { + for (Type b1 : uv.getBounds(InferenceBound.UPPER)) { + for (Type b2 : uv.getBounds(InferenceBound.LOWER)) { + if (!inferenceContext.inferenceVars().contains(b1) && + !inferenceContext.inferenceVars().contains(b2) && + types.asSuper(b2, b1.tsym) != null) { + types.isSubtypeUnchecked(inferenceContext.asFree(b2, types), inferenceContext.asFree(b1, types)); + } + } + } + } + }, + new IncorporationStep() { + public void apply(UndetVar uv, InferenceContext inferenceContext) { + for (Type b1 : uv.getBounds(InferenceBound.UPPER)) { + for (Type b2 : uv.getBounds(InferenceBound.EQ)) { + if (!inferenceContext.inferenceVars().contains(b1) && + !inferenceContext.inferenceVars().contains(b2) && + types.asSuper(b2, b1.tsym) != null) { + types.isSubtypeUnchecked(inferenceContext.asFree(b2, types), inferenceContext.asFree(b1, types)); + } + } + } + } + }, + new IncorporationStep() { + public void apply(UndetVar uv, InferenceContext inferenceContext) { + for (Type b1 : uv.getBounds(InferenceBound.EQ)) { + for (Type b2 : uv.getBounds(InferenceBound.LOWER)) { + if (!inferenceContext.inferenceVars().contains(b1) && + !inferenceContext.inferenceVars().contains(b2) && + types.asSuper(b2, b1.tsym) != null) { + types.isSubtypeUnchecked(inferenceContext.asFree(b2, types), inferenceContext.asFree(b1, types)); + } + } + } + } + }, + //cross pollination of bounds --- propagate upper/lower bounds + //in constraints of the kind alpha <: beta, alpha :> beta, alpha == beta + new IncorporationStep() { + public void apply(UndetVar uv, InferenceContext inferenceContext) { + for (Type b : uv.getBounds(InferenceBound.UPPER)) { + if (inferenceContext.inferenceVars().contains(b)) { + UndetVar uv2 = (UndetVar)inferenceContext.asFree(b, types); + //alpha <: beta + //1. copy alpha's lower to beta's + for (Type l : uv.getBounds(InferenceBound.LOWER)) { + uv2.addBound(InferenceBound.LOWER, l, types); + } + //2. copy beta's upper to alpha's + for (Type u : uv2.getBounds(InferenceBound.UPPER)) { + uv.addBound(InferenceBound.UPPER, u, types); + } + } + } + } + }, + new IncorporationStep() { + public void apply(UndetVar uv, InferenceContext inferenceContext) { + for (Type b : uv.getBounds(InferenceBound.LOWER)) { + if (inferenceContext.inferenceVars().contains(b)) { + UndetVar uv2 = (UndetVar)inferenceContext.asFree(b, types); + //alpha :> beta + //1. copy alpha's upper to beta's + for (Type u : uv.getBounds(InferenceBound.UPPER)) { + uv2.addBound(InferenceBound.UPPER, u, types); + } + //2. copy beta's lower to alpha's + for (Type l : uv2.getBounds(InferenceBound.LOWER)) { + uv.addBound(InferenceBound.UPPER, l, types); + } + } + } + } + }, + new IncorporationStep() { + public void apply(UndetVar uv, InferenceContext inferenceContext) { + for (Type b : uv.getBounds(InferenceBound.EQ)) { + if (inferenceContext.inferenceVars().contains(b)) { + UndetVar uv2 = (UndetVar)inferenceContext.asFree(b, types); + //alpha == beta + //1. copy all alpha's bounds to beta's + for (InferenceBound ib : InferenceBound.values()) { + for (Type b2 : uv.getBounds(ib)) { + uv2.addBound(ib, b2, types); + } + } + //2. copy all beta's bounds to alpha's + for (InferenceBound ib : InferenceBound.values()) { + for (Type b2 : uv2.getBounds(ib)) { + uv.addBound(ib, b2, types); + } + } + } + } + } + } + }; + + // <editor-fold desc="SAM type instantiation"> + @Override + public Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext) { + if (types.capture(samType) == samType) { + //if capture doesn't change the type then return the target unchanged + //(this means the target contains no wilddcards!) + return samType; + } else { + List<Type> tvars = types.newInstances(samType.tsym.type.getTypeArguments()); + Type formalSam = types.subst(samType.tsym.type, samType.tsym.type.getTypeArguments(), tvars); + GraphInferenceContext samInferenceContext = new GraphInferenceContext(tvars); + if (paramTypes != null) { + //get constraints from explicit params (this is done by + //checking that explicit param types are equal to the ones + //in the SAM descriptors) + List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes(); + if (descParameterTypes.size() != paramTypes.size()) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + for (Type p : descParameterTypes) { + if (!types.isSameType(samInferenceContext.asFree(p, types), paramTypes.head)) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + paramTypes = paramTypes.tail; + } + } + //propagate constraints on wildcards + if (!types.isSubtypeUnchecked(samInferenceContext.asFree(formalSam, types), samType)) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + + if (!checkContext.inferenceContext().free(samType)) { + //since there are no inference variable in the target type + //we can immediately solve the inference context + try { + samInferenceContext.solve(); + return samInferenceContext.asInstType(formalSam, types); + } catch (InferenceException ex) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + } else { + //if the target type depends on one or more inference variables + //we need to propagate the wildcards inference context onto + //the enclosing inference context [only if lambda has implicit parameters] + if (paramTypes == null) { + try { + //we need to fix synthetic inference variables in argument position + samInferenceContext.solve(samInferenceContext.freeVarsIn(types.findDescriptor(formalSam).getParameterTypes())); + } catch (InferenceException ex) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + } + if (samInferenceContext.restvars().nonEmpty()) { + samInferenceContext.dupTo(checkContext.inferenceContext()); + } + return samInferenceContext.asInstType(formalSam, types); + } + } + } + // </editor-fold> + + /** + * Inference strategy - act as an input to the inference solver; a strategy is + * composed of two ingredients: (i) find a node to solve in the inference graph, + * and (ii) tell th engine when we are done fixing inference variables + */ + interface SolverStrategy { + /** + * Pick the next node (leaf) to solve in th graph + */ + Node pickNode(AcyclicInferenceGraph g); + /** + * Is this the last step? + */ + boolean done(); + } + + /** + * Simple solver strategy class that locates all leaves inside a graph + * and picks the first leaf as the next node to solve + */ + abstract class LeafSolver implements SolverStrategy { + + protected ArrayList<Node> leaves(AcyclicInferenceGraph g) { + //pick the first node with no outgoing edges (= no dependencies) + ArrayList<Node> leaves = new ArrayList<Node>(); + for (Node n : g.nodes) { + if (!g.graph_deps.containsKey(n)) { + leaves.add(n); + } + } + return leaves; + } + + public Node pickNode(AcyclicInferenceGraph g) { + ArrayList<Node> leaves = leaves(g); + Assert.check(!leaves.isEmpty(), "no nodes to solve!"); + return leaves.get(0); + } + } + + /** + * This solver uses an heuristic to pick the best leaf - the heuristic + * tries to select the node that has maximal probability to contain one + * or more inference variables in a given list + */ + abstract class BestLeafSolver extends LeafSolver { + + List<Type> varsToSolve; + + BestLeafSolver(List<Type> varsToSolve) { + this.varsToSolve = varsToSolve; + } + + public Node pickNode(final AcyclicInferenceGraph g) { + //pick the first node with no outgoing edges (= no dependencies) + ArrayList<Node> leaves = super.leaves(g); + Assert.check(!leaves.isEmpty(), "no nodes to solve!"); + Comparator<Node> cnode = new Comparator<Node>() { + int varsCount(Node n) { + int count = 0; + for (Type t : n.node_vars) { + if (t.containsAny(varsToSolve)) { + //does this node contain any stuck vars? + count++; + } + for (Node n2 : g.nodes) { + if (n2.edgeTo(n)) { + //does any dependant node contains any stuck vars? + count += varsCount(n2); + } + } + } + return count; + } + + public int compare(Node o1, Node o2) { + return varsCount(o2) - varsCount(o1); + } + }; + Collections.sort(leaves, cnode); + return leaves.get(0); + } + } + + /** + * Stateful inference context - state of the context can be saved/restore + * (this feature is used by the JDK 8 inference engine); on-demand inference + * variable solving is addressed by instantiating at least one variable using + * an heuristic to find the best path in the inference graph + */ + class GraphInferenceContext extends Infer.InferenceContext { + + /** backed up inference variables */ + List<Type> saved_undet; + + GraphInferenceContext(List<Type> inferenceVars) { + super(inferenceVars, types); + } + + /** + * Save the state of this inference context + */ + void save() { + ListBuffer<Type> buf = ListBuffer.lb(); + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + UndetVar uv2 = new UndetVar((TypeVar)uv.qtype, true, types); + for (InferenceBound ib : InferenceBound.values()) { + for (Type b : uv.getBounds(ib)) { + uv2.addBound(ib, b, types); + } + } + uv2.inst = uv.inst; + buf.add(uv2); + } + saved_undet = buf.toList(); + } + + /** + * Restore the state of this inference context to the previous known checkpoint + */ + void rollback() { + Assert.check(saved_undet != null && saved_undet.length() == undetvars.length()); + undetvars = saved_undet; + saved_undet = null; + } + + /** + * Copy variable in this inference context to the given context + */ + void dupTo(InferenceContext that) { + that.undetvars = that.undetvars.appendList(undetvars); + that.pendingChecks = that.pendingChecks.appendList(pendingChecks); + } + + private void solve(SolverStrategy ss) { + InferenceSolver s = new InferenceSolver(this); + s.solve(ss); + } + + /** + * solve all variables in this context + */ + public void solve() { + solve(new LeafSolver() { + public boolean done() { + return restvars().isEmpty(); + } + }); + } + + /** + * solve all variables in the given list + */ + public void solve(final List<Type> vars) { + solve(new BestLeafSolver(vars) { + public boolean done() { + return !free(asInstTypes(vars, types)); + } + }); + } + + @Override + public void solveAny(final List<Type> stuckvars) { + solve(new BestLeafSolver(stuckvars) { + public boolean done() { + return asInstTypes(stuckvars, types) != stuckvars; + } + }); + } + } + + /** + * This is the inference solver - the solver organizes all inference variables in + * a given inference context by bound dependencies - in the general case, such dependencies + * would lead to a cyclic directed graph; the dependency info is used to build + * an acyclic graph, where all cyclic variables are bundled together. An inference + * step corresponds to solving a node in the acyclic graph - this is done by + * relying on a given strategy (see SolverStrategy). + */ + class InferenceSolver { + /** + * There are two kind of inference strategies: (i) lower bounds can be used to + * infer a type using lub, alternatively (ii) upper bounds can be used to + * infer a type using glb. + */ + abstract class InferenceStep implements Filter<UndetVar> { + + InferenceBound ib; + + public InferenceStep(InferenceBound ib) { + this.ib = ib; + } + + abstract Type solve(UndetVar uv); + + boolean exact(UndetVar uv) { + return uv.getBounds(ib).length() == filterBounds(uv).length(); + } + + public boolean accepts(UndetVar t) { + return filterBounds(t).nonEmpty(); + } + + List<Type> filterBounds(UndetVar uv) { + return Type.filter(uv.getBounds(ib), new Filter<Type>() { + public boolean accepts(Type t) { + return !t.containsAny(inferenceContext.inferenceVars()); + } + }); + } + } + + /** eq bound inference */ + InferenceStep eq = new InferenceStep(InferenceBound.EQ) { + @Override + Type solve(UndetVar uv) { + return filterBounds(uv).head; + } + }; + + /** lower bound inference */ + InferenceStep lower = new InferenceStep(InferenceBound.LOWER) { + @Override + Type solve(UndetVar uv) { + List<Type> lobounds = filterBounds(uv); + Type owntype = types.lub(lobounds); + if (owntype.tag == ERROR) { + throw inferenceException + .setMessage("no.unique.minimal.instance.exists", + uv.qtype, lobounds); + } else { + return owntype; + } + } + }; + + /** upper bound inference */ + InferenceStep upper = new InferenceStep(InferenceBound.UPPER) { + @Override + Type solve(UndetVar uv) { + List<Type> hibounds = filterBounds(uv); + Type owntype = types.glb(hibounds); + if (owntype.isErroneous()) { + throw inferenceException + .setMessage("no.unique.maximal.instance.exists", + uv.qtype, hibounds); + } else { + return owntype; + } + } + }; + + /** inference steps - steps are ordered by priority; first, only eq bounds + * are considered; then eq and lower bound (corresponding roughly to old 15.12.2.7) + * then all bounds are considered. + */ + InferenceStep[][] phases = { { eq }, { eq, lower }, { eq, lower, upper } }; + + Map<Type, List<Type>> deps; + GraphInferenceContext inferenceContext; + + InferenceSolver(GraphInferenceContext inferenceContext) { + this.inferenceContext = inferenceContext; + computeDependencies(); + } + + private void computeDependencies() { + deps = new HashMap<Type, List<Type>>(); + for (Type i : inferenceContext.restvars()) { + for (Type j : inferenceContext.restvars()) { + UndetVar uv_i = (UndetVar)inferenceContext.asFree(i, types); + if (Type.containsAny(uv_i.getBounds(InferenceBound.values()), List.of(j))) { + //update i's deps + List<Type> depVars_i = deps.get(i); + if (depVars_i == null) { + depVars_i = List.nil(); + } + depVars_i = depVars_i.prepend(j); + deps.put(i, depVars_i); + //update j's deps - only if i's bounds contain _exactly_ j + if (uv_i.getBounds(InferenceBound.values()).contains(j)) { + List<Type> depVars_j = deps.get(j); + if (depVars_j == null) { + depVars_j = List.nil(); + } + depVars_j = depVars_j.prepend(i); + deps.put(j, depVars_j); + } + } + } + } + } + + /** + * Solve variables in a given inference context. The amount of variables + * to be solved, and the way in which the underlying acyclic graph is explored + * depends on the selected solver strategy. + */ + void solve(SolverStrategy sstrategy) { + checkWithinBounds(inferenceContext, Warner.noWarnings); //initial propagation of bounds + while (!sstrategy.done()) { + List<Type> varsToSolve = sstrategy.pickNode(new AcyclicInferenceGraph()).node_vars; + inferenceContext.save(); + boolean exact = true; + //repeat until all variables are solved + while (Type.containsAny(inferenceContext.restvars(), varsToSolve)) { + boolean stuck = true; + //for each inference phase + for (InferenceStep[] phase : phases) { + //for each variable... + for (Type i : varsToSolve) { + //skip instantiated vars + UndetVar uv_i = (UndetVar)inferenceContext.asFree(i, types); + if (uv_i.inst != null) continue; + //try to instantiate using one of the steps allowed in this phase + for (InferenceStep step : phase) { + if (step.accepts(uv_i)) { + uv_i.inst = step.solve(uv_i); + exact = exact && step.exact(uv_i); + stuck = false; + } + } + } + if (!stuck) { + try { + checkWithinBounds(inferenceContext, Warner.noWarnings); + } catch (InferenceException ex) { + if (exact) { + throw ex; + } else { + inferenceContext.rollback(); + instantiateAsUninferredVars(varsToSolve, inferenceContext); + checkWithinBounds(inferenceContext, Warner.noWarnings); + } + } + break; + } + } + if (stuck) { + inferenceContext.rollback(); + instantiateAsUninferredVars(varsToSolve, inferenceContext); + checkWithinBounds(inferenceContext, Warner.noWarnings); + } + } + } + } + + /** + * Debugging: dump a string containing a dot representation of the bound + * dependencies in this solver. + */ + String toDot() { + StringBuilder buf = new StringBuilder(); + buf.append(String.format("digraph %s {\n", hashCode())); + buf.append("label = \"Inference variables:\\n"); + for (Type t : inferenceContext.undetvars) { + UndetVar uv = (UndetVar)t; + buf.append(String.format("var %s - upper bounds = %s, lower bounds = %s, eq bounds = %s\\n", + uv.qtype, uv.getBounds(InferenceBound.UPPER), uv.getBounds(InferenceBound.LOWER), uv.getBounds(InferenceBound.EQ))); + } + buf.append("\";\n"); + //dump nodes + for (Type iv : inferenceContext.inferenceVars()) { + buf.append(String.format("%s [label = \"%s\"];\n", iv.hashCode(), iv.tsym.name)); + } + //dump arcs + for (Map.Entry<Type, List<Type>> entry : deps.entrySet()) { + Type from = entry.getKey(); + for (Type to : entry.getValue()) { + StringBuilder buf2 = new StringBuilder(); + String sep = ""; + for (Type t : ((UndetVar)inferenceContext.asFree(from, types)).getBounds(InferenceBound.UPPER, InferenceBound.LOWER, InferenceBound.EQ)) { + if (t.contains(to)) { + buf2.append(sep); + buf2.append(t); + sep = ","; + } + } + buf.append(String.format("%s -> %s [label = \" %s \"];\n", from.hashCode(), to.hashCode(), buf2)); + } + } + buf.append("}\n"); + return buf.toString(); + } + + /** + * The acyclic reduction of the directed (possibly cyclic) graph + * computed by this solver. Each node in this graph contains one + * or more (in case of bound cycles) inference variables. + */ + class AcyclicInferenceGraph { + + class Node { + List<Type> node_vars; + + Node(List<Type> node_vars) { + this.node_vars = node_vars; + } + + public boolean edgeTo(Node node) { + for (Type i : node_vars) { + for (Type j : node.node_vars) { + //skip edges that point to same super-node + if (node_vars.contains(j)) continue; + List<Type> depVars = deps.get(i); + if (depVars != null && depVars.contains(j)) { + return true; + } + } + } + return false; + } + } + + List<Node> nodes; + Map<Node, List<Node>> graph_deps; + + AcyclicInferenceGraph() { + nodes = findNodes(); + computeDependencies(); + } + + private Set<Set<Type>> findCycles() { + Set<Set<Type>> cycles = new HashSet<Set<Type>>(); + for (Type iv : inferenceContext.restvars()) { + findCycles(iv, iv, new ArrayList<Type>(), cycles); + } + Set<Set<Type>> maxCycles = new HashSet<Set<Type>>(cycles); + while (mergeCycles(cycles, maxCycles)) { + cycles = maxCycles; + maxCycles = new HashSet<Set<Type>>(cycles); + } + return maxCycles; + } + + private boolean mergeCycles(Set<Set<Type>> cycles, Set<Set<Type>> maxCycles) { + //merge overlapping cycles + for (Set<Type> cycle1 : cycles) { + for (Set<Type> cycle2 : cycles) { + if (cycle1 == cycle2) continue; + for (Type t : cycle1) { + if (cycle2.contains(t)) { + maxCycles.remove(cycle1); + maxCycles.remove(cycle2); + Set<Type> cycle3 = new HashSet<Type>(cycle1); + cycle3.addAll(cycle2); + maxCycles.add(cycle3); + return true; + } + } + } + } + return false; + } + + private void findCycles(Type start, Type current, ArrayList<Type> path, Set<Set<Type>> cycles) { + //System.out.printf("find cycles - start = %s, current = %s, path = %s, cycles = %s\n" , start, current, path, cycles); + if (current == start && !path.isEmpty()) { + cycles.add(new HashSet<Type>(path)); + } else if (path.contains(current)) { + return; + } else { + path.add(current); + List<Type> depVars = deps.get(current); + if (depVars != null) { + for (Type iv : depVars) { + findCycles(start, iv, path, cycles); + } + } + path.remove(current); + } + } + + private List<Node> findNodes() { + Set<Set<Type>> cycles = findCycles(); + List<Node> nodes = List.nil(); + for (Set<Type> cycle : cycles) { + nodes = nodes.prepend(new Node(List.from(cycle.toArray(new Type[cycle.size()])))); + } + + for (Type iv : inferenceContext.restvars()) { + boolean found = false; + for (Set<Type> cycle : cycles) { + if (cycle.contains(iv)) { + found = true; + } + } + if (!found) { + nodes = nodes.prepend(new Node(List.of(iv))); + } + } + return nodes; + } + + private void computeDependencies() { + graph_deps = new HashMap<Node, List<Node>>(); + for (Node i : nodes) { + for (Node j : nodes) { + if (i.edgeTo(j)) { + //update i's deps + List<Node> depNodes_i = graph_deps.get(i); + if (depNodes_i == null) { + depNodes_i = List.nil(); + } + depNodes_i = depNodes_i.prepend(j); + graph_deps.put(i, depNodes_i); + } + } + } + } + + /** + * Debugging: dot representation of this graph + */ + String toDot() { + StringBuilder buf = new StringBuilder(); + buf.append(String.format("digraph %s {\n", hashCode())); + //dump nodes + for (Node n : nodes) { + buf.append(String.format("%s [label = \"%s\"];\n", n.hashCode(), n.node_vars)); + } + //dump arcs + for (Map.Entry<Node, List<Node>> entry : graph_deps.entrySet()) { + Node from = entry.getKey(); + for (Node to : entry.getValue()) { + StringBuilder buf2 = new StringBuilder(); + String sep = ""; + for (Type from2 : from.node_vars) { + for (Type t : ((UndetVar)inferenceContext.asFree(from2, types)).getBounds(InferenceBound.UPPER, InferenceBound.LOWER, InferenceBound.EQ)) { + if (t.containsAny(to.node_vars)) { + buf2.append(sep); + buf2.append(t); + sep = ","; + } + } + } + buf.append(String.format("%s -> %s [label = \" %s \"];\n", from.hashCode(), to.hashCode(), buf2)); + } + } + buf.append("}\n"); + return buf.toString(); + } + } + } +}
--- a/src/share/classes/com/sun/tools/javac/comp/Infer.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Aug 03 12:48:20 2012 +0100 @@ -29,16 +29,16 @@ import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.comp.Resolve.InapplicableMethodException; -import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import java.util.Arrays; -import java.util.EnumSet; +import java.util.Set; + import static com.sun.tools.javac.code.TypeTags.*; /** Helper class for type parameter inference, used by the attribution phase. @@ -48,46 +48,19 @@ * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ -public class Infer { - protected static final Context.Key<Infer> inferKey = - new Context.Key<Infer>(); - - /** A value for prototypes that admit any type, including polymorphic ones. */ - public static final Type anyPoly = new Type(NONE, null); +public abstract class Infer { + DeferredAttr deferredAttr; Symtab syms; - Types types; - Check chk; - Resolve rs; - DeferredAttr deferredAttr; - Log log; + Types types; JCDiagnostic.Factory diags; - public static Infer instance(Context context) { - Infer instance = context.get(inferKey); - if (instance == null) - instance = new Infer(context); - return instance; - } - protected Infer(Context context) { - context.put(inferKey, this); + deferredAttr = DeferredAttr.instance(context); syms = Symtab.instance(context); types = Types.instance(context); - rs = Resolve.instance(context); - deferredAttr = DeferredAttr.instance(context); - log = Log.instance(context); - chk = Check.instance(context); diags = JCDiagnostic.Factory.instance(context); - ambiguousNoInstanceException = - new NoInstanceException(true, diags); - unambiguousNoInstanceException = - new NoInstanceException(false, diags); - invalidInstanceException = - new InvalidInstanceException(diags); - cyclicInferenceException = - new CyclicInferenceException(diags); - + inferenceException = new InferenceException(diags); } public static class InferenceException extends InapplicableMethodException { @@ -98,282 +71,14 @@ } } - public static class NoInstanceException extends InferenceException { - private static final long serialVersionUID = 1; - - boolean isAmbiguous; // exist several incomparable best instances? - - NoInstanceException(boolean isAmbiguous, JCDiagnostic.Factory diags) { - super(diags); - this.isAmbiguous = isAmbiguous; - } - } - - public static class InvalidInstanceException extends InferenceException { - private static final long serialVersionUID = 2; - - InvalidInstanceException(JCDiagnostic.Factory diags) { - super(diags); - } - } - - public static class CyclicInferenceException extends InferenceException { - private static final long serialVersionUID = 3; - - CyclicInferenceException(JCDiagnostic.Factory diags) { - super(diags); - } - } - - private final NoInstanceException ambiguousNoInstanceException; - private final NoInstanceException unambiguousNoInstanceException; - private final InvalidInstanceException invalidInstanceException; - final CyclicInferenceException cyclicInferenceException; - -/*************************************************************************** - * Auxiliary type values and classes - ***************************************************************************/ - - /** A mapping that turns type variables into undetermined type variables. - */ - Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") { - public Type apply(Type t) { - if (t.tag == TYPEVAR) return new UndetVar(t); - else return t.map(this); - } - }; - - /** A mapping that returns its type argument with every UndetVar replaced - * by its `inst' field. Throws a NoInstanceException - * if this not possible because an `inst' field is null. - * Note: mutually referring undertvars will be left uninstantiated - * (that is, they will be replaced by the underlying type-variable). - */ - - Mapping getInstFun = new Mapping("getInstFun") { - public Type apply(Type t) { - switch (t.tag) { - case UNKNOWN: - throw ambiguousNoInstanceException - .setMessage("undetermined.type"); - case UNDETVAR: - UndetVar that = (UndetVar) t; - if (that.inst == null) - throw ambiguousNoInstanceException - .setMessage("type.variable.has.undetermined.type", - that.qtype); - return isConstraintCyclic(that) ? - that.qtype : - apply(that.inst); - default: - return t.map(this); - } - } - - private boolean isConstraintCyclic(UndetVar uv) { - Types.UnaryVisitor<Boolean> constraintScanner = - new Types.UnaryVisitor<Boolean>() { - - List<Type> seen = List.nil(); - - Boolean visit(List<Type> ts) { - for (Type t : ts) { - if (visit(t)) return true; - } - return false; - } - - public Boolean visitType(Type t, Void ignored) { - return false; - } - - @Override - public Boolean visitClassType(ClassType t, Void ignored) { - if (t.isCompound()) { - return visit(types.supertype(t)) || - visit(types.interfaces(t)); - } else { - return visit(t.getTypeArguments()); - } - } - @Override - public Boolean visitWildcardType(WildcardType t, Void ignored) { - return visit(t.type); - } - - @Override - public Boolean visitUndetVar(UndetVar t, Void ignored) { - if (seen.contains(t)) { - return true; - } else { - seen = seen.prepend(t); - return visit(t.inst); - } - } - }; - return constraintScanner.visit(uv); - } - }; - -/*************************************************************************** - * Mini/Maximization of UndetVars - ***************************************************************************/ - - /** Instantiate undetermined type variable to its minimal upper bound. - * Throw a NoInstanceException if this not possible. + protected final InferenceException inferenceException; + + // <editor-fold defaultstate="collapsed" desc="generic method type-inference"> + /** + * Main inference entry point - instantiate a generic method type + * using given argument types and (possibly) an expected target-type. */ - void maximizeInst(UndetVar that, Warner warn) throws NoInstanceException { - List<Type> hibounds = Type.filter(that.hibounds, errorFilter); - if (that.inst == null) { - if (hibounds.isEmpty()) - that.inst = syms.objectType; - else if (hibounds.tail.isEmpty()) - that.inst = hibounds.head; - else - that.inst = types.glb(hibounds); - } - if (that.inst == null || - that.inst.isErroneous()) - throw ambiguousNoInstanceException - .setMessage("no.unique.maximal.instance.exists", - that.qtype, hibounds); - } - //where - private boolean isSubClass(Type t, final List<Type> ts) { - t = t.baseType(); - if (t.tag == TYPEVAR) { - List<Type> bounds = types.getBounds((TypeVar)t); - for (Type s : ts) { - if (!types.isSameType(t, s.baseType())) { - for (Type bound : bounds) { - if (!isSubClass(bound, List.of(s.baseType()))) - return false; - } - } - } - } else { - for (Type s : ts) { - if (!t.tsym.isSubClass(s.baseType().tsym, types)) - return false; - } - } - return true; - } - - private Filter<Type> errorFilter = new Filter<Type>() { - @Override - public boolean accepts(Type t) { - return !t.isErroneous(); - } - }; - - /** Instantiate undetermined type variable to the lub of all its lower bounds. - * Throw a NoInstanceException if this not possible. - */ - void minimizeInst(UndetVar that, Warner warn) throws NoInstanceException { - List<Type> lobounds = Type.filter(that.lobounds, errorFilter); - if (that.inst == null) { - if (lobounds.isEmpty()) - that.inst = syms.botType; - else if (lobounds.tail.isEmpty()) - that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head; - else { - that.inst = types.lub(lobounds); - } - if (that.inst == null || that.inst.tag == ERROR) - throw ambiguousNoInstanceException - .setMessage("no.unique.minimal.instance.exists", - that.qtype, lobounds); - // VGJ: sort of inlined maximizeInst() below. Adding - // bounds can cause lobounds that are above hibounds. - List<Type> hibounds = Type.filter(that.hibounds, errorFilter); - Type hb = null; - if (hibounds.isEmpty()) - hb = syms.objectType; - else if (hibounds.tail.isEmpty()) - hb = hibounds.head; - else - hb = types.glb(hibounds); - if (hb == null || - hb.isErroneous()) - throw ambiguousNoInstanceException - .setMessage("incompatible.upper.bounds", - that.qtype, hibounds); - } - } - -/*************************************************************************** - * Exported Methods - ***************************************************************************/ - - /** - * Instantiate uninferred inference variables (JLS 15.12.2.8). First - * if the method return type is non-void, we derive constraints from the - * expected type - then we use declared bound well-formedness to derive additional - * constraints. If no instantiation exists, or if several incomparable - * best instantiations exist throw a NoInstanceException. - */ - public void instantiateUninferred(DiagnosticPosition pos, - InferenceContext inferenceContext, - MethodType mtype, - Attr.ResultInfo resultInfo, - Warner warn) throws InferenceException { - for (List<Type> l = inferenceContext.undetvars; l.nonEmpty(); l = l.tail) { - UndetVar uv = (UndetVar)l.head; - uv.hibounds = uv.hibounds.appendList(inferenceContext.asFree(types.getBounds((TypeVar)uv.qtype))); - } - Type to = resultInfo.pt; - if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { - to = mtype.getReturnType().tag <= VOID ? - mtype.getReturnType() : syms.objectType; - } - Type qtype1 = inferenceContext.asFree(mtype.getReturnType()); - if (!types.isSubtype(qtype1, - qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) { - throw unambiguousNoInstanceException - .setMessage("infer.no.conforming.instance.exists", - inferenceContext.restvars(), mtype.getReturnType(), to); - } - inferenceContext.instantiate(warn, false, EnumSet.of(InferenceKind.UPPER)); - - // System.out.println(" = " + qtype1.map(getInstFun));//DEBUG - - List<Type> targs = Type.map(inferenceContext.undetvars, getInstFun); - if (Type.containsAny(targs, inferenceContext.inferenceVars())) { - //replace uninferred type-vars - targs = types.subst(targs, - inferenceContext.inferenceVars(), - instantiateAsUninferredVars(inferenceContext.undetvars, inferenceContext.inferenceVars())); - } - inferenceContext.insttypes = targs; - } - //where - private List<Type> instantiateAsUninferredVars(List<Type> undetvars, List<Type> tvars) { - Assert.check(undetvars.length() == tvars.length()); - ListBuffer<Type> new_targs = ListBuffer.lb(); - //step 1 - create synthetic captured vars - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - Type newArg = new CapturedType(t.tsym.name, t.tsym, uv.inst, syms.botType, null); - new_targs = new_targs.append(newArg); - } - //step 2 - replace synthetic vars in their bounds - List<Type> formals = tvars; - for (Type t : new_targs.toList()) { - CapturedType ct = (CapturedType)t; - ct.bound = types.subst(ct.bound, tvars, new_targs.toList()); - WildcardType wt = new WildcardType(syms.objectType, BoundKind.UNBOUND, syms.boundClass); - wt.bound = (TypeVar)formals.head; - ct.wildcard = wt; - formals = formals.tail; - } - return new_targs.toList(); - } - - /** Instantiate a generic method type by finding instantiations for all its - * inference variables so that it can be applied to a given argument type list. - */ - public Type instantiateMethod(Env<AttrContext> env, + public abstract Type instantiateMethod(Env<AttrContext> env, List<Type> tvars, MethodType mt, Symbol msym, @@ -382,145 +87,227 @@ boolean allowBoxing, boolean useVarargs, Resolve.MethodResolutionContext resolveContext, - Warner warn) throws InferenceException { - //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG - final InferenceContext inferenceContext = new InferenceContext(tvars); - - rs.checkRawArgumentsAcceptable(env, resolveContext.attrMode(), inferenceContext, argtypes, mt.getParameterTypes(), - allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext)); - - // minimize as yet undetermined type variables - inferenceContext.instantiate(warn, false, EnumSet.of(InferenceKind.LOWER)); - - checkWithinBounds(tvars, inferenceContext.asFree(inferenceContext.insttypes), warn); - - mt = (MethodType)inferenceContext.asInstType(mt); - - List<Type> restvars = inferenceContext.restvars(); - - if (!restvars.isEmpty()) { - if (resultInfo != null) { - instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo, warn); - checkWithinBounds(tvars, inferenceContext.asInstTypes(tvars), warn); - mt = (MethodType)inferenceContext.asInstType(mt); - inferenceContext.finish(); - if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { - log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt); - } - } - } else { - inferenceContext.finish(); - } - - // return instantiated version of method type - return mt; - } - - /** inference check handler **/ - class InferenceCheckHandler implements Resolve.MethodCheckHandler { - - InferenceContext inferenceContext; - - public InferenceCheckHandler(InferenceContext inferenceContext) { - this.inferenceContext = inferenceContext; - } - - public InapplicableMethodException arityMismatch() { - return unambiguousNoInstanceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars()); - } - public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic details) { - String key = varargs ? - "infer.varargs.argument.mismatch" : - "infer.no.conforming.assignment.exists"; - return unambiguousNoInstanceException.setMessage(key, - inferenceContext.inferenceVars(), details); - } - public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { - return unambiguousNoInstanceException.setMessage("inaccessible.varargs.type", - expected, Kinds.kindName(location), location); - } - } + Warner warn) throws InferenceException; - // <editor-fold desc="SAM type instantiation"> /** * This method is used to infer a suitable target SAM in case the original * SAM type contains one or more 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 inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext) { - if (types.capture(samType) == samType) { - //if capture doesn't change the type then return the target unchanged - //(this means the target contains no wilddcards!) - return samType; - } else { - Type formalSam = samType.tsym.type; - InferenceContext samInferenceContext = new InferenceContext(samType.tsym.type.getTypeArguments()); - if (paramTypes != null) { - //get constraints from explicit params (this is done by - //checking that explicit param types are equal to the ones - //in the SAM descriptors) - List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes(); - if (descParameterTypes.size() != paramTypes.size()) { - checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); - return types.createErrorType(samType); - } - for (Type p : descParameterTypes) { - if (!types.isSameType(samInferenceContext.asFree(p), paramTypes.head)) { - checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); - return types.createErrorType(samType); - } - paramTypes = paramTypes.tail; - } - samInferenceContext.instantiate(Warner.noWarnings, true, - EnumSet.of(InferenceKind.LOWER, InferenceKind.UPPER)); - - formalSam = samInferenceContext.asInstType(formalSam); - } - ListBuffer<Type> typeargs = ListBuffer.lb(); - List<Type> actualTypeargs = samType.getTypeArguments(); - //for remaining uninferred type-vars in the SAM type, - //simply replace the wildcards with its bound - for (Type t : formalSam.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(formalSam, samInferenceContext.inferenceVars(), typeargs.toList()); - if (!chk.checkValidGenericType(owntype)) { - //if the inferred SAM 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.sam.inst", samType)); - return types.createErrorType(samType); - } - return owntype; + public abstract Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext); + + /** + * Inference check handler - used to report inference error during method + * instantiation (see Infer.intantiateMethod). + */ + class InferenceCheckHandler implements Resolve.MethodCheckHandler { + + InferenceContext inferenceContext; + + public InferenceCheckHandler(InferenceContext inferenceContext) { + this.inferenceContext = inferenceContext; + } + + public InapplicableMethodException arityMismatch() { + return inferenceException.setMessage("infer.arg.length.mismatch", inferenceContext.inferenceVars()); + } + public InapplicableMethodException argumentMismatch(boolean varargs, JCDiagnostic diag) { + String key = varargs ? + "infer.varargs.argument.mismatch" : + "infer.no.conforming.assignment.exists"; + return inferenceException.setMessage(key, + inferenceContext.inferenceVars(), diag); + } + public InapplicableMethodException inaccessibleVarargs(Symbol location, Type expected) { + return inferenceException.setMessage("inaccessible.varargs.type", + expected, Kinds.kindName(location), location); } } // </editor-fold> - /** check that type parameters are within their bounds. + // <editor-fold defaultstate="collapsed" desc="Bound checking"> + + /** + * This interface defines an entry point for doing inference variable + * bound incorporation - it can be used to inject custom incorporation + * logic into the basic bound checking routine + */ + interface IncorporationStep { + void apply(UndetVar uv, InferenceContext inferenceContext); + } + + /** + * Check that type parameters are within their bounds. */ - void checkWithinBounds(List<Type> tvars, - List<Type> arguments, - Warner warn) - throws InvalidInstanceException { - for (List<Type> tvs = tvars, args = arguments; - tvs.nonEmpty(); - tvs = tvs.tail, args = args.tail) { - if (args.head instanceof UndetVar || - tvars.head.getUpperBound().isErroneous()) continue; - List<Type> bounds = types.subst(types.getBounds((TypeVar)tvs.head), tvars, arguments); - if (!types.isSubtypeUnchecked(args.head, bounds, warn)) - throw invalidInstanceException - .setMessage("inferred.do.not.conform.to.bounds", - args.head, bounds); + void checkWithinBounds(InferenceContext inferenceContext, + Warner warn, IncorporationStep... incorporationSteps) throws InferenceException { + MultiUndetVarListener mlistener = new MultiUndetVarListener(inferenceContext.undetvars); + try { + while (true) { + mlistener.changed = false; + for (Type t : inferenceContext.undetvars) { + UndetVar uv = (UndetVar)t; + uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.insttypes(), types); + checkCompatibleUpperBounds(uv, inferenceContext); + if (uv.inst != null) { + Type inst = uv.inst; + for (Type u : uv.getBounds(InferenceBound.UPPER)) { + if (!types.isSubtypeUnchecked(inst, inferenceContext.asFree(u, types), warn)) { + reportBoundError(uv, BoundErrorKind.UPPER); + } + } + for (Type l : uv.getBounds(InferenceBound.LOWER)) { + if (!types.isSubtypeUnchecked(inferenceContext.asFree(l, types), inst, warn)) { + reportBoundError(uv, BoundErrorKind.LOWER); + } + } + for (Type e : uv.getBounds(InferenceBound.EQ)) { + if (!types.isSameType(inst, inferenceContext.asFree(e, types))) { + reportBoundError(uv, BoundErrorKind.EQ); + } + } + } + //check eq bounds consistency + for (Type e : uv.getBounds(InferenceBound.EQ)) { + if (e.containsAny(inferenceContext.inferenceVars())) continue; + for (Type u : uv.getBounds(InferenceBound.UPPER)) { + if (!types.isSubtypeUnchecked(e, inferenceContext.asFree(u, types), warn)) { + reportBoundError(uv, BoundErrorKind.BAD_EQ_UPPER); + } + } + for (Type l : uv.getBounds(InferenceBound.LOWER)) { + if (!types.isSubtypeUnchecked(inferenceContext.asFree(l, types), e, warn)) { + reportBoundError(uv, BoundErrorKind.BAD_EQ_LOWER); + } + } + } + //bound incorporation + for (IncorporationStep is : incorporationSteps) { + is.apply(uv, inferenceContext); + } + } + if (!mlistener.changed) break; + } + } + finally { + mlistener.detach(); } } + //where + /** + * This listener keeps track of changes on a group of inference variable + * bounds. Note: the listener must be detached (calling corresponding + * method) to make sure that the underlying inference variable is + * left in a clean state. + */ + class MultiUndetVarListener implements UndetVar.UndetVarListener { + boolean changed; + List<Type> undetvars; + + public MultiUndetVarListener(List<Type> undetvars) { + this.undetvars = undetvars; + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + uv.listener = this; + } + } + + public void varChanged(UndetVar uv, Set<InferenceBound> ibs) { + changed = true; + } + + void detach() { + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + uv.listener = null; + } + } + }; + + void checkCompatibleUpperBounds(UndetVar uv, InferenceContext inferenceContext) { + // VGJ: sort of inlined maximizeInst() below. Adding + // bounds can cause lobounds that are above hibounds. + List<Type> hibounds = Type.filter(uv.getBounds(InferenceBound.UPPER), new BoundFilter(inferenceContext)); + Type hb = null; + if (hibounds.isEmpty()) + hb = syms.objectType; + else if (hibounds.tail.isEmpty()) + hb = hibounds.head; + else + hb = types.glb(hibounds); + if (hb == null || hb.isErroneous()) + reportBoundError(uv, BoundErrorKind.BAD_UPPER); + } + //where + protected class BoundFilter implements Filter<Type> { + + InferenceContext inferenceContext; + + public BoundFilter(InferenceContext inferenceContext) { + this.inferenceContext = inferenceContext; + } + + @Override + public boolean accepts(Type t) { + return !t.isErroneous() && !inferenceContext.free(t); + } + }; + + enum BoundErrorKind { + BAD_UPPER() { + @Override + InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) { + return ex.setMessage("incompatible.upper.bounds", uv.qtype, + uv.getBounds(InferenceBound.UPPER)); + } + }, + BAD_EQ_UPPER() { + @Override + InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) { + return ex.setMessage("incompatible.eq.upper.bounds", uv.qtype, + uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.UPPER)); + } + }, + BAD_EQ_LOWER() { + @Override + InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) { + return ex.setMessage("incompatible.eq.lower.bounds", uv.qtype, + uv.getBounds(InferenceBound.EQ), uv.getBounds(InferenceBound.LOWER)); + } + }, + UPPER() { + @Override + InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) { + return ex.setMessage("inferred.do.not.conform.to.upper.bounds", uv.inst, + uv.getBounds(InferenceBound.UPPER)); + } + }, + LOWER() { + @Override + InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) { + return ex.setMessage("inferred.do.not.conform.to.lower.bounds", uv.inst, + uv.getBounds(InferenceBound.LOWER)); + } + }, + EQ() { + @Override + InapplicableMethodException setMessage(InferenceException ex, UndetVar uv) { + return ex.setMessage("inferred.do.not.conform.to.eq.bounds", uv.inst, + uv.getBounds(InferenceBound.EQ)); + } + }; + + abstract InapplicableMethodException setMessage(InferenceException ex, UndetVar uv); + } + //where + void reportBoundError(UndetVar uv, BoundErrorKind bk) { + throw bk.setMessage(inferenceException, uv); + } + // </editor-fold> + + // <editor-fold defaultstate="collapsed" desc="Polymorphic signature inference (JSR 292)"> /** * Compute a synthetic method type corresponding to the requested polymorphic * method signature. The target return type is computed from the immediately @@ -584,34 +371,8 @@ } }; // </editor-fold> - - /** - * Single-method-interface for defining inference callbacks. Certain actions - * (i.e. subtyping checks) might need to be redone after all inference variables - * have been fixed. - */ - interface PendingCheck { - void eval(); - } - - /** - * There are two kind of inference strategies: (i) lower bounds can be used to - * infer a type using lub, alternatively (ii) upper bounds can be used to - * infer a type using glb. - */ - enum InferenceKind { - LOWER, - UPPER; - - boolean upperBoundInference() { - return this == UPPER; - } - - boolean lowerBoundInference() { - return this == LOWER; - } - } - + + // <editor-fold defaultstate="collapsed" desc="Inference context"> /** * An inference context keeps track of the set of variables that are free * in the current context. It provides utility methods for opening/closing @@ -620,18 +381,33 @@ * it can be used as an entry point for performing upper/lower bound inference * (see InferenceKind). */ - class InferenceContext { + static abstract class InferenceContext { + + /** + * Single-method-interface for defining inference callbacks. Certain actions + * (i.e. subtyping checks) might need to be redone after all inference variables + * have been fixed. + */ + interface PendingCheck { + void eval(); + } /** list of inference vars as undet vars */ List<Type> undetvars; - /** list of instantiated types in this context */ - List<Type> insttypes; ListBuffer<PendingCheck> pendingChecks = ListBuffer.lb(); - public InferenceContext(List<Type> inferenceVars) { - this.undetvars = Type.map(inferenceVars, fromTypeVarFun); - this.insttypes = inferenceVars; + public InferenceContext(List<Type> inferenceVars, final Types types) { + this(inferenceVars, types, true); + } + + public InferenceContext(List<Type> inferenceVars, final Types types, final boolean includeBounds) { + this.undetvars = Type.map(inferenceVars, new Mapping("fromTypeVarFun") { + public Type apply(Type t) { + if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, includeBounds, types); + else return t.map(this); + } + }); } /** @@ -645,6 +421,19 @@ } return tvars.toList(); } + + List<Type> insttypes() { + ListBuffer<Type> insttypes = ListBuffer.lb(); + for (Type t : undetvars) { + UndetVar uv = (UndetVar)t; + if (uv.inst != null) { + insttypes.append(uv.inst); + } else { + insttypes.append(uv.qtype); + } + } + return insttypes.toList(); + } /** * returns the list of uninstantiated variables (as type-variables) in this @@ -653,7 +442,7 @@ List<Type> restvars() { List<Type> undetvars = this.undetvars; ListBuffer<Type> restvars = ListBuffer.lb(); - for (Type t : insttypes) { + for (Type t : insttypes()) { UndetVar uv = (UndetVar)undetvars.head; if (uv.qtype == t) { restvars.append(t); @@ -676,20 +465,44 @@ } return false; } + + final List<Type> freeVarsIn(Type t) { + ListBuffer<Type> buf = ListBuffer.lb(); + for (Type iv : inferenceVars()) { + if (t.contains(iv)) { + buf.add(iv); + } + } + return buf.toList(); + } + + final List<Type> freeVarsIn(List<Type> ts) { + ListBuffer<Type> buf = ListBuffer.lb(); + for (Type t : ts) { + buf.appendList(freeVarsIn(t)); + } + ListBuffer<Type> buf2 = ListBuffer.lb(); + for (Type t : buf) { + if (!buf2.contains(t)) { + buf2.add(t); + } + } + return buf2.toList(); + } /** * Replace all free variables in a given type with corresponding * undet vars (used ahead of subtyping/compatibility checks to allow propagation * of inference constraints). */ - final Type asFree(Type t) { + final Type asFree(Type t, Types types) { return types.subst(t, inferenceVars(), undetvars); } - final List<Type> asFree(List<Type> ts) { + final List<Type> asFree(List<Type> ts, Types types) { ListBuffer<Type> buf = ListBuffer.lb(); for (Type t : ts) { - buf.append(asFree(t)); + buf.append(asFree(t, types)); } return buf.toList(); } @@ -699,48 +512,20 @@ * instantiated types - if one or more free variable has not been * fully instantiated, it will still be available in the resulting type. */ - Type asInstType(Type t) { - return types.subst(t, inferenceVars(), insttypes); - } - - List<Type> asInstTypes(List<Type> ts) { - ListBuffer<Type> buf = ListBuffer.lb(); - for (Type t : ts) { - buf.append(asInstType(t)); - } - return buf.toList(); + Type asInstType(Type t, Types types) { + return types.subst(t, inferenceVars(), insttypes()); } - /** - * Perform upper/lower type-inference - */ - void instantiate(Warner warn, boolean skipIfNoBounds, EnumSet<InferenceKind> iks) { - for (InferenceKind ik : InferenceKind.values()) { - if (!iks.contains(ik)) continue; - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - if (ik.lowerBoundInference() && - (uv.lobounds.nonEmpty() || !skipIfNoBounds)) { - minimizeInst((UndetVar) t, warn); - } else if (ik.upperBoundInference() && - (uv.hibounds.nonEmpty() || !skipIfNoBounds)) { - maximizeInst((UndetVar) t, warn); - } - } - - insttypes = List.nil(); - - for (Type t : undetvars) { - UndetVar uv = (UndetVar)t; - if (uv.inst == null || uv.inst.tag == BOT) { - uv.inst = null; - insttypes = insttypes.append(uv.qtype); - } else { - insttypes = insttypes.append(uv.inst); - } - } + List<Type> asInstTypes(List<Type> ts, Types types) { + ListBuffer<Type> buf = ListBuffer.lb(); + boolean changed = false; + for (Type t : ts) { + Type t2 = asInstType(t, types); + changed |= t2 != t; + buf.append(t2); } - } + return changed ? buf.toList() : ts; + } /** * Add custom hook for performing post-inference action @@ -754,12 +539,20 @@ * of all deferred checks. */ void finish() { - Assert.check(!free(insttypes)); + Assert.check(restvars().isEmpty()); for (PendingCheck pc : pendingChecks) { pc.eval(); } } + + abstract void solveAny(List<Type> stuckvars); } - final InferenceContext emptyContext = new InferenceContext(List.<Type>nil()); + final InferenceContext emptyContext = new InferenceContext(List.<Type>nil(), types) { + @Override + void solveAny(List<Type> stuckvars) { + Assert.error(); + } + }; + // </editor-fold> }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/comp/InferFactory.java Fri Aug 03 12:48:20 2012 +0100 @@ -0,0 +1,66 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +/** + * A factory for creating inference engines. + * + * <p><b>This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class InferFactory { + + /** The context key for the infer factory. */ + protected static final Context.Key<InferFactory> inferFactoryKey = new Context.Key<InferFactory>(); + + public static InferFactory instance(Context context) { + InferFactory instance = context.get(inferFactoryKey); + if (instance == null) { + instance = new InferFactory(context); + } + return instance; + } + + final Infer infer; + + protected InferFactory(Context context) { + context.put(inferFactoryKey, this); + Source source = Source.instance(context); + Options options = Options.instance(context); + infer = source.allowBetterInference() && options.isSet("useGraphInference") ? + new GraphInfer(context) : new LegacyInfer(context); + } + + public Infer getInfer() { + return infer; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/comp/LegacyInfer.java Fri Aug 03 12:48:20 2012 +0100 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 1999, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.comp; + +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; + +import static com.sun.tools.javac.code.TypeTags.*; + +/** Helper class for type parameter inference, used by the attribution phase. + * + * <p><b>This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice.</b> + */ +public class LegacyInfer extends Infer { + + Check chk; + Resolve rs; + Log log; + + protected LegacyInfer(Context context) { + super(context); + rs = Resolve.instance(context); + log = Log.instance(context); + chk = Check.instance(context); + } + +/*************************************************************************** + * Mini/Maximization of UndetVars + ***************************************************************************/ + + /** Instantiate undetermined type variable to its minimal upper bound. + * Throw a NoInstanceException if this not possible. + */ + private void maximizeInst(UndetVar that, InferenceContext inferenceContext) throws InferenceException { + List<Type> hibounds = Type.filter(that.getBounds(InferenceBound.UPPER), new BoundFilter(inferenceContext)); + if (that.getBounds(InferenceBound.EQ).isEmpty()) { + if (hibounds.isEmpty()) + that.inst = syms.objectType; + else if (hibounds.tail.isEmpty()) + that.inst = hibounds.head; + else + that.inst = types.glb(hibounds); + } else { + that.inst = that.getBounds(InferenceBound.EQ).head; + } + if (that.inst == null || + that.inst.isErroneous()) + throw inferenceException + .setMessage("no.unique.maximal.instance.exists", + that.qtype, hibounds); + } + + /** Instantiate undetermined type variable to the lub of all its lower bounds. + * Throw a NoInstanceException if this not possible. + */ + private void minimizeInst(UndetVar that, InferenceContext inferenceContext) throws InferenceException { + List<Type> lobounds = Type.filter(that.getBounds(InferenceBound.LOWER), new BoundFilter(inferenceContext)); + if (that.getBounds(InferenceBound.EQ).isEmpty()) { + if (lobounds.nonEmpty()) { + if (lobounds.tail.isEmpty()) + that.inst = lobounds.head.isPrimitive() ? syms.errType : lobounds.head; + else { + that.inst = types.lub(lobounds); + } + if (that.inst == null || that.inst.tag == ERROR) + throw inferenceException + .setMessage("no.unique.minimal.instance.exists", + that.qtype, lobounds); + } + } else { + that.inst = that.getBounds(InferenceBound.EQ).head; + } + } + +/*************************************************************************** + * Exported Methods + ***************************************************************************/ + + /** + * Instantiate uninferred inference variables (JLS 15.12.2.8). First + * if the method return type is non-void, we derive constraints from the + * expected type - then we use declared bound well-formedness to derive additional + * constraints. If no instantiation exists, or if several incomparable + * best instantiations exist throw a NoInstanceException. + */ + private void instantiateUninferred(DiagnosticPosition pos, + InferenceContext inferenceContext, + MethodType mtype, + Attr.ResultInfo resultInfo) throws InferenceException { + Type to = resultInfo.pt; + if (to.tag == NONE || resultInfo.checkContext.inferenceContext().free(resultInfo.pt)) { + to = mtype.getReturnType().tag <= VOID ? + mtype.getReturnType() : syms.objectType; + } + Type qtype1 = inferenceContext.asFree(mtype.getReturnType(), types); + if (!types.isSubtype(qtype1, + qtype1.tag == UNDETVAR ? types.boxedTypeOrType(to) : to)) { + throw inferenceException + .setMessage("infer.no.conforming.instance.exists", + inferenceContext.restvars(), mtype.getReturnType(), to); + } + + while (true) { + boolean stuck = true; + for (Type t : inferenceContext.undetvars) { + UndetVar uv = (UndetVar)t; + if (uv.inst == null && + (uv.getBounds(InferenceBound.EQ).nonEmpty() || + !inferenceContext.free(uv.getBounds(InferenceBound.UPPER)))) { + maximizeInst((UndetVar)t, inferenceContext); + stuck = false; + } + } + if (inferenceContext.restvars().isEmpty()) { + //all variables have been instantiated - exit + break; + } else if (stuck) { + //some variables could not be instantiated because of cycles in + //upper bounds - provide a (possibly recursive) default instantiation + instantiateAsUninferredVars(inferenceContext); + break; + } else { + //some variables have been instantiated - replace newly instantiated + //variables in remaining upper bounds and continue + for (Type t : inferenceContext.undetvars) { + UndetVar uv = (UndetVar)t; + uv.substBounds(inferenceContext.inferenceVars(), inferenceContext.insttypes(), types); + } + } + } + } + + /** + * Infer cyclic inference variables as described in 15.12.2.8. + */ + private void instantiateAsUninferredVars(InferenceContext inferenceContext) { + ListBuffer<Type> todo = ListBuffer.lb(); + //step 1 - create fresh tvars + for (Type t : inferenceContext.undetvars) { + UndetVar uv = (UndetVar)t; + if (uv.inst == null) { + TypeSymbol fresh_tvar = new TypeSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner); + fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null); + todo.append(uv); + uv.inst = fresh_tvar.type; + } + } + //step 2 - replace fresh tvars in their bounds + List<Type> formals = inferenceContext.inferenceVars(); + for (Type t : todo) { + UndetVar uv = (UndetVar)t; + TypeVar ct = (TypeVar)uv.inst; + ct.bound = types.glb(inferenceContext.asInstTypes(types.getBounds(ct), types)); + if (ct.bound.isErroneous()) { + //report inference error if glb fails + reportBoundError(uv, BoundErrorKind.BAD_UPPER); + } + formals = formals.tail; + } + } + + @Override + public Type instantiateMethod(Env<AttrContext> env, + List<Type> tvars, + MethodType mt, + Symbol msym, + Attr.ResultInfo resultInfo, + List<Type> argtypes, + boolean allowBoxing, + boolean useVarargs, + Resolve.MethodResolutionContext resolveContext, + Warner warn) throws InferenceException { + //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG + final InferenceContext inferenceContext = new LegacyInferenceContext(tvars, true); + + rs.checkRawArgumentsAcceptable(env, resultInfo != null ? DeferredAttr.AttrMode.CHECK : DeferredAttr.AttrMode.SPECULATIVE, inferenceContext, argtypes, mt.getParameterTypes(), + allowBoxing, useVarargs, warn, new InferenceCheckHandler(inferenceContext)); + + // minimize as yet undetermined type variables + for (Type t : inferenceContext.undetvars) { + minimizeInst((UndetVar)t, inferenceContext); + } + + checkWithinBounds(inferenceContext, warn); + + mt = (MethodType)inferenceContext.asInstType(mt, types); + + List<Type> restvars = inferenceContext.restvars(); + + if (!restvars.isEmpty() && resultInfo != null && + !warn.hasNonSilentLint(Lint.LintCategory.UNCHECKED)) { + if (resultInfo != null) { + instantiateUninferred(env.tree.pos(), inferenceContext, mt, resultInfo); + checkWithinBounds(inferenceContext, warn); + mt = (MethodType)inferenceContext.asInstType(mt, types); + inferenceContext.finish(); + if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { + log.note(env.tree.pos, "deferred.method.inst", msym, mt, resultInfo.pt); + } + } + } else if (restvars.isEmpty()) { + inferenceContext.finish(); + } + + // return instantiated version of method type + return mt; + } + + @Override + public Type inferSAM(DiagnosticPosition pos, Type samType, List<Type> paramTypes, Check.CheckContext checkContext) { + if (types.capture(samType) == samType) { + //if capture doesn't change the type then return the target unchanged + //(this means the target contains no wilddcards!) + return samType; + } else { + Type formalSam = samType.tsym.type; + InferenceContext samInferenceContext = new LegacyInferenceContext(samType.tsym.type.getTypeArguments(), 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 SAM descriptors) + List<Type> descParameterTypes = types.findDescriptor(formalSam).getParameterTypes(); + if (descParameterTypes.size() != paramTypes.size()) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + for (Type p : descParameterTypes) { + if (!types.isSameType(samInferenceContext.asFree(p, types), paramTypes.head)) { + checkContext.report(pos, diags.fragment("no.suitable.sam.inst", samType)); + return types.createErrorType(samType); + } + paramTypes = paramTypes.tail; + } + for (Type t : samInferenceContext.undetvars) { + UndetVar uv = (UndetVar)t; + minimizeInst(uv, checkContext.inferenceContext()); + if (uv.inst == null && + Type.filter(uv.getBounds(InferenceBound.UPPER), new BoundFilter(checkContext.inferenceContext())).nonEmpty()) { + maximizeInst(uv, samInferenceContext); + } + } + + formalSam = samInferenceContext.asInstType(formalSam, types); + } + ListBuffer<Type> typeargs = ListBuffer.lb(); + List<Type> actualTypeargs = samType.getTypeArguments(); + //for remaining uninferred type-vars in the SAM type, + //simply replace the wildcards with its bound + for (Type t : formalSam.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(formalSam, samInferenceContext.inferenceVars(), typeargs.toList()); + if (!chk.checkValidGenericType(owntype)) { + //if the inferred SAM 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.sam.inst", samType)); + return types.createErrorType(samType); + } + return owntype; + } + } + + /** + * Simple inference context - on-demand inference variable solving is addressed + * by instantiating at least one variable using lower bound inference + */ + class LegacyInferenceContext extends InferenceContext { + + public LegacyInferenceContext(List<Type> inferenceVars, boolean includeBounds) { + super(inferenceVars, types, includeBounds); + } + + @Override + void solveAny(List<Type> varsToSolve) { + boolean progress = false; + for (Type t : varsToSolve) { + UndetVar uv = (UndetVar)asFree(t, types); + minimizeInst(uv, this); + if (uv.inst != null) { + progress = true; + } + } + if (!progress) { + throw inferenceException.setMessage(); + } + } + } +}
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Aug 03 12:48:20 2012 +0100 @@ -33,6 +33,7 @@ import com.sun.tools.javac.comp.Check.CheckContext; import com.sun.tools.javac.comp.DeferredAttr.DeferredType; import com.sun.tools.javac.comp.Infer.InferenceContext; +import com.sun.tools.javac.comp.Infer.InferenceContext.PendingCheck; import com.sun.tools.javac.comp.Resolve.MethodResolutionContext.Candidate; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.tree.*; @@ -46,6 +47,7 @@ import java.util.Collection; import java.util.EnumMap; import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; @@ -112,7 +114,7 @@ attr = Attr.instance(context); deferredAttr = DeferredAttr.instance(context); chk = Check.instance(context); - infer = Infer.instance(context); + infer = InferFactory.instance(context).getInfer(); reader = ClassReader.instance(context); treeinfo = TreeInfo.instance(context); types = Types.instance(context); @@ -686,30 +688,33 @@ varargsAccessible(env, elt, handler, inferenceContext); } - boolean unstuckRound = false; while (!deferredTypeQueue.isEmpty()) { + List<Type> stuckVars = List.nil(); Map<DeferredType<?>, ResultInfo> todo = new LinkedHashMap<DeferredType<?>, ResultInfo>(); for (Map.Entry<DeferredType<?>, ResultInfo> e : deferredTypeQueue.entrySet()) { DeferredType<?> ptype = e.getKey(); ResultInfo mresult = e.getValue(); - mresult = mresult.dup(inferenceContext.asInstType(mresult.pt)); + mresult = mresult.dup(inferenceContext.asInstType(mresult.pt, types)); try { deferredAttr.attribDeferred(ptype, mode, mresult); } catch (DeferredAttr.StuckDeferredAttrException ex) { + for (Type t : ex.tvars) { + if (!stuckVars.contains(t)) { + stuckVars = stuckVars.prepend(t); + } + } todo.put(ptype, mresult); } } if (todo.size() == deferredTypeQueue.size()) { - if (unstuckRound) { + //instantiate a portion of the stuck vars and resume checking + try { + inferenceContext.solveAny(stuckVars); + } catch (Infer.InferenceException ex) { + //this can only happen with the legacy solver throw new Infer.InferenceException(diags).setMessage("cyclic.lambda.inference"); - } else { - //lower bound inst - inferenceContext.instantiate(warn, true, EnumSet.of(Infer.InferenceKind.LOWER)); - unstuckRound = true; - } - } else { - unstuckRound = false; + } } deferredTypeQueue = todo; } @@ -717,9 +722,9 @@ void varargsAccessible(final Env<AttrContext> env, final Type t, final Resolve.MethodCheckHandler handler, final InferenceContext inferenceContext) { if (inferenceContext.free(t)) { - inferenceContext.addPendingCheck(new Infer.PendingCheck() { + inferenceContext.addPendingCheck(new PendingCheck() { public void eval() { - varargsAccessible(env, inferenceContext.asInstType(t), handler, inferenceContext); + varargsAccessible(env, inferenceContext.asInstType(t, types), handler, inferenceContext); } }); } else { @@ -772,7 +777,7 @@ } public boolean compatible(Type found, Type req, Warner warn) { - return types.isSubtypeUnchecked(found, inferenceContext.asFree(req), warn); + return types.isSubtypeUnchecked(found, inferenceContext.asFree(req, types), warn); } public boolean allowBoxing() { @@ -791,7 +796,7 @@ } public boolean compatible(Type found, Type req, Warner warn) { - return types.isConvertible(found, inferenceContext.asFree(req), warn); + return types.isConvertible(found, inferenceContext.asFree(req, types), warn); } public boolean allowBoxing() { @@ -2143,7 +2148,7 @@ * @param typeargtypes The types of the constructor invocation's type * arguments. */ - Symbol resolveDiamond(DiagnosticPosition pos, + Pair<Symbol, Symbol> resolveDiamond(DiagnosticPosition pos, Env<AttrContext> env, Type site, List<Type> argtypes, @@ -2151,23 +2156,23 @@ MethodResolutionContext prevResolutionContext = currentResolutionContext; try { currentResolutionContext = new MethodResolutionContext(); - Symbol sym = methodNotFound; + Pair<Symbol, Symbol> res = new Pair<Symbol, Symbol>(methodNotFound, methodNotFound); List<MethodResolutionPhase> steps = methodResolutionSteps; while (steps.nonEmpty() && steps.head.isApplicable(boxingEnabled, varargsEnabled) && - sym.kind >= ERRONEOUS) { + res.fst.kind >= ERRONEOUS) { currentResolutionContext.step = steps.head; - sym = findDiamond(env, site, argtypes, typeargtypes, + res = findDiamond(env, site, argtypes, typeargtypes, steps.head.isBoxingRequired(), env.info.varArgs = steps.head.isVarargsRequired()); - currentResolutionContext.resolutionCache.put(steps.head, sym); + currentResolutionContext.resolutionCache.put(steps.head, res.fst); steps = steps.tail; } - if (sym.kind >= AMBIGUOUS) { + if (res.fst.kind >= AMBIGUOUS) { Symbol errSym = currentResolutionContext.resolutionCache.get(currentResolutionContext.firstErroneousResolutionPhase()); final JCDiagnostic details = errSym.kind == WRONG_MTH ? - ((InapplicableSymbolError)errSym).errCandidate().details : + currentResolutionContext.candidates.head.details : null; errSym = new ResolveError(WRONG_MTH, "diamond error") { @Override @@ -2181,10 +2186,10 @@ } }; MethodResolutionPhase errPhase = currentResolutionContext.firstErroneousResolutionPhase(); - sym = access(errSym, pos, site, names.init, true, argtypes, typeargtypes); + res = new Pair<Symbol, Symbol>(access(errSym, pos, site, names.init, true, argtypes, typeargtypes), res.snd); env.info.varArgs = errPhase.isVarargsRequired(); } - return sym; + return res; } finally { currentResolutionContext = prevResolutionContext; @@ -2199,13 +2204,14 @@ * inference. The inferred return type of the synthetic constructor IS * the inferred type for the diamond operator. */ - private Symbol findDiamond(Env<AttrContext> env, + private Pair<Symbol, Symbol> findDiamond(Env<AttrContext> env, Type site, List<Type> argtypes, List<Type> typeargtypes, boolean allowBoxing, boolean useVarargs) { Symbol bestSoFar = methodNotFound; + Map<Symbol, Symbol> constrMap = new HashMap<Symbol, Symbol>(); for (Scope.Entry e = site.tsym.members().lookup(names.init); e.scope != null; e = e.next()) { @@ -2217,15 +2223,17 @@ List.<Type>nil(); Type constrType = new ForAll(site.tsym.type.getTypeArguments().appendList(oldParams), types.createMethodTypeWithReturn(e.sym.type.asMethodType(), site)); + MethodSymbol newConstr = new MethodSymbol(e.sym.flags(), names.init, constrType, site.tsym); + constrMap.put(newConstr, e.sym); bestSoFar = selectBest(env, site, argtypes, typeargtypes, - new MethodSymbol(e.sym.flags(), names.init, constrType, site.tsym), + newConstr, bestSoFar, allowBoxing, useVarargs, false); } } - return bestSoFar; + return new Pair<Symbol, Symbol>(bestSoFar, constrMap.containsKey(bestSoFar) ? constrMap.get(bestSoFar) : syms.errSymbol); } /**
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Aug 03 12:48:20 2012 +0100 @@ -1638,14 +1638,6 @@ ## The following are all possible strings for the last argument of all those ## diagnostics whose key ends in ".1" -# 0: type, 1: message segment -compiler.misc.undetermined.type=\ - cannot infer type arguments for {0}\n\ - reason: {1} - -compiler.misc.type.variable.has.undetermined.type=\ - type variable {0} has undetermined type - # 0: type, 1: list of type compiler.misc.no.unique.maximal.instance.exists=\ no unique maximal instance exists for type variable {0} with upper bounds {1} @@ -1657,6 +1649,18 @@ compiler.misc.incompatible.upper.bounds=\ inference variable {0} has incompatible upper bounds {1} +# 0: type, 1: list of type, 2: list of type +compiler.misc.incompatible.eq.upper.bounds=\ + inference variable {0} has incompatible bounds\n\ + equality constraints: {1}\n\ + upper bounds: {2} + +# 0: type, 1: list of type, 2: list of type +compiler.misc.incompatible.eq.lower.bounds=\ + inference variable {0} has incompatible bounds\n\ + equality constraints: {1}\n\ + lower bounds: {2} + # 0: list of type, 1: type, 2: type compiler.misc.infer.no.conforming.instance.exists=\ no instance(s) of type variable(s) {0} exist so that {1} conforms to {2} @@ -1677,10 +1681,22 @@ (varargs mismatch; {1}) # 0: type, 1: list of type -compiler.misc.inferred.do.not.conform.to.bounds=\ - inferred type does not conform to declared bound(s)\n\ +compiler.misc.inferred.do.not.conform.to.upper.bounds=\ + inferred type does not conform to upper bound(s)\n\ inferred: {0}\n\ - bound(s): {1} + upper bound(s): {1} + +# 0: type, 1: list of type +compiler.misc.inferred.do.not.conform.to.lower.bounds=\ + inferred type does not conform to lower bound(s)\n\ + inferred: {0}\n\ + lower bound(s): {1} + +# 0: type, 1: list of type +compiler.misc.inferred.do.not.conform.to.eq.bounds=\ + inferred type does not conform to equality constraint(s)\n\ + inferred: {0}\n\ + equality constraints(s): {1} # 0: symbol compiler.misc.diamond=\
--- a/src/share/classes/com/sun/tools/javac/util/List.java Mon Jul 30 13:34:28 2012 -0700 +++ b/src/share/classes/com/sun/tools/javac/util/List.java Fri Aug 03 12:48:20 2012 +0100 @@ -131,6 +131,14 @@ xs = new List<A>(array[i], xs); return xs; } + + public static <A> List<A> from(Collection<A> coll) { + List<A> xs = nil(); + for (A a : coll) { + xs = new List<A>(a, xs); + } + return xs; + } /** Construct a list consisting of a given number of identical elements. * @param len The number of elements in the list.
--- a/test/tools/javac/6758789/T6758789b.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/6758789/T6758789b.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,4 +1,4 @@ -T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<java.lang.Object> +T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo<X> T6758789b.java:16:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6758789a.Foo<X>, T6758789a.Foo, kindname.class, T6758789a - compiler.err.warnings.and.werror 1 error
--- a/test/tools/javac/Diagnostics/6722234/T6722234b_1.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/Diagnostics/6722234/T6722234b_1.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.type.captureof: 1, ? extends T6722234b>,List<compiler.misc.type.captureof: 2, ? extends T6722234b>, kindname.class, T6722234b, (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: List<compiler.misc.type.captureof: 2, ? extends T6722234b>, List<T>)) +T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.type.captureof: 1, ? extends T6722234b>,List<compiler.misc.type.captureof: 2, ? extends T6722234b>, kindname.class, T6722234b, (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.type.captureof: 2, ? extends T6722234b, compiler.misc.type.captureof: 2, ? extends T6722234b,compiler.misc.type.captureof: 1, ? extends T6722234b) 1 error
--- a/test/tools/javac/Diagnostics/6722234/T6722234b_2.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/Diagnostics/6722234/T6722234b_2.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,4 +1,4 @@ -T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.captured.type: 1>,List<compiler.misc.captured.type: 2>, kindname.class, T6722234b, (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: List<compiler.misc.captured.type: 2>, List<T>)) +T6722234b.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, List<T>,List<T>, List<compiler.misc.captured.type: 1>,List<compiler.misc.captured.type: 2>, kindname.class, T6722234b, (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.captured.type: 2, compiler.misc.captured.type: 2,compiler.misc.captured.type: 1) - compiler.misc.where.description.typevar: T,{(compiler.misc.where.typevar: T, Object, kindname.method, <T>m(List<T>,List<T>))} - compiler.misc.where.description.captured.1: compiler.misc.captured.type: 1,compiler.misc.captured.type: 2,{(compiler.misc.where.captured.1: compiler.misc.captured.type: 1, T6722234b, compiler.misc.type.null, ? extends T6722234b),(compiler.misc.where.captured.1: compiler.misc.captured.type: 2, T6722234b, compiler.misc.type.null, ? extends T6722234b)} 1 error
--- a/test/tools/javac/Diagnostics/6799605/T6799605.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/Diagnostics/6799605/T6799605.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,4 +1,4 @@ -T6799605.java:17:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.inferred.do.not.conform.to.bounds: compiler.misc.type.captureof: 1, ?, T6799605<compiler.misc.type.captureof: 1, ?>))} -T6799605.java:18:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: T6799605<compiler.misc.type.captureof: 2, ?>, T6799605<T>))),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))} -T6799605.java:19:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,T6799605<compiler.misc.type.captureof: 3, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.inconvertible.types: T6799605<compiler.misc.type.captureof: 2, ?>, T6799605<T>))),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))} +T6799605.java:17:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.inferred.do.not.conform.to.upper.bounds: compiler.misc.type.captureof: 1, ?, T6799605<compiler.misc.type.captureof: 1, ?>))} +T6799605.java:18:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.type.captureof: 2, ?, compiler.misc.type.captureof: 2, ?,compiler.misc.type.captureof: 1, ?)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))} +T6799605.java:19:9: compiler.err.cant.apply.symbols: kindname.method, m, T6799605<compiler.misc.type.captureof: 1, ?>,T6799605<compiler.misc.type.captureof: 2, ?>,T6799605<compiler.misc.type.captureof: 3, ?>,{(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>,T6799605<T>), (compiler.misc.inferred.do.not.conform.to.eq.bounds: compiler.misc.type.captureof: 3, ?, compiler.misc.type.captureof: 3, ?,compiler.misc.type.captureof: 2, ?,compiler.misc.type.captureof: 1, ?)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>,T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.method, T6799605, <T>m(T6799605<T>), (compiler.misc.infer.arg.length.mismatch: T))} 3 errors
--- a/test/tools/javac/api/TestJavacTaskScanner.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/api/TestJavacTaskScanner.java Fri Aug 03 12:48:20 2012 +0100 @@ -41,6 +41,8 @@ import java.util.Arrays; import java.util.Stack; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; @@ -110,9 +112,13 @@ void testParseType(TypeElement clazz) { DeclaredType type = (DeclaredType)task.parseType("List<String>", clazz); for (Element member : elements.getAllMembers((TypeElement)type.asElement())) { - TypeMirror mt = types.asMemberOf(type, member); - System.out.format("%s : %s -> %s%n", member.getSimpleName(), member.asType(), mt); - numParseTypeElements++; + //exclude default methods from the count + if (member.getEnclosingElement().getKind() == ElementKind.CLASS || + member.getModifiers().contains(Modifier.ABSTRACT)) { + TypeMirror mt = types.asMemberOf(type, member); + System.out.format("%s : %s -> %s%n", member.getSimpleName(), member.asType(), mt); + numParseTypeElements++; + } } }
--- a/test/tools/javac/cast/7123100/T7123100a.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/cast/7123100/T7123100a.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,4 +1,4 @@ -T7123100a.java:14:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), compiler.misc.type.captureof: 1, ?, Z +T7123100a.java:14:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), E, Z - compiler.err.warnings.and.werror 1 error 1 warning
--- a/test/tools/javac/defender/Pos01.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/defender/Pos01.java Fri Aug 03 12:48:20 2012 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -37,7 +37,7 @@ } interface ExtendedList<T> extends List<T> { - List<T> map(Mapper<T> r) default { + List<T> testMap(Mapper<T> r) default { return Pos01.<T>listMapper(this, r); } } @@ -47,7 +47,7 @@ public static void main(String[] args) { MyList<Integer> l = new MyList<Integer>(); l.add(1); l.add(2); l.add(3); - l.map((Integer x) -> x * x ); + l.testMap((Integer x) -> x * x ); } static <T> List<T> listMapper(List<T> l, Mapper<T> mapper) {
--- a/test/tools/javac/diags/examples.not-yet.txt Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/diags/examples.not-yet.txt Fri Aug 03 12:48:20 2012 +0100 @@ -62,6 +62,7 @@ compiler.misc.kindname.type.variable compiler.misc.kindname.type.variable.bound compiler.misc.kindname.value +compiler.misc.incompatible.eq.lower.bounds # cannot happen? compiler.misc.no.unique.minimal.instance.exists compiler.misc.resume.abort # prompt for a response compiler.misc.source.unavailable # DiagnosticSource @@ -77,10 +78,8 @@ compiler.misc.type.captureof.1 compiler.misc.type.none compiler.misc.type.req.exact -compiler.misc.type.variable.has.undetermined.type compiler.misc.unable.to.access.file # ClassFile compiler.misc.undecl.type.var # ClassReader -compiler.misc.undetermined.type compiler.misc.unicode.str.not.supported # ClassReader compiler.misc.verbose.retro # UNUSED compiler.misc.verbose.retro.with # UNUSED
--- a/test/tools/javac/diags/examples/CantApplyDiamond1.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/diags/examples/CantApplyDiamond1.java Fri Aug 03 12:48:20 2012 +0100 @@ -23,7 +23,7 @@ // key: compiler.err.prob.found.req // key: compiler.misc.cant.apply.diamond.1 -// key: compiler.misc.infer.no.conforming.instance.exists +// key: compiler.misc.inferred.do.not.conform.to.upper.bounds // key: compiler.misc.diamond class CantApplyDiamond1<X> {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/diags/examples/IncompatibleEqUpperBounds.java Fri Aug 03 12:48:20 2012 +0100 @@ -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.apply.symbol.1 +//key: compiler.misc.incompatible.eq.upper.bounds + +import java.util.List; + +class IncompatibleEqUpperBounds { + <S, T extends List<S>> void m(List<? super S> s1, T s2) { } + + void test(List<Integer> li, List<String> ls) { + m(li, ls); + } +}
--- a/test/tools/javac/diags/examples/IncompatibleTypes1.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/diags/examples/IncompatibleTypes1.java Fri Aug 03 12:48:20 2012 +0100 @@ -21,13 +21,13 @@ * questions. */ +// key: compiler.err.prob.found.req // key: compiler.misc.infer.no.conforming.instance.exists -// key: compiler.err.prob.found.req class IncompatibleTypes1<V> { - <T extends Integer & Runnable> IncompatibleTypes1<T> m() { + <T> IncompatibleTypes1<Integer> m() { return null; } - IncompatibleTypes1<? super String> o = m(); + IncompatibleTypes1<? extends String> o = m(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/diags/examples/InferNoConformingAssignment.java Fri Aug 03 12:48:20 2012 +0100 @@ -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.apply.symbol.1 +// key: compiler.misc.inconvertible.types +// key: compiler.misc.infer.no.conforming.assignment.exists + +import java.util.*; + +class InferNoConformingAssignment { + <X extends Number> List<X> m(String s) { return null; } + { this.m(1); } +} +
--- a/test/tools/javac/diags/examples/InferredDoNotConformToBounds.java Mon Jul 30 13:34:28 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2010, 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.misc.inferred.do.not.conform.to.bounds -// key: compiler.err.cant.apply.diamond.1 -// key: compiler.misc.diamond - -class InferredDoNotConformToBounds { - static class SuperFoo<X> {} - static class Foo<X extends Number> extends SuperFoo<X> { - Foo(X x) {} - } - - SuperFoo<String> sf1 = new Foo<>(""); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/diags/examples/InferredDoNotConformToEq.java Fri Aug 03 12:48:20 2012 +0100 @@ -0,0 +1,32 @@ +/* + * 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.apply.symbol.1 +// key: compiler.misc.inferred.do.not.conform.to.eq.bounds + +import java.util.*; + +class InferredDoNotConformToEq { + <X> void m(List<X> lx1, List<X> lx2) {} + { this.m(Arrays.asList(""), Arrays.asList(1)); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/diags/examples/InferredDoNotConformToLower.java Fri Aug 03 12:48:20 2012 +0100 @@ -0,0 +1,32 @@ +/* + * 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.inferred.do.not.conform.to.lower.bounds + +import java.util.*; + +class InferredDoNotConformToLower { + <X extends Number> List<X> m() { return null; } + { List<? super String> lss = this.m(); } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/diags/examples/InferredDoNotConformToUpper.java Fri Aug 03 12:48:20 2012 +0100 @@ -0,0 +1,32 @@ +/* + * 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.apply.symbol.1 +// key: compiler.misc.inferred.do.not.conform.to.upper.bounds + +import java.util.*; + +class InferredDoNotConformToUpper { + <X> void m(X x, List<? super X> lx) {} + { this.m("", Arrays.asList(1)); } +}
--- a/test/tools/javac/diags/examples/WhereCaptured.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/diags/examples/WhereCaptured.java Fri Aug 03 12:48:20 2012 +0100 @@ -26,8 +26,7 @@ // key: compiler.misc.where.description.typevar // key: compiler.misc.where.typevar // key: compiler.err.cant.apply.symbol.1 -// key: compiler.misc.infer.no.conforming.assignment.exists -// key: compiler.misc.inconvertible.types +// key: compiler.misc.inferred.do.not.conform.to.eq.bounds // key: compiler.misc.captured.type // options: -XDdiags=where,simpleNames // run: simple
--- a/test/tools/javac/diags/examples/WhereCaptured1.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/diags/examples/WhereCaptured1.java Fri Aug 03 12:48:20 2012 +0100 @@ -26,8 +26,7 @@ // key: compiler.misc.where.description.typevar // key: compiler.misc.where.typevar // key: compiler.err.cant.apply.symbol.1 -// key: compiler.misc.infer.no.conforming.assignment.exists -// key: compiler.misc.inconvertible.types +// key: compiler.misc.inferred.do.not.conform.to.eq.bounds // key: compiler.misc.captured.type // key: compiler.misc.type.null // options: -XDdiags=where,simpleNames
--- a/test/tools/javac/generics/7015430/T7015430.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/7015430/T7015430.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,14 +1,14 @@ -T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception> +T7015430.java:41:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E> T7015430.java:41:14: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430 T7015430.java:50:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException> T7015430.java:50:41: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception> +T7015430.java:68:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E> T7015430.java:68:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430 T7015430.java:77:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException> T7015430.java:77:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430 T7015430.java:104:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.RuntimeException> T7015430.java:104:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<java.lang.Exception> +T7015430.java:113:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable<E> T7015430.java:113:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, <init>, java.lang.Iterable<E>, java.lang.Iterable, kindname.class, T7015430 T7015430.java:41:14: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception T7015430.java:68:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
--- a/test/tools/javac/generics/7151802/T7151802.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/7151802/T7151802.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,5 +1,5 @@ T7151802.java:14:31: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get1, Z, T7151802.Foo, kindname.class, T7151802 -T7151802.java:22:31: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo<java.lang.Object> +T7151802.java:22:31: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo<Z> T7151802.java:22:30: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get3, T7151802.Foo<Z>, T7151802.Foo, kindname.class, T7151802 T7151802.java:30:36: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get5, compiler.misc.no.args, compiler.misc.no.args, kindname.class, T7151802 T7151802.java:38:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo<java.lang.String>
--- a/test/tools/javac/generics/diamond/neg/Neg06.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/diamond/neg/Neg06.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -Neg06.java:16:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.infer.no.conforming.instance.exists: X, Neg06.CFoo<X>, Neg06.CSuperFoo<java.lang.String>)) +Neg06.java:16:37: compiler.err.prob.found.req: (compiler.misc.cant.apply.diamond.1: (compiler.misc.diamond: Neg06.CFoo), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number)) 1 error
--- a/test/tools/javac/generics/diamond/neg/Neg07.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/diamond/neg/Neg07.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -Neg07.java:17:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.String, java.lang.Number) +Neg07.java:17:27: compiler.err.cant.apply.diamond.1: (compiler.misc.diamond: Neg07.Foo), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.String, java.lang.Number) 1 error
--- a/test/tools/javac/generics/diamond/neg/Neg10.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/diamond/neg/Neg10.java Fri Aug 03 12:48:20 2012 +0100 @@ -5,6 +5,7 @@ * @summary Check that 'complex' diamond can infer type that is too specific * @author mcimadamore * @compile/fail/ref=Neg10.out Neg10.java -XDrawDiagnostics + * @compile Neg10.java -XDuseGraphInference -XDrawDiagnostics * */
--- a/test/tools/javac/generics/diamond/neg/Neg10.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/diamond/neg/Neg10.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -Neg10.java:16:22: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>) +Neg10.java:17:22: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Neg10.Foo<java.lang.Integer>, Neg10.Foo<java.lang.Number>) 1 error
--- a/test/tools/javac/generics/inference/6315770/T6315770.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/6315770/T6315770.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,3 +1,3 @@ T6315770.java:16:42: compiler.err.prob.found.req: (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable) -T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.instance.exists: T, T6315770<T>, T6315770<? super java.lang.String>) +T6315770.java:17:40: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer&java.lang.Runnable, java.lang.String) 2 errors
--- a/test/tools/javac/generics/inference/6611449/T6611449.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/6611449/T6611449.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,5 +1,5 @@ -T6611449.java:18:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S))} -T6611449.java:19:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.infer.arg.length.mismatch: T))} -T6611449.java:20:9: compiler.err.cant.apply.symbol.1: kindname.method, m1, T, int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S) -T6611449.java:21:9: compiler.err.cant.apply.symbol.1: kindname.method, m2, T,T, int,int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.bounds: java.lang.Integer, S) +T6611449.java:18:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.infer.arg.length.mismatch: T)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S))} +T6611449.java:19:9: compiler.err.cant.apply.symbols: kindname.constructor, T6611449, int,int,{(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T,T), (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S)),(compiler.misc.inapplicable.method: kindname.constructor, T6611449, <T>T6611449(T), (compiler.misc.infer.arg.length.mismatch: T))} +T6611449.java:20:9: compiler.err.cant.apply.symbol.1: kindname.method, m1, T, int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S) +T6611449.java:21:9: compiler.err.cant.apply.symbol.1: kindname.method, m2, T,T, int,int, kindname.class, T6611449<S>, (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, S) 4 errors
--- a/test/tools/javac/generics/inference/6638712/T6638712b.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/6638712/T6638712b.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.instance.exists: T, T, java.lang.String) +T6638712b.java:14:21: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Integer, java.lang.String,java.lang.Object) 1 error
--- a/test/tools/javac/generics/inference/6638712/T6638712d.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/6638712/T6638712d.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -T6638712d.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, U,java.util.List<java.util.List<U>>, int,java.util.List<java.util.List<java.lang.String>>, kindname.class, T6638712d, (compiler.misc.infer.no.conforming.assignment.exists: U, (compiler.misc.inconvertible.types: int, java.lang.String)) +T6638712d.java:16:9: compiler.err.cant.apply.symbol.1: kindname.method, m, U,java.util.List<java.util.List<U>>, int,java.util.List<java.util.List<java.lang.String>>, kindname.class, T6638712d, (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.String, java.lang.Integer) 1 error
--- a/test/tools/javac/generics/inference/6638712/T6638712e.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/6638712/T6638712e.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.instance.exists: X, T6638712e.Foo<X,java.lang.String>, T6638712e.Foo<java.lang.Object,java.lang.String>) +T6638712e.java:17:27: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.upper.bounds: java.lang.Object, java.lang.Boolean,java.lang.Object) 1 error
--- a/test/tools/javac/generics/inference/6650759/T6650759m.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/6650759/T6650759m.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List<compiler.misc.type.captureof: 1, ? super java.lang.Integer>, java.util.List<? super java.lang.String>) +T6650759m.java:43:36: compiler.err.prob.found.req: (compiler.misc.inferred.do.not.conform.to.lower.bounds: java.lang.Integer, java.lang.String) 1 error
--- a/test/tools/javac/generics/inference/7086601/T7086601a.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/generics/inference/7086601/T7086601a.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,5 +1,5 @@ -T7086601a.java:20:9: compiler.err.cant.apply.symbols: kindname.method, m1, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m1(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m1(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String))} -T7086601a.java:24:9: compiler.err.cant.apply.symbols: kindname.method, m2, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m2(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m2(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String))} -T7086601a.java:28:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String) -T7086601a.java:32:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String) +T7086601a.java:20:9: compiler.err.cant.apply.symbols: kindname.method, m1, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m1(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m1(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String,java.lang.Object))} +T7086601a.java:24:9: compiler.err.cant.apply.symbols: kindname.method, m2, java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>,{(compiler.misc.inapplicable.method: kindname.method, T7086601, m2(java.lang.Object), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, T7086601, <S>m2(java.lang.Iterable<? super S>,java.lang.Iterable<? super S>,java.lang.Iterable<? super S>), (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String,java.lang.Object))} +T7086601a.java:28:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Integer,java.lang.String,java.lang.Object) +T7086601a.java:32:9: compiler.err.cant.apply.symbol.1: kindname.method, m3, java.lang.Iterable<? super S>[], java.lang.Iterable<java.lang.String>,java.lang.Iterable<java.lang.Integer>,java.lang.Iterable<java.lang.Double>, kindname.class, T7086601, (compiler.misc.incompatible.upper.bounds: S, java.lang.Double,java.lang.Integer,java.lang.String,java.lang.Object) 4 errors
--- a/test/tools/javac/lambda/TargetType10.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/lambda/TargetType10.java Fri Aug 03 12:48:20 2012 +0100 @@ -26,6 +26,7 @@ * @summary check that wildcards in the target method of a lambda conversion is handled correctly * @author Maurizio Cimadamore * @compile/fail/ref=TargetType10.out -XDrawDiagnostics TargetType10.java + * @compile -XDuseGraphInference -XDrawDiagnostics TargetType10.java */ class TargetType10 {
--- a/test/tools/javac/lambda/TargetType10.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/lambda/TargetType10.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -TargetType10.java:38:11: compiler.err.cant.apply.symbol.1: kindname.method, compose, TargetType10.Function<B,C>,TargetType10.Function<A,? extends B>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType10.Test, (compiler.misc.cyclic.lambda.inference) +TargetType10.java:39:11: compiler.err.cant.apply.symbol.1: kindname.method, compose, TargetType10.Function<B,C>,TargetType10.Function<A,? extends B>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType10.Test, (compiler.misc.cyclic.lambda.inference) 1 error
--- a/test/tools/javac/lambda/TargetType20.java Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/lambda/TargetType20.java Fri Aug 03 12:48:20 2012 +0100 @@ -26,6 +26,7 @@ * @summary complex case of lambda return type that depends on generic method * inference variable * @compile/fail/ref=TargetType20.out -XDrawDiagnostics TargetType20.java + * @compile -XDuseGraphInference -XDrawDiagnostics TargetType20.java */ import java.util.*;
--- a/test/tools/javac/lambda/TargetType20.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/lambda/TargetType20.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -TargetType20.java:40:10: compiler.err.cant.apply.symbol.1: kindname.method, call, TargetType20.SAM2<Z>,TargetType20.SAM2<Z>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType20.Test, (compiler.misc.infer.no.conforming.assignment.exists: Z, (compiler.misc.infer.incompatible.ret.types.in.lambda: (compiler.misc.inconvertible.types: java.util.ArrayList<java.lang.String>, java.util.List<Z>))) +TargetType20.java:41:10: compiler.err.cant.apply.symbol.1: kindname.method, call, TargetType20.SAM2<Z>,TargetType20.SAM2<Z>, compiler.misc.type.lambda,compiler.misc.type.lambda, kindname.class, TargetType20.Test, (compiler.misc.inferred.do.not.conform.to.eq.bounds: java.lang.String, java.lang.String,java.lang.Object) 1 error
--- a/test/tools/javac/multicatch/Neg07.out Mon Jul 30 13:34:28 2012 -0700 +++ b/test/tools/javac/multicatch/Neg07.out Fri Aug 03 12:48:20 2012 +0100 @@ -1,2 +1,2 @@ -Neg07.java:14:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Class<compiler.misc.type.captureof: 1, ? extends Neg07.ParentException>, java.lang.Class<? extends Neg07.HasFoo>) +Neg07.java:14:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Class<? extends Neg07.ParentException>, java.lang.Class<? extends Neg07.HasFoo>) 1 error