Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8231461: static/instance overload leads to 'unexpected static method …
…found in unbound lookup' when resolving method reference

Reviewed-by: mcimadamore
  • Loading branch information
Vicente Romero committed Jan 13, 2021
1 parent 42d2d6d commit ac4cd2e3c977d5919b490e9e5ec08692ee3e7a2a
@@ -112,6 +112,7 @@
private final boolean allowLocalVariableTypeInference;
private final boolean allowYieldStatement;
final EnumSet<VerboseResolutionMode> verboseResolutionMode;
final boolean dumpMethodReferenceSearchResults;

WriteableScope polymorphicSignatureScope;

@@ -151,6 +152,7 @@ protected Resolve(Context context) {
polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
allowModules = Feature.MODULES.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
dumpMethodReferenceSearchResults = options.isSet("debug.dumpMethodReferenceSearchResults");
}

/** error symbols, which are returned when resolution fails
@@ -2777,7 +2779,7 @@ Symbol findPolymorphicSignatureInstance(final Symbol spMethod,
// Check that there is already a method symbol for the method
// type and owner
if (types.isSameType(mtype, sym.type) &&
spMethod.owner == sym.owner) {
spMethod.owner == sym.owner) {
return sym;
}
}
@@ -3090,6 +3092,9 @@ ReferenceLookupHelper makeReferenceLookupHelper(JCMemberReference referenceTree,
Symbol boundSym = lookupMethod(boundEnv, env.tree.pos(),
site.tsym, boundSearchResolveContext, boundLookupHelper);
ReferenceLookupResult boundRes = new ReferenceLookupResult(boundSym, boundSearchResolveContext);
if (dumpMethodReferenceSearchResults) {
dumpMethodReferenceSearchResults(referenceTree, boundSearchResolveContext, boundSym, true);
}

//step 2 - unbound lookup
Symbol unboundSym = methodNotFound;
@@ -3103,6 +3108,9 @@ ReferenceLookupHelper makeReferenceLookupHelper(JCMemberReference referenceTree,
unboundSym = lookupMethod(unboundEnv, env.tree.pos(),
site.tsym, unboundSearchResolveContext, unboundLookupHelper);
unboundRes = new ReferenceLookupResult(unboundSym, unboundSearchResolveContext);
if (dumpMethodReferenceSearchResults) {
dumpMethodReferenceSearchResults(referenceTree, unboundSearchResolveContext, unboundSym, false);
}
}

//merge results
@@ -3126,6 +3134,42 @@ ReferenceLookupHelper makeReferenceLookupHelper(JCMemberReference referenceTree,
return res;
}

private void dumpMethodReferenceSearchResults(JCMemberReference referenceTree,
MethodResolutionContext resolutionContext,
Symbol bestSoFar,
boolean bound) {
ListBuffer<JCDiagnostic> subDiags = new ListBuffer<>();
int pos = 0;
int mostSpecificPos = -1;
for (Candidate c : resolutionContext.candidates) {
if (resolutionContext.step != c.step || !c.isApplicable()) {
continue;
} else {
JCDiagnostic subDiag = null;
if (c.sym.type.hasTag(FORALL)) {
subDiag = diags.fragment(Fragments.PartialInstSig(c.mtype));
}

String key = subDiag == null ?
"applicable.method.found.2" :
"applicable.method.found.3";
subDiags.append(diags.fragment(key, pos,
c.sym.isStatic() ? Fragments.Static : Fragments.NonStatic, c.sym, subDiag));
if (c.sym == bestSoFar)
mostSpecificPos = pos;
pos++;
}
}
JCDiagnostic main = diags.note(
log.currentSource(),
referenceTree,
"method.ref.search.results.multi",
bound ? Fragments.Bound : Fragments.Unbound,
referenceTree.toString(), mostSpecificPos);
JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, subDiags.toList());
log.report(d);
}

/**
* This class is used to represent a method reference lookup result. It keeps track of two
* things: (i) the symbol found during a method reference lookup and (ii) the static kind
@@ -3280,12 +3324,12 @@ ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {

@Override
ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
if (boundRes.hasKind(StaticKind.STATIC) &&
if (boundRes.isSuccess() && boundRes.sym.isStatic() &&
(!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
//the first search produces a static method and no non-static method is applicable
//during the second search
return boundRes;
} else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
} else if (unboundRes.isSuccess() && !unboundRes.sym.isStatic() &&
(!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) {
//the second search produces a non-static method and no static method is applicable
//during the first search
@@ -3066,6 +3066,37 @@ compiler.note.deferred.method.inst=\
compiler.note.verbose.l2m.deduplicate=\
deduplicating lambda implementation method {0}

########################################
# Diagnostics for method reference search
# results used by Resolve (debug only)
########################################

# 0: fragment, 1: string, 2: number
compiler.note.method.ref.search.results.multi=\
{0} search results for {1}, with most specific {2}\n\
applicable candidates:

# 0: number, 1: fragment, 2: symbol
compiler.misc.applicable.method.found.2=\
#{0} applicable method found: {1} {2}

# 0: number, 1: fragment, 2: symbol, 3: message segment
compiler.misc.applicable.method.found.3=\
#{0} applicable method found: {1} {2}\n\
({3})

compiler.misc.static=\
static

compiler.misc.non.static=\
non-static

compiler.misc.bound=\
bound

compiler.misc.unbound=\
unbound

########################################
# Diagnostics for where clause implementation
# used by the RichDiagnosticFormatter.
@@ -121,6 +121,10 @@ protected File assertOK(boolean generate, String... constructs) {
return assertCompile(expandMarkers(constructs), this::assertCompileSucceeded, generate);
}

protected File assertOK(Consumer<Diagnostic<?>> diagConsumer, String... constructs) {
return assertCompile(expandMarkers(constructs), () -> assertCompileSucceeded(diagConsumer), false);
}

protected void assertOKWithWarning(String warning, String... constructs) {
assertCompile(expandMarkers(constructs), () -> assertCompileSucceededWithWarning(warning), false);
}
@@ -66,6 +66,10 @@ public boolean errorsFound() {
return null;
}

public List<Diagnostic<?>> getAllDiags() {
return diags.stream().map(d -> (Diagnostic<?>)d).collect(toList());
}

/** Do the diagnostics contain the specified error key? */
public boolean containsErrorKey(String key) {
return diags.stream()
@@ -177,6 +177,13 @@ protected void assertCompileSucceeded() {
fail("Expected successful compilation");
}

/** Assert that all previous calls to compile() succeeded, also accepts a diagnostics consumer */
protected void assertCompileSucceeded(Consumer<Diagnostic<?>> diagConsumer) {
if (diags.errorsFound())
fail("Expected successful compilation");
diags.getAllDiags().stream().forEach(diagConsumer);
}

/** Assert that all previous calls to compile() succeeded */
protected void assertCompileSucceededWithWarning(String warning) {
if (diags.errorsFound())
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

// key: compiler.note.method.ref.search.results.multi
// key: compiler.misc.bound
// key: compiler.misc.applicable.method.found.2
// key: compiler.misc.static
// key: compiler.misc.non.static
// key: compiler.misc.unbound
// options: --debug=dumpMethodReferenceSearchResults

import java.util.function.*;

class BoundUnboundMethRefSearch {
public String foo(Object o) { return "foo"; }
public static String foo(String o) { return "bar"; }

void m() {
Function<String, String> f = BoundUnboundMethRefSearch::foo;
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

// key: compiler.note.method.ref.search.results.multi
// key: compiler.misc.bound
// key: compiler.misc.applicable.method.found.3
// key: compiler.misc.static
// key: compiler.misc.partial.inst.sig
// key: compiler.misc.unbound
// options: --debug=dumpMethodReferenceSearchResults

import java.util.function.*;

class BoundUnboundMethRefSearch2 {
interface SAM <T> {
boolean test(T n, T m);
}

static <T> boolean foo(T x, T y) {
return false;
}

void bar() {
SAM <Integer> mRef = BoundUnboundMethRefSearch2::<Integer>foo;
}

}
Loading

1 comment on commit ac4cd2e

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on ac4cd2e Jan 13, 2021

Please sign in to comment.