#
# Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Distribution License v. 1.0, which is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# SPDX-License-Identifier: BSD-3-Clause
#

Method Overload Resolution for codegen

MOR is a rather complex aspect of the Java language.  It has
gone from complex in Java 1.4 to baroque in Java 5 due to
the addition of generics, varargs, and autoboxing. 
Since codegen is really only intended to support a
Java 1.4 level language, we will ignore the newer MOR 
algorithm.

We should implement most/all of Java 1.4 MOR for codegen.
Here are the relevant definitions:

From JLS 5.3

A method invocation conversion is applied to each argument of
a method on a method call.  method invocation conversion allows:

1. Identity conversion (5.1.1)
    This is what it sounds like: converting a type to itself
2. Widening primitive conversion (5.1.2)
    The following are permitted:
    byte    -> short, int, long, float, double
    short   -> int, long, float, double
    char    -> int, long, float, double
    int	    -> long, float, double
    long    -> float, double
    float   -> double
3. Widening reference conversion (5.1.4)
    class S	-> class T if S is a subclass of T
    class S	-> interface K if S implements K
    null type	-> any class, interface, array
    interface J	-> interface K if J is a subinterface of K
    interface J	-> Object
    array A[]	-> Object
    array A[]	-> Cloneable
    array A[]	-> array B[] if A, B ref types and there is a
		   widening reference conversion from A to B

MOR is defined in 3 steps:

1. (15.12.1) Determine class or interface to search (as adapted for the 
   Wrapper syntax):

    Form: MethodName
	Expr.identifier: the type to search is the type of Expr
	Type.identifier: the type to search is the type named Type
	super.identifier: the type to search is the superClass of the
	    current ClassGenerator
	this.identifier: the type to search is the class of the current
	    ClassGenerator.

Given a member reference, define the access type as follows:

member access:
StaticFieldAccessExpression x:	    x.targetType() 
NonStaticFieldAccessExpression x:   x.targetType() 
StaticCallExpression x:		    x.target()
NonStaticCallExpression x:	    x.target().type()
SuperCallExpression x:		    x.getContainingClass().superType()

constructor access:
NewObjExpression x:		    x.type()
NewArrExpression x:		    x.ctype()
SuperObjExpression x:		    x.getContainingClass().superType (super( ) in cons)
ThisObjExpression x:		    x.getContainingClass().thisType() (this( ) in cons)

2. (15.12.2) Determine method signatures
    A method declaration is applicable to a method invocation iff:
    1. The number of parameters in the declaration equals the number
       of argument expressions in the method invocation.
    2. The type of each actual argument can be converted by method
       invocation conversion to the type of the corresponding parameter.

    The method must also be accessible (6.6) :
	1. Public class or interface is always accessible
	2. Array type is accessible iff its component type is accessible
	3. A member (field or method) of a reference (class, interface, or array)
	   or a constructor of a class type is accessible iff:
	   1. The member or constructor is declared public
	   2. Otherwise, if declared protected, accessible iff:
	      1. The access occurs in the same package as where the member or constructor 
		 is declared, OR
	      2. Let C be a class declaring protected member m with identifier id. 
	         Let S be the class containing the reference to m.
		 Let K be the accessor type 
	   3. Otherwise, if declared private, accessible iff accessed from same class.
	   4. Otherwise, we have default access, accessible iff accessed from same package.

    3. Choose the most specific method
	Let m be a name.  Suppose we have m defined in two places:
	    T.m( T1, ..., Tn ) (mu)
	    U.m( U1, ..., Un ) (mt)

	Then mu is more specific than mt iff
	1. T can be converted to U by method invocation conversion
	2. For each i, Ti can be converted to U1 by method invocation conversion

	A method is maximally specific if it is applicable and accessible and no
	other method is more specific.

	If there is only one maximally specific method, go to step 3.
	Otherwise (we will simplify here and declare this to be ambiguous,
	ignoring 15.12.2.2 discussion about methods with the same signature).

3. (15.12.3) Is the chosen method appropriate?
    (basically static vs. non-static)
    1. If we have an invocation expr.ident in a static context, this is an error.
    2. If we have an invocation type.ident, the chosen method must be static,
       or an error occurs.
    3. If the invocation is super.ident,
	- if the method is abstract, error.
	- if the invocation is in a static context, error.
    4. If the result type is void, the expr must be in a statement context (in codegen)

    If the method is appropriate, then the invocation mode is determined as follows:
    1. If the method has the static modifier, mode is static
       (invokestatic).
    2. Otherwise, if the method has the private modifier, mode is nonvirtual
       (invokespecial).
    3. Otherwise, if the method invocation is super.ident, mode is super
       (invokespecial).
    4. Otherwise, if the method is declared in an interface, mode is interface
       (invokeinterface).
    5. Otherwise, mode is virtual
       (invokevirtual).
	
    
