This document proposes changes to the Java Language Specification to support inference of the types of local variables. See JEP 286 for an overview.

4.10.5 Type Projections

A synthetic type variable is a type variable introduced by the compiler during capture conversion (5.1.10) or inference variable resolution (18.4).

It is sometimes necessary to find a close supertype of a type, where that supertype does not mention certain synthetic type variables. This is achieved with an upward projection applied to the type.

Similarly, a downward projection may be applied to find a close subtype of a type, where that subtype does not mention certain synthetic type variables. Because such a type does not always exist, downward projection is a partial function.

These operations take as input a set of type variables that should no longer be referenced, referred to as the restricted type variables. When the operations recur, the set of restricted type variables is implicitly passed on to the recursive application.

The upward projection of a type T with respect to a set of restricted type variables is defined as follows:

The downward projection of a type T with respect to a set of restricted type variables is a partial function, defined as follows:

Like lub (4.10.4), upward projection and downward projection may produce infinite types, due to the recursion on type variable bounds.

14.4 Local Variable Declaration Statements

A local variable declaration statement declares one or more local variable names.

LocalVariableDeclarationStatement:

LocalVariableDeclaration ;

LocalVariableDeclaration:

{ VariableModifier } UnannType LocalVariableType VariableDeclaratorList

LocalVariableType:

UnannType
var

See 8.3 for UnannType. The following productions from 4.3, 8.4.1, and 8.3 are shown here for convenience:

VariableModifier:

(one of)
Annotation final

VariableDeclaratorList:

VariableDeclarator { , VariableDeclarator }

VariableDeclarator:

VariableDeclaratorId [ = VariableInitializer ]

VariableDeclaratorId:

Identifier [ Dims ]

Dims:

{ Annotation } [ ] { { Annotation } [ ] }

VariableInitializer:

Expression
ArrayInitializer

Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.

Apart from local variable declaration statements, a local variable declaration can appear in can be declared by the header of a basic for statement (14.14 14.14.1), an enhanced for statement (14.14.2) or a try-with-resources statement (14.20.3). In these cases, it is executed in the same manner as if it were part of a local variable declaration statement.

The try-with-resources statement doesn't actually use the LocalVariableDeclaration production, which it appears is what this paragraph was originally meant to assert. But anyway, it's useful to point out that not all local variables are introduced by LocalVariableDeclarationStatement, and be specific about it.

The details of execution vary for these different kinds of statements. Better not to assert anything about their execution here.

The rules for annotation modifiers on a local variable declaration are specified in 9.7.4 and 9.7.5.

It is a compile-time error if final appears more than once as a modifier for a local variable declaration.

It is a compile-time error if the LocalVariableType is var and any of the following are true:

Example 14.4-1. Local Variables Declared With var

The following code illustrates these rules restricting the use of var:

var a = 1;            // good
var b = 2, c = 3.0;   // Error: multiple declarators
var d[] = new int[4]; // Error: extra bracket pairs
var e;                // Error: no initializer
var f = { 6 };        // Error: array initializer
var g = (g = 7);      // Error: reference in initializer

These restrictions help to avoid confusion about the type being represented by var.

14.4.1 Local Variable Declarators and Types

Each declarator in a local variable declaration declares one local variable, whose name is the Identifier that appears in the declarator.

If the optional keyword final appears at the start of the declaration, the variable being declared is a final variable (4.12.4).

The declared type of a local variable is denoted by UnannType if no bracket pairs appear in UnannType and VariableDeclaratorId, and is specified by 10.2 otherwise.

The type of a local variable is determined as follows:

Example 14.4.1-1. Type of Local Variables Declared With var

The following code illustrates the typing of variables declared with var:

var a = 1;                                       // a has type 'int'
var b = java.util.List.of(1, 2);                 // b has type 'List<Integer>'
var c = "x".getClass();                          // c has type 'Class<? extends String>'
var d = new Object() {};                         // d has the type of the anonymous class
var e = (CharSequence & Comparable<String>) "x"; // e has type CharSequence & Comparable<String>
var f = () -> "hello";                           // Error: lambda not in an assignment context
var g = null;                                    // Error: null type

Note that some variables declared with var cannot be declared with an explicit type, because the type of the variable is not denoteable.

Upward projection is applied to the type of the initializer when determining the type of the variable. If the type of the initializer contains capture variables, this maps the type to a supertype that does not contain capture variables.

