# HG changeset patch # User mcimadamore # Date 1360945798 0 # Node ID 0c291a3cd60d3547e20887c9074cd4e94cdeccdb # Parent bf5e87940aee61651babe2b7cac9991e1e375a3c 8007462: Fix provisional applicability for method references Summary: Add speculative arity-based check to rule out potential candidates when stuck reference is passed to method Reviewed-by: jjg diff -r bf5e87940aee -r 0c291a3cd60d langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Feb 15 16:28:57 2013 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Fri Feb 15 16:29:58 2013 +0000 @@ -2532,8 +2532,7 @@ try { //attribute member reference qualifier - if this is a constructor //reference, the expected kind must be a type - Type exprType = attribTree(that.expr, - env, new ResultInfo(that.getMode() == ReferenceMode.INVOKE ? VAL | TYP : TYP, Type.noType)); + Type exprType = attribTree(that.expr, env, memberReferenceQualifierResult(that)); if (that.getMode() == JCMemberReference.ReferenceMode.NEW) { exprType = chk.checkConstructorRefType(that.expr, exprType); @@ -2688,6 +2687,12 @@ return; } } + //where + ResultInfo memberReferenceQualifierResult(JCMemberReference tree) { + //if this is a constructor reference, the expected kind must be a type + return new ResultInfo(tree.getMode() == ReferenceMode.INVOKE ? VAL | TYP : TYP, Type.noType); + } + @SuppressWarnings("fallthrough") void checkReferenceCompatible(JCMemberReference tree, Type descriptor, Type refType, CheckContext checkContext, boolean speculativeAttr) { diff -r bf5e87940aee -r 0c291a3cd60d langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Feb 15 16:28:57 2013 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Fri Feb 15 16:29:58 2013 +0000 @@ -68,6 +68,7 @@ final JCDiagnostic.Factory diags; final Enter enter; final Infer infer; + final Resolve rs; final Log log; final Symtab syms; final TreeMaker make; @@ -87,6 +88,7 @@ diags = JCDiagnostic.Factory.instance(context); enter = Enter.instance(context); infer = Infer.instance(context); + rs = Resolve.instance(context); log = Log.instance(context); syms = Symtab.instance(context); make = TreeMaker.instance(context); @@ -463,10 +465,12 @@ ResultInfo resultInfo; InferenceContext inferenceContext; + Env env; public Type complete(DeferredType dt, ResultInfo resultInfo, DeferredAttrContext deferredAttrContext) { this.resultInfo = resultInfo; this.inferenceContext = deferredAttrContext.inferenceContext; + this.env = dt.env.dup(dt.tree, dt.env.info.dup()); dt.tree.accept(this); dt.speculativeCache.put(deferredAttrContext.msym, stuckTree, deferredAttrContext.phase); return Type.noType; @@ -511,12 +515,30 @@ return; } else { try { - //TODO: we should speculative determine if there's a match - //based on arity - if yes, method is applicable. types.findDescriptorType(pt); } catch (Types.FunctionDescriptorLookupError ex) { checkContext.report(null, ex.getDiagnostic()); } + JCExpression exprTree = (JCExpression)attribSpeculative(tree.getQualifierExpression(), env, + attr.memberReferenceQualifierResult(tree)); + ListBuffer argtypes = ListBuffer.lb(); + for (Type t : types.findDescriptorType(pt).getParameterTypes()) { + argtypes.append(syms.errType); + } + JCMemberReference mref2 = new TreeCopier(make).copy(tree); + mref2.expr = exprTree; + Pair lookupRes = + rs.resolveMemberReference(tree, env, mref2, exprTree.type, tree.name, argtypes.toList(), null, true); + switch (lookupRes.fst.kind) { + //note: as argtypes are erroneous types, type-errors must + //have been caused by arity mismatch + case Kinds.ABSENT_MTH: + case Kinds.WRONG_MTH: + case Kinds.WRONG_MTHS: + case Kinds.STATICERR: + case Kinds.MISSING_ENCL: + checkContext.report(null, diags.fragment("incompatible.arg.types.in.mref")); + } } } } diff -r bf5e87940aee -r 0c291a3cd60d langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Feb 15 16:28:57 2013 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Fri Feb 15 16:29:58 2013 +0000 @@ -2501,10 +2501,10 @@ //merge results Pair res; - if (unboundSym.kind != MTH) { + if (!lookupSuccess(unboundSym)) { res = new Pair(boundSym, boundLookupHelper); env.info.pendingResolutionPhase = boundEnv.info.pendingResolutionPhase; - } else if (boundSym.kind == MTH) { + } else if (lookupSuccess(boundSym)) { res = new Pair(ambiguityError(boundSym, unboundSym), boundLookupHelper); env.info.pendingResolutionPhase = boundEnv.info.pendingResolutionPhase; } else { @@ -2514,6 +2514,10 @@ return res; } + //private + boolean lookupSuccess(Symbol s) { + return s.kind == MTH || s.kind == AMBIGUOUS; + } /** * Helper for defining custom method-like lookup logic; a lookup helper @@ -2706,9 +2710,11 @@ UnboundMethodReferenceLookupHelper(JCMemberReference referenceTree, Name name, Type site, List argtypes, List typeargtypes, MethodResolutionPhase maxPhase) { - super(referenceTree, name, - site.isRaw() ? types.asSuper(argtypes.head, site.tsym) : site, - argtypes.tail, typeargtypes, maxPhase); + super(referenceTree, name, site, argtypes.tail, typeargtypes, maxPhase); + Type asSuperSite = types.asSuper(argtypes.head, site.tsym); + if (site.isRaw() && !asSuperSite.isErroneous()) { + this.site = asSuperSite; + } } @Override diff -r bf5e87940aee -r 0c291a3cd60d langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Feb 15 16:28:57 2013 +0000 +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Feb 15 16:29:58 2013 +0000 @@ -724,6 +724,9 @@ compiler.misc.incompatible.arg.types.in.lambda=\ incompatible parameter types in lambda expression +compiler.misc.incompatible.arg.types.in.mref=\ + incompatible parameter types in method reference + compiler.err.new.not.allowed.in.annotation=\ ''new'' not allowed in an annotation diff -r bf5e87940aee -r 0c291a3cd60d langtools/test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/diags/examples/IncompatibleArgTypesInMethodRef.java Fri Feb 15 16:29:58 2013 +0000 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013, 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 +// key: compiler.misc.infer.no.conforming.assignment.exists +// key: compiler.misc.incompatible.arg.types.in.mref + +class IncompatibleArgTypesInMethodRef { + interface SAM { + void m(X x); + } + + void g(String s, Integer i) { } + + void m(SAM s) { } + + void test() { + m(this::g); + } +} diff -r bf5e87940aee -r 0c291a3cd60d langtools/test/tools/javac/lambda/TargetType60.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/TargetType60.java Fri Feb 15 16:29:58 2013 +0000 @@ -0,0 +1,51 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8007462 + * @summary Fix provisional applicability for method references + * @compile/fail/ref=TargetType60.out -XDrawDiagnostics TargetType60.java + */ +class TargetType60 { + + interface Sam0 { + void m(); + } + + interface Sam1 { + void m(X x); + } + + interface Sam2 { + void m(X x, Y y); + } + + void m0() { } + void m1(String s) { } + void m2(String s1, String s2) { } + + void m01() { } + void m01(String s) { } + + void m012() { } + void m012(String s) { } + void m012(String s1, String s2) { } + + static String g(Sam0 s) { return null; } + static U g(Sam1 s) { return null; } + static U g(Sam2 s) { return null; } + + void testBound() { + String s1 = g(this::m0); //ok - resolves to g(Sam0) + String s2 = g(this::m1); //ok - resolves to g(Sam1) + String s3 = g(this::m2); //ok - resolves to g(Sam2) + String s4 = g(this::m01);//ambiguous (g(Sam0), g(Sam1) apply) + String s5 = g(this::m012);//ambiguous (g(Sam0), g(Sam1), g(Sam2) apply) + } + + static void testUnbound() { + TargetType60 s1 = g(TargetType60::m0); //ok - resolves to g(Sam1) + TargetType60 s2 = g(TargetType60::m1); //ok - resolves to g(Sam2) + TargetType60 s3 = g(TargetType60::m2); //none is applicable + TargetType60 s4 = g(TargetType60::m01);//ambiguous (g(Sam1), g(Sam2) apply) + TargetType60 s5 = g(TargetType60::m012);//ambiguous (g(Sam1), g(Sam2) apply) + } +} diff -r bf5e87940aee -r 0c291a3cd60d langtools/test/tools/javac/lambda/TargetType60.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/TargetType60.out Fri Feb 15 16:29:58 2013 +0000 @@ -0,0 +1,6 @@ +TargetType60.java:40:21: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType60.Sam0), TargetType60, kindname.method, g(TargetType60.Sam1), TargetType60 +TargetType60.java:41:21: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType60.Sam1), TargetType60, kindname.method, g(TargetType60.Sam2), TargetType60 +TargetType60.java:47:27: compiler.err.cant.apply.symbols: kindname.method, g, @1308,{(compiler.misc.inapplicable.method: kindname.method, TargetType60, g(TargetType60.Sam0), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.invalid.mref: kindname.method, (compiler.misc.cant.apply.symbol: kindname.method, m2, java.lang.String,java.lang.String, compiler.misc.no.args, kindname.class, TargetType60, (compiler.misc.arg.length.mismatch))))),(compiler.misc.inapplicable.method: kindname.method, TargetType60, g(TargetType60.Sam1), (compiler.misc.infer.no.conforming.assignment.exists: U, (compiler.misc.incompatible.arg.types.in.mref))),(compiler.misc.inapplicable.method: kindname.method, TargetType60, g(TargetType60.Sam2), (compiler.misc.infer.no.conforming.assignment.exists: U, (compiler.misc.incompatible.arg.types.in.mref)))} +TargetType60.java:48:27: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType60.Sam1), TargetType60, kindname.method, g(TargetType60.Sam2), TargetType60 +TargetType60.java:49:27: compiler.err.ref.ambiguous: g, kindname.method, g(TargetType60.Sam1), TargetType60, kindname.method, g(TargetType60.Sam2), TargetType60 +5 errors