Welcome! Please see the About page for a little more info on how this works.

+2 votes
in Compiler by
retagged by

Currently, the Clojure compiler doesn't emit an entry in the line number table for a constructor callsite, unlike for a method callsite.

For example, let's say you have code like the following:

(ns example.core)

(defn f []

This code will generate the following bytecode and line number table:

public static java.lang.Object invokeStatic();
    descriptor: ()Ljava/lang/Object;
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
      stack=2, locals=0, args_size=0
         0: new           #13                 // class java/lang/StringBuilder
         3: dup
         4: invokespecial #14                 // Method java/lang/StringBuilder."<init>":()V
         7: areturn
        line 3: 0 
        // line 4: 4 <- this entry should be here

Note that the entry line 4: 4 should be in the line number table, but it actually does not.

In fact, we can confirm that the Compiler doesn't call visitLineNumber at all in the NewExpr's implementation of emit().

This can be a real problem when you are writing a function that may throw more than one exception explicitly:

(ns example.core)

(defn f [x]
  (if (>= x 0)
    (throw (IllegalArgumentException.))
    (throw (ArithmeticException.))))

In such a case, the stack trace of the exception raised will not indicate the exact location where the exception occurred:

user=> (f 1)
Execution error (IllegalArgumentException) at example.core/f (core.clj:4).
user=> (pst)
        example.core/f (core.clj:4) ;; <- should be "core.clj:5"
        example.core/f (core.clj:3)
        user/eval160 (NO_SOURCE_FILE:1)
user=> (f -1)
Execution error (ArithmeticException) at example.core/f (core.clj:4).
user=> (pst)
        example.core/f (core.clj:4) ;; <- should be "core.clj:6"
        example.core/f (core.clj:3)
        user/eval164 (NO_SOURCE_FILE:1)

Is there any reason that constructor callsites don't have their own entry in the line number table?

1 Answer

+1 vote
selected by