Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8242900: [lworld] Allow an inline type to declare a superclass that meets specified restrictions #23

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -126,6 +126,19 @@ public static String toString(long flags) {
*/
public static final int HASINIT = 1<<18;

/** Flag is set for a class symbol if it defines one or more non-empty
* instance initializer block(s). This is relevenat only for class symbols
* that originate from source types. For binary types the instance initializer
* blocks are "normalized" into the constructors.
*/
public static final int HASINITBLOCK = 1<<18;

/** Flag is set for a method symbol if it is an empty no-arg ctor.
* i.e one that simply returns (jlO) or merely chains to a super's
* EMPTYNOARGCONSTR
*/
public static final int EMPTYNOARGCONSTR = 1<<18;

/** Flag is set for a value based class.
*/
public static final int VALUEBASED = 1<<19;
@@ -458,6 +471,8 @@ public static boolean isConstant(Symbol.VarSymbol symbol) {
ANNOTATION(Flags.ANNOTATION),
DEPRECATED(Flags.DEPRECATED),
HASINIT(Flags.HASINIT),
HASINITBLOCK(Flags.HASINITBLOCK),
EMPTYNOARGCONSTR(Flags.EMPTYNOARGCONSTR),
BLOCK(Flags.BLOCK),
ENUM(Flags.ENUM),
MANDATED(Flags.MANDATED),
@@ -1194,7 +1194,7 @@ public void visitMethodDef(JCMethodDecl tree) {
if (tree.name == names.init && owner.type != syms.objectType) {
JCBlock body = tree.body;
if (body.stats.isEmpty() ||
TreeInfo.getConstructorInvocationName(body.stats, names) == names.empty) {
TreeInfo.getConstructorInvocationName(body.stats, names, true) == names.empty) {
JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
make.Ident(names._super), make.Idents(List.nil())));
body.stats = body.stats.prepend(supCall);
@@ -1230,6 +1230,12 @@ public void visitMethodDef(JCMethodDecl tree) {
}
}
}
if (m.isConstructor() && m.type.getParameterTypes().size() == 0) {
if ((owner.type == syms.objectType) ||
(tree.body.stats.size() == 1 && TreeInfo.getConstructorInvocationName(tree.body.stats, names, false) == names._super)) {
m.flags_field |= EMPTYNOARGCONSTR;
}
}

// Attribute all type annotations in the body
annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null);
@@ -1427,7 +1433,11 @@ public void visitBlock(JCBlock tree) {
final Env<AttrContext> localEnv =
env.dup(tree, env.info.dup(env.info.scope.dupUnshared(fakeOwner)));

if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
if ((tree.flags & STATIC) != 0)
localEnv.info.staticLevel++;
else if (tree.stats.size() > 0)
env.info.scope.owner.flags_field |= HASINITBLOCK;

// Attribute all type annotations in the block
annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner, null);
annotate.flush();
@@ -5203,6 +5213,14 @@ void attribClass(ClassSymbol c) throws CompletionFailure {

attribClassBody(env, c);

if ((c.flags() & (VALUE | ABSTRACT)) == VALUE) { // for non-intersection, concrete values.
Assert.check(env.tree.hasTag(CLASSDEF));
JCClassDecl classDecl = (JCClassDecl) env.tree;
if (classDecl.extending != null) {
chk.checkConstraintsOfInlineSuper(env.tree.pos(), c);
}
}

chk.checkDeprecatedAnnotation(env.tree.pos(), c);
chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
chk.checkFunctionalInterface((JCClassDecl) env.tree, c);
@@ -743,6 +743,50 @@ private Object asTypeParam(Type t) {
: t;
}

void checkConstraintsOfInlineSuper(DiagnosticPosition pos, ClassSymbol c) {
boolean indirectSuper = false;
for(Type st = types.supertype(c.type); st != Type.noType; indirectSuper = true, st = types.supertype(st)) {
if (st == null || st.tsym == null || st.tsym.kind == ERR)
return;
if (indirectSuper && st.tsym == syms.objectType.tsym)
return;
if (!st.tsym.isAbstract()) {
log.error(pos, Errors.ConcreteSupertypeForInlineClass(c, st));
}
if ((st.tsym.flags() & HASINITBLOCK) != 0) {
log.error(pos, Errors.SuperClassDeclaresInitBlock(c, st));
}
// No instance fields and no arged constructors both mean inner classes cannot be inline supers.
Type encl = st.getEnclosingType();
if (encl != null && encl.hasTag(CLASS)) {
log.error(pos, Errors.SuperClassCannotBeInner(c, st));
}
for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
switch (s.kind) {
case VAR:
if ((s.flags() & STATIC) == 0) {
log.error(pos, Errors.SuperFieldNotAllowed(s, c, st));
}
break;
case MTH:
if ((s.flags() & SYNCHRONIZED) != 0) {
log.error(pos, Errors.SuperMethodCannotBeSynchronized(s, c, st));
} else if (s.isConstructor()) {
MethodSymbol m = (MethodSymbol)s;
if (m.getParameters().size() > 0) {
log.error(pos, Errors.SuperConstructorCannotTakeArguments(m, c, st));
} else {
if ((m.flags() & (GENERATEDCONSTR | EMPTYNOARGCONSTR)) == 0) {
log.error(pos, Errors.SuperNoArgConstructorMustBeEmpty(m, c, st));
}
}
}
break;
}
}
}
}