While it would be possible to allow the variable's type to mention capture variables, by projecting them away we enforce an attractive invariant that the scope of a capture variable is never larger than the statement containing the expression whose type is captured. Informally, capture variables cannot "leak" into subsequent statements.

A local variable of type float always contains a value that is an element of the float value set (4.2.3); similarly, a local variable of type double always contains a value that is an element of the double value set. It is not permitted for a local variable of type float to contain an element of the float-extended-exponent value set that is not also an element of the float value set, nor for a local variable of type double to contain an element of the double-extended-exponent value set that is not also an element of the double value set.

The scope and shadowing of a local variable declaration is specified in 6.3 and 6.4.

14.14.2 The Enhanced for Statement

The enhanced for statement has the form:

EnhancedForStatement:

for ( { VariableModifier } LocalVariableType VariableDeclaratorId

: Expression ) Statement

EnhancedForStatementNoShortIf:

for ( { VariableModifier } LocalVariableType VariableDeclaratorId

: Expression ) StatementNoShortIf

See 8.3 for UnannType. The following productions from 4.3, 8.4.1, and 8.3 4.3, 8.3, 8.4.1, and 14.4 are shown here for convenience:

VariableModifier:

(one of)
Annotation final

LocalVariableType:

UnannType
var

VariableDeclaratorId:

Identifier [ Dims ]

Dims:

{ Annotation } [ ] { { Annotation } [ ] }

The header of the enhanced for statement declares a local variable, whose name is the identifier given by VariableDeclaratorId.

If the optional keyword final appears at the start of the declaration, the variable being declared is a final variable (4.12.4).

It is a compile-time error if the LocalVariableType is var and the VariableDeclaratorId has one or more bracket pairs.

The local variable is initialized, on each iteration of the loop, by the elements of an array or Iterable produced by Expression. The type of the Expression must be a subtype of raw Iterable or an array type (10.1), or a compile-time error occurs.

The declared type of the local variable in the header of the enhanced for statement is denoted by UnannType if no bracket pairs appear in UnannType and VariableDeclaratorId, and is specified by 10.2 otherwise.

The type of the local variable is determined as follows:

The scope and shadowing of the local variable declared in the header of an enhanced for statement is specified in 6.3 and 6.4.

...

The var keyword can also be used in a basic for statement (14.14.1), but in that case the grammar is described in terms of LocalVariableDeclaration, so no spec changes are necessary.

14.20.3 try-With-Resources

A try-with-resources statement is parameterized with local variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block. catch clauses and a finally clause are often unnecessary when resources are closed automatically.

TryWithResourcesStatement:

try ResourceSpecification Block [ Catches ] [ Finally ]

ResourceSpecification:

( ResourceList [ ; ] )

ResourceList:

Resource { ; Resource }

Resource:

{ VariableModifier } LocalVariableType VariableDeclaratorId Identifier = Expression

See 8.3 for UnannType. The following productions from 4.3, 8.4.1, and 8.3 8.4.1 and 14.4 are shown here for convenience:

VariableModifier:

(one of)
Annotation final

LocalVariableType:

UnannType
var

VariableDeclaratorId:

Identifier [ Dims ]

Dims:

{ Annotation } [ ] { { Annotation } [ ] }

A resource's type must be a subtype of AutoCloseable, so cannot be an array type. Thus, there's no need for the grammar to support bracket pairs following the resource's name. That simplifies some of the text below.

A resource specification declares one or more local variables with initializer expressions to act as resources for the try statement.

It is a compile-time error for a resource specification to declare two variables with the same name.

It is a compile-time error if final appears more than once as a modifier for each any variable declared in a resource specification.

A variable declared in a resource specification is implicitly declared final (4.12.4) if it is not explicitly declared final.

It is a compile-time error if the LocalVariableType of a variable declared in a resource specification is var and the initializer of the VariableDeclarator contains a reference to the variable.

The type of a variable declared in a resource specification is determined as follows:

The type of a variable declared in a resource specification each variable must be a subtype of AutoCloseable, or a compile-time error occurs.

The scope and shadowing of a variable declared in a resource specification is specified in 6.3 and 6.4.

Resources are initialized in left-to-right order. If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by the try-with-resources statement are closed. If all resources initialize successfully, the try block executes as normal and then all non-null resources of the try-with-resources statement are closed.

Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources. Such an exception is suppressed if an exception was thrown previously by an initializer, the try block, or the closing of a resource.

