~ chicken-core (chicken-5) 37d3cd16bc1e15771b1fdb08b16fd78cc89fdc9f


commit 37d3cd16bc1e15771b1fdb08b16fd78cc89fdc9f
Author:     megane <meganeka@gmail.com>
AuthorDate: Sat Apr 10 07:46:01 2021 +0300
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Sat Apr 10 15:08:02 2021 +0200

    Make ir-macro-transformer retain more of line-number information
    
    Presently, if you have errors inside code expanded by an
    ir-macro-transformer, the error's reported line numbers are often very
    inaccurate. Most often the reported line number is for the form
    defining the current function.
    
    Line numbers are lost whenever a macro transformer renames a pair.
    This can be due to user (using the rename / inject facility of er/ir
    transformers) or the automatic renaming done by ir macro trasformer.
    
    This is a smaller problem with er-macro-transformer as most such
    macros don't rename pairs, but only plain identifiers. But,
    ir-macro-transformer does 2 complete renamigs of the input form, one
    before transformation, and one after.
    
    A new pair is created whenever a pair is renamed. This new pair
    doesn't have any line number entry. This patch adds to the new pair
    the old pair's line number, if any.
    
    Given this input:
    
         1  (define-syntax baz
         2    (ir-macro-transformer
         3     (lambda (e inj cmp)
         4       (cadr e))))
         5
         6  (define (foo)
         7    (baz
         8     (baz
         9      (+ 'a))))
    
    Signed-off-by: Peter Bex <peter@more-magic.net>

diff --git a/distribution/manifest b/distribution/manifest
index cf2dc045..5416eff7 100644
--- a/distribution/manifest
+++ b/distribution/manifest
@@ -184,6 +184,8 @@ tests/scrutiny-2.expected
 tests/redact-gensyms.scm
 tests/test-scrutinizer-message-format.scm
 tests/scrutinizer-message-format.expected
+tests/test-line-numbers.scm
+tests/test-line-numbers.expected
 tests/syntax-rule-stress-test.scm
 tests/syntax-tests.scm
 tests/syntax-tests-2.scm
diff --git a/expand.scm b/expand.scm
index 3dea8407..8da8b2c0 100644
--- a/expand.scm
+++ b/expand.scm
@@ -51,6 +51,7 @@
 	chicken.platform)
 
 (include "common-declarations.scm")
+(include "mini-srfi-1.scm")
 
 (define-syntax d (syntax-rules () ((_ . _) (void))))
 
@@ -833,10 +834,19 @@
    'transformer
    (lambda (form se dse)
      (let ((renv '()))	  ; keep rename-environment for this expansion
+       (define (inherit-pair-line-numbers old new)
+	 (and-let* ((name (car new))
+		    ((symbol? name))
+		    (ln (get-line-number old))
+		    (cur (or (hash-table-ref ##sys#line-number-database name) '())) )
+	   (unless (assq new cur)
+	     (hash-table-set! ##sys#line-number-database name
+			      (alist-cons new ln cur))))
+	 new)
        (assert (list? se) "not a list" se) ;XXX remove later
        (define (rename sym)
 	 (cond ((pair? sym)
-		(cons (rename (car sym)) (rename (cdr sym))))
+		(inherit-pair-line-numbers sym (cons (rename (car sym)) (rename (cdr sym)))))
 	       ((vector? sym)
 		(list->vector (rename (vector->list sym))))
 	       ((or (not (symbol? sym)) (keyword? sym)) sym)
@@ -898,7 +908,8 @@
 	  (else (assq-reverse s (cdr l)))))
        (define (mirror-rename sym)
 	 (cond ((pair? sym)
-		(cons (mirror-rename (car sym)) (mirror-rename (cdr sym))))
+		(inherit-pair-line-numbers
+		 sym (cons (mirror-rename (car sym)) (mirror-rename (cdr sym)))))
 	       ((vector? sym)
 		(list->vector (mirror-rename (vector->list sym))))
 	       ((or (not (symbol? sym)) (keyword? sym)) sym)
diff --git a/tests/runtests.bat b/tests/runtests.bat
index e1803727..bca2691f 100644
--- a/tests/runtests.bat
+++ b/tests/runtests.bat
@@ -144,6 +144,14 @@ if errorlevel 1 exit /b 1
 a.out
 if errorlevel 1 exit /b 1
 
+echo ======================================== line number database ...
+%compile% -O3 test-line-numbers.scm 2>test-line-numbers.out
+if errorlevel 1 exit /b 1
+fc /lb%FCBUFSIZE% /w test-line-numbers.expected test-line-numbers.out
+if errorlevel 1 exit /b 1
+a.out
+if errorlevel 1 exit /b 1
+
 echo ======================================== specialization tests ...
 del /f /q foo.types foo.import.*
 %compile% specialization-test-1.scm -emit-types-file foo.types -specialize -debug ox -emit-import-library foo
diff --git a/tests/runtests.sh b/tests/runtests.sh
index 92fd961f..b1e9205f 100755
--- a/tests/runtests.sh
+++ b/tests/runtests.sh
@@ -141,6 +141,11 @@ $compile scrutiny-tests-3.scm -specialize -block
 $compile scrutiny-tests-strict.scm -strict-types -specialize
 ./a.out
 
+echo "======================================== line number database ..."
+$compile -O3 test-line-numbers.scm 2> test-line-numbers.out
+diff $DIFF_OPTS test-line-numbers.expected test-line-numbers.out
+./a.out
+
 echo "======================================== specialization tests ..."
 rm -f foo.types foo.import.*
 $compile specialization-test-1.scm -emit-types-file foo.types -specialize \
diff --git a/tests/test-line-numbers.expected b/tests/test-line-numbers.expected
new file mode 100644
index 00000000..a01add0d
--- /dev/null
+++ b/tests/test-line-numbers.expected
@@ -0,0 +1,23 @@
+
+Warning: Invalid argument
+  In file `test-line-numbers.scm:19',
+  In procedure `f',
+  In procedure call:
+
+    (scheme#+ 'a)
+
+  Argument #1 to procedure `+' has an invalid type:
+
+    symbol
+
+  The expected type is:
+
+    number
+
+  This is the expression:
+
+    'a
+
+  Procedure `+' from module `scheme' has this type:
+
+    (#!rest number -> number)
diff --git a/tests/test-line-numbers.scm b/tests/test-line-numbers.scm
new file mode 100644
index 00000000..15f995de
--- /dev/null
+++ b/tests/test-line-numbers.scm
@@ -0,0 +1,19 @@
+(define-syntax bar
+  (er-macro-transformer
+   (lambda (e inj cmp) (get-line-number (cadr e)))))
+
+(define-syntax foo
+  (ir-macro-transformer
+   (lambda (e inj cmp) (get-line-number (cadr e)))))
+
+(assert (equal? "test-line-numbers.scm:9" (the * (foo (hello-ir)))))
+(assert (equal? "test-line-numbers.scm:10" (the * (bar (hello-er)))))
+
+(define-syntax baz
+  (ir-macro-transformer
+   (lambda (e inj cmp)
+     (cadr e))))
+
+(define (f)
+  (baz
+   (+ 'a)))
Trap