8004101: Add checks for method reference well-formedness

Bring method reference type-checking in sync with latest EDR

Reviewed-by: jjg
This commit is contained in:
Maurizio Cimadamore 2012-11-30 15:14:36 +00:00
parent 0db60b7bb2
commit c76c08e82a
15 changed files with 195 additions and 57 deletions

View File

@ -2458,7 +2458,7 @@ public class Attr extends JCTree.Visitor {
}
//attrib type-arguments
List<Type> typeargtypes = null;
List<Type> typeargtypes = List.nil();
if (that.typeargs != null) {
typeargtypes = attribTypes(that.typeargs, localEnv);
}
@ -2528,6 +2528,26 @@ public class Attr extends JCTree.Visitor {
}
}
if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
if (refSym.isStatic() && TreeInfo.isStaticSelector(that.expr, names) &&
exprType.getTypeArguments().nonEmpty()) {
//static ref with class type-args
log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
diags.fragment("static.mref.with.targs"));
result = that.type = types.createErrorType(target);
return;
}
if (refSym.isStatic() && !TreeInfo.isStaticSelector(that.expr, names) &&
!lookupHelper.referenceKind(refSym).isUnbound()) {
//no static bound mrefs
log.error(that.expr.pos(), "invalid.mref", Kinds.kindName(that.getMode()),
diags.fragment("static.bound.mref"));
result = that.type = types.createErrorType(target);
return;
}
}
if (desc.getReturnType() == Type.recoveryType) {
// stop here
result = that.type = target;

View File

@ -288,21 +288,20 @@ public class LambdaToMethod extends TreeTranslator {
JCExpression init;
switch(tree.kind) {
case IMPLICIT_INNER: /** Inner # new */
case SUPER: /** super # instMethod */
case IMPLICIT_INNER: /** Inner :: new */
case SUPER: /** super :: instMethod */
init = makeThis(
localContext.owner.owner.asType(),
localContext.owner);
break;
case BOUND: /** Expr # instMethod */
case BOUND: /** Expr :: instMethod */
init = tree.getQualifierExpression();
break;
case STATIC_EVAL: /** Expr # staticMethod */
case UNBOUND: /** Type # instMethod */
case STATIC: /** Type # staticMethod */
case TOPLEVEL: /** Top level # new */
case UNBOUND: /** Type :: instMethod */
case STATIC: /** Type :: staticMethod */
case TOPLEVEL: /** Top level :: new */
init = null;
break;
@ -315,14 +314,6 @@ public class LambdaToMethod extends TreeTranslator {
//build a sam instance using an indy call to the meta-factory
result = makeMetaFactoryIndyCall(tree, tree.targetType, localContext.referenceKind(), refSym, indy_args);
//if we had a static reference with non-static qualifier, add a let
//expression to force the evaluation of the qualifier expr
if (tree.hasKind(ReferenceKind.STATIC_EVAL)) {
VarSymbol rec = new VarSymbol(0, names.fromString("rec$"), tree.getQualifierExpression().type, localContext.owner);
JCVariableDecl recDef = make.VarDef(rec, tree.getQualifierExpression());
result = make.LetExpr(recDef, result).setType(tree.type);
}
}
/**

View File

@ -2617,8 +2617,7 @@ public class Resolve {
@Override
ReferenceKind referenceKind(Symbol sym) {
if (sym.isStatic()) {
return TreeInfo.isStaticSelector(referenceTree.expr, names) ?
ReferenceKind.STATIC : ReferenceKind.STATIC_EVAL;
return ReferenceKind.STATIC;
} else {
Name selName = TreeInfo.name(referenceTree.getQualifierExpression());
return selName != null && selName == names._super ?

View File

@ -215,6 +215,12 @@ compiler.err.invalid.mref=\
compiler.misc.invalid.mref=\
invalid {0} reference; {1}
compiler.misc.static.mref.with.targs=\
parameterized qualifier on static method reference
compiler.misc.static.bound.mref=\
static bound method reference
# 0: symbol
compiler.err.cant.assign.val.to.final.var=\
cannot assign a value to final variable {0}

View File

@ -1829,8 +1829,6 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
STATIC(ReferenceMode.INVOKE, false),
/** Expr # instMethod */
BOUND(ReferenceMode.INVOKE, false),
/** Expr # staticMethod */
STATIC_EVAL(ReferenceMode.INVOKE, false),
/** Inner # new */
IMPLICIT_INNER(ReferenceMode.NEW, false),
/** Toplevel # new */

View File

@ -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.invalid.mref
// key: compiler.misc.static.bound.mref
class StaticBoundMref {
Runnable r = new StaticBoundMref()::m;
static void m() { }
}

View File

@ -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.invalid.mref
// key: compiler.misc.static.mref.with.targs
class StaticMrefWithTargs<X> {
Runnable r = StaticMrefWithTargs<String>::m;
static void m() { }
}

View File

@ -46,7 +46,7 @@ public class MethodReference30 {
assertTrue(true);
}
static void m() { }
void m() { }
public static void main(String[] args) {
SAM s = new MethodReference30()::m;

View File

@ -0,0 +1,45 @@
/*
* 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.
*/
/*
* @test
* @bug 8004101
* @summary Add checks for method reference well-formedness
* @compile/fail/ref=MethodReference55.out -XDrawDiagnostics MethodReference55.java
*/
class MethodReference55<X> {
interface V {
void m(Object o);
}
V v = new MethodReference55<String>()::m;
void test() {
g(new MethodReference55<String>()::m);
}
void g(V v) { }
static void m(Object o) { };
}

View File

@ -0,0 +1,3 @@
MethodReference55.java:36:11: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.bound.mref)
MethodReference55.java:39:11: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.bound.mref)
2 errors

View File

@ -0,0 +1,45 @@
/*
* 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.
*/
/*
* @test
* @bug 8004101
* @summary Add checks for method reference well-formedness
* @compile/fail/ref=MethodReference56.out -XDrawDiagnostics MethodReference56.java
*/
class MethodReference56<X> {
interface V {
void m(Object o);
}
V v = MethodReference56<String>::m;
void test() {
g(MethodReference56<String>::m);
}
void g(V v) { }
static void m(Object o) { };
}

View File

@ -0,0 +1,3 @@
MethodReference56.java:36:28: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.mref.with.targs)
MethodReference56.java:39:28: compiler.err.invalid.mref: kindname.method, (compiler.misc.static.mref.with.targs)
2 errors

View File

@ -70,9 +70,6 @@ public class MethodRef1 {
b = MethodRef1::foo; //static reference to foo(int)
b.m(1);
b = new MethodRef1()::foo; //instance reference to static methods, supported for now
b.m(1);
b = MethodRef1::bar; //static reference to bar(int)
b.m(2);

View File

@ -133,15 +133,6 @@ public class SamConversion {
} catch (Exception e) {
assertTrue(false);
}
bar = new A()::method6;
try {
bar.m(1);
assertTrue(false);
} catch (MyException e) {
} catch (Exception e) {
assertTrue(false);
}
}
/**

View File

@ -119,20 +119,6 @@ public class MethodReferenceTestKinds extends MethodReferenceTestKindsSup {
assertEquals(var.get(inst("arg")), "SM:1-MethodReferenceTestKinds(arg)");
}
public void testMRStaticEval() {
MethodReferenceTestKinds evalCheck;
S0 var = (evalCheck = inst("discard"))::staticMethod0;
assertEquals(evalCheck.toString(), "MethodReferenceTestKinds(discard)");
assertEquals(var.get(), "SM:0");
}
public void testMRStaticEvalArg() {
MethodReferenceTestKinds evalCheck;
S1 var = (evalCheck = inst("discard"))::staticMethod1;
assertEquals(evalCheck.toString(), "MethodReferenceTestKinds(discard)");
assertEquals(var.get(inst("arg")), "SM:1-MethodReferenceTestKinds(arg)");
}
public void testMRTopLevel() {
SN0 var = MethodReferenceTestKindsBase::new;
assertEquals(var.make().toString(), "MethodReferenceTestKindsBase(blank)");
@ -142,17 +128,7 @@ public class MethodReferenceTestKinds extends MethodReferenceTestKindsSup {
SN1 var = MethodReferenceTestKindsBase::new;
assertEquals(var.make("name").toString(), "MethodReferenceTestKindsBase(name)");
}
/* unbound inner case not supported anymore (dropped by EG)
public void testMRUnboundInner() {
SXN0 var = MethodReferenceTestKinds.In::new;
assertEquals(var.make(inst("out")).toString(), "In(blank)");
}
public void testMRUnboundInnerArg() {
SXN1 var = MethodReferenceTestKinds.In::new;
assertEquals(var.make(inst("out"), "name").toString(), "In(name)");
}
*/
public void testMRImplicitInner() {
SN0 var = MethodReferenceTestKinds.In::new;
assertEquals(var.make().toString(), "In(blank)");