Lambda Specification, Part F: Overload Resolution

Navigation: Overview - Part A - Part B - Part C - Part D - Part E - Part F - Part G - Part H - Part J
Sections: 15.12.2 - 15.12.2.1 - 15.12.2.2 - 15.12.2.3 - 15.12.2.4 - 15.12.2.5 - 15.12.2.6 - 15.12.3 - 15.9.3
Version 0.9.3. Copyright © 2014 Oracle America, Inc. Legal Notice.

Summary

Method and constructor declarations can be overloaded, meaning multiple matching declarations with different parameter types can co-exist in a type. In order to interpret a method invocation or a class instance creation expression, the compiler performs "overload resolution," inferring the declaration intended by the user at a particular invocation site. This occurs in three steps: i) identifying potentially applicable methods, that is, methods of the appropriate shape; ii) performing type analysis to identify applicable methods for the given arguments; iii) among the applicable methods, choosing one that is most specific.

To accomodate lambda expressions, the definition of potential applicability is expanded to take into account both the arity of the candidate methods and the presence and "shape" of functional interface target types.

To check for applicability, the types of an invocation's arguments can no longer, in general, be inputs to the analysis. This is because:

Instead, the input to the applicability check is a list of argument expressions, which can be checked for compatibility with potential target types, even if the ultimate types of the expressions are unknown.

The meaning of an implicitly-typed lambda expression or an inexact method reference is sufficiently vague prior to resolving a target type that arguments containing these expressions are not considered pertinent to applicability; they are simply ignored (except for their expected arity) until overload resolution is finished.

The Java 7 most-specific analysis was defined as a pairwise comparison of method declarations via subtyping. Here, we augment the analysis so that, where the corresponding argument is an explicitly-typed lambda expression or an exact method reference, one functional interface type can be preferred over another if it has a "better" function type return type, by a variety of measures: subtyping, boxing, or void vs. non-void.

15.12.2 Compile-Time Step 2: Determine Method Signature [Modified]

Compare JLS 15.12.2

The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the argument expressions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.

There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is the one used at run time to perform the method dispatch.

A method is applicable if it is either applicable by one of strict invocation (15.12.2.2), applicable by loose invocation (15.12.2.3), or it is an applicable variable arity method invocation (15.12.2.4). [jls-15.12.2-120]

Certain argument expressions that contain implicitly-typed lambda expressions (15.27.1) or inexact method references (15.13.1) are ignored by the applicability tests, because their meaning cannot be determined until a target type is selected.

Although the method invocation may be a poly expression, only its argument expressions—not the invocation's target type—influence the selection of applicable methods.

...

Deciding whether a method is applicable will, in the case of generic methods (8.4.4), require an analysis of the type arguments. Type arguments may be passed explicitly or implicitly. If they are passed implicitly, bounds on the type arguments must be inferred (18) from the types of the argument expressions.

...

Discussion and motivation:

  1. To check for applicability, the types of an invocation's arguments can no longer, in general, be inputs to the analysis. This is because:

    • The arguments to a method invocation may be poly expressions
    • Poly expressions cannot be typed in the absence of a target type
    • Overload resolution has to be completed before the arguments' target types will be known

    Instead, the input to the applicability check is a list of argument expressions, which can be checked for compatibility with potential target types, even if the ultimate types of the expressions are unknown.

  2. Overload resolution is independent of a target type for two reasons:

    • First, it makes the user model more accessible and less error-prone. The meaning of a method name (i.e., the declaration corresponding to the name) is too fundamental to the meaning of a program to depend on subtle contextual hints. (In contrast, other poly expressions may have different behavior depending on a target type; but the variation in behavior is always limited and essentially equivalent, while no such guarantees can be made about the behavior of an arbitrary set of methods that share a name and arity.)
    • Second, it allows other properties—such as whether or not the method is a poly expression (15.12) or how to categorize a conditional (15.25)—to depend on the meaning of the method name, even before a target type is known.

15.12.2.1 Identify Potentially Applicable Methods [Modified]

Compare JLS 15.12.2.1

...

A member method is potentially applicable to a method invocation if and only if all of the following are true: [jls-15.12.2.1-200]

...

