Bug 133737 - [1.5][compiler] Eclipse compiler compiles program but javac does not (1 of 2)
Summary: [1.5][compiler] Eclipse compiler compiles program but javac does not (1 of 2)
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.2 RC2   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-03-28 17:21 EST by e2e4e7e5f2f4@yahoo.de CLA
Modified: 2006-11-13 14:35 EST (History)
2 users (show)

See Also:


Attachments
Exporter.java (103 bytes, text/plain)
2006-11-03 12:11 EST, Christopher Sahnwaldt CLA
no flags Details
Importer.java (190 bytes, text/plain)
2006-11-03 12:12 EST, Christopher Sahnwaldt CLA
no flags Details
Base.java (103 bytes, text/plain)
2006-11-03 12:13 EST, Christopher Sahnwaldt CLA
no flags Details
Exporter.java (for real!) (134 bytes, text/plain)
2006-11-13 14:35 EST, Christopher Sahnwaldt CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description e2e4e7e5f2f4@yahoo.de CLA 2006-03-28 17:21:42 EST
// Puzzle 71 from "Java Puzzlers" by Joshua Bloch and Neal Gafter

import static java.util.Arrays.toString;

class ImportDuty {
  public static void main(String[] args) {
    printArgs(1, 2, 3, 4, 5);
  }

  static void printArgs(Object... args) {
    System.out.println(toString(args));
  }
}


This program does compile within Eclipse 3.1.2 using JRE 1.5.0_02
but it does not compile using the JDK 1.5.0_02 directly.
The output of the JDK is:

javac ImportDuty.java
ImportDuty.java:9: toString() in java.lang.Object cannot be applied to (java.lang.Object[])
    System.out.println(toString(args));
                       ^
1 error

The OS used in both cases is Windows XP.
Comment 1 Kent Johnson CLA 2006-03-29 14:29:12 EST
So the question is: do we search static import methods after we have found a method that is not applicable or just report the non-applicable error?

Here's another testcase:

[ImportTest]
import static p.DefinesFoo.foo;
class ImportTest extends SuperImportTest {
	void test() { foo("fails?"); }
}
class SuperImportTest {
	private void foo() {}
}

[DefinesFoo]
package p;
public class DefinesFoo {
	public static void foo(String s) {}
}

This compiles without error on javac but fails if SuperImportTest.foo() is visible.
Comment 2 Kent Johnson CLA 2006-03-29 14:38:58 EST
From the spec in section 7.5.3:

A single-static-import declaration d in a compilation unit c of package p that
imports a method named n with signature s shadows the declaration of any static
method named n with signature s imported by a static-import-on-demand declaration in c, throughout c.


Why specify the signature s if it just shadows the method name n?
Comment 3 e2e4e7e5f2f4@yahoo.de CLA 2006-03-29 16:32:48 EST
This is part of the explanation from the book:

"The first thing the compiler does when selecting a method to be invoked at run time is to choose the scope in which the method must be found [JLS 15.12.1]. The compiler chooses the smallest enclosing scope that has a method with the right name. In our program, this scope is the class ImportDuty, which contains the toString method inherited from Object. This scope has no applicable method for the invocation toString(args), so the compiler must reject the program."

They further mention that "one consequence is that static methods with the same name as Object methods cannot be used with the static import facility."
Comment 4 Kent Johnson CLA 2006-03-30 11:31:32 EST
Ok - but then I would expect the non-visible case of:

class SuperImportTest {
	private void foo(String s) {}
}

to report that SuperImportTest.foo(String) is not visible instead of searching the static imports and finding a match in the static import.

It seems strange that a complete argument mismatch is an error, but a visibility problem on an exact match is not & must be skipped over.
Comment 5 Kent Johnson CLA 2006-03-30 16:50:07 EST
Here is another case to consider, start with:

package p;
public class Y {
	public int foo(int i) {return i;}
}

then define:

class X extends p.Y {
	void foo() {}
	void test() {
		class L {
			int i = foo(2);
		}
	}
}

So if javac chooses the smallest enclosing scope that has a method with the
right name, why does this example compile without errors?
Comment 6 e2e4e7e5f2f4@yahoo.de CLA 2006-03-30 19:55:30 EST
Your comment#2 does not apply here as it describes the "precedence" of 
single-static-import declarations (like import static p.DefinesFoo.foo;) 
and static-import-on-demand declarations (like import static p.DefinesFoo.*;).

This is how I see the two cases:

In my example (ImportDuty) when identifying potentially applicable methods 
for toString(args) in the scope of class ImportDuty the compiler finds as candidates

A1) public ImportDuty.toString()
A2) public static java.util.Arrays.toString(Object[]) 

