Qualified class name inside qualified instance creation expression

Alex Buckley alex.buckley at oracle.com
Thu Jan 31 22:02:18 UTC 2019


On 1/31/2019 3:33 AM, Tagir Valeev wrote:
> Consider the following code:
>
> class Test {
>      class Inner {}
>
>      void test() {
>          new Test.Inner(); // compiles successfully
>          this.new Test.Inner(); // error
>      }
> }

Both the unqualified class instance creation expression and the 
qualified class instance creation expression should compile. Each has 
`this` as the immediately enclosing instance.

> javac reports:
> Test.java:6: error: '(' expected
>          this.new Test.Inner();
>                       ^
> 1 error
>
> I read JLS 15.9 [1]:
> ClassInstanceCreationExpression:
>      UnqualifiedClassInstanceCreationExpression
>      ExpressionName . UnqualifiedClassInstanceCreationExpression
>      Primary . UnqualifiedClassInstanceCreationExpression
> UnqualifiedClassInstanceCreationExpression:
>      new [TypeArguments] ClassOrInterfaceTypeToInstantiate (
> [ArgumentList] ) [ClassBody]
> ClassOrInterfaceTypeToInstantiate:
>      {Annotation} Identifier {. {Annotation} Identifier} [TypeArgumentsOrDiamond]
>
> Thus this.new Test.Inner() could be parsed as Primary .
> UnqualifiedClassInstanceCreationExpression where
> ClassOrInterfaceTypeToInstantiate could be parsed as Identifier .
> Identifier, so there should not be parse error.

Correct. There has been shimmer in this part of the language. In Java SE 
7, `this.new Test.Inner()` was illegal; only `this.new SIMPLENAME()` was 
allowed. (See 
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.9) 
In Java SE 8, the grammar of `ClassInstanceCreationExpression` was 
modified to support type annotations, and `this.new QUALIFIEDNAME()` was 
allowed. In principle, there is no reason to disallow a qualified name 
in a qualified CICE. The phrase `new Test.Inner()` is meaningful as an 
unqualified CICE, and enriching the phrase to be a qualified CICE, with 
an explicit immediately enclosing instance, doesn't make it 
unmeaningful. I suspect javac is still expecting (modulo type arguments) 
a simple name after `new`.

The 15.9.1 rules about the class denoted by 
`ClassOrInterfaceTypeToInstantiate` have not changed substantively since 
Java SE 7 (though they have been refactored numerous times in relation 
to diamond). They have always mandated "a class" (in an unqualified 
CICE) versus "an inner class" (in a qualified CICE).

Alex

> Next, spec (15.9.1) says different thing for qualified and unqualified
> instance creation expressions:
>
> If the class instance creation expression is unqualified:
> The ClassOrInterfaceTypeToInstantiate must denote a class that is
> accessible, non-abstract, and not an enum type. Otherwise, a
> compile-time error occurs.
>
> If the class instance creation expression is qualified:
> The ClassOrInterfaceTypeToInstantiate must unambiguously denote an
> inner class that is accessible, non-abstract, not an enum type, and a
> member of the compile-time type of the Primary expression or the
> ExpressionName.
>
> To me it's not quite evident why Test.Inner denotes a class for
> unqualified expression, but does not denote the same class for
> qualified expression. I'm not sure that the word "unambiguously"
> changes the picture: there's only one class named Inner, so I don't
> see any ambuguity.
>
> Is this javac problem, or probably I'm missing something? Should such
> code be allowed or not? If not, probably this should be explicitly
> specified, that qualified class name is not allowed for qualified
> instance creation expression? What do you think?
>
> Thank you in advance,
> Tagir Valeev.
>
> [1] https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.9


More information about the compiler-dev mailing list