Gauche Devlog

< :immutable slot option | Segmented completion >

2023/09/26

Hints for unbound variable error

While working on REPL, sometimes you accidentally try to evaluate a variable that isn't visible from your current module. It is a bit annoying if you know the module is loaded, just you forget to use it in the current module.

So we added a little feature. When REPL reports an unbound varriable error, it also lists if there are variables of that name, exported from modules that are loaded into the process but not visible from the evaluating module:

gosh$ (thread-start! (make-thread (^[] (print "Hi"))))
*** UNBOUND-VARIABLE-ERROR: unbound variable: make-thread
    NOTE: `make-thread' is exported from the following module:
     - gauche.threads
Stack Trace:
_______________________________________
  0  (report-error e)
  1  (make-thread (^ () (print "Hi")))
        at "(input string port)":1

It may be nice to show modules that aren't even loaded, too, but that would be too costly so we avoided it. It also doesn't show non-exported variables, which is debatable--sometimes you forgot to export one and that caused this error. Let's use this for a while and see if we need non-exported ones, too.


This is realized in a general mechanism in error reporting. We haven't documented it yet, for we may tweak the interface, but I'll show it to give the general idea.

The error message in REPL, including the stack trace, is produced by report-error (ref:report-error). It prints *** ... line, with the condition class name and error message, then calls a generic function report-additional-condition on the condition. We have a specialized method for <unbound-variable-error> which searches the name in the loaded modules and prints the hint.

If the thrown condition is a compound condition, report-additional-condition is called over each component of the compound condition. This allows custom report for each component. When you load a file that has a statically detectable error, you get the additional information (While compiling ...). It is also realized by the same mechanism. The compiler and the loader adds the location information as a compound condition, and report-error calls report-additional-condition on them, which shows those additional messages.

gosh> ,l ./foo
*** ERROR: wrong number of arguments: cons requires 2, but got 1
    While compiling "./foo.scm" at line 1: (define (bar x) (cons x))
    While loading "./foo.scm" at line 2
Stack Trace:
_______________________________________
  0  (report-error e)
  1  (errorf "wrong number of arguments: ~a requires ~a, but got ~"...
  2  (pass1/expand-inliner program id gval cenv)

Tags: 0.9.13, REPL, report-error