Both methods are accessible since they are public. However, A2) from the 
static import is shadowed by A1). Then, by the statement [JLS 15.12.2.1, p.444]
"In addition, if the method invocation has, before the left parenthesis, 
a MethodName of the form Identifier, then the search process also examines 
all methods that are (a) imported by single-static-import declarations [JLS 7.5.3]and static-import-on-demand declarations [JLS 7.5.4] within the compilation unit [JLS 7.3] within which the method invocation occurs, and (b) not shadowed [JLS 6.3.1] at the place where the method invocation appears."
the second possibility A2) is ruled out.
Later on, the compiler rejects A1) due to the signature mismatch.

In your example (DefinesFoo & ImportTest) we have the methods 

B1) public static void p.DefinesFoo.foo(String s)
B2) <modifier> void (SuperImportTest).foo( <signature> )

Case#1: <modifier> is not private and <signature> is empty:
Both javac and Eclipse complain that "foo() in SuperImportTest cannot be 
applied to (java.lang.Strng)". B1) is ruled out since it is shadowed by B2).

Case#2: <modifier> is not private and <signature> is String s:
Both javac and Eclipse compile and choose method B2) since it has the appropriate signature. B1) is ruled out since it is shadowed by B2). 

Case#3: <modifier> is private and <signature> is empty:
Here, javac compiles and chooses method B1) since B2) is not accessible from ImportTest.
Eclipse, however, incorrectly complains that "foo() in SuperImportTest cannot 
be applied to (java.lang.String)".

Case#4: <modifier> is private and <signature> is String s:
Both javac and Eclipse compile and choose method B1) since B2) is not accessible from ImportTest.

Concerning your new example, class X inherits the method foo(int i) from p.Y and defines the method foo(). Therefore, we have method overloading here, not shadowing. 
Comment 7 Kent Johnson CLA 2006-04-24 16:16:51 EDT
Added StaticImport test042
Comment 8 Olivier Thomann CLA 2006-04-28 13:30:25 EDT
Verified with I20060427-1600 for 3.2RC2
Comment 9 Christopher Sahnwaldt CLA 2006-11-03 12:11:31 EST
Created attachment 53214 [details]
Exporter.java

demonstrates bug
Comment 10 Christopher Sahnwaldt CLA 2006-11-03 12:12:32 EST
Created attachment 53215 [details]
Importer.java

demonstrates bug
Comment 11 Christopher Sahnwaldt CLA 2006-11-03 12:13:01 EST
Created attachment 53216 [details]
Base.java

demonstrates bug
Comment 12 Christopher Sahnwaldt CLA 2006-11-03 12:21:52 EST
It seems that this bug is not fixed and should be re-opened.

The attached classes compile in Eclipse, but javac complains:

error\Importer.java:10: getName() in error.Base cannot be applied to (java.lang.Class<error.Importer>)
    getName(Importer.class);
    ^
1 error

I'm using javac 1.5.0_06 and Eclipse Version: 3.2.0 Build id: M20060629-1905.

From the Eclipse Configuration Details:

org.eclipse.jdt (3.2.0.v20060609m-F7snq1fxia-Z4XP) "Eclipse Java Development Tools"
org.eclipse.jdt.source (3.2.0.v20060609m-F7snq1fxia-Z4XP) "Eclipse Java Development Tools SDK"

As expected, Eclipse finds the errors in the class ImportDuty above.
Comment 13 Philipe Mulet CLA 2006-11-03 13:09:11 EST
Please log a separate bug rather than touching a closed one.
It is a different scenario.
Comment 14 Christopher Sahnwaldt CLA 2006-11-03 13:16:58 EST
Sorry - false alarm. I just ran an update - Eclipse finds the error in Importer.java with Version: 3.2.1 Build id: M20060921-0945 
org.eclipse.jdt (3.2.1.r321_v20060905-R4CM1Znkvre9wC-) "Eclipse Java Development Tools"
org.eclipse.jdt.source (3.2.1.r321_v20060905-R4CM1Znkvre9wC-) "Eclipse Java Development Tools SDK"

Sorry for any confusion.
Comment 15 Olivier Thomann CLA 2006-11-07 13:18:22 EST
(In reply to comment #9)
> Created an attachment (id=53214) [edit]
> Exporter.java
> 
> demonstrates bug
Could you please reattach Exporter.java? This is Base.java. I'd like to add a regression test with your test case.
Comment 16 Olivier Thomann CLA 2006-11-07 13:25:50 EST
Never mind.
I believe I got it.
Added org.eclipse.jdt.core.tests.compiler.regression.StaticImportTest#test046
Comment 17 Christopher Sahnwaldt CLA 2006-11-13 14:35:17 EST
Created attachment 53767 [details]
Exporter.java (for real!)

just for the record... here's the real Exporter.java.