Go to the first, previous, next, last section, table of contents.
This section describes the currently used algorithm for selecting which
method to actually invoke for a given method invocation.
-
Resolve the receiver to be an object.
-
Get for the receiver a list of eligible methods. A method is eligible
if
-
it is defined for the receiver or inherited by the receiver,
-
the name parts of the invocation fit the name parts of the method,
i.e. the order of the name parts provided match the order of the
corresponding name parts in the method, and no name part of a
non-optional argument is omitted,
-
its return type is either
dynamic
or it matches at least one type
in the context (if that is non-empty),
-
it is not a method which is overridden, in a subclass, by another
eligible method, and
-
if the receiver is not
super
and the types of the arguments and
return values exactly match those of an already eligible method.
-
Build the possible argument types.
-
For each actual argument, resolve it in the context of its possible
types. If it is unresolvable (i.e its set of possible types is empty),
this invocation can not be resolved either.
-
If any of the possible argument types was restricted by the attempt to
resolve, eliminate from the eligible method those methods which are no
longer applicable. If at least one method was eliminated, rebuild the
possible argument types and continue with the previous step.
-
If the context is a single type or all arguments have been fully
resolved (i.e. typed) or all but one method have been eliminated,
continue with the next step, otherwise return the list of possible types
for this invocation.
-
If we're expected to fully resolve, i.e. the context is a single type,
eliminate those methods from the eligible set which do not fit the
expected type best.
-
Eliminate those methods from the eligible set which do not have the
highest number of fully matching arguments.
-
Eliminate those methods from the eligible set which do not have the
highest number of name parts. This favours methods with lots of
optional parts over methods with less optional parts. The rationale
behind this is that the latter is probably only provided to invoke the
former with its default arguments while responding to an additional
selector.
-
If any of the eligible methods involve dynamic typing while some do not,
eliminate the former. This is needed, for instance, to have
[[stdio out] print 1234]
invoke the integer printing routine
instead of the dynamic one which would just invoke the integer printing
routine for this argument anyway.
-
If we're down to one method, fully type any remaining arguments which
are yet untyped. The type of the invocation is the return type of the
method, and the set returned is deduced from the context and the type in
the usual way. If the return type is
dynamic
, the context must
specify a single type.
-
Otherwise, resolving failed and, in the empty context, we return the set
of possible return types of the remaining methods; in a non-empty
context, return those types in the context which can be matched by at
least one of the remaining methods.
An important aspect of this algorithm is that it correctly produces an
error for undecidable invocations, such as the invocation of foo
(byte (3), byte (4))
while the available methods are foo (int,
byte)
and foo (byte, int)
.
A disadvantage of the current setup in the compiler is that an attempt
to invoke a method with slightly wrong argument types results in an
error indicating that the expression could not be typed, without any
positive hints about the possibly applicable methods.
Go to the first, previous, next, last section, table of contents.