Skip to content
Permalink
Browse files
8244711: [lworld] Javac needs to tweak checks for interface implement…
…ation by an inline type.
  • Loading branch information
Srikanth Adayapalam committed May 11, 2020
1 parent bc0e647 commit ec1930c03b1f9e03c779e8475ef7b7ea7aa12013
@@ -2165,6 +2165,23 @@ public ArrayType makeArrayType(Type t) {
* @param sym a symbol
*/
public Type asSuper(Type t, Symbol sym) {
return asSuper(t, sym, false);
}

/**
* Return the (most specific) base type of t that starts with the
* given symbol. If none exists, return null.
*
* Caveat Emptor: Since javac represents the class of all arrays with a singleton
* symbol Symtab.arrayClass, which by being a singleton cannot hold any discriminant,
* this method could yield surprising answers when invoked on arrays. For example when
* invoked with t being byte [] and sym being t.sym itself, asSuper would answer null.
*
* @param t a type
* @param sym a symbol
* @param checkReferenceProjection if true, first compute reference projection of t
*/
public Type asSuper(Type t, Symbol sym, boolean checkReferenceProjection) {
/* Some examples:
*
* (Enum<E>, Comparable) => Comparable<E>
@@ -2173,6 +2190,14 @@ public Type asSuper(Type t, Symbol sym) {
* (j.u.List<capture#160 of ? extends c.s.s.d.DocTree>, Iterable) =>
* Iterable<capture#160 of ? extends c.s.s.d.DocTree>
*/

/* For a (value or identity) class V, whether it implements an interface I, boils down to whether
V.ref is a subtype of I. OIOW, whether asSuper(V.ref, sym) != null. (Likewise for an abstract
superclass)
*/
if (checkReferenceProjection)
t = t.isValue() ? t.referenceProjection() : t;

if (sym.type == syms.objectType) { //optimization
if (!isValue(t))
return syms.objectType;
@@ -1572,7 +1572,7 @@ public void visitForeachLoop(JCEnhancedForLoop tree) {
Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
if (elemtype == null) {
// or perhaps expr implements Iterable<T>?
Type base = types.asSuper(exprType, syms.iterableType.tsym);
Type base = types.asSuper(exprType, syms.iterableType.tsym, true);
if (base == null) {
log.error(tree.expr.pos(),
Errors.ForeachNotApplicableToType(exprType,
@@ -1867,7 +1867,7 @@ public void report(DiagnosticPosition pos, JCDiagnostic details) {

void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
if (!resource.isErroneous() &&
types.asSuper(resource, syms.autoCloseableType.tsym) != null &&
types.asSuper(resource, syms.autoCloseableType.tsym, true) != null &&
!types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
Symbol close = syms.noSymbol;
Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log);
@@ -2678,12 +2678,8 @@ void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
}
checkCompatibleConcretes(pos, c);

/* Check for inline/identity incompatibilities: But first, we may need to switch to the
reference universe to make the hierarchy navigable.
*/
Type asRefType = c.isValue() ? c.referenceProjection() : c;
boolean isIdentityObject = types.asSuper(asRefType, syms.identityObjectType.tsym) != null;
boolean isInlineObject = types.asSuper(asRefType, syms.inlineObjectType.tsym) != null;
boolean isIdentityObject = types.asSuper(c, syms.identityObjectType.tsym, true) != null;
boolean isInlineObject = types.asSuper(c, syms.inlineObjectType.tsym, true) != null;
if (c.isValue() && isIdentityObject) {
log.error(pos, Errors.InlineTypeMustNotImplementIdentityObject(c));
} else if (!c.isInterface() && !c.tsym.isAbstract() && !c.isValue() && isInlineObject) {
@@ -1225,7 +1225,7 @@ public void visitTry(JCTry tree) {
types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
List.of(resource.type);
for (Type sup : closeableSupertypes) {
if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
if (types.asSuper(sup, syms.autoCloseableType.tsym, true) != null) {
Symbol closeMethod = rs.resolveQualifiedMethod(tree,
attrEnv,
types.skipTypeVars(sup, false),
@@ -1718,7 +1718,7 @@ private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {

private JCStatement makeResourceCloseInvocation(JCExpression resource) {
// convert to AutoCloseable if needed
if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
if (types.asSuper(resource.type, syms.autoCloseableType.tsym, true) == null) {
resource = convert(resource, syms.autoCloseableType);
}

@@ -3506,7 +3506,7 @@ private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
make_at(tree.expr.pos());
Type iteratorTarget = syms.objectType;
Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type),
syms.iterableType.tsym);
syms.iterableType.tsym, true);
if (iterableType.getTypeArguments().nonEmpty())
iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
Type eType = types.skipTypeVars(tree.expr.type, false);
@@ -0,0 +1,57 @@
/*
* 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 8244711
* @summary Test that inline types work well with TWR
* @run main AutoCloseableTest
*/

public class AutoCloseableTest {

inline static class Foo implements AutoCloseable {

String s = "Exception while closing AutoCloseable";

@Override
public void close() throws Exception {
throw new Exception(s);
}

}

public static void main(String[] args) {
String expected = "";
String found = "";
try (Foo foo = new Foo()) {
expected = foo.s;
} catch (Exception e) {
found = e.getMessage();
}
if (expected.length() == 0 || !expected.equals(found))
throw new AssertionError("Should not get here!");
}
}
@@ -0,0 +1,15 @@
/*
* @test /nodynamiccopyright/
* @bug 8244711
* @summary Javac should complain about an inline class with conflicting super interfaces.
* @compile/fail/ref=ConflictingSuperInterfaceTest.out -XDrawDiagnostics ConflictingSuperInterfaceTest.java
*/

public class ConflictingSuperInterfaceTest {

interface I<T> {}
abstract class S implements I<String> {}
inline static class Foo extends S implements I<Integer> {
String s = "";
}
}
@@ -0,0 +1,2 @@
ConflictingSuperInterfaceTest.java:12:19: compiler.err.cant.inherit.diff.arg: ConflictingSuperInterfaceTest.I, java.lang.Integer, java.lang.String
1 error
@@ -0,0 +1,69 @@
/*
* 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 8244711
* @summary Test that inline types work well with enhanced for loop.
* @run main EnhancedForLoopTest
*/

import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;

public class EnhancedForLoopTest {

inline static class Foo<V> implements Iterable<V> {

List<V> lv;

public Foo() {
lv = new ArrayList<>();
}

public void add(V v) {
lv.add(v);
}

public Iterator<V> iterator() {
return lv.iterator();
}
}

public static void main(String[] args) {
Foo<String> foo = new Foo<String>();
foo.add ("Hello");
foo.add (" ");
foo.add ("World");
foo.add ("!");
String output = "";
for (var s : foo) {
output += s;
}
if (!output.equals("Hello World!"))
throw new AssertionError("Unexpected: " + output);
}
}

0 comments on commit ec1930c

Please sign in to comment.