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.
|
||||
*/
|
||||
public static final int
|
||||
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
|
||||
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
|
||||
StaticLocalFlags = LocalClassFlags | STATIC | INTERFACE,
|
||||
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
|
||||
MemberRecordFlags = MemberClassFlags | STATIC,
|
||||
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
|
||||
InterfaceVarFlags = FINAL | STATIC | PUBLIC,
|
||||
VarFlags = AccessFlags | FINAL | STATIC |
|
||||
VOLATILE | TRANSIENT | ENUM,
|
||||
ConstructorFlags = AccessFlags,
|
||||
InterfaceMethodFlags = ABSTRACT | PUBLIC,
|
||||
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
|
||||
SYNCHRONIZED | FINAL | STRICTFP,
|
||||
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
|
||||
SYNCHRONIZED | FINAL | STRICTFP;
|
||||
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
|
||||
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
|
||||
StaticLocalFlags = LocalClassFlags | STATIC | INTERFACE,
|
||||
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
|
||||
MemberStaticClassFlags = MemberClassFlags | STATIC,
|
||||
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
|
||||
InterfaceVarFlags = FINAL | STATIC | PUBLIC,
|
||||
VarFlags = AccessFlags | FINAL | STATIC |
|
||||
VOLATILE | TRANSIENT | ENUM,
|
||||
ConstructorFlags = AccessFlags,
|
||||
InterfaceMethodFlags = ABSTRACT | PUBLIC,
|
||||
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
|
||||
SYNCHRONIZED | FINAL | STRICTFP,
|
||||
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
|
||||
SYNCHRONIZED | FINAL | STRICTFP;
|
||||
public static final long
|
||||
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED,
|
||||
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED,
|
||||
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED,
|
||||
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
|
||||
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
|
||||
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
|
||||
LocalVarFlags = FINAL | PARAMETER,
|
||||
ReceiverParamFlags = PARAMETER;
|
||||
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED,
|
||||
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED,
|
||||
ExtendedMemberStaticClassFlags = (long) MemberStaticClassFlags | SEALED | NON_SEALED,
|
||||
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED,
|
||||
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
|
||||
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
|
||||
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
|
||||
LocalVarFlags = FINAL | PARAMETER,
|
||||
ReceiverParamFlags = PARAMETER;
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
public static Set<Modifier> asModifierSet(long flags) {
|
||||
|
@ -171,6 +171,7 @@ public class Attr extends JCTree.Visitor {
|
||||
allowReifiableTypesInInstanceof =
|
||||
Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source) &&
|
||||
(!preview.isPreview(Feature.REIFIABLE_TYPES_INSTANCEOF) || preview.isEnabled());
|
||||
allowRecords = Feature.RECORDS.allowedInSource(source);
|
||||
sourceName = source.name;
|
||||
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
||||
|
||||
@ -207,6 +208,10 @@ public class Attr extends JCTree.Visitor {
|
||||
*/
|
||||
boolean allowReifiableTypesInInstanceof;
|
||||
|
||||
/** Are records allowed
|
||||
*/
|
||||
private final boolean allowRecords;
|
||||
|
||||
/**
|
||||
* Switch: warn about use of variable before declaration?
|
||||
* RFE: 6425594
|
||||
@ -5309,14 +5314,15 @@ public class Attr extends JCTree.Visitor {
|
||||
attribStat(l.head, env);
|
||||
// Check that declarations in inner classes are not static (JLS 8.1.2)
|
||||
// Make an exception for static constants.
|
||||
if (c.owner.kind != PCK &&
|
||||
((c.flags() & STATIC) == 0 || c.name == names.empty) &&
|
||||
(TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) {
|
||||
if (!allowRecords &&
|
||||
c.owner.kind != PCK &&
|
||||
((c.flags() & STATIC) == 0 || c.name == names.empty) &&
|
||||
(TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) {
|
||||
Symbol sym = null;
|
||||
if (l.head.hasTag(VARDEF)) sym = ((JCVariableDecl) l.head).sym;
|
||||
if (sym == null ||
|
||||
sym.kind != VAR ||
|
||||
((VarSymbol) sym).getConstValue() == null)
|
||||
sym.kind != VAR ||
|
||||
((VarSymbol) sym).getConstValue() == null)
|
||||
log.error(l.head.pos(), Errors.IclsCantHaveStaticDecl(c));
|
||||
}
|
||||
}
|
||||
|
@ -1216,23 +1216,20 @@ public class Check {
|
||||
implicit |= sym.owner.flags_field & STRICTFP;
|
||||
break;
|
||||
case TYP:
|
||||
if (sym.isLocal()) {
|
||||
if (sym.owner.kind.matches(KindSelector.VAL_MTH)) {
|
||||
boolean implicitlyStatic = !sym.isAnonymous() &&
|
||||
((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
|
||||
boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
|
||||
// local statics are allowed only if records are allowed too
|
||||
mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
|
||||
implicit = implicitlyStatic ? STATIC : implicit;
|
||||
if (staticOrImplicitlyStatic) {
|
||||
if (sym.owner.kind == TYP) {
|
||||
log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
|
||||
}
|
||||
}
|
||||
} 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 ||
|
||||
(sym.owner.flags_field & STATIC) != 0)
|
||||
(sym.owner.flags_field & STATIC) != 0) {
|
||||
mask |= STATIC;
|
||||
else if ((flags & ENUM) != 0 || (flags & RECORD) != 0) {
|
||||
} else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
|
||||
log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
|
||||
}
|
||||
// Nested interfaces and enums are always STATIC (Spec ???)
|
||||
|
@ -24,10 +24,11 @@
|
||||
/*
|
||||
* @test
|
||||
* @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
|
||||
*
|
||||
* @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 {
|
||||
|
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/
|
||||
* @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
|
||||
*
|
||||
* @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 {
|
||||
|
@ -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 warning
|
||||
|
@ -4,7 +4,8 @@
|
||||
* @summary Verify rejection of illegal static variables in inner classes.
|
||||
* @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 {
|
||||
|
@ -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/
|
||||
* @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
|
||||
*
|
||||
* @compile/fail/ref=InterfaceInInner.out -XDrawDiagnostics InterfaceInInner.java
|
||||
* @compile/fail/ref=InterfaceInInner.out -XDrawDiagnostics -source 15 InterfaceInInner.java
|
||||
* @compile InterfaceInInner.java
|
||||
*/
|
||||
class 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 warning
|
||||
|
@ -25,7 +25,8 @@
|
||||
* @test
|
||||
* @bug 8222035
|
||||
* @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;
|
||||
|
@ -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:44:25: compiler.err.mod.not.allowed.here: static
|
||||
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
|
||||
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<?>>))
|
||||
1 error
|
@ -22,6 +22,8 @@
|
||||
*/
|
||||
|
||||
// key: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||
// key: compiler.warn.source.no.system.modules.path
|
||||
// options: -source 15
|
||||
|
||||
class EnumsMustBeStatic {
|
||||
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.
|
||||
*
|
||||
* 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.warn.source.no.system.modules.path
|
||||
// options: -source 15
|
||||
|
||||
class InnerClassCantHaveStatic {
|
||||
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/
|
||||
* @bug 5071831
|
||||
* @summary javac allows enum in an inner class
|
||||
* @summary javac allows enum in an inner class for source >= 16
|
||||
* @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 {
|
||||
|
@ -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 warning
|
||||
|
@ -1,9 +1,10 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @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
|
||||
* @compile/fail/ref=T5081785.out -XDrawDiagnostics T5081785.java
|
||||
* @compile/fail/ref=T5081785.out -XDrawDiagnostics -source 15 T5081785.java
|
||||
* @compile T5081785.java
|
||||
*/
|
||||
|
||||
class A1 {
|
||||
|
@ -1,5 +1,7 @@
|
||||
T5081785.java:29:9: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||
T5081785.java:12:13: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||
T5081785.java:19:27: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||
T5081785.java:24:31: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||
- compiler.warn.source.no.system.modules.path: 15
|
||||
T5081785.java:30:9: compiler.err.static.declaration.not.allowed.in.inner.classes
|
||||
T5081785.java:13:13: 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
|
||||
1 warning
|
||||
|
@ -48,6 +48,12 @@ import combo.ComboTask;
|
||||
import combo.ComboTask.Result;
|
||||
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> {
|
||||
|
||||
static final String sourceTemplate =
|
||||
@ -57,10 +63,12 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
||||
int INSTANCE_FIELD = 0;
|
||||
static int STATIC_FIELD = 0;
|
||||
// instance initializer
|
||||
{ int LOCAL_VARIABLE = 0;
|
||||
{
|
||||
int LOCAL_VARIABLE = 0;
|
||||
#{CONTAINER}
|
||||
}
|
||||
Test() {
|
||||
int LOCAL_VARIABLE = 0;
|
||||
#{CONTAINER}
|
||||
}
|
||||
void m() {
|
||||
@ -93,7 +101,7 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
||||
),
|
||||
RECORD("record CR() { #{STATIC_LOCAL} }"),
|
||||
CLASS("class CC { #{STATIC_LOCAL} }"),
|
||||
ENUM("enum CE { #{STATIC_LOCAL} }"),
|
||||
ENUM("enum CE { CE1; #{STATIC_LOCAL} }"),
|
||||
LAMBDA("Runnable run = () -> { #{STATIC_LOCAL} };");
|
||||
|
||||
String container;
|
||||
@ -124,7 +132,6 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
||||
}
|
||||
|
||||
enum Member implements ComboParameter {
|
||||
NONE(""),
|
||||
METHOD("int foo() { return #{EXPR}; }"),
|
||||
DEFAULT_METHOD("default int foo() { return #{EXPR}; }");
|
||||
|
||||
@ -179,13 +186,13 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
||||
}
|
||||
|
||||
boolean notTriviallyIncorrect() {
|
||||
return decl == StaticLocalDecl.INTERFACE && (member == Member.DEFAULT_METHOD || member == Member.NONE) ||
|
||||
decl != StaticLocalDecl.INTERFACE && (member == Member.METHOD || member == Member.NONE);
|
||||
return decl == StaticLocalDecl.INTERFACE && member == Member.DEFAULT_METHOD ||
|
||||
decl != StaticLocalDecl.INTERFACE && member == Member.METHOD;
|
||||
}
|
||||
|
||||
void check(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
|
||||
if (shouldFail()) {
|
||||
Assert.check(result.hasErrors(), result.compilationInfo());
|
||||
Assert.check(result.hasErrors(), "unexpected compilation\n" + result.compilationInfo());
|
||||
if (!expectedDiagFound(result)) {
|
||||
fail("test failing with unexpected error message\n" + result.compilationInfo());
|
||||
}
|
||||
@ -195,10 +202,7 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
||||
}
|
||||
|
||||
boolean shouldFail() {
|
||||
return ((container != Container.NO_CONTAINER &&
|
||||
container != Container.LAMBDA &&
|
||||
container != Container.ANONYMOUS)) ||
|
||||
(member != Member.NONE && !acceptableExpr());
|
||||
return (expr == Expression.LOCAL_VARIABLE || expr == Expression.INSTANCE_FIELD);
|
||||
}
|
||||
|
||||
boolean acceptableExpr() {
|
||||
@ -206,14 +210,9 @@ public class LocalStaticDeclarations extends ComboInstance<LocalStaticDeclaratio
|
||||
}
|
||||
|
||||
boolean expectedDiagFound(ComboTask.Result<Iterable<? extends JavaFileObject>> result) {
|
||||
if ((container == Container.NO_CONTAINER ||
|
||||
container == Container.LAMBDA ||
|
||||
container == Container.ANONYMOUS) &&
|
||||
!acceptableExpr()) {
|
||||
if (expr == Expression.LOCAL_VARIABLE || expr == Expression.INSTANCE_FIELD) {
|
||||
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);
|
||||
}
|
||||
|
||||
public void testStaticLocalTypes() {
|
||||
// local records can also be final
|
||||
assertOK("class R { \n" +
|
||||
" void m() { \n" +
|
||||
" final record RR(int x) { };\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
public void testStaticLocals() {
|
||||
// static locals can't capture local variables, instance fields or type variables
|
||||
for (String s : List.of(
|
||||
"record RR(int x) { public int x() { return y; }};",
|
||||
"record RR(int x) { public int x() { return z; }};",
|
||||
"record RR(int x) { public int x() { return instance; }};",
|
||||
"record RR(T t) {};",
|
||||
"record RR(U u) {};",
|
||||
|
||||
// Can't capture locals
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R { \n" +
|
||||
" void m(int y) { \n" +
|
||||
" record RR(int x) { public int x() { return y; }};\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
"interface I { default int x() { return y; }};",
|
||||
"interface I { default int x() { return z; }};",
|
||||
"interface I { default int x() { return instance; }};",
|
||||
"interface I { default int x(T t) { return 0; }};",
|
||||
"interface I { default int x(U u) { return 0; }};",
|
||||
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"class R { \n" +
|
||||
" void m() {\n" +
|
||||
" int y;\n" +
|
||||
" record RR(int x) { public int x() { return y; }};\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
|
||||
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",
|
||||
"enum E { A; int x() { return y; }};",
|
||||
"enum E { A; int x() { return z; }};",
|
||||
"enum E { A; int x() { return instance; }};",
|
||||
"enum E { A; int x(T t) { return 0; }};",
|
||||
"enum E { A; int x(U u) { return 0; }};"
|
||||
)) {
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"""
|
||||
class R {
|
||||
void m() {
|
||||
record R(int x) { };
|
||||
class R<T> {
|
||||
int instance = 0;
|
||||
<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
|
||||
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 {
|
||||
void m() {
|
||||
static record RR(int x) { };
|
||||
record R() {
|
||||
void test() { System.err.println(field); }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
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
|
||||
assertOK(
|
||||
// another, more complex, example
|
||||
// static defs in inner classes can't capture instance locals, fields or type variables
|
||||
for (String s : List.of(
|
||||
"""
|
||||
import java.security.*;
|
||||
class Test {
|
||||
static Test newInstance(Object provider) {
|
||||
return new Test() {
|
||||
private final PrivilegedExceptionAction<KeyStore> action = new PrivilegedExceptionAction<KeyStore>() {
|
||||
public KeyStore run() throws Exception {
|
||||
if (provider == null) {}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
record R() {
|
||||
void test() { System.err.println(field); }
|
||||
}
|
||||
""",
|
||||
"""
|
||||
record R() {
|
||||
void test1() {
|
||||
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) {} }
|
||||
}
|
||||
}
|
||||
"""
|
||||
);
|
||||
|
||||
assertOK(
|
||||
"""
|
||||
import java.security.*;
|
||||
class Test {
|
||||
static Test newInstance(Object provider) {
|
||||
return new Test() {
|
||||
int m(PrivilegedExceptionAction<KeyStore> a) { return 0; }
|
||||
{
|
||||
m(
|
||||
new PrivilegedExceptionAction<KeyStore>() {
|
||||
public KeyStore run() throws Exception {
|
||||
if (provider == null) {}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
)) {
|
||||
assertFail("compiler.err.non-static.cant.be.ref",
|
||||
"""
|
||||
class C<T> {
|
||||
String field = "field";
|
||||
<U> U m(String param) {
|
||||
String local = "local";
|
||||
class Local {
|
||||
class Inner { #S }
|
||||
}
|
||||
};
|
||||
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() {
|
||||
assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
|
||||
assertOK(
|
||||
"""
|
||||
class Outer {
|
||||
class Inner {
|
||||
@ -878,7 +996,7 @@ public class RecordCompilationTests extends CompilationTestCase {
|
||||
}
|
||||
"""
|
||||
);
|
||||
assertFail("compiler.err.static.declaration.not.allowed.in.inner.classes",
|
||||
assertOK(
|
||||
"""
|
||||
class Outer {
|
||||
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 {
|
||||
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 {
|
||||
void m() {
|
||||
|
Loading…
Reference in New Issue
Block a user