A try-with-resources statement whose resource specification declares multiple resources is treated as if it were multiple try-with-resources statements, each of which has a resource specification that declares a single resource. When a try-with-resources statement with n resources (n > 1) is translated, the result is a try-with-resources statement with n-1 resources. After n such translations, there are n nested try-catch-finally statements, and the overall translation is complete.

9.7.4 Where Annotations May Appear

...

It is possible for an annotation to appear at a syntactic location in a program where it could plausibly apply to a declaration, or a type, or both. This can happen in any of the five declaration contexts where modifiers immediately precede the type of the declared entity:

The grammar of the Java programming language unambiguously treats annotations at these locations as modifiers for a declaration (8.3), but that is purely a syntactic matter. Whether an annotation applies to a declaration or to the type of the declared entity—and thus, whether the annotation is a declaration annotation or a type annotation—depends on the applicability of the annotation's type:

In the second and third cases above, the type which is closest to the annotation is the type written in source code for the declared entity; if that type is an array type, then the element type is deemed to be closest to the annotation. determined as follows:

For example, in the field declaration @Foo public static String f;, the type which is closest to @Foo is String. (If the type of the field declaration had been written as java.lang.String, then java.lang.String would be the type closest to @Foo, and later rules would prohibit a type annotation from applying to the package name java.) In the generic method declaration @Foo <T> int[] m() {...}, the type written for the declared entity is int[], so @Foo applies to the element type int.

Local variable declarations are similar to formal parameter declarations of lambda expressions, in that both allow declaration annotations and type annotations in source code, but only the type annotations can be stored in the class file.

There are two special cases involving method/constructor declarations:

For the purpose of type annotations, we treat var the same as void, its closest analog. In addition, some restructuring here helps to clarify what constitutes a "closest type".

...

Type Declarations and References

The following sections make grammatical changes to the declaration and use of types. These changes make it impossible to declare or reference a type named var.

An alternative design might allow declarations while prohibiting references, or even allow all references except the unqualified use of var in a local variable declaration. However, we believe a straightforward, blanket prohibition of types named var will be easier to understand and better-suited to future language evolution.

As a practical matter, the widespread convention of capitalizing the names of types in Java means these grammatical changes should have very little impact. Existing code that does not follow the convention and declares a class or interface named var will have to make a binary-incompatible change to the name of the type.

3.8 Identifiers

An identifier is an unlimited-length sequence of Java letters and Java digits, the first of which must be a Java letter.

Identifier:

IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral

IdentifierChars:

JavaLetter { JavaLetterOrDigit }

JavaLetter:

any Unicode character that is a "Java letter"

JavaLetterOrDigit:

any Unicode character that is a "Java letter-or-digit"

A "Java letter" is a character for which the method Character.isJavaIdentifierStart(int) returns true.

A "Java letter-or-digit" is a character for which the method Character.isJavaIdentifierPart(int) returns true.

The "Java letters" include uppercase and lowercase ASCII Latin letters A-Z (\u0041-\u005a), and a-z (\u0061-\u007a), and, for historical reasons, the ASCII underscore (_, or \u005f) and dollar sign ($, or \u0024). The $ sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems.

The "Java digits" include the ASCII digits 0-9 (\u0030-\u0039).

Letters and digits may be drawn from the entire Unicode character set, which supports most writing scripts in use in the world today, including the large sets for Chinese, Japanese, and Korean. This allows programmers to use identifiers in their programs that are written in their native languages.

An identifier cannot have the same spelling (Unicode character sequence) as a keyword (3.9), boolean literal (3.10.3), or the null literal (3.10.7), or a compile-time error occurs.

Two identifiers are the same only if they are identical, that is, have the same Unicode character for each letter or digit. Identifiers that have the same external appearance may yet be different.

For example, the identifiers consisting of the single letters LATIN CAPITAL LETTER A (A, \u0041), LATIN SMALL LETTER A (a, \u0061), GREEK CAPITAL LETTER ALPHA (A, \u0391), CYRILLIC SMALL LETTER A (a, \u0430) and MATHEMATICAL BOLD ITALIC SMALL A (a,\ud835\udc82) are all different.

Unicode composite characters are different from their canonical equivalent decomposed characters. For example, a LATIN CAPITAL LETTER A ACUTE (,\u00c1) is different from a LATIN CAPITAL LETTER A (A, 041) immediately followed by a NON-SPACING ACUTE (́, \u0301) in identifiers. See The Unicode Standard, Section 3.11 "Normalization Forms".

