diff -r b4b0377b8dba -r c7ec7facdd20 langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Thu Oct 04 13:04:53 2012 +0100 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java Fri Oct 05 14:35:24 2012 +0100 @@ -274,7 +274,7 @@ Resolve.MethodResolutionContext resolveContext, Warner warn) throws InferenceException { //-System.err.println("instantiateMethod(" + tvars + ", " + mt + ", " + argtypes + ")"); //DEBUG - final InferenceContext inferenceContext = new InferenceContext(tvars, this); + final InferenceContext inferenceContext = new InferenceContext(tvars, this, true); inferenceException.clear(); try { @@ -467,6 +467,75 @@ throw bk.setMessage(inferenceException, uv); } + // + /** + * This method is used to infer a suitable target functional interface in case + * the original parameterized interface contains wildcards. An inference process + * is applied so that wildcard bounds, as well as explicit lambda/method ref parameters + * (where applicable) are used to constraint the solution. + */ + public Type instantiateFunctionalInterface(DiagnosticPosition pos, Type funcInterface, + List paramTypes, Check.CheckContext checkContext) { + if (types.capture(funcInterface) == funcInterface) { + //if capture doesn't change the type then return the target unchanged + //(this means the target contains no wildcards!) + return funcInterface; + } else { + Type formalInterface = funcInterface.tsym.type; + InferenceContext funcInterfaceContext = + new InferenceContext(funcInterface.tsym.type.getTypeArguments(), this, false); + if (paramTypes != null) { + //get constraints from explicit params (this is done by + //checking that explicit param types are equal to the ones + //in the functional interface descriptors) + List descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes(); + if (descParameterTypes.size() != paramTypes.size()) { + checkContext.report(pos, diags.fragment("incompatible.arg.types.in.lambda")); + return types.createErrorType(funcInterface); + } + for (Type p : descParameterTypes) { + if (!types.isSameType(funcInterfaceContext.asFree(p, types), paramTypes.head)) { + checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface)); + return types.createErrorType(funcInterface); + } + paramTypes = paramTypes.tail; + } + for (Type t : funcInterfaceContext.undetvars) { + UndetVar uv = (UndetVar)t; + minimizeInst(uv, Warner.noWarnings); + if (uv.inst == null && + Type.filter(uv.getBounds(InferenceBound.UPPER), boundFilter).nonEmpty()) { + maximizeInst(uv, Warner.noWarnings); + } + } + + formalInterface = funcInterfaceContext.asInstType(formalInterface, types); + } + ListBuffer typeargs = ListBuffer.lb(); + List actualTypeargs = funcInterface.getTypeArguments(); + //for remaining uninferred type-vars in the functional interface type, + //simply replace the wildcards with its bound + for (Type t : formalInterface.getTypeArguments()) { + if (actualTypeargs.head.tag == WILDCARD) { + WildcardType wt = (WildcardType)actualTypeargs.head; + typeargs.append(wt.type); + } else { + typeargs.append(actualTypeargs.head); + } + actualTypeargs = actualTypeargs.tail; + } + Type owntype = types.subst(formalInterface, funcInterfaceContext.inferenceVars(), typeargs.toList()); + if (!chk.checkValidGenericType(owntype)) { + //if the inferred functional interface type is not well-formed, + //or if it's not a subtype of the original target, issue an error + checkContext.report(pos, diags.fragment("no.suitable.functional.intf.inst", funcInterface)); + return types.createErrorType(funcInterface); + } + return owntype; + } + } + // + /** * Compute a synthetic method type corresponding to the requested polymorphic * method signature. The target return type is computed from the immediately @@ -536,9 +605,17 @@ * Mapping that turns inference variables into undet vars * (used by inference context) */ - Mapping fromTypeVarFun = new Mapping("fromTypeVarFun") { + class FromTypeVarFun extends Mapping { + + boolean includeBounds; + + FromTypeVarFun(boolean includeBounds) { + super("fromTypeVarFunWithBounds"); + this.includeBounds = includeBounds; + } + public Type apply(Type t) { - if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types); + if (t.tag == TYPEVAR) return new UndetVar((TypeVar)t, types, includeBounds); else return t.map(this); } }; @@ -573,8 +650,8 @@ List freetypeListeners = List.nil(); - public InferenceContext(List inferencevars, Infer infer) { - this.undetvars = Type.map(inferencevars, infer.fromTypeVarFun); + public InferenceContext(List inferencevars, Infer infer, boolean includeBounds) { + this.undetvars = Type.map(inferencevars, infer.new FromTypeVarFun(includeBounds)); this.inferencevars = inferencevars; } @@ -737,5 +814,5 @@ } } - final InferenceContext emptyContext = new InferenceContext(List.nil(), this); + final InferenceContext emptyContext = new InferenceContext(List.nil(), this, false); }