Skip to content

Commit

Permalink
[24] don't request access to enclosing class if it's never used
Browse files Browse the repository at this point in the history
Fixes after re-opening:
+ essentially revert previous change
+ replace with specific detection wrt local type alloc in static context

Fixes eclipse-jdt#3194
  • Loading branch information
stephan-herrmann committed Dec 15, 2024
1 parent feb6e0c commit b6980e6
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* IBM Corporation - added the following constants
Expand Down Expand Up @@ -2759,6 +2763,11 @@ public interface IProblem {
*/
int ConstructorCallNotAllowedHere = PreviewRelated + 2031;

/**
* @since 3.40
*/
int AllocatingLocalInStaticContext = TypeRelated + 2032;

/**
* @since 3.40
* @noreference preview feature
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contributions for
Expand Down Expand Up @@ -363,6 +367,11 @@ public TypeBinding resolveType(BlockScope scope) {
} else {
this.resolvedType = this.type.resolveType(scope, true /* check bounds*/);
}
if (this.resolvedType instanceof LocalTypeBinding local && this.enumConstant == null) {
MethodScope enclosingMethodScope = local.scope.enclosingMethodScope();
if (enclosingMethodScope != null && !enclosingMethodScope.isStatic && scope.isInStaticContext())
scope.problemReporter().allocationInStaticContext(this, local);
}
if (this.type != null) {
checkIllegalNullAnnotation(scope, this.resolvedType);
checkParameterizedAllocation: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Jesper S Moller - Contributions for
Expand Down Expand Up @@ -718,6 +722,12 @@ enclosing instance of this (8.1.3)", we will actually implement this check in co
if (isMethodReference) {
someMethod = scope.getMethod(this.receiverType, this.selector, descriptorParameters, this);
} else {
if (this.receiverType instanceof LocalTypeBinding local) {
MethodScope enclosingMethodScope = local.scope.enclosingMethodScope();
if (enclosingMethodScope != null && !enclosingMethodScope.isStatic && scope.isInStaticContext()) {
scope.problemReporter().allocationInStaticContext(this, local);
}
}
if (argumentsTypeElided() && this.receiverType.isRawType()) {
boolean[] inferredReturnType = new boolean[1];
someMethod = AllocationExpression.inferDiamondConstructor(scope, this, this.receiverType, this.descriptor.parameters, inferredReturnType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
Expand Down Expand Up @@ -921,22 +925,18 @@ public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo f
if ((this.bits & Binding.FIELD) != 0) {
FieldBinding fieldBinding = (FieldBinding) this.binding;
FieldBinding codegenField = fieldBinding.original();
if ((this.bits & ASTNode.DepthMASK) != 0) {
if ((codegenField.isPrivate() // private access
&& !currentScope.enclosingSourceType().isNestmateOf(codegenField.declaringClass))
|| (codegenField.isProtected() // implicit protected access
&& codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) {
if (this.syntheticAccessors == null)
this.syntheticAccessors = new MethodBinding[2];
this.syntheticAccessors[isReadAccess ? SingleNameReference.READ : SingleNameReference.WRITE] =
((SourceTypeBinding) currentScope.enclosingSourceType().
enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess, false /* not super access */);
currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess);
return;
}
if (!codegenField.isStatic() && currentScope.enclosingSourceType() instanceof NestedTypeBinding nestedType) {
nestedType.requestEnclosingInstancePathTo(codegenField.declaringClass);
}
if (((this.bits & ASTNode.DepthMASK) != 0)
&& ((codegenField.isPrivate() // private access
&& !currentScope.enclosingSourceType().isNestmateOf(codegenField.declaringClass) )
|| (codegenField.isProtected() // implicit protected access
&& codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) {
if (this.syntheticAccessors == null)
this.syntheticAccessors = new MethodBinding[2];
this.syntheticAccessors[isReadAccess ? SingleNameReference.READ : SingleNameReference.WRITE] =
((SourceTypeBinding)currentScope.enclosingSourceType().
enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess, false /*not super access*/);
currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess);
return;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contributions for
Expand Down Expand Up @@ -1072,14 +1076,9 @@ public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, Fl
outerScope = outerScope.enclosingInstanceScope();
earlySeen = methodScope.isInsideEarlyConstructionContext(nestedType.enclosingType(), false);
}
if (JavaFeature.FLEXIBLE_CONSTRUCTOR_BODIES.isSupported(currentScope.compilerOptions())
&& nestedType.enclosingInstances != null) // only if access to enclosing instance has already been requested
{
if (JavaFeature.FLEXIBLE_CONSTRUCTOR_BODIES.isSupported(currentScope.compilerOptions())) {
// JEP 482: this is the central location for organizing synthetic arguments and fields
// to serve far outer instances even in inner early construction context.
// Only SingleNameReference.manageSyntheticAccessIfNecessary() may add more synth outers later on
// (using NestedTypeBinding.requestEnclosingInstancePathTo()).
//
// Locations MethodBinding.computeSignature() and BlockScope.getEmulationPath() will faithfully
// use the information generated here, to decide about signature and call sequence.
while (outerScope != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,27 +126,14 @@ public SyntheticArgumentBinding addSyntheticArgumentAndField(ReferenceBinding ta
if (!isPrototype()) throw new IllegalStateException();
if (this.scope.isInsideEarlyConstructionContext(targetEnclosingType, false))
return null;
return doAddSyntheticArgumentAndField(targetEnclosingType);
}

private SyntheticArgumentBinding doAddSyntheticArgumentAndField(ReferenceBinding targetEnclosingType) {
SyntheticArgumentBinding synthLocal = addSyntheticArgument(targetEnclosingType);
if (synthLocal == null)
return null;
if (synthLocal == null) return null;

if (synthLocal.matchingField == null)
synthLocal.matchingField = addSyntheticFieldForInnerclass(targetEnclosingType);
return synthLocal;
}

public void requestEnclosingInstancePathTo(ReferenceBinding targetEnclosingClass) {
if (isCompatibleWith(targetEnclosingClass))
return;
if (getSyntheticField(targetEnclosingClass, false) == null)
doAddSyntheticArgumentAndField(targetEnclosingClass);
if (this.enclosingType instanceof NestedTypeBinding nestedType)
nestedType.requestEnclosingInstancePathTo(targetEnclosingClass);
}

/* Answer the receiver's enclosing type... null if the receiver is a top level type.
*/
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contributions for
Expand Down Expand Up @@ -5797,6 +5801,11 @@ public List<ClassScope> collectClassesBeingInitialized() {
return list;
}

public boolean isInStaticContext() {
MethodScope methodScope = methodScope();
return methodScope != null && methodScope.isStatic;
}

public void include(LocalVariableBinding[] bindings) {
// `this` is assumed to be populated with bindings.
if (bindings != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*
* SPDX-License-Identifier: EPL-2.0
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
* Benjamin Muskalla - Contribution for bug 239066
Expand Down Expand Up @@ -12425,6 +12429,15 @@ public void allocationInEarlyConstructionContext(Expression expr, TypeBinding al
expr.sourceStart,
expr.sourceEnd);
}
public void allocationInStaticContext(ASTNode location, LocalTypeBinding allocatedType) {
this.handle(
IProblem.AllocatingLocalInStaticContext,
new String[] { String.valueOf(allocatedType.readableName()) },
new String[] { String.valueOf(allocatedType.shortReadableName()) },
location.sourceStart,
location.sourceEnd);
}

public void fieldReadInEarlyConstructionContext(char[] token, int sourceStart, int sourceEnd) {
String[] arguments = new String[] {String.valueOf(token)};
this.handle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,7 @@
2029 = Cannot assign field ''{0}'' from class ''{1}'' in an early construction context
2030 = Cannot assign field ''{0}'' in an early construction context, because it has an initializer
2031 = Constructor call is not allowed here
2032 = Cannot instantiate local class ''{0}'' in a static context

# JEP 455 Primitive Types in Patterns, instanceof, and switch (Preview)
2100 = Case constants in a switch on ''{0}'' must have type ''{1}''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ class ProblemAttributes {
expectedProblemAttributes.put("AbstractMethodMustBeImplementedOverConcreteMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
expectedProblemAttributes.put("AbstractMethodsInConcreteClass", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("AbstractServiceImplementation", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("AllocatingLocalInStaticContext", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("AmbiguousConstructor", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
expectedProblemAttributes.put("AmbiguousConstructorInDefaultConstructor", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
expectedProblemAttributes.put("AmbiguousConstructorInImplicitConstructorCall", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
Expand Down Expand Up @@ -1480,6 +1481,7 @@ class ProblemAttributes {
expectedProblemAttributes.put("AbstractMethodMustBeImplementedOverConcreteMethod", SKIP);
expectedProblemAttributes.put("AbstractMethodsInConcreteClass", SKIP);
expectedProblemAttributes.put("AbstractServiceImplementation", SKIP);
expectedProblemAttributes.put("AllocatingLocalInStaticContext", SKIP);
expectedProblemAttributes.put("AmbiguousConstructor", SKIP);
expectedProblemAttributes.put("AmbiguousConstructorInDefaultConstructor", SKIP);
expectedProblemAttributes.put("AmbiguousConstructorInImplicitConstructorCall", SKIP);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2074,12 +2074,7 @@ class C4 { // not early for C3
^^
Cannot read field f2 in an early construction context
----------
2. ERROR in C1.java (at line 15)
new C4();
^^^^^^^^
No enclosing instance of the type C1 is accessible in scope
----------
3. WARNING in C1.java (at line 18)
2. WARNING in C1.java (at line 18)
super();
^^^^^^^^
You are using a preview language feature that may or may not be supported in a future release
Expand Down Expand Up @@ -2378,14 +2373,16 @@ class Local {}
"");
}

public void testCtorRef_neg () {
runNegativeTest(new String[] {
public void testLocalAccesToOuter () {
runConformTest(new String[] {
"Outer.java",
"""
import java.util.function.Supplier;
@SuppressWarnings("unused")
class Outer {
void m() { }
void m() {
System.out.print("m");
}
class Inner {
Inner() {
class Foo {
Expand All @@ -2394,54 +2391,94 @@ void g() {
}
}
super();
new Foo().g();
}
}
public static void main(String... args) {
new Outer().new Inner();
}
}
"""
},
"m");
}

public void testCtorRef_staticContext () {
runNegativeTest(new String[] {
"Outer.java",
"""
import java.util.function.Supplier;
class Outer {
class Inner {
Inner() {
class Foo {
void g() {
System.out.print("g");
}
}
super();
class Bar {
static void p() {
new Foo().g();
}
static void r() {
Supplier<Foo> sfoo = Foo::new;
sfoo.get().g();
}
};
Bar.r();
}
}
public static void main(String... args) {
new Outer().new Inner();
}
}
"""
},
"""
----------
1. ERROR in Outer.java (at line 9)
m();
^^^
No enclosing instance of the type Outer is accessible in scope
----------
2. WARNING in Outer.java (at line 12)
1. WARNING in Outer.java (at line 10)
super();
^^^^^^^^
You are using a preview language feature that may or may not be supported in a future release
----------
2. ERROR in Outer.java (at line 13)
new Foo().g();
^^^^^^^^^
Cannot instantiate local class 'Foo' in a static context
----------
3. ERROR in Outer.java (at line 16)
Supplier<Foo> sfoo = Foo::new;
^^^^^^^^
Cannot instantiate local class 'Foo' in a static context
----------
""");
}

public void testCtorRef_pos () {
public void testCtorRef_nonStatic () {
runConformTest(new String[] {
"Outer.java",
"""
import java.util.function.Supplier;
class Outer {
void m() { }
class Inner {
Inner() {
class Foo {
void g() {
System.out.print("g");
// m();
}
}
super();
class Bar {
static void r() {
void p() {
new Foo().g();
}
void r() {
Supplier<Foo> sfoo = Foo::new;
sfoo.get().g();
}
};
Bar.r();
new Bar().r();
}
}
public static void main(String... args) {
Expand Down

0 comments on commit b6980e6

Please sign in to comment.