Bug 222648 - [Generics + ITD] Strange 'return types don't match' error when trying to override
Summary: [Generics + ITD] Strange 'return types don't match' error when trying to over...
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.4   Edit
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: 1.6.2   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-03-13 15:42 EDT by Michael Esser CLA
Modified: 2008-08-21 10:02 EDT (History)
2 users (show)

See Also:


Attachments
Eclipse 3.3 Project (2.57 KB, application/octet-stream)
2008-03-13 15:42 EDT, Michael Esser CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Esser CLA 2008-03-13 15:42:21 EDT
Created attachment 92501 [details]
Eclipse 3.3 Project

Occurs with AspectJ 1.5.4 as well as with my latest V1.6 cvs checkout (4 days old):


Compiling and running the following code:


abstract public class Foo <CONTENT extends Resource<CONTENT>, DATA extends DataInterface<CONTENT>
>  extends FooBase<DATA>
{ }


abstract public class FooBase<A>
{ }


public aspect DataAspect
{
	public CONTENT Marker<CONTENT>.getContent() { return null; }
}


public interface DataInterface<CONTENT> 
{
	public CONTENT getContent();		
}


public interface Marker<CONTENT> extends DataInterface<CONTENT>
{ }


public interface Resource<RESOURCE> 
{ }



produces the following error:

    [iajc] error at public CONTENT Marker<CONTENT>.getContent()
     [iajc]                                ^^^^^^^^^^
     [iajc] C:\Checkouts\FES\AspectJTest\Test B\src\test\DataAspect.aj:6:0::0 can't override CONTENT test.DataInterface<CONTENT>.getContent() with java.lang.Object test.Marker.getContent() return types don't match

     [iajc] error at public CONTENT getContent();
     [iajc]                ^^^^^^^^^^
     [iajc] C:\Checkouts\FES\AspectJTest\Test B\src\test\DataInterface.java:7:0::0 can't override CONTENT test.DataInterface<CONTENT>.getContent() with java.lang.Object test.Marker.getContent() return types don't match



I don't understand why it says:
' ... override ... with java.lang.Object Marker.getContent()'
since it should be
' ... override ... with CONTENT Marker<CONTENT>.getContent()'
!?


Strangely, by minor changes the errror message does not appear. E.g. if I do:

1.
Rename the generic type in the marker interface:

public interface Marker<CONTENT_B> extends DataInterface<CONTENT_B>
{ }

The same holds if I do this in the Foo class (but not in both, of course).


2.
Change Foo such that it does not inherit from FooBase:

abstract public class Foo <CONTENT extends Resource<CONTENT>, DATA extends DataInterface<CONTENT>
> 
{ }

In both cases it compiles fine.

Cheers, 
 Michael
Comment 1 Andrew Clement CLA 2008-03-13 17:28:25 EDT
> I don't understand why it says:
> ' ... override ... with java.lang.Object Marker.getContent()'
> since it should be
> ' ... override ... with CONTENT Marker<CONTENT>.getContent()'
> !?

I have seen similar bugs - it is usually because the type variable has been inadvertently collapsed/erased to its bound, so you see Object instead of the type var CONTENT.
Comment 2 Andrew Clement CLA 2008-08-21 10:02:01 EDT
fix committed, thanks for the testcase.

Problem here is type caching - when we encounter:

abstract public class Foo <CONTENT extends Resource<CONTENT>, DATA extends
DataInterface<CONTENT>
>  extends FooBase<DATA>
{ }

we record an entry in the cache for signature DataInterface<CONTENT> that points to DataInterface<Content extends Resource>

later when we are walking up the Marker hierarchy we lookup DataInterface<CONTENT> and find that variant - which is the wrong one (the type variable bounds are different in the second use of DataInterface, although the type variable has the same name).  And because the ITD doesn't match a variant where the signature of getContent is

<CONTENT extends Resource> getContent()

then we fail with the overrides error.

The solution is to stop caching those things as it can get us into trouble.  that is the fix I've implemented - but i need to keep an eye on things to make sure it hasn't affected performance too much.  if it has I will need to change the caching key in some way (likely include the bounds in the key).