This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Parameterizing on incomplete types


On Dec 3, 2011, at 3:37 PM, Per Bothner wrote:

On 12/03/2011 10:59 AM, Jamison Hope wrote:
OK, here's what I've got so far. It appears to handle our Comparable
test case

(define-simple-class Foo (java.lang.Comparable[Foo])
(x ::int)
((compare-to (o ::Foo)) ::int
(- x o:x)))

generating a bridge method equivalent to

public int compareTo(java.lang.Object o)
{
return this.compareTo((Foo) o);
}

That's a pretty good start. Thanks!


The patch consists of two parts: the new
Compilation#generateBridgeMethod(),
and a few lines added to ClassExp#compileMembers.

I would prefer to keep generateBridgeMethod in ClassExp, even if it has to be a static method with an explicit Compilation method: It's only called from one class, and there is too much stuff in Compilation.java anyway.

OK, I moved generateBridgeMethod to ClassExp. In that case, I'm not sure
what its accessibility should be; for now, I left it marked as public final.


generateBridgeMethod takes an existing method and desired arg/ return types,
creates a new method with the desired signature and emits bytecode to
checkcast
its args and then call the existing method. In my limited testing so
far, this
is the same bytecode generated by javac for similar cases.


The addition to ClassExp sits after the call to getImplMethods() where
the current
"missing implementation" error is. Before triggering that error, we look
to see
if the problem was 0 implementations found (as opposed to multiple,
which is a
different problem), and if so, we look to see if there's a method with
the right
name and number of args but wrong signature. If there is such a method,
then
we check its arg types and return type to see if they're compatible with
the
required signature, and if so we generate the bridge method. If not,
then we still
do the error message.

One problem is this doesn't handle multiple overloaded methods with the
same number of parameters. You might have to iterate over the list
returned from getDeclaredMethods() and check each if it's bridgeable.
(At the least add a comment about the limitation.)

To address this I added ClassExp#findMethodForBridge(), which I based off
of ClassType#getDeclaredMethod(String,boolean,int). One difference is that
I left out the ambiguity check; so, there's still a potential bug if someone
writes something crazy like:


(define-simple-class Foo (java.lang.Comparable[Foo])
(x ::int)
((compare-to (o ::Foo)) ::int
(- x o:x))
((compare-to (o ::String)) ::int 0)) ;; findMethodForBridge might find this instead


Really, it needs more intelligent logic that knows that the Comparable<Foo> interface
maps to int compareTo(Foo) and not to any int <T> compareTo(T) we happen to find.


There is also the case of an abstract class that implements an
instantiated method.  Should we generate the bridge method in the
abstract class, or only when we get to a concrete class?  Ideally,
I think the former.  (I'm guessing javac does that, but I haven't
verified it.)  But this is fine-tuning.

Ideally, one would go carefully through the Java Language Specification
to better understand the issues. That is probably best done if/when
we add wildcard support, definition of generic types, and sotherwise
start approaching "completeness" (i.e. Java parity). We quite a ways
from that. (I would like a mechanism where generic instantiation can
inherit or default a wildcard from the type declaration, as in Scala.)

Agreed, though the documentation on bridge methods is pretty sparse AFAICT.
I suspect that it'll still require a bit of experimenting with javac.


I'm not handling covariant returns yet, because I'm not sure where/ how
to check
for those.

I have an attempted solution now. After compiling each child LambdaExp, we search its superclass hierarchy for a method with the same name and parameter types. If we find one, and its return type is less specific than the return type of the LambdaExp we just compiled, then add a bridge method.

It does the right thing for my test:

(define-simple-class A ()  ((get) ::A #!null))
(define-simple-class B (A) ((get) ::B #!null))

generating a second get() method for B which returns an A.

We could use the same generateBridgeMethod there, but in that
case the
checkcast instructions aren't needed. I suppose I should put the
emitCheckcast
inside of something like "if
(bridge_arg_types[i].compare(src_arg_types[i]) != 0)".

That's handled automatically by the castNeeded in emitCheckCast.

Awesome.


--
Jamison Hope
The PTR Group
www.theptrgroup.com


Attachment: bridge2.patch
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]