From: Andreas Rottmann <a.rottmann@gmx.at>
To: Guile Bugs <bug-guile@gnu.org>
Subject: Quite sneaky bug in SRFI-9
Date: Thu, 10 Mar 2011 01:23:03 +0100 [thread overview]
Message-ID: <87fwqvg6xk.fsf@gmx.at> (raw)
[-- Attachment #1: Type: text/plain, Size: 1951 bytes --]
Hi! After being puzzled for some time, I found the root cause
for an issue with my code was actually a quite serious bug in
SRFI-9's `define-inlinable' (here we go again -- but this time
it's an actual bug, I promise ;-)): The current implementation of
`define-inlinable' duplicates actual parameters passed to the
macros it generates, for example (note the `(find-next-solution! s
10000)' expression): scheme@(guile-user)> (tree-il->scheme
(macroexpand '(solution? (find-next-solution! s 10000))))
$6 = (if ((@@ (srfi srfi-9) struct?) (find-next-solution! s 10000))
((@@ (srfi srfi-9) eq?)
((@@ (srfi srfi-9) struct-vtable) (find-next-solution! s 10000))
(@@ (dorodango solver) solution))
#f)
Attached is a patch to fix this (along with a test case), but I guess
it's not as good as it could be:
- It doesn't preserve the current error-at-syntax-time behavior when an
argument count mismatch occurs (this makes the first two "constructor"
testcases in srfi-9.test fail, and obsolete). I don't know if this is
considered important.
- It's certainly not as efficient as the current, broken implementation.
Ideally, the expansion would be a `let' block instead of the
`call-with-values' invocation. I'd guess the former might be more
amendable for optimization, but perhaps I'm wrong here. I didn't
implement the solution using `let', as I believe it cannot be done in
a straightforward way (i.e. by exploiting the pattern matcher only)
with Guile's current syntax-case implementation.
Has anyone done benchmarks of the benefits of the current (broken)
SRFI-9 accessors and predicates vs. regular procedures on real code?
Given the argument duplication issue, it might be the case that
`define-inlinable' actually slowed things down :-).
Perhaps removing `define-inlinable' entirely would be an acceptable
alternative fix for this issue?
Anyway, here's the patch:
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: srfi-9-fix2.diff --]
[-- Type: text/x-diff, Size: 2561 bytes --]
From: Andreas Rottmann <a.rottmann@gmx.at>
Subject: Fix argument duplication `define-inlinable' in SRFI-9
* modules/srfi/srfi-9.scm (define-inlinable): Don't duplicate argument
expressions in the expansion of the macros generated.
* test-suite/tests/srfi-9.test (constructor): Adapted.
(side-effecting arguments): New test for the argument duplication
issue.
---
module/srfi/srfi-9.scm | 5 +++--
test-suite/tests/srfi-9.test | 22 +++++++++-------------
2 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/module/srfi/srfi-9.scm b/module/srfi/srfi-9.scm
index fad570b..34dbb53 100644
--- a/module/srfi/srfi-9.scm
+++ b/module/srfi/srfi-9.scm
@@ -87,8 +87,9 @@
(define-syntax name
(lambda (x)
(syntax-case x ()
- ((_ formals ...)
- #'(begin body ...))
+ ((_ . arguments)
+ #'(call-with-values (lambda () (values . arguments))
+ (lambda (formals ...) body ...)))
(_
(identifier? x)
#'proc-name))))))))))
diff --git a/test-suite/tests/srfi-9.test b/test-suite/tests/srfi-9.test
index f8006c4..6766482 100644
--- a/test-suite/tests/srfi-9.test
+++ b/test-suite/tests/srfi-9.test
@@ -38,21 +38,10 @@
(with-test-prefix "constructor"
- ;; Constructors are defined using `define-integrable', meaning that direct
- ;; calls as in `(make-foo)' lead to a compile-time psyntax error, hence the
- ;; distinction below.
-
- (pass-if-exception "foo 0 args (inline)" exception:syntax-pattern-unmatched
- (compile '(make-foo) #:env (current-module)))
- (pass-if-exception "foo 2 args (inline)" exception:syntax-pattern-unmatched
- (compile '(make-foo 1 2) #:env (current-module)))
-
(pass-if-exception "foo 0 args" exception:wrong-num-args
- (let ((make-foo make-foo))
- (make-foo)))
+ (make-foo))
(pass-if-exception "foo 2 args" exception:wrong-num-args
- (let ((make-foo make-foo))
- (make-foo 1 2))))
+ (make-foo 1 2)))
(with-test-prefix "predicate"
@@ -94,6 +83,13 @@
(pass-if-exception "set-y! on bar" exception:wrong-type-arg
(set-y! b 99)))
+(with-test-prefix "side-effecting arguments"
+
+ (pass-if "predicate"
+ (let ((x 0))
+ (and (foo? (begin (set! x (+ x 1)) f))
+ (= x 1)))))
+
(with-test-prefix "non-toplevel"
(define-record-type :frotz (make-frotz a b) frotz?
--
tg: (df12979..) t/srfi-9-fix2 (depends on: stable-2.0)
[-- Attachment #3: Type: text/plain, Size: 63 bytes --]
Regards, Rotty
--
Andreas Rottmann -- <http://rotty.yi.org/>
next reply other threads:[~2011-03-10 0:23 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-10 0:23 Andreas Rottmann [this message]
2011-03-11 13:55 ` Quite sneaky bug in SRFI-9 Ludovic Courtès
2011-03-11 19:28 ` Andy Wingo
2011-03-11 19:30 ` Andy Wingo
2011-03-11 20:03 ` Ludovic Courtès
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87fwqvg6xk.fsf@gmx.at \
--to=a.rottmann@gmx.at \
--cc=bug-guile@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).