An expression is potentially compatible with a target type according to the following rules: [jsr335-15.12.2.1-10]

If the search does not yield at least one method that is potentially applicable, then a compile-time error occurs. [jls-15.12.2.1-210]

Discussion and motivation:

This definition of potential applicability expands the previous arity check to also take into account the presence and "shape" of functional interface target types.

In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after overload resolution. These rules allow the form of the lambda expression to still be taken into account, discarding obviously incorrect target types that might otherwise cause ambiguity errors.

15.12.2.2 Phase 1: Identify Matching Arity Methods Applicable by Subtyping Strict Invocation [Modified]

Compare JLS 15.12.2.2

An argument expression is considered pertinent to applicability for a potentially-applicable method m unless it has one of the following forms: [jsr335-15.12.2.2-5]

Let m be a potentially applicable method (15.12.2.1) with arity n, let e1, ..., en be the actual argument expressions of the method invocation, and let Ai be the type of ei (1 ≤ i ≤ n) F1, ..., Fn be the types of the formal parameters of m. Then: [jls-15.12.2.2-100]

If no method applicable by strict invocation is found, the search for applicable methods continues with phase 2 (15.12.2.3). [jls-15.12.2.2-120]

Otherwise, the most specific method (15.12.2.5) is chosen among the methods that are applicable by strict invocation. [jls-15.12.2.2-130]

Discussion and motivation:

  1. The rules for handling generic method type argument inference, and associated terminology, have become too unwieldy to simply inline in the applicability rules. Instead, in this and the subsequent applicability sections, the inference problem has been factored out to 18.5.1.
  2. The meaning of an implicitly-typed lambda expression or an inexact method reference is sufficiently vague prior to resolving a target type that arguments containing these expressions are not considered pertinent to applicability; they are simply ignored (except for their expected arity) until overload resolution is finished.

15.12.2.3 Phase 2: Identify Matching Arity Methods Applicable by Invocation Conversion Loose Invocation [Modified]

Compare JLS 15.12.2.3

Let m be a potentially applicable method (15.12.2.1) with arity n, let e1, ..., en be the actual argument expressions of the method invocation, and let Ai be the type of ei (1 ≤ i ≤ n) F1, ..., Fn be the types of the formal parameters of m. Then: [jls-15.12.2.3-100]

If no method applicable by loose invocation is found, the search for applicable methods continues with phase 3 (15.12.2.4). [jls-15.12.2.3-120]

Otherwise, the most specific method (15.12.2.5) is chosen among the methods that are applicable by loose invocation. [jls-15.12.2.3-130]

15.12.2.4 Phase 3: Identify Methods Applicable by Variable Arity Methods Invocation [Modified]

Compare JLS 15.12.2.4

Where a variable-arity method has formal parameter types F1, ..., Fn-1, Fn[], define the ith variable-arity parameter type of the method as follows: [jsr335-15.12.2.4-5]

Let m be a potentially applicable method (15.12.2.1) with variable arity, let e1, ..., ek be the actual argument expressions of the method invocation and let Ai be the type of ei (1 ≤ i ≤ k) T1, ..., Tk be first k variable-arity parameter types of m. Then: [jls-15.12.2.4-100]

If no method applicable by variable-arity method invocation is found, a compile-time error occurs. [jls-15.12.2.4-120]

Otherwise, the most specific method (15.12.2.5) is chosen among the methods applicable by variable-arity methods invocation. [jls-15.12.2.4-130]

Discussion and motivation:

  1. The previous "applicable variable arity method" terminology incorrectly hinted that, if a variable-arity method is applicable in any phase, it is applicable in and only in Phase 3. This overlooks the fact that variable arity methods can act as fixed-arity methods in Phases 1 and 2. What is relevant is the kinds of adaptations actually used to determine applicability, not the kinds of adaptations allowed by the method declaration.
  2. The ith variable arity parameter type is a notational shorthand that simplifies the problem of describing all possible ways in which arguments might be matched up with parameter types. This is especially useful in the next section.
  3. An access check on the type of the last parameter appeared here previously, but has been moved to 15.12.3.

15.12.2.5 Choosing the Most Specific Method [Modified]

