Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

8263614: javac allows local variables to be accessed from a static context #4004

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -1486,6 +1486,11 @@ Symbol findVar(Env<AttrContext> env, Name name) {
Symbol bestSoFar = varNotFound;
Env<AttrContext> env1 = env;
boolean staticOnly = false;
/** the static level value in the current environment should count the number of nested static modifiers
* but this calculation doesn't consider static type declarations. Now that implicitly static
* local type declarations like records, interfaces and enums, are allowed we need to adjust the static level
*/
int adjustedStaticLevel = env.info.staticLevel;
while (env1.outer != null) {
Symbol sym = null;
if (isStatic(env1)) staticOnly = true;
Expand All @@ -1504,22 +1509,24 @@ Symbol findVar(Env<AttrContext> env, Name name) {
sym.kind == VAR &&
// if it is a field
(sym.owner.kind == TYP ||
// or it is a local variable but it is not declared inside of the static local type
// then error
/* or it is a local variable but it is not declared in the same static context it is being
* referred from
*/
allowRecords &&
(sym.owner.kind == MTH) &&
env1 != env &&
!isInnerClassOfMethod(sym.owner, env.tree.hasTag(CLASSDEF) ?
((JCClassDecl)env.tree).sym :
env.enclClass.sym)))
adjustedStaticLevel > env1.info.staticLevel))
return new StaticError(sym);
else
return sym;
} else {
bestSoFar = bestOf(bestSoFar, sym);
}

if ((env1.enclClass.sym.flags() & STATIC) != 0) staticOnly = true;
if ((env1.enclClass.sym.flags() & STATIC) != 0) {
staticOnly = true;
adjustedStaticLevel++;
}
env1 = env1.outer;
}

Expand Down Expand Up @@ -2313,7 +2320,8 @@ Symbol findGlobalType(Env<AttrContext> env, Scope scope, Name name, RecoveryLoad
return bestSoFar;
}

Symbol findTypeVar(Env<AttrContext> currentEnv, Env<AttrContext> originalEnv, Name name, boolean staticOnly) {
Symbol findTypeVar(Env<AttrContext> currentEnv, Env<AttrContext> originalEnv, Name name, boolean staticOnly, int adjustedStaticLevel) {
// the adjusted static level is the
for (Symbol sym : currentEnv.info.scope.getSymbolsByName(name)) {
if (sym.kind == TYP) {
if (staticOnly &&
Expand All @@ -2323,9 +2331,7 @@ Symbol findTypeVar(Env<AttrContext> currentEnv, Env<AttrContext> originalEnv, Na
allowRecords &&
(sym.owner.kind == MTH &&
currentEnv != originalEnv &&
!isInnerClassOfMethod(sym.owner, originalEnv.tree.hasTag(CLASSDEF) ?
((JCClassDecl)originalEnv.tree).sym :
originalEnv.enclClass.sym)))) {
adjustedStaticLevel > currentEnv.info.staticLevel))) {
return new StaticError(sym);
}
return sym;
Expand All @@ -2334,14 +2340,6 @@ Symbol findTypeVar(Env<AttrContext> currentEnv, Env<AttrContext> originalEnv, Na
return typeNotFound;
}

boolean isInnerClassOfMethod(Symbol msym, Symbol csym) {
while (csym.owner != msym) {
if (csym.isStatic()) return false;
csym = csym.owner.enclClass();
}
return (csym.owner == msym && !csym.isStatic());
}

/** Find an unqualified type symbol.
* @param env The current environment.
* @param name The type's name.
Expand All @@ -2352,10 +2350,11 @@ Symbol findType(Env<AttrContext> env, Name name) {
Symbol bestSoFar = typeNotFound;
Symbol sym;
boolean staticOnly = false;
int adjustedStaticLevel = env.info.staticLevel;
for (Env<AttrContext> env1 = env; env1.outer != null; env1 = env1.outer) {
if (isStatic(env1)) staticOnly = true;
// First, look for a type variable and the first member type
final Symbol tyvar = findTypeVar(env1, env, name, staticOnly);
final Symbol tyvar = findTypeVar(env1, env, name, staticOnly, adjustedStaticLevel);
sym = findImmediateMemberType(env1, env1.enclClass.sym.type,
name, env1.enclClass.sym);

Expand Down Expand Up @@ -2385,8 +2384,12 @@ Symbol findType(Env<AttrContext> env, Name name) {
else bestSoFar = bestOf(bestSoFar, sym);

JCClassDecl encl = env1.baseClause ? (JCClassDecl)env1.tree : env1.enclClass;
if ((encl.sym.flags() & STATIC) != 0)
if ((encl.sym.flags() & STATIC) != 0) {
staticOnly = true;
}
if ((env1.enclClass.sym.flags() & STATIC) != 0) {
adjustedStaticLevel++;
}
}

if (!env.tree.hasTag(IMPORT)) {
Expand Down
74 changes: 74 additions & 0 deletions test/langtools/tools/javac/records/RecordCompilationTests.java
Expand Up @@ -746,12 +746,24 @@ void test(T t) {}
}
""",
"""
record R() {
void test(U u) {}
}
""",
"""
record R() {
void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
record R() {
void test1() {
class X { void test2(U u) {} }
}
}
""",

"""
interface I {
Expand Down Expand Up @@ -801,12 +813,24 @@ default void test(T t) {}
}
""",
"""
interface I {
default void test(U u) {}
}
""",
"""
interface I {
default void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
interface I {
default void test1() {
class X { void test2(U u) {} }
}
}
""",

"""
enum E {
Expand Down Expand Up @@ -863,13 +887,27 @@ void test(T t) {}
}
""",
"""
enum E {
A;
void test(U u) {}
}
""",
"""
enum E {
A;
void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
enum E {
A;
void test1() {
class X { void test2(U u) {} }
}
}
""",

"""
static class SC {
Expand Down Expand Up @@ -919,11 +957,23 @@ void test(T t) {}
}
""",
"""
static class SC {
void test(U u) {}
}
""",
"""
static class SC {
void test1() {
class X { void test2(T t) {} }
}
}
""",
"""
static class SC {
void test1() {
class X { void test2(U u) {} }
}
}
"""
)) {
assertFail("compiler.err.non-static.cant.be.ref",
Expand Down Expand Up @@ -965,6 +1015,30 @@ static void m() {}
}
"""
);

// but still non-static declarations can't be accessed from a static method inside a local class
for (String s : List.of(
"System.out.println(localVar)",
"System.out.println(param)",
"System.out.println(field)",
"T t",
"U u"
)) {
assertFail("compiler.err.non-static.cant.be.ref",
"""
class C<T> {
int field = 0;
<U> void foo(int param) {
int localVar = 1;
class Local {
static void m() {
#S;
}
}
}
}
""".replaceFirst("#S", s));
}
}

public void testReturnInCanonical_Compact() {
Expand Down