8268312: Compilation error with nested generic functional interface

Reviewed-by: mcimadamore
This commit is contained in:
Vicente Romero 2022-07-15 13:06:03 +00:00
parent 92deab5465
commit f3abb82989
5 changed files with 112 additions and 11 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac
test/langtools/tools/javac/diags

@ -68,6 +68,7 @@ import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@ -4174,16 +4175,11 @@ public class Resolve {
return null;
Pair<Symbol, JCDiagnostic> c = errCandidate();
if (compactMethodDiags) {
JCDiagnostic simpleDiag =
MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd);
if (simpleDiag != null) {
return simpleDiag;
}
}
Symbol ws = c.fst.asMemberOf(site, types);
return diags.create(dkind, log.currentSource(), pos,
"cant.apply.symbol",
compactMethodDiags ?
d -> MethodResolutionDiagHelper.rewrite(diags, pos, log.currentSource(), dkind, c.snd) : null,
kindName(ws),
ws.name == names.init ? ws.owner.name : ws.name,
methodArguments(ws.type.getParameterTypes()),
@ -4244,8 +4240,8 @@ public class Resolve {
JCDiagnostic err = diags.create(dkind,
null,
truncatedDiag ?
EnumSet.of(DiagnosticFlag.COMPRESSED) :
EnumSet.noneOf(DiagnosticFlag.class),
EnumSet.of(DiagnosticFlag.COMPRESSED) :
EnumSet.noneOf(DiagnosticFlag.class),
log.currentSource(),
pos,
"cant.apply.symbols",

@ -182,7 +182,11 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter
String s = null;
depth++;
try {
s = formatMessage(diagnostic, l);
JCDiagnostic rewrittenDiagnostic = null;
if (diagnostic.hasRewriter()) {
rewrittenDiagnostic = diagnostic.rewrite();
}
s = formatMessage(rewrittenDiagnostic != null ? rewrittenDiagnostic : diagnostic, l);
}
finally {
depth--;

@ -26,6 +26,7 @@
package com.sun.tools.javac.util;
import java.util.EnumSet;
import java.util.function.UnaryOperator;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
@ -243,6 +244,21 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, prefix, key, args));
}
/**
* Create a new diagnostic of the given kind, which is not mandatory and which has
* no lint category.
* @param kind The diagnostic kind
* @param source The source of the compilation unit, if any, in which to report the message.
* @param pos The source position at which to report the message.
* @param key The key for the localized message.
* @param rewriter A rewriter function used if this diagnostic needs to be rewritten
* @param args Fields of the message.
*/
public JCDiagnostic create(
DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, UnaryOperator<JCDiagnostic> rewriter, Object... args) {
return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, prefix, key, args), rewriter);
}
/**
* Create a new diagnostic of the given kind, which is not mandatory and which has
* no lint category.
@ -282,6 +298,11 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo) {
return new JCDiagnostic(formatter, normalize(diagnosticInfo), lc, flags, source, pos);
}
public JCDiagnostic create(
LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo, UnaryOperator<JCDiagnostic> rewriter) {
return new JCDiagnostic(formatter, normalize(diagnosticInfo), lc, flags, source, pos, rewriter);
}
//where
DiagnosticInfo normalize(DiagnosticInfo diagnosticInfo) {
//replace all nested FragmentKey with full-blown JCDiagnostic objects
@ -446,6 +467,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
/** source line position (set lazily) */
private SourcePosition sourcePosition;
private final UnaryOperator<JCDiagnostic> rewriter;
/**
* This class is used to defer the line/column position fetch logic after diagnostic construction.
*/
@ -596,6 +619,25 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
Set<DiagnosticFlag> flags,
DiagnosticSource source,
DiagnosticPosition pos) {
this(formatter, diagnosticInfo, lc, flags, source, pos, null);
}
/**
* Create a diagnostic object.
* @param formatter the formatter to use for the diagnostic
* @param diagnosticInfo the diagnostic key
* @param lc the lint category for the diagnostic
* @param source the name of the source file, or null if none.
* @param pos the character offset within the source file, if given.
* @param rewriter the rewriter function used if this diagnostic needs to be rewritten
*/
protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
DiagnosticInfo diagnosticInfo,
LintCategory lc,
Set<DiagnosticFlag> flags,
DiagnosticSource source,
DiagnosticPosition pos,
UnaryOperator<JCDiagnostic> rewriter) {
if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
throw new IllegalArgumentException();
@ -605,6 +647,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
this.flags = flags;
this.source = source;
this.position = pos;
this.rewriter = rewriter;
}
/**
@ -807,6 +850,14 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
return flags.contains(flag);
}
boolean hasRewriter() {
return rewriter != null;
}
JCDiagnostic rewrite() {
return rewriter.apply(this);
}
public static class MultilineDiagnostic extends JCDiagnostic {
private final List<JCDiagnostic> subdiagnostics;

@ -28,7 +28,6 @@ package com.sun.tools.javac.util;
import java.io.*;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Queue;
@ -671,6 +670,11 @@ public class Log extends AbstractLog {
if (expectDiagKeys != null)
expectDiagKeys.remove(diagnostic.getCode());
if (diagnostic.hasRewriter()) {
JCDiagnostic rewrittenDiag = diagnostic.rewrite();
diagnostic = rewrittenDiag != null ? rewrittenDiag : diagnostic;
}
switch (diagnostic.getType()) {
case FRAGMENT:
throw new IllegalArgumentException();

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, 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 8268312
* @summary Compilation error with nested generic functional interface
* @compile DiagnosticRewriterTest3.java
*/
import java.util.Optional;
class DiagnosticRewriterTest3 {
void m() {
Optional.of("").map(outer -> {
Optional.of("")
.map(inner -> returnGeneric(outer))
.ifPresent(String::toString);
return "";
});
}
<T> T returnGeneric(T generic) {
return generic;
}
}