A type identifier is an identifier that is not the reserved word var.

TypeIdentifier:

Identifier but not var

This restricted form of identifier is used in certain contexts involving the declaration or use of types. For example, the name of a class must be a TypeIdentifier, so it is illegal to declare a class named var (8.1).

Examples of identifiers are:

3.9 Keywords

50 character sequences, formed from ASCII letters, are reserved for use as keywords and cannot be used as identifiers (3.8).

Keyword:

(one of)

abstract   continue   for          new         switch
assert     default    if           package     synchronized
boolean    do         goto         private     this
break      double     implements   protected   throw
byte       else       import       public      throws
case       enum       instanceof   return      transient
catch      extends    int          short       try
char       final      interface    static      void
class      finally    long         strictfp    volatile
const      float      native       super       while

The keywords const and goto are reserved, even though they are not currently used. This may allow a Java compiler to produce better error messages if these C++ keywords incorrectly appear in programs.

While true and false might appear to be keywords, they are technically boolean literals (3.10.3). Similarly, while null might appear to be a keyword, it is technically the null literal (3.10.7).

The character sequence var is generally treated as an identifier, but in certain special cases acts as if it were a keyword instead. Syntactic ambiguities are avoided by making use of the TypeIdentifier production (3.8).

4.3 Reference Types and Values

...

ClassType:

{ Annotation } TypeIdentifier [ TypeArguments ]
PackageName . { Annotation } TypeIdentifier [ TypeArguments ]
ClassOrInterfaceType . { Annotation } TypeIdentifier [ TypeArguments ]

InterfaceType:

ClassType

TypeVariable

{ Annotation } TypeIdentifier

...

This section needs some cleanup, a separate effort. For now, we want to force TypeIdentifiers in the right places, but don't want to prohibit qualified names like var.Foo. A lightweight workaround is to add an ambiguous variant pointing to PackageName.

4.4 Type Variables

A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.

A type variable is introduced by the declaration of a type parameter of a generic class, interface, method, or constructor (8.1.2, 9.1.2, 8.4.4, 8.8.4).

TypeParameter:

{ TypeParameterModifier } TypeIdentifier [ TypeBound ]

TypeParameterModifier:

Annotation

TypeBound:

extends TypeVariable
extends ClassOrInterfaceType { AdditionalBound }

AdditionalBound:

& InterfaceType

...

6.1 Declarations

A declaration introduces an entity into a program and includes an identifier (3.8) that can be used in a name to refer to this entity. The identifier is constrained to be a type identifier when the entity being introduced is a class, interface, or type parameter.

A declared entity is one of the following:

...

6.5 Determining the Meaning of a Name

The meaning of a name depends on the context in which it is used. The determination of the meaning of a name requires three steps:

PackageName:

Identifier
PackageName . Identifier

TypeName:

TypeIdentifier
PackageOrTypeName . TypeIdentifier

PackageOrTypeName:

Identifier
PackageOrTypeName . Identifier

ExpressionName:

Identifier
AmbiguousName . Identifier

MethodName:

Identifier

AmbiguousName:

Identifier AmbiguousName . Identifier

A TypeName has a restricted form: the identifier must be a TypeIdentifier, which excludes the reserved word var (3.8).

The use of context helps to minimize name conflicts between entities of different kinds. Such conflicts will be rare if the naming conventions described in 6.1 are followed. Nevertheless, conflicts may arise unintentionally as types developed by different programmers or different organizations evolve. For example, types, methods, and fields may have the same name. It is always possible to distinguish between a method and a field with the same name, since the context of a use always tells whether a method is intended.

6.5.2 Reclassification of Contextually Ambiguous Names

An AmbiguousName is then reclassified as follows.

If the AmbiguousName is a simple name, consisting of a single Identifier:

If the AmbiguousName is a qualified name, consisting of a name, a ".", and an Identifier, then the name to the left of the "." is first reclassified, for it is itself an AmbiguousName. There is then a choice:

...

The requirement that a potential type name be "a valid TypeIdentifier" prevents treating var as a type name. It is usually redundant, because the rules for declarations already prevent the introduction of types named var. However, in some cases, a compiler may find a binary class named var, and we want to be clear that such classes can never be named. The simplest solution is to consistently check for a valid TypeIdentifier.

6.5.4.1 Simple PackageOrTypeNames

