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

8267923: [lworld] Javac's implementation differs from JEP401 in a few matters. #432

Closed
wants to merge 7 commits into from
@@ -2277,7 +2277,7 @@ public Type asSuper(Type t, Symbol sym) {
} else if (sym == syms.primitiveObjectType.tsym) {
if (t.isPrimitiveClass() || t.isReferenceProjection())
return syms.primitiveObjectType;
if (t.hasTag(ARRAY) || t.tsym == syms.objectType.tsym)
if (t.hasTag(ARRAY) || t.tsym == syms.objectType.tsym || !t.hasTag(CLASS))
return null;
// else fall through and look for explicit coded super interface
}
@@ -175,7 +175,6 @@ protected Attr(Context context) {
allowRecords = Feature.RECORDS.allowedInSource(source);
sourceName = source.name;
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
allowValueMemberCycles = options.isSet("allowValueMemberCycles");

statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
@@ -224,11 +223,6 @@ protected Attr(Context context) {
*/
boolean useBeforeDeclarationWarning;

/**
* Switch: Allow value type member cycles?
*/
boolean allowValueMemberCycles;

/**
* Switch: name of source level; used for error reporting.
*/
@@ -1229,6 +1223,12 @@ public void visitMethodDef(JCMethodDecl tree) {
// generated one.
log.error(tree.body.stats.head.pos(),
Errors.CallToSuperNotAllowedInEnumCtor(env.enclClass.sym));
} else if ((env.enclClass.sym.flags() & PRIMITIVE_CLASS) != 0 &&
(tree.mods.flags & GENERATEDCONSTR) == 0 &&
TreeInfo.isSuperCall(body.stats.head)) {
// primitive constructors are not allowed to call super directly,
// but tolerate compiler generated ones
log.error(tree.body.stats.head.pos(), Errors.CallToSuperNotAllowedInPrimitiveCtor);
}
if (env.enclClass.sym.isRecord() && (tree.sym.flags_field & RECORD) != 0) { // we are seeing the canonical constructor
List<Name> recordComponentNames = TreeInfo.recordFields(env.enclClass).map(vd -> vd.sym.name);
@@ -1830,7 +1830,7 @@ private Symbol enumConstant(JCTree tree, Type enumType) {
}

public void visitSynchronized(JCSynchronized tree) {
chk.checkRefType(tree.pos(), attribExpr(tree.lock, env), false);
chk.checkIdentityType(tree.pos(), attribExpr(tree.lock, env));
if (env.info.lint.isEnabled(LintCategory.SYNCHRONIZATION) && isValueBased(tree.lock.type)) {
log.warning(LintCategory.SYNCHRONIZATION, tree.pos(), Warnings.AttemptToSynchronizeOnInstanceOfValueBasedClass);
}
@@ -2581,12 +2581,6 @@ public void visitApply(JCMethodInvocation tree) {
if (argSize == 0)
log.error(tree.pos(), Errors.PrimitiveClassDoesNotSupport(name));
break;
case "hashCode":
case "equals":
case "toString":
if (superCallOnValueReceiver)
log.error(tree.pos(), Errors.PrimitiveClassDoesNotSupport(names.fromString("invocation of super." + name)));
break;
}
}
}
@@ -5255,10 +5249,8 @@ public void attribClass(DiagnosticPosition pos, ClassSymbol c) {
attribClass(c);
if (types.isPrimitiveClass(c.type)) {
final Env<AttrContext> env = typeEnvs.get(c);
if (!allowValueMemberCycles) {
if (env != null && env.tree != null && env.tree.hasTag(CLASSDEF))
chk.checkNonCyclicMembership((JCClassDecl)env.tree);
}
if (env != null && env.tree != null && env.tree.hasTag(CLASSDEF))
chk.checkNonCyclicMembership((JCClassDecl)env.tree);
}
} catch (CompletionFailure ex) {
chk.completionError(pos, ex);
@@ -848,6 +848,32 @@ Type checkRefType(DiagnosticPosition pos, Type t, boolean valueOK) {
t);
}

/** Check that type is an identity type, i.e. not a primitive type
* nor its reference projection. When not discernible statically,
* give it the benefit of doubt and defer to runtime.
*
* @param pos Position to be used for error reporting.
* @param t The type to be checked.
*/
Type checkIdentityType(DiagnosticPosition pos, Type t) {

if (t.hasTag(ARRAY))
return t;

if (!t.hasTag(CLASS) || t.isPrimitiveClass() || t.isReferenceProjection())
return typeTagError(pos,
diags.fragment(Fragments.TypeReqIdentity),
t);

/* Not appropriate to check
* if (types.asSuper(t, syms.identityObjectType.tsym) != null)
* since jlO, interface types and abstract types may fail that check
* at compile time.
*/

return t;
}

/** Check that type is a reference type, i.e. a class, interface or array type
* or a type variable.
* @param pos Position to be used for error reporting.
@@ -2416,8 +2442,7 @@ void checkNonCyclicMembership(JCClassDecl tree) {
if (l.head.hasTag(VARDEF)) {
JCVariableDecl field = (JCVariableDecl) l.head;
if (cyclePossible(field.sym)) {
Type fieldType = field.sym.type;
checkNonCyclicMembership((ClassSymbol) fieldType.tsym, field.pos());
checkNonCyclicMembership((ClassSymbol) field.type.tsym, field.pos());
}
}
}
@@ -681,7 +681,7 @@ protected void attribSuperTypes(Env<AttrContext> env, Env<AttrContext> baseEnv)
// Determine supertype.
Type supertype;
JCExpression extending;
final boolean isValueType = (tree.mods.flags & Flags.PRIMITIVE_CLASS) != 0;
final boolean isPrimitiveClass = (tree.mods.flags & Flags.PRIMITIVE_CLASS) != 0;

if (tree.extending != null) {
extending = clearTypeParams(tree.extending);
@@ -708,6 +708,9 @@ protected void attribSuperTypes(Env<AttrContext> env, Env<AttrContext> baseEnv)
iface = clearTypeParams(iface);
Type it = attr.attribBase(iface, baseEnv, false, true, true);
if (it.hasTag(CLASS)) {
if (isPrimitiveClass && it.tsym == syms.cloneableType.tsym) {
log.error(tree, Errors.PrimitiveClassMustNotImplementCloneable(ct));
}
interfaces.append(it);
if (all_interfaces != null) all_interfaces.append(it);
} else {
@@ -2449,6 +2449,9 @@ compiler.misc.type.req.ref=\
compiler.misc.type.req.exact=\
class or interface without bounds

compiler.misc.type.req.identity=\
a type with identity

# 0: type
compiler.misc.type.parameter=\
type parameter {0}
@@ -3820,6 +3823,10 @@ compiler.err.generic.parameterization.with.primitive.class=\
compiler.err.primitive.class.must.not.implement.identity.object=\
The primitive class {0} attempts to implement the incompatible interface IdentityObject

# 0: type
compiler.err.primitive.class.must.not.implement.cloneable=\
The primitive class {0} attempts to implement the incompatible interface Cloneable

# 0: type
compiler.err.identity.class.must.not.implement.primitive.object=\
The identity class {0} attempts to implement the incompatible interface PrimitiveObject
@@ -3859,6 +3866,8 @@ compiler.err.super.class.cannot.be.inner=\
compiler.err.projection.cant.be.instantiated=\
Illegal attempt to instantiate a projection type

compiler.err.call.to.super.not.allowed.in.primitive.ctor=\
call to super not allowed in primitive class constructor

# 0: kind name, 1: symbol
compiler.warn.declared.using.preview=\
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2021, 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.primitive.class.must.not.implement.cloneable

primitive class Primitive implements Cloneable {
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2021, 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.call.to.super.not.allowed.in.primitive.ctor

primitive class SuperNotAllowedInPrimitiveCtor {

SuperNotAllowedInPrimitiveCtor() {
super();
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021, 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.misc.type.req.identity
// key: compiler.err.type.found.req

primitive class TypeReqIdentity {
{ synchronized (this) {} }
}
@@ -1,7 +1,7 @@
/*
* @test /nodynamiccopyright/
* @summary Value types may not declare fields of its own type either directly or indirectly.
* @compile -XDallowValueMemberCycles -XDrawDiagnostics CheckCyclicMembership.java
*
* @compile/fail/ref=CheckCyclicMembership.out -XDrawDiagnostics CheckCyclicMembership.java
*/

@@ -1,7 +1,7 @@
/*
* @test /nodynamiccopyright/
* @summary Check for cycles through fields declared flattenable.
* @compile -XDallowValueMemberCycles -XDrawDiagnostics CheckFlattenableCycles.java
*
* @compile/fail/ref=CheckFlattenableCycles.out -XDrawDiagnostics CheckFlattenableCycles.java
*/

@@ -12,9 +12,6 @@ CheckObjectMethodsUsage.java:23:21: compiler.err.primitive.class.does.not.suppor
CheckObjectMethodsUsage.java:24:18: compiler.err.primitive.class.does.not.support: notifyAll
CheckObjectMethodsUsage.java:25:24: compiler.err.primitive.class.does.not.support: notifyAll
CheckObjectMethodsUsage.java:26:20: compiler.err.primitive.class.does.not.support: clone
CheckObjectMethodsUsage.java:27:23: compiler.err.primitive.class.does.not.support: invocation of super.hashCode
CheckObjectMethodsUsage.java:28:23: compiler.err.primitive.class.does.not.support: invocation of super.toString
CheckObjectMethodsUsage.java:29:21: compiler.err.primitive.class.does.not.support: invocation of super.equals
- compiler.note.deprecated.filename: CheckObjectMethodsUsage.java
- compiler.note.deprecated.recompile
17 errors
14 errors
@@ -1,19 +1,37 @@
/*
* @test /nodynamiccopyright/
* @summary Check behavior of synzhronized key word on value instances and methods.
* @summary Check behavior of synzhronized key word on primitive class instances and methods.
*
* @compile/fail/ref=CheckSynchronized.out -XDrawDiagnostics CheckSynchronized.java
*/

primitive final class CheckSynchronized {
primitive final class CheckSynchronized implements java.io.Serializable {
synchronized void foo() { // <<-- ERROR, no monitor associated with `this'
}
void goo() {
synchronized(this) {} // <<-- ERROR, no monitor associated with `this'
}
synchronized static void zoo(CheckSynchronized cs) { // OK, static method.
synchronized(cs) { // <<-- ERROR, no monitor associated with value instance.
synchronized(cs) { // <<-- ERROR, no monitor associated with primitive class instance.
}

CheckSynchronized.ref csr = cs;
synchronized(csr) {
// Error, no identity.
}

synchronized(x) {
// Error, no identity.
}

Object o = cs;
synchronized(o) {
// Error BUT not discernible at compile time
}
java.io.Serializable jis = cs;
synchronized(jis) {
// Error BUT not discernible at compile time
}
}
int x = 10;
static int x = 10;
}
@@ -1,4 +1,6 @@
CheckSynchronized.java:9:23: compiler.err.mod.not.allowed.here: synchronized
CheckSynchronized.java:12:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.ref)
CheckSynchronized.java:15:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.ref)
3 errors
CheckSynchronized.java:12:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.identity)
CheckSynchronized.java:15:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.identity)
CheckSynchronized.java:19:9: compiler.err.type.found.req: CheckSynchronized.ref, (compiler.misc.type.req.identity)
CheckSynchronized.java:23:9: compiler.err.type.found.req: int, (compiler.misc.type.req.identity)
5 errors
@@ -0,0 +1,24 @@
/*
* @test /nodynamiccopyright/
* @bug 8267843
* @summary Check that javac diagnoses `this` being passed around and instance method being invoked before primitive class instance is fully initialized.
* @compile/fail/ref=DualNonDuplicateErrors.out -XDrawDiagnostics DualNonDuplicateErrors.java
*/

public primitive class DualNonDuplicateErrors {

int x;

DualNonDuplicateErrors() {
// The call below should trigger two errors - they are not duplicates really.
// First one is for `this` being passed around ("exposed")
// Second is for instance method being invoked thereby allowing that method to
// observe the primitive class instance in a partially initialized state.
foo(this);
x = 10;
foo(this); // No error here.
}

void foo(DualNonDuplicateErrors x) {
}
}
@@ -0,0 +1,3 @@
DualNonDuplicateErrors.java:17:13: compiler.err.this.exposed.prematurely
DualNonDuplicateErrors.java:17:12: compiler.err.this.exposed.prematurely
2 errors
@@ -1,4 +1,2 @@
SneakThroSuperCallTest.java:13:21: compiler.err.primitive.class.does.not.support: notify
SneakThroSuperCallTest.java:17:30: compiler.err.primitive.class.does.not.support: invocation of super.hashCode
SneakThroSuperCallTest.java:21:30: compiler.err.primitive.class.does.not.support: invocation of super.toString
3 errors
1 error