| [#382] | project: compiler | priority: low | category: bug | |
|---|---|---|---|---|
| submitter | assigned to | status | date submitted | |
| Michel | Martin | fixed | 2004-12-03 16:03:00.0 | |
| subject | "null" considered as a valid prefix | |||
| code | trait C {
  type T;
  class D {
    var f: T = _;
  }
}
object Main {
  def main(args: Array[String]) = {
    val c: C = null;
    System.out.println((new c.D).f);
  }
}
 | |||
| what happened | No compilation (or execution) error. | |||
| what expected | An error at compile time. It should not be legal to create an instance of C.Dbefore having created an instance of (some concrete subclass) ofC, yet this is precisely what I do here. This enables me to create a field of typeTwithout definingTfirst. | |||
| [back to overview] | ||||
| Martin edited on 2004-12-03 17:36:07.0 | 
| I fail to see how this can be detected at compile time. This is clearly a run-time violation. How does Java behave in situations like that? | 
| Michel edited on 2004-12-06 10:27:00.0 | 
| Hm, indeed that's pretty hard to detect at compile time. Sorry for that. 
Anyway, Java handles that in a pretty strange fashion. It does a NPE as soon as one tries to create an inner class with  
class C {
    void h() { System.out.println("C.h"); }
    public class D {
        void f() { System.out.println("C.D.f"); }
        void g() { h(); }
    }
}
class Main {
    public static void main(String[] args) {
        C c = null;
        C.D d = c.new D();
        d.f();
        d.g();
    }
}
And here is the relevant excerpt from the disassembly of class  public static void main(java.lang.String[]); Code: 0:aconst_null 1:astore_1 2:new#2; //class C$D 5:dup 6:aload_1 7:dup 8:invokevirtual#3; //Method java/lang/Object.getClass:()Ljava/lang/Class; 11:pop 12:invokespecial#4; //Method C$D."<init>":(LC;)V 15:astore_2 | 
| Martin edited on 2006-03-30 18:38:46.0 | 
| You now get an error at run time:
Exception in thread "main" java.lang.NullPointerException
	at C$D. |