8254105: allow static nested declarations
Reviewed-by: mcimadamore
This commit is contained in:
parent
14de791d60
commit
9a19eb6918
@ -383,30 +383,31 @@ public class Flags {
|
|||||||
/** Modifier masks.
|
/** Modifier masks.
|
||||||
*/
|
*/
|
||||||
public static final int
|
public static final int
|
||||||
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
|
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
|
||||||
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
|
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
|
||||||
StaticLocalFlags = LocalClassFlags | STATIC | INTERFACE,
|
StaticLocalFlags = LocalClassFlags | STATIC | INTERFACE,
|
||||||
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
|
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
|
||||||
MemberRecordFlags = MemberClassFlags | STATIC,
|
MemberStaticClassFlags = MemberClassFlags | STATIC,
|
||||||
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
|
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
|
||||||
InterfaceVarFlags = FINAL | STATIC | PUBLIC,
|
InterfaceVarFlags = FINAL | STATIC | PUBLIC,
|
||||||
VarFlags = AccessFlags | FINAL | STATIC |
|
VarFlags = AccessFlags | FINAL | STATIC |
|
||||||
VOLATILE | TRANSIENT | ENUM,
|
VOLATILE | TRANSIENT | ENUM,
|
||||||
ConstructorFlags = AccessFlags,
|
ConstructorFlags = AccessFlags,
|
||||||
InterfaceMethodFlags = ABSTRACT | PUBLIC,
|
InterfaceMethodFlags = ABSTRACT | PUBLIC,
|
||||||
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
|
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
|
||||||
SYNCHRONIZED | FINAL | STRICTFP,
|
SYNCHRONIZED | FINAL | STRICTFP,
|
||||||
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
|
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
|
||||||
SYNCHRONIZED | FINAL | STRICTFP;
|
SYNCHRONIZED | FINAL | STRICTFP;
|
||||||
public static final long
|
public static final long
|
||||||
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED,
|
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED,
|
||||||
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED,
|
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED,
|
||||||
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED,
|
ExtendedMemberStaticClassFlags = (long) MemberStaticClassFlags | SEALED | NON_SEALED,
|
||||||
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
|
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED,
|
||||||
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
|
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
|
||||||
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
|
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
|
||||||
LocalVarFlags = FINAL | PARAMETER,
|
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
|
||||||
ReceiverParamFlags = PARAMETER;
|
LocalVarFlags = FINAL | PARAMETER,
|
||||||
|
ReceiverParamFlags = PARAMETER;
|
||||||
|
|
||||||
@SuppressWarnings("preview")
|
@SuppressWarnings("preview")
|
||||||
public static Set<Modifier> asModifierSet(long flags) {
|
public static Set<Modifier> asModifierSet(long flags) {
|
||||||
|
@ -171,6 +171,7 @@ public class Attr extends JCTree.Visitor {
|
|||||||
allowReifiableTypesInInstanceof =
|
allowReifiableTypesInInstanceof =
|
||||||
Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source) &&
|
Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source) &&
|
||||||
(!preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF) || preview.isEnabled());
|
(!preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF) || preview.isEnabled());
|
||||||
|
allowRecords = Feature.RECORDS.allowedInSource(source);
|
||||||
sourceName = source.name;
|
sourceName = source.name;
|
||||||
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
||||||
|
|
||||||
@ -207,6 +208,10 @@ public class Attr extends JCTree.Visitor {
|
|||||||
*/
|
*/
|
||||||
boolean allowReifiableTypesInInstanceof;
|
boolean allowReifiableTypesInInstanceof;
|
||||||
|
|
||||||
|
/** Are records allowed
|
||||||
|
*/
|
||||||
|
private final boolean allowRecords;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch: warn about use of variable before declaration?
|
* Switch: warn about use of variable before declaration?
|
||||||
* RFE: 6425594
|
* RFE: 6425594
|
||||||
@ -5309,14 +5314,15 @@ public class Attr extends JCTree.Visitor {
|
|||||||
attribStat(l.head, env);
|
attribStat(l.head, env);
|
||||||
// Check that declarations in inner classes are not static (JLS 8.1.2)
|
// Check that declarations in inner classes are not static (JLS 8.1.2)
|
||||||
// Make an exception for static constants.
|
// Make an exception for static constants.
|
||||||
if (c.owner.kind != PCK &&
|
if (!allowRecords &&
|
||||||
((c.flags() & STATIC) == 0 || c.name == names.empty) &&
|
c.owner.kind != PCK &&
|
||||||
(TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) {
|
((c.flags() & STATIC) == 0 || c.name == names.empty) &&
|
||||||
|
(TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) {
|
||||||
Symbol sym = null;
|
Symbol sym = null;
|
||||||
if (l.head.hasTag(VARDEF)) sym = ((JCVariableDecl) l.head).sym;
|
if (l.head.hasTag(VARDEF)) sym = ((JCVariableDecl) l.head).sym;
|
||||||
if (sym == null ||
|
if (sym == null ||
|
||||||
sym.kind != VAR ||
|
sym.kind != VAR ||
|
||||||
((VarSymbol) sym).getConstValue() == null)
|
((VarSymbol) sym).getConstValue() == null)
|
||||||
log.error(l.head.pos(), Errors.IclsCantHaveStaticDecl(c));
|
log.error(l.head.pos(), Errors.IclsCantHaveStaticDecl(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1216,23 +1216,20 @@ public class Check {
|
|||||||
implicit |= sym.owner.flags_field & STRICTFP;
|
implicit |= sym.owner.flags_field & STRICTFP;
|
||||||
break;
|
break;
|
||||||
case TYP:
|
case TYP:
|
||||||
if (sym.isLocal()) {
|
if (sym.owner.kind.matches(KindSelector.VAL_MTH)) {
|
||||||
boolean implicitlyStatic = !sym.isAnonymous() &&
|
boolean implicitlyStatic = !sym.isAnonymous() &&
|
||||||
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
|
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
|
||||||
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
|
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
|
||||||
|
// local statics are allowed only if records are allowed too
|
||||||
mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
|
mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
|
||||||
implicit = implicitlyStatic ? STATIC : implicit;
|
implicit = implicitlyStatic ? STATIC : implicit;
|
||||||
if (staticOrImplicitlyStatic) {
|
|
||||||
if (sym.owner.kind == TYP) {
|
|
||||||
log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (sym.owner.kind == TYP) {
|
} else if (sym.owner.kind == TYP) {
|
||||||
mask = (flags & RECORD) != 0 ? MemberRecordFlags : ExtendedMemberClassFlags;
|
// statics in inner classes are allowed only if records are allowed too
|
||||||
|
mask = ((flags & STATIC) != 0) && allowRecords ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
|
||||||
if (sym.owner.owner.kind == PCK ||
|
if (sym.owner.owner.kind == PCK ||
|
||||||
(sym.owner.flags_field & STATIC) != 0)
|
(sym.owner.flags_field & STATIC) != 0) {
|
||||||
mask |= STATIC;
|
mask |= STATIC;
|
||||||
else if ((flags & ENUM) != 0 || (flags & RECORD) != 0) {
|
} else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
|
||||||
log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
|
log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
|
||||||
}
|
}
|
||||||
// Nested interfaces and enums are always STATIC (Spec ???)
|
// Nested interfaces and enums are always STATIC (Spec ???)
|
||||||
|
@ -24,10 +24,11 @@
|
|||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 4279339
|
* @bug 4279339
|
||||||
* @summary Verify that an anonymous class cannot contain a static field.
|
* @summary Verify that an anonymous class can contain a static field only if source >= 16
|
||||||
* @author maddox
|
* @author maddox
|
||||||
*
|
*
|
||||||
* @run compile/fail AnonStaticMember_1.java
|
* @compile/fail/ref=AnonStaticMember_1.out -source 15 -XDrawDiagnostics AnonStaticMember_1.java
|
||||||
|
* @compile AnonStaticMember_1.java
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AnonStaticMember_1 {
|
class AnonStaticMember_1 {
|
||||||
|
4
test/langtools/tools/javac/AnonStaticMember_1.out
Normal file
4
test/langtools/tools/javac/AnonStaticMember_1.out
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
|
AnonStaticMember_1.java:36:20: compiler.err.icls.cant.have.static.decl: compiler.misc.anonymous.class: AnonStaticMember_1$1
|
||||||
|
1 error
|
||||||
|
1 warning
|
@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @test /nodynamiccopyright/
|
* @test /nodynamiccopyright/
|
||||||
* @bug 4279339 6969184
|
* @bug 4279339 6969184
|
||||||
* @summary Verify that an anonymous class cannot contain a static method.
|
* @summary Verify that an anonymous class can contain a static method only if source >= 16
|
||||||
* @author maddox
|
* @author maddox
|
||||||
*
|
*
|
||||||
* @run compile/fail/ref=AnonStaticMember_2.out -XDrawDiagnostics AnonStaticMember_2.java
|
* @compile/fail/ref=AnonStaticMember_2.out -source 15 -XDrawDiagnostics AnonStaticMember_2.java
|
||||||
|
* @compile AnonStaticMember_2.java
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class AnonStaticMember_2 {
|
class AnonStaticMember_2 {
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
AnonStaticMember_2.java:12:21: compiler.err.icls.cant.have.static.decl: compiler.misc.anonymous.class: AnonStaticMember_2$1
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
|
AnonStaticMember_2.java:13:21: compiler.err.icls.cant.have.static.decl: compiler.misc.anonymous.class: AnonStaticMember_2$1
|
||||||
1 error
|
1 error
|
||||||
|
1 warning
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
* @summary Verify rejection of illegal static variables in inner classes.
|
* @summary Verify rejection of illegal static variables in inner classes.
|
||||||
* @author William Maddox (maddox)
|
* @author William Maddox (maddox)
|
||||||
*
|
*
|
||||||
* @compile/fail/ref=InnerNamedConstant_2.out -XDrawDiagnostics InnerNamedConstant_2.java
|
* @compile/fail/ref=InnerNamedConstant_2_A.out -XDrawDiagnostics -source 15 InnerNamedConstant_2.java
|
||||||
|
* @compile/fail/ref=InnerNamedConstant_2_B.out -XDrawDiagnostics InnerNamedConstant_2.java
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class InnerNamedConstant_2 {
|
public class InnerNamedConstant_2 {
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
InnerNamedConstant_2.java:22:20: compiler.err.icls.cant.have.static.decl: InnerNamedConstant_2.Inner2
|
|
||||||
InnerNamedConstant_2.java:23:29: compiler.err.icls.cant.have.static.decl: InnerNamedConstant_2.Inner2
|
|
||||||
InnerNamedConstant_2.java:25:13: compiler.err.cant.assign.val.to.final.var: z
|
|
||||||
InnerNamedConstant_2.java:34:26: compiler.err.icls.cant.have.static.decl: InnerNamedConstant_2.Inner3
|
|
||||||
4 errors
|
|
7
test/langtools/tools/javac/InnerNamedConstant_2_A.out
Normal file
7
test/langtools/tools/javac/InnerNamedConstant_2_A.out
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
|
InnerNamedConstant_2.java:23:20: compiler.err.icls.cant.have.static.decl: InnerNamedConstant_2.Inner2
|
||||||
|
InnerNamedConstant_2.java:24:29: compiler.err.icls.cant.have.static.decl: InnerNamedConstant_2.Inner2
|
||||||
|
InnerNamedConstant_2.java:26:13: compiler.err.cant.assign.val.to.final.var: z
|
||||||
|
InnerNamedConstant_2.java:35:26: compiler.err.icls.cant.have.static.decl: InnerNamedConstant_2.Inner3
|
||||||
|
4 errors
|
||||||
|
1 warning
|
2
test/langtools/tools/javac/InnerNamedConstant_2_B.out
Normal file
2
test/langtools/tools/javac/InnerNamedConstant_2_B.out
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
InnerNamedConstant_2.java:26:13: compiler.err.cant.assign.val.to.final.var: z
|
||||||
|
1 error
|
@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @test /nodynamiccopyright/
|
* @test /nodynamiccopyright/
|
||||||
* @bug 4063740 6969184
|
* @bug 4063740 6969184
|
||||||
* @summary Interfaces may only be declared in top level classes.
|
* @summary Interfaces can be declared in inner classes only for source >= 16
|
||||||
* @author turnidge
|
* @author turnidge
|
||||||
*
|
*
|
||||||
* @compile/fail/ref=InterfaceInInner.out -XDrawDiagnostics InterfaceInInner.java
|
* @compile/fail/ref=InterfaceInInner.out -XDrawDiagnostics -source 15 InterfaceInInner.java
|
||||||
|
* @compile InterfaceInInner.java
|
||||||
*/
|
*/
|
||||||
class InterfaceInInner {
|
class InterfaceInInner {
|
||||||
InterfaceInInner() {
|
InterfaceInInner() {
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
InterfaceInInner.java:12:13: compiler.err.static.declaration.not.allowed.in.inner.classes
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
|
InterfaceInInner.java:13:13: compiler.err.icls.cant.have.static.decl: foo
|
||||||
1 error
|
1 error
|
||||||
|
1 warning
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
* @test
|
* @test
|
||||||
* @bug 8222035
|
* @bug 8222035
|
||||||
* @summary minimal inference context optimization is forcing resolution with incomplete constraints
|
* @summary minimal inference context optimization is forcing resolution with incomplete constraints
|
||||||
* @compile/fail/ref=MinContextOpTest.out -XDrawDiagnostics MinContextOpTest.java
|
* @compile/fail/ref=MinContextOpTest_A.out -XDrawDiagnostics -source 15 MinContextOpTest.java
|
||||||
|
* @compile/fail/ref=MinContextOpTest_B.out -XDrawDiagnostics MinContextOpTest.java
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
|
MinContextOpTest.java:39:25: compiler.err.mod.not.allowed.here: static
|
||||||
|
MinContextOpTest.java:45:25: compiler.err.mod.not.allowed.here: static
|
||||||
|
MinContextOpTest.java:51:34: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,K,V,E, (compiler.misc.inconvertible.types: java.util.function.Function<MinContextOpTest.A.T,MinContextOpTest.A.T>, java.util.function.Function<? super MinContextOpTest.A.T,? extends MinContextOpTest.A.T<?>>))
|
||||||
|
3 errors
|
||||||
|
1 warning
|
@ -1,4 +1,2 @@
|
|||||||
MinContextOpTest.java:38:25: compiler.err.mod.not.allowed.here: static
|
MinContextOpTest.java:51:34: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,K,V,E, (compiler.misc.inconvertible.types: java.util.function.Function<MinContextOpTest.A.T,MinContextOpTest.A.T>, java.util.function.Function<? super MinContextOpTest.A.T,? extends MinContextOpTest.A.T<?>>))
|
||||||
MinContextOpTest.java:44:25: compiler.err.mod.not.allowed.here: static
|
1 error
|
||||||
MinContextOpTest.java:50:34: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T,K,V,E, (compiler.misc.inconvertible.types: java.util.function.Function<MinContextOpTest.A.T,MinContextOpTest.A.T>, java.util.function.Function<? super MinContextOpTest.A.T,? extends MinContextOpTest.A.T<?>>))
|
|
||||||
3 errors
|
|
@ -22,6 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.err.static.declaration.not.allowed.in.inner.classes
|
// key: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||||
|
// key: compiler.warn.source.no.system.modules.path
|
||||||
|
// options: -source 15
|
||||||
|
|
||||||
class EnumsMustBeStatic {
|
class EnumsMustBeStatic {
|
||||||
class Nested {
|
class Nested {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -22,6 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// key: compiler.err.icls.cant.have.static.decl
|
// key: compiler.err.icls.cant.have.static.decl
|
||||||
|
// key: compiler.warn.source.no.system.modules.path
|
||||||
|
// options: -source 15
|
||||||
|
|
||||||
class InnerClassCantHaveStatic {
|
class InnerClassCantHaveStatic {
|
||||||
class Inner {
|
class Inner {
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019, 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.err.static.declaration.not.allowed.in.inner.classes
|
|
||||||
|
|
||||||
class Outer {
|
|
||||||
class Inner {
|
|
||||||
record R(int a) {}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @test /nodynamiccopyright/
|
* @test /nodynamiccopyright/
|
||||||
* @bug 5071831
|
* @bug 5071831
|
||||||
* @summary javac allows enum in an inner class
|
* @summary javac allows enum in an inner class for source >= 16
|
||||||
* @author gafter
|
* @author gafter
|
||||||
*
|
*
|
||||||
* @compile/fail/ref=NestedEnum.out -XDrawDiagnostics NestedEnum.java
|
* @compile/fail/ref=NestedEnum.out -XDrawDiagnostics -source 15 NestedEnum.java
|
||||||
|
* @compile NestedEnum.java
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class NestedEnum {
|
class NestedEnum {
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
NestedEnum.java:12:9: compiler.err.static.declaration.not.allowed.in.inner.classes
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
|
NestedEnum.java:13:9: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||||
1 error
|
1 error
|
||||||
|
1 warning
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* @test /nodynamiccopyright/
|
* @test /nodynamiccopyright/
|
||||||
* @bug 5081785
|
* @bug 5081785
|
||||||
* @summary Empty Enums allowed in non-static contexts
|
* @summary enums should be allowed in non-static contexts
|
||||||
* @author Peter von der Ah\u00e9
|
* @author Peter von der Ah\u00e9
|
||||||
* @compile/fail/ref=T5081785.out -XDrawDiagnostics T5081785.java
|
* @compile/fail/ref=T5081785.out -XDrawDiagnostics -source 15 T5081785.java
|
||||||
|
* @compile T5081785.java
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class A1 {
|
class A1 {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
T5081785.java:29:9: compiler.err.static.declaration.not.allowed.in.inner.classes
|
- compiler.warn.source.no.system.modules.path: 15
|
||||||
T5081785.java:12:13: compiler.err.static.declaration.not.allowed.in.inner.classes
|
T5081785.java:30:9: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||||
T5081785.java:19:27: compiler.err.static.declaration.not.allowed.in.inner.classes
|
T5081785.java:13:13: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||||
T5081785.java:24:31: compiler.err.static.declaration.not.allowed.in.inner.classes
|
T5081785.java:20:27: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||||
|
T5081785.java:25:31: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||||
4 errors
|
4 errors
|
||||||
|
1 warning
|
||||||
|
@ -48,6 +48,12 @@ import combo.ComboTask;
|
|||||||
import combo.ComboTask.Result;
|
import combo.ComboTask.Result;
|
||||||
import combo.ComboTestHelper;
|
import combo.ComboTestHelper;
|
||||||
|
|
||||||
|
/** this test checks two thinks:
|
||||||
|
* 1 - that static declarations are allowed inside inner classes
|
||||||
|
* 2 - and in addtion that non-static variables can't be captured
|
||||||
|
* by static contexts
|
||||||
|
*/
|
||||||
|
|
||||||
public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclarations> {
|
public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclarations> {
|
||||||
|
|
||||||
static final String sourceTemplate =
|
static final String sourceTemplate =
|
||||||
@ -57,10 +63,12 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
|||||||
int INSTANCE_FIELD = 0;
|
int INSTANCE_FIELD = 0;
|
||||||
static int STATIC_FIELD = 0;
|
static int STATIC_FIELD = 0;
|
||||||
// instance initializer
|
// instance initializer
|
||||||
{ int LOCAL_VARIABLE = 0;
|
{
|
||||||
|
int LOCAL_VARIABLE = 0;
|
||||||
#{CONTAINER}
|
#{CONTAINER}
|
||||||
}
|
}
|
||||||
Test() {
|
Test() {
|
||||||
|
int LOCAL_VARIABLE = 0;
|
||||||
#{CONTAINER}
|
#{CONTAINER}
|
||||||
}
|
}
|
||||||
void m() {
|
void m() {
|
||||||
@ -93,7 +101,7 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
|||||||
),
|
),
|
||||||
RECORD("record CR() { #{STATIC_LOCAL} }"),
|
RECORD("record CR() { #{STATIC_LOCAL} }"),
|
||||||
CLASS("class CC { #{STATIC_LOCAL} }"),
|
CLASS("class CC { #{STATIC_LOCAL} }"),
|
||||||
ENUM("enum CE { #{STATIC_LOCAL} }"),
|
ENUM("enum CE { CE1; #{STATIC_LOCAL} }"),
|
||||||
LAMBDA("Runnable run = () -> { #{STATIC_LOCAL} };");
|
LAMBDA("Runnable run = () -> { #{STATIC_LOCAL} };");
|
||||||
|
|
||||||
String container;
|
String container;
|
||||||
@ -124,7 +132,6 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Member implements ComboParameter {
|
enum Member implements ComboParameter {
|
||||||
NONE(""),
|
|
||||||
METHOD("int foo() { return #{EXPR}; }"),
|
METHOD("int foo() { return #{EXPR}; }"),
|
||||||
DEFAULT_METHOD("default int foo() { return #{EXPR}; }");
|
DEFAULT_METHOD("default int foo() { return #{EXPR}; }");
|
||||||
|
|
||||||
@ -179,13 +186,13 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean notTriviallyIncorrect() {
|
boolean notTriviallyIncorrect() {
|
||||||
return decl == StaticLocalDecl.INTERFACE && (member == Member.DEFAULT_METHOD || member == Member.NONE) ||
|
return decl == StaticLocalDecl.INTERFACE && member == Member.DEFAULT_METHOD ||
|
||||||
decl != StaticLocalDecl.INTERFACE && (member == Member.METHOD || member == Member.NONE);
|
decl != StaticLocalDecl.INTERFACE && member == Member.METHOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
|
void check(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
|
||||||
if (shouldFail()) {
|
if (shouldFail()) {
|
||||||
Assert.check(result.hasErrors(), result.compilationInfo());
|
Assert.check(result.hasErrors(), "unexpected compilation\n" + result.compilationInfo());
|
||||||
if (!expectedDiagFound(result)) {
|
if (!expectedDiagFound(result)) {
|
||||||
fail("test failing with unexpected error message\n" + result.compilationInfo());
|
fail("test failing with unexpected error message\n" + result.compilationInfo());
|
||||||
}
|
}
|
||||||
@ -195,10 +202,7 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean shouldFail() {
|
boolean shouldFail() {
|
||||||
return ((container != Container.NO_CONTAINER &&
|
return (expr == Expression.LOCAL_VARIABLE || expr == Expression.INSTANCE_FIELD);
|
||||||
container != Container.LAMBDA &&
|
|
||||||
container != Container.ANONYMOUS)) ||
|
|
||||||
(member != Member.NONE && !acceptableExpr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean acceptableExpr() {
|
boolean acceptableExpr() {
|
||||||
@ -206,14 +210,9 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean expectedDiagFound(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
|
boolean expectedDiagFound(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
|
||||||
if ((container == Container.NO_CONTAINER ||
|
if (expr == Expression.LOCAL_VARIABLE || expr == Expression.INSTANCE_FIELD) {
|
||||||
container == Container.LAMBDA ||
|
|
||||||
container == Container.ANONYMOUS) &&
|
|
||||||
!acceptableExpr()) {
|
|
||||||
return result.containsKey("compiler.err.non-static.cant.be.ref");
|
return result.containsKey("compiler.err.non-static.cant.be.ref");
|
||||||
} else if (container == Container.ENUM) {
|
|
||||||
return result.containsKey("compiler.err.enum.constant.expected" );
|
|
||||||
}
|
}
|
||||||
return result.containsKey("compiler.err.static.declaration.not.allowed.in.inner.classes" );
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -477,365 +477,483 @@ public class RecordCompilationTests extends CompilationTestCase {
|
|||||||
assertFail("compiler.err.already.defined", template);
|
assertFail("compiler.err.already.defined", template);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testStaticLocalTypes() {
|
public void testStaticLocals() {
|
||||||
// local records can also be final
|
// static locals can't capture local variables, instance fields or type variables
|
||||||
assertOK("class R { \n" +
|
for (String s : List.of(
|
||||||
" void m() { \n" +
|
"record RR(int x) { public int x() { return y; }};",
|
||||||
" final record RR(int x) { };\n" +
|
"record RR(int x) { public int x() { return z; }};",
|
||||||
" }\n" +
|
"record RR(int x) { public int x() { return instance; }};",
|
||||||
"}");
|
"record RR(T t) {};",
|
||||||
|
"record RR(U u) {};",
|
||||||
|
|
||||||
// Can't capture locals
|
"interface I { default int x() { return y; }};",
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
"interface I { default int x() { return z; }};",
|
||||||
"class R { \n" +
|
"interface I { default int x() { return instance; }};",
|
||||||
" void m(int y) { \n" +
|
"interface I { default int x(T t) { return 0; }};",
|
||||||
" record RR(int x) { public int x() { return y; }};\n" +
|
"interface I { default int x(U u) { return 0; }};",
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
"enum E { A; int x() { return y; }};",
|
||||||
"class R { \n" +
|
"enum E { A; int x() { return z; }};",
|
||||||
" void m() {\n" +
|
"enum E { A; int x() { return instance; }};",
|
||||||
" int y;\n" +
|
"enum E { A; int x(T t) { return 0; }};",
|
||||||
" record RR(int x) { public int x() { return y; }};\n" +
|
"enum E { A; int x(U u) { return 0; }};"
|
||||||
" }\n" +
|
)) {
|
||||||
"}");
|
assertFail("compiler.err.non-static.cant.be.ref",
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static void m() {\n" +
|
|
||||||
" String hello = \"hello\";\n" +
|
|
||||||
" interface I {\n" +
|
|
||||||
" public default void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(hello);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static void m() {\n" +
|
|
||||||
" String hello = \"hello\";\n" +
|
|
||||||
" record R(int i) {\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(hello);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static void m() {\n" +
|
|
||||||
" String hello = \"hello\";\n" +
|
|
||||||
" enum E {\n" +
|
|
||||||
" A;\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(hello);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static void m(String param) {\n" +
|
|
||||||
" interface I {\n" +
|
|
||||||
" public default void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(param);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static void m(String param) {\n" +
|
|
||||||
" record R(int i) {\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(param);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static void m(String param) {\n" +
|
|
||||||
" enum E {\n" +
|
|
||||||
" A;\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(param);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" String instanceField = \"instance\";\n" +
|
|
||||||
" public static void m() {\n" +
|
|
||||||
" interface I {\n" +
|
|
||||||
" public default void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(instanceField);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" String instanceField = \"instance\";\n" +
|
|
||||||
" public static void m(String param) {\n" +
|
|
||||||
" record R(int i) {\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(instanceField);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" String instanceField = \"instance\";\n" +
|
|
||||||
" public static void m(String param) {\n" +
|
|
||||||
" enum E {\n" +
|
|
||||||
" A;\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" System.err.println(instanceField);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
// instance fields
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class R { \n" +
|
|
||||||
" int z = 0;\n" +
|
|
||||||
" void m() { \n" +
|
|
||||||
" record RR(int x) { public int x() { return z; }};\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
// or type variables
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class R<T> { \n" +
|
|
||||||
" void m() { \n" +
|
|
||||||
" record RR(T t) {};\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class R {\n" +
|
|
||||||
" static <U> U make(U u) { //method is static\n" +
|
|
||||||
" interface Checker {\n" +
|
|
||||||
" void check(U u);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" return null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class LocalEnum {\n" +
|
|
||||||
" static <U> U getAndSet(U u) { //method is static\n" +
|
|
||||||
" enum X {\n" +
|
|
||||||
" A;\n" +
|
|
||||||
" U u;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" return null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class R {\n" +
|
|
||||||
" static <U> U make(U u) { //method is static\n" +
|
|
||||||
" record Checker() {\n" +
|
|
||||||
" void check(U u);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" return null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class R {\n" +
|
|
||||||
" <U> U make(U u) { // enclosing method is not static\n" +
|
|
||||||
" interface Checker {\n" +
|
|
||||||
" void check(U u);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" return null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class LocalEnum {\n" +
|
|
||||||
" <U> U getAndSet(U u) { // enclosing method is not static\n" +
|
|
||||||
" enum X {\n" +
|
|
||||||
" A;\n" +
|
|
||||||
" U u;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" return null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}\n");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class R {\n" +
|
|
||||||
" <U> U make(U u) { // enclosing method is not static\n" +
|
|
||||||
" record Checker() {\n" +
|
|
||||||
" void check(U u);\n" +
|
|
||||||
" }\n" +
|
|
||||||
" return null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static <T> void main(String[] args) {\n" +
|
|
||||||
" interface I {\n" +
|
|
||||||
" public default void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" T t = null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static <T> void main(String[] args) {\n" +
|
|
||||||
" record R(int i) {\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" T t = null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
assertFail("compiler.err.non-static.cant.be.ref",
|
|
||||||
"class C {\n" +
|
|
||||||
" public static <T> void main(String[] args) {\n" +
|
|
||||||
" enum E {\n" +
|
|
||||||
" A;\n" +
|
|
||||||
" public void test1() {\n" +
|
|
||||||
" class X {\n" +
|
|
||||||
" public void test2() {\n" +
|
|
||||||
" T t = null;\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
|
|
||||||
// but static fields are OK
|
|
||||||
assertOK("class R { \n" +
|
|
||||||
" static int z = 0;\n" +
|
|
||||||
" void m() { \n" +
|
|
||||||
" record RR(int x) { public int x() { return z; }};\n" +
|
|
||||||
" }\n" +
|
|
||||||
"}");
|
|
||||||
// Can't self-shadow
|
|
||||||
assertFail("compiler.err.already.defined",
|
|
||||||
"""
|
"""
|
||||||
class R {
|
class R<T> {
|
||||||
void m() {
|
int instance = 0;
|
||||||
record R(int x) { };
|
<U> U m(int y) {
|
||||||
|
int z;
|
||||||
|
#S
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
""".replaceFirst("#S", s));
|
||||||
);
|
}
|
||||||
|
|
||||||
|
// a similar example but a bit more complex
|
||||||
|
for (String s : List.of(
|
||||||
|
"record R() { void test1() { class X { void test2() { System.err.println(localVar); } } } }",
|
||||||
|
"record R() { void test1() { class X { void test2() { System.err.println(param); } } } }",
|
||||||
|
"record R() {void test1() { class X { void test2() { System.err.println(instanceField); } } } }",
|
||||||
|
"record R() { void test1() { class X { T t; } } }",
|
||||||
|
"record R() { void test1() { class X { U u; } } }",
|
||||||
|
|
||||||
|
"interface I { default void test1() { class X { void test2() { System.err.println(localVar); } } } }",
|
||||||
|
"interface I() { default void test1() { class X { void test2() {System.err.println(param);} } } }",
|
||||||
|
"interface I { default void test1() { class X { void test2() { System.err.println(instanceField); } } } }",
|
||||||
|
"interface I { default void test1() { class X { T t; } } }",
|
||||||
|
"interface I() { default void test1() { class X {U u;} } }",
|
||||||
|
|
||||||
|
"enum E { A; void test1() { class X { void test2() { System.err.println(localVar); } } } }",
|
||||||
|
"enum E { A; void test1() { class X { void test2() {System.err.println(param);} } } }",
|
||||||
|
"enum E { A; void test1() { class X { void test2() { System.err.println(instanceField); } } } }",
|
||||||
|
"enum E { A; void test1() { class X { T t; } } }",
|
||||||
|
"enum E { A; void test1() { class X {U u;} } }"
|
||||||
|
)) {
|
||||||
|
assertFail("compiler.err.non-static.cant.be.ref",
|
||||||
|
"""
|
||||||
|
class C<T> {
|
||||||
|
String instanceField = "instance";
|
||||||
|
static <U> U m(String param) {
|
||||||
|
String localVar = "local";
|
||||||
|
#S
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replaceFirst("#S", s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't self-shadow
|
||||||
|
for (String s : List.of("record R() {}", "interface R {}", "enum R { A }")) {
|
||||||
|
assertFail("compiler.err.already.defined", "class R { void m() { #S } }".replaceFirst("#S", s));
|
||||||
|
}
|
||||||
|
|
||||||
// can't be explicitly static
|
// can't be explicitly static
|
||||||
assertFail("compiler.err.illegal.start.of.expr",
|
for (String s : List.of("static record RR() { }", "static interface I {}", "static enum E { A }")) {
|
||||||
|
assertFail("compiler.err.illegal.start.of.expr", "class R { void m() { #S } }".replaceFirst("#S", s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// but static fields can be accessed
|
||||||
|
for (String s : List.of(
|
||||||
|
"record RR() { public int x() { return z; } };",
|
||||||
|
"interface I { default int x() { return z; } }",
|
||||||
|
"enum E { A; int x() { return z; } }"
|
||||||
|
)) {
|
||||||
|
assertOK("class R { static int z = 0; void m() { #S } }".replaceFirst("#S", s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// local records can also be final
|
||||||
|
assertOK("class R { void m() { final record RR(int x) { }; } }");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStaticDefinitionsInInnerClasses() {
|
||||||
|
// static defs in inner classes can't capture instance fields or type variables
|
||||||
|
for (String s : List.of(
|
||||||
"""
|
"""
|
||||||
class R {
|
record R() {
|
||||||
void m() {
|
void test() { System.err.println(field); }
|
||||||
static record RR(int x) { };
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
);
|
)) {
|
||||||
|
assertFail("compiler.err.non-static.cant.be.ref",
|
||||||
|
"""
|
||||||
|
class C<T> {
|
||||||
|
String field = "field";
|
||||||
|
class Inner {
|
||||||
|
#S
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replaceFirst("#S", s));
|
||||||
|
}
|
||||||
|
|
||||||
// positive cases
|
// another, more complex, example
|
||||||
assertOK(
|
// static defs in inner classes can't capture instance locals, fields or type variables
|
||||||
|
for (String s : List.of(
|
||||||
"""
|
"""
|
||||||
import java.security.*;
|
record R() {
|
||||||
class Test {
|
void test() { System.err.println(field); }
|
||||||
static Test newInstance(Object provider) {
|
}
|
||||||
return new Test() {
|
""",
|
||||||
private final PrivilegedExceptionAction<KeyStore> action = new PrivilegedExceptionAction<KeyStore>() {
|
"""
|
||||||
public KeyStore run() throws Exception {
|
record R() {
|
||||||
if (provider == null) {}
|
void test1() {
|
||||||
return null;
|
class X { void test2() { System.err.println(field); } }
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
};
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test1() {
|
||||||
|
class X { void test2() { System.err.println(param); } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test1() {
|
||||||
|
class X { void test2() { System.err.println(local); } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
record R() {
|
||||||
|
void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
interface I {
|
||||||
|
default void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
enum E {
|
||||||
|
A;
|
||||||
|
void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(field); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(param); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test1() {
|
||||||
|
class X {
|
||||||
|
void test2() { System.err.println(local); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test(T t) {}
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
"""
|
||||||
|
static class SC {
|
||||||
|
void test1() {
|
||||||
|
class X { void test2(T t) {} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
);
|
)) {
|
||||||
|
assertFail("compiler.err.non-static.cant.be.ref",
|
||||||
assertOK(
|
"""
|
||||||
"""
|
class C<T> {
|
||||||
import java.security.*;
|
String field = "field";
|
||||||
class Test {
|
<U> U m(String param) {
|
||||||
static Test newInstance(Object provider) {
|
String local = "local";
|
||||||
return new Test() {
|
class Local {
|
||||||
int m(PrivilegedExceptionAction<KeyStore> a) { return 0; }
|
class Inner { #S }
|
||||||
{
|
|
||||||
m(
|
|
||||||
new PrivilegedExceptionAction<KeyStore>() {
|
|
||||||
public KeyStore run() throws Exception {
|
|
||||||
if (provider == null) {}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
""".replaceFirst("#S", s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// inner classes can contain static methods too
|
||||||
|
assertOK(
|
||||||
|
"""
|
||||||
|
class C {
|
||||||
|
class Inner {
|
||||||
|
// static method inside inner class
|
||||||
|
static void m() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
|
||||||
|
assertOK(
|
||||||
|
"""
|
||||||
|
class C {
|
||||||
|
void m() {
|
||||||
|
new Object() {
|
||||||
|
// static method inside inner class
|
||||||
|
static void m() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
);
|
);
|
||||||
@ -869,7 +987,7 @@ public class RecordCompilationTests extends CompilationTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testRecordsInsideInner() {
|
public void testRecordsInsideInner() {
|
||||||
assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
|
assertOK(
|
||||||
"""
|
"""
|
||||||
class Outer {
|
class Outer {
|
||||||
class Inner {
|
class Inner {
|
||||||
@ -878,7 +996,7 @@ public class RecordCompilationTests extends CompilationTestCase {
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
);
|
);
|
||||||
assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
|
assertOK(
|
||||||
"""
|
"""
|
||||||
class Outer {
|
class Outer {
|
||||||
public void test() {
|
public void test() {
|
||||||
@ -888,7 +1006,7 @@ public class RecordCompilationTests extends CompilationTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
|
assertOK(
|
||||||
"""
|
"""
|
||||||
class Outer {
|
class Outer {
|
||||||
Runnable run = new Runnable() {
|
Runnable run = new Runnable() {
|
||||||
@ -897,7 +1015,7 @@ public class RecordCompilationTests extends CompilationTestCase {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
|
assertOK(
|
||||||
"""
|
"""
|
||||||
class Outer {
|
class Outer {
|
||||||
void m() {
|
void m() {
|
||||||
|
Loading…
Reference in New Issue
Block a user