Compare JLS 15.12.2.5

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error. In cases such as an explicitly-typed lambda expression argument (15.27.1) or a variable-arity invocation (15.12.2.4), some flexibility is allowed to adapt one signature to the other.

One fixed-arity member applicable method named m m1 is more specific than another member applicable method of the same name and arity, m2, for an invocation with argument expressions exp1, ..., expk, if any of the following are true: [jls-15.12.2.5-200]

The above conditions are the only circumstances under which one method may be more specific than another. [jls-15.12.2.5-400]

A type S is more specific than a type T for any expression if S <: T. [jsr335-15.12.2.5-10-A]

In addition, a functional interface type S is more specific than a functional interface type T for an expression exp if T is not a subtype of S and one of the following conditions apply. Let U1, ..., Uk and R1 be the parameter types and return type, respectively, of the function type of the capture of S, and let V1, ..., Vk and R2 be the parameter types and return type, respectively, of the function type of T. [jsr335-15.12.2.5-10]

A method m1 is strictly more specific than another method m2 if and only if m1 is more specific than m2 and m2 is not more specific than m1. [jls-15.12.2.5-500]

...

Discussion and motivation:

  1. The Java 7 most-specific analysis was defined as a pairwise comparison of method declarations via subtyping. Here, we augment the analysis so that, where the corresponding argument is an explicitly-typed lambda expression or an exact method reference, one functional interface type can be preferred over another if it has a "better" function type return type, by a variety of measures: subtyping, boxing, or void vs. non-void.

  2. As above, the inference problem associated with the most-specific analysis has been factored out into its own section, 18.5.4.

15.12.2.6 Method Invocation Type Result and Throws Types [Modified]

Compare JLS 15.12.2.6

The invocation type of a most-specific accessible and applicable method is a method type (8.2) expressing the target types of the invocation arguments, the result type of the invocation, and the exception types of the invocation. It is determined as follows: [jsr335-15.12.2.6-10]

The type of the method invocation expression is obtained by applying capture conversion (5.1.10) to the return type of the invocation type of the chosen method. [jls-15.12.2.6-100-C.1]

The exception types that a method invocation expression can throw are specified in 11.2.1. [jls-15.12.2.6-300]

Discussion and motivation:

  1. We introduce invocation type here to group together the return type, exception types, and parameter types. Because poly expressions can appear as method arguments, we need to be more explicit than before about what the target type of a method argument is. This new abstraction also clarifies the interaction with inference (18.5.2), and simplifies the text for this section, which was needlessly concerned with the details of substitution and erasure on lists of types.
  2. The return type of the getClass method was already defined in 4.3.2, but the definition was added here for clarity. (In particular, it should be clear that this special return type is also used for method reference compatibility testing (15.13.2).)

15.12.3 Compile-Time Step 3: Is the Chosen Method Appropriate? [Addendum]

See JLS 15.12.3

It is a compile-time error if an argument to a method invocation is not compatible with its target type, as derived from the invocation type. [jsr335-15.12.3-10]

If the compile-time declaration is applicable by variable-arity invocation, then where the last formal parameter type of the invocation type of the method is Fn[], it is a compile-time error if the type which is the erasure of Fn is not accessible at the point of invocation. [jsr335-15.12.3-20]

Discussion and motivation:

The JLS 7 version of 15.12.2.4 performed this vararg access check during overload resolution. The check is necessary in order to guarantee that it is possible for the compiler to create an array of the given type. But it creates a soundness problem for inference (18.5.1): how can inference guarantee that an inferred type will be accessible? Thus, the access check is more appropriate as a post-resolution step.

15.9.3 Choosing the Constructor and its Arguments [Addendum]

See JLS 15.9.3

It is a compile-time error if an argument to a class instance creation expression is not compatible with its target type, as derived from the invocation type (15.12.2.6). [jsr335-15.9.3-10]

If the compile-time declaration is applicable by variable-arity invocation (15.12.2.4), then where the last formal parameter type of the invocation type of the constructor is Fn[], it is a compile-time error if the type which is the erasure of Fn is not accessible at the point of invocation. [jsr335-15.9.3-20]

These rules are identical to those for 15.12.3. The same checks should be performed for both constructors and methods.