If the PackageOrTypeName, Q, is a valid TypeIdentifier and occurs in the scope of a type named Q, then the PackageOrTypeName is reclassified as a TypeName.

Otherwise, the PackageOrTypeName is reclassified as a PackageName. The meaning of the PackageOrTypeName is the meaning of the reclassified name.

6.5.4.2 Qualified PackageOrTypeNames

Given a qualified PackageOrTypeName of the form Q.Id, if Id is a valid TypeIdentifier and the type or package denoted by Q has a member type named Id, then the qualified PackageOrTypeName name is reclassified as a TypeName.

Otherwise, it is reclassified as a PackageName. The meaning of the qualified PackageOrTypeName is the meaning of the reclassified name.

8.1 Class Declarations

A class declaration specifies a new named reference type.

There are two kinds of class declarations: normal class declarations and enum declarations.

ClassDeclaration:

NormalClassDeclaration
EnumDeclaration

NormalClassDeclaration:

{ ClassModifier } class TypeIdentifier [ TypeParameters ]

[ Superclass ] [ Superinterfaces ] ClassBody

The rules in this section apply to all class declarations, including enum declarations. However, special rules apply to enum declarations with regard to class modifiers, inner classes, and superclasses; these rules are stated in 8.9.

The TypeIdentifier in a class declaration specifies the name of the class.

It is a compile-time error if a class has the same simple name as any of its enclosing classes or interfaces.

The scope and shadowing of a class declaration is specified in 6.3 and 6.4.

8.3 Field Declarations

...

UnannClassType:

TypeIdentifier [ TypeArguments ]
PackageName . { Annotation } TypeIdentifier [ TypeArguments ]
UnannClassOrInterfaceType . { Annotation } TypeIdentifier [ TypeArguments ]

UnannInterfaceType:

UnannClassType

UnannTypeVariable:

TypeIdentifier

...

8.8 Constructor Declarations

A constructor is used in the creation of an object that is an instance of a class (12.5, 15.9).

ConstructorDeclaration:

{ ConstructorModifier } ConstructorDeclarator [ Throws ] ConstructorBody

ConstructorDeclarator:

[ TypeParameters ] SimpleTypeName TypeIdentifier ( [ FormalParameterList ] )

SimpleTypeName:

Identifier

The rules in this section apply to constructors in all class declarations, including enum declarations. However, special rules apply to enum declarations with regard to constructor modifiers, constructor bodies, and default constructors; these rules are stated in 8.9.2.

The SimpleTypeName TypeIdentifier in the ConstructorDeclarator must be the simple name of the class that contains the constructor declaration, or a compile-time error occurs.

In all other respects, a constructor declaration looks just like a method declaration that has no result (8.4.5).

...

The SimpleTypeName production seems to serve no purpose, and is unused outside of this section. It's possible the intent was to treat this identifier as a restricted form of TypeName. But identifiers used in declarations are not usually considered names (see 6.2).

8.9 Enum Types

An enum declaration specifies a new enum type, a special kind of class type.

EnumDeclaration:

{ ClassModifier } enum TypeIdentifier [ Superinterfaces ] EnumBody

...

9.1 Interface Declarations

An interface declaration specifies a new named reference type. There are two kinds of interface declarations—normal interface declarations and annotation type declarations (9.6).

InterfaceDeclaration:

NormalInterfaceDeclaration
AnnotationTypeDeclaration

NormalInterfaceDeclaration:

{ InterfaceModifier } interface TypeIdentifier [ TypeParameters ]

[ ExtendsInterfaces ] InterfaceBody

The TypeIdentifier in an interface declaration specifies the name of the interface.

It is a compile-time error if an interface has the same simple name as any of its enclosing classes or interfaces.

The scope and shadowing of an interface declaration is specified in 6.3 and 6.4.

9.6 Annotation Types

An annotation type declaration specifies a new annotation type, a special kind of interface type. To distinguish an annotation type declaration from a normal interface declaration, the keyword interface is preceded by an at-sign (@).

AnnotationTypeDeclaration:

{ InterfaceModifier } @ interface TypeIdentifier AnnotationTypeBody

Note that the at-sign (@) and the keyword interface are distinct tokens. It is possible to separate them with whitespace, but this is discouraged as a matter of style.

The rules for annotation modifiers on an annotation type declaration are specified in 9.7.4 and 9.7.5.

The TypeIdentifier in an annotation type declaration specifies the name of the annotation type.

...