Bug 116745 - [compiler] VerifyError: Incompatible type for getting or setting field
Summary: [compiler] VerifyError: Incompatible type for getting or setting field
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 3.1.2   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-11-16 18:10 EST by Art Dyer CLA
Modified: 2006-01-09 11:16 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Art Dyer CLA 2005-11-16 18:10:01 EST
I discovered this on 3.1, but it still appears to be broken as of the November 
16th 3.2 integration build (I20051116-1332).

Compiled by javac 1.5 or jikes 1.21, this program runs fine on java 1.4 or 1.5; 
compiled by JDT it reports: "java.lang.VerifyError: (class: Derived, method: 
<init> signature: (Z)V) Incompatible type for getting or setting field".

public abstract class Base
{
  protected Base twin;
}

public class Derived extends Base
{
  public Derived(boolean flag)
  {
    if (flag)
    {
      twin = new Derived(false);
      twin.twin = this;
    }
  }

  public static void main(String[] args) throws Throwable
  {
    System.out.println(new Derived(true));
  }
}

Here is the code (via javap) of Derived's constructor:

Javac version:
public Derived(boolean);
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method Base."<init>":()V
   4:	iload_1
   5:	ifeq	28
   8:	aload_0
   9:	new	#2; //class Derived
   12:	dup
   13:	iconst_0
   14:	invokespecial	#3; //Method "<init>":(Z)V
   17:	putfield	#4; //Field twin:LBase;
   20:	aload_0
   21:	getfield	#4; //Field twin:LBase;
   24:	aload_0
   25:	putfield	#5; //Field Base.twin:LBase;
   28:	return

JDT version:
public Derived(boolean);
  Code:
   0:	aload_0
   1:	invokespecial	#8; //Method Base."<init>":()V
   4:	iload_1
   5:	ifeq	28
   8:	aload_0
   9:	new	#1; //class Derived
   12:	dup
   13:	iconst_0
   14:	invokespecial	#11; //Method "<init>":(Z)V
   17:	putfield	#13; //Field twin:LBase;
   20:	aload_0
   21:	getfield	#13; //Field twin:LBase;
   24:	aload_0
   25:	putfield	#13; //Field twin:LBase;
   28:	return

Except for the numbering of the constant pool entries, which doesn't matter, 
the only difference is at offset 25 (the storing of this into twin.twin).  The 
javac version references a FieldInfo for "Base.twin" while the JDT version 
references a FieldInfo for "twin" (unqualified, which I think implies the class 
being disassembled, i.e. Derived).

The compiler probably knows that 'twin' contains a Derived because it was just 
set to the result of 'new Derived' at offset 9.  But the verifier isn't that 
smart, and only knows that an object of type Base was pushed at 21.  And it 
doesn't like you attempting to access a field of Derived from an instance of 
Base.
Comment 1 Olivier Thomann CLA 2005-11-16 20:29:49 EST
This comes from the test line in 832
org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference.
If compiled with a target lower than 1.4 or a compliance lower than 1.4, it
works fine.
Comment 2 Philipe Mulet CLA 2005-11-17 07:58:59 EST
The compiler is getting fooled by the fact the two fields in sequence are
denoting the same binding. We have checked for lastField == firstField, and then
believe we are processing the first field portion.

We should use index instead of binding comparison.
Comment 3 Philipe Mulet CLA 2005-11-18 06:18:56 EST
Added ConformTest#test248.

Released fix both in 3.1.2 and 3.2 streams (3.0 doesn't seem impacted).
Comment 4 Olivier Thomann CLA 2005-12-13 10:32:31 EST
Verified for 3.2M4 in I20051212-2000
Comment 5 Olivier Thomann CLA 2006-01-09 11:16:07 EST
Verified for 3.1.2 in M20060109-0800.