/** Check that type is a valid qualifier for a constructor reference expression
*/
Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
@@ -688,8 +688,6 @@ protected void attribSuperTypes(Env<AttrContext> env, Env<AttrContext> baseEnv)
final boolean isValueType = (tree.mods.flags & Flags.VALUE) != 0;

if (tree.extending != null) {
if (isValueType)
log.error(tree.pos(), Errors.ValueMayNotExtend);
extending = clearTypeParams(tree.extending);
supertype = attr.attribBase(extending, baseEnv, true, false, true);
if (supertype == syms.recordType) {
@@ -710,7 +708,7 @@ protected void attribSuperTypes(Env<AttrContext> env, Env<AttrContext> baseEnv)
if (injectTopInterfaceTypes) {
if (isValueType || types.isValue(supertype)) {
interfaceToInject = syms.inlineObjectType;
} else if ((sym.flags_field & INTERFACE) == 0) { // skip interfaces and annotations.
} else if ((sym.flags_field & (INTERFACE | ABSTRACT)) == 0) { // skip interfaces, abstract classes and annotations.
if (sym.fullname != names.java_lang_Object) {
interfaceToInject = syms.identityObjectType;
}
@@ -792,6 +792,17 @@ private void initAttributeReaders() {

new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
if (allowInlineTypes) {
if (sym.isConstructor() && ((MethodSymbol) sym).type.getParameterTypes().size() == 0) {
int code_length = buf.getInt(bp + 4);
if ((code_length == 1 && buf.getByte( bp + 8) == (byte) ByteCodes.return_) ||
(code_length == 5 && buf.getByte(bp + 8) == ByteCodes.aload_0 &&
buf.getByte( bp + 9) == (byte) ByteCodes.invokespecial &&
buf.getByte( bp + 12) == (byte) ByteCodes.return_)) {
sym.flags_field |= EMPTYNOARGCONSTR;
}
}
}
if (saveParameterNames)
((MethodSymbol)sym).code = readCode(sym);
else
@@ -194,7 +194,6 @@ public void visitMethodDef(JCMethodDecl tree) {
MethodSymbol symbol = (MethodSymbol)TreeInfo.symbol(call.meth);
if (names._super.equals(name)) { // "initial" constructor.
// Synthesize code to allocate factory "product" via: V $this = V.default;
Assert.check(symbol.owner == syms.objectType.tsym);
Assert.check(symbol.type.getParameterTypes().size() == 0);
final JCExpression type = make.Type(currentClass.type);
rhs = make.Select(type, new VarSymbol(STATIC, names._default, currentClass.type, currentClass.sym));
@@ -3715,3 +3715,33 @@ compiler.err.identity.type.must.not.implement.inline.object=\
compiler.err.mutually.incompatible.interfaces=\
The interfaces IdentityObject and InlineObject are mutually exclusive. The type {0} cannot implement both

# 0: symbol, 1: type
compiler.err.concrete.supertype.for.inline.class=\
The concrete class {1} is not allowed to be a super class of the inline class {0} either directly or indirectly

# 0: symbol, 1: symbol, 2: type
compiler.err.super.method.cannot.be.synchronized=\
The method {0} in the super class {2} of the inline type {1} is synchronized. This is disallowed

# 0: symbol, 1: symbol, 2: type
compiler.err.super.constructor.cannot.take.arguments=\
The super class {2} of the inline type {1} defines a constructor {0} that takes arguments. This is disallowed

# 0: symbol, 1: symbol, 2: type
compiler.err.super.field.not.allowed=\
The super class {2} of the inline type {1} defines an instance field {0}. This is disallowed

# 0: symbol, 1: symbol, 2: type
compiler.err.super.no.arg.constructor.must.be.empty=\
The super class {2} of the inline type {1} defines a nonempty no-arg constructor {0}. This is disallowed

# 0: symbol, 1: type
compiler.err.super.class.declares.init.block=\
The super class {1} of the inline class {0} declares one or more non-empty instance initializer blocks. This is disallowed.

# 0: symbol, 1: type
compiler.err.super.class.cannot.be.inner=\
The super class {1} of the inline class {0} is an inner class. This is disallowed.



@@ -109,17 +109,20 @@ public static boolean hasConstructors(List<JCTree> trees) {
}

/** Is there a constructor invocation in the given list of trees?
* Optionally, check only for no-arg ctor invocation
*/
public static Name getConstructorInvocationName(List<? extends JCTree> trees, Names names) {
public static Name getConstructorInvocationName(List<? extends JCTree> trees, Names names, boolean argsAllowed) {
for (JCTree tree : trees) {
if (tree.hasTag(EXEC)) {
JCExpressionStatement stat = (JCExpressionStatement)tree;
if (stat.expr.hasTag(APPLY)) {
JCMethodInvocation apply = (JCMethodInvocation)stat.expr;
Name methName = TreeInfo.name(apply.meth);
if (methName == names._this ||
methName == names._super) {
return methName;
if (argsAllowed || apply.args.size() == 0) {
Name methName = TreeInfo.name(apply.meth);
if (methName == names._this ||
methName == names._super) {
return methName;
}
}
}
}
@@ -74,9 +74,8 @@ private static void testSuper() throws Exception {
private static void testInterfaces() throws Exception {
AnnotatedType[] as;
as = TestClassArray.class.getAnnotatedInterfaces();
check(as.length == 4); // Adjust as per JDK-8237952
check(as.length == 3);
check(as[1].getAnnotations().length == 0);
check(as[3].getAnnotations().length == 0); // Adjust as per JDK-8237952

Annotation[] annos;
annos = as[0].getAnnotations();
@@ -327,9 +326,8 @@ private static void testParameterizedType() {
// Base
AnnotatedType[] as;
as = TestParameterizedType.class.getAnnotatedInterfaces();
check(as.length == 2); // Adjust as per JDK-8237952
check(as.length == 1);
check(as[0].getAnnotations().length == 1);
check(as[1].getAnnotations().length == 0); // Adjust as per JDK-8237952
check(as[0].getAnnotation(TypeAnno.class).value().equals("M"));

Annotation[] annos;
@@ -80,9 +80,8 @@ static void testSuperInterfaces() {
System.out.println("testing superinterfaces");
Type[] sis = cls.getGenericInterfaces();
assert
(sis.length == 1) : // Adjust based on JDK-8237952
"C1 should have one generic superinterface"; // Adjust based on JDK-8237952
assert (sis[0] == IdentityObject.class); // Adjust based on JDK-8237952
(sis.length == 0) :
"C1 should have no generic superinterfaces";
}

static void testTypeParameters() {
@@ -183,8 +183,8 @@ static void testSuperInterfaces() {
System.out.println("testing superinterfaces");
Type[] sis = cls.getGenericInterfaces();
assert
((sis.length == 4)): // Adjust based on JDK-8237952
"C2 should have four generic superinterfaces"; // Adjust based on JDK-8237952
((sis.length == 3)):
"C2 should have three generic superinterfaces";

Type t = sis[0];
assert
@@ -217,8 +217,6 @@ static void testSuperInterfaces() {
t == I3.class :
"Third superinterface of C2 is I3";

assert (sis[3] == IdentityObject.class); // Adjust based on JDK-8237952

// Test interfaces themselves

TypeVariable[] tvs = I1.class.getTypeParameters();
@@ -211,3 +211,10 @@ compiler.warn.this.exposed.prematurely
compiler.err.identity.type.must.not.implement.inline.object
compiler.err.inline.type.must.not.implement.identity.object
compiler.err.mutually.incompatible.interfaces
compiler.err.concrete.supertype.for.inline.class
compiler.err.super.class.cannot.be.inner
compiler.err.super.class.declares.init.block
compiler.err.super.constructor.cannot.take.arguments
compiler.err.super.field.not.allowed
compiler.err.super.method.cannot.be.synchronized
compiler.err.super.no.arg.constructor.must.be.empty
@@ -22,15 +22,15 @@ public class GeneratedClass<T> extends java.util.ArrayList<java.lang.String> imp
round: 2

@javax.annotation.processing.SupportedAnnotationTypes({"*"})
public abstract class GeneratedSource<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence, java.lang.IdentityObject {
public abstract class GeneratedSource<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence {

public GeneratedSource();

public void test(long a);
}

@javax.annotation.processing.SupportedAnnotationTypes({"*"})
public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence, java.lang.IdentityObject {
public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence {

public GeneratedClass();

@@ -39,15 +39,15 @@ public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.N
round: 3

@javax.annotation.processing.SupportedAnnotationTypes({"*"})
public abstract class GeneratedSource<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence, java.lang.IdentityObject {
public abstract class GeneratedSource<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence {

public GeneratedSource();

public void test(long a);
}

@javax.annotation.processing.SupportedAnnotationTypes({"*"})
public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence, java.lang.IdentityObject {
public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence {

public GeneratedClass();

@@ -1,15 +1,15 @@
round: 1

@javax.annotation.processing.SupportedAnnotationTypes({"*"})
public abstract class GeneratedSource<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence, java.lang.IdentityObject {
public abstract class GeneratedSource<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence {

public GeneratedSource();

public void test(long a);
}

@javax.annotation.processing.SupportedAnnotationTypes({"*"})
public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence, java.lang.IdentityObject {
public abstract class GeneratedClass<E> extends java.util.LinkedList<java.lang.Number> implements java.lang.Runnable, java.lang.CharSequence {

public GeneratedClass();