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