~ chicken-core (chicken-5) 8d038d86c17ef59c0d61697966dc7a32fbf56d15


commit 8d038d86c17ef59c0d61697966dc7a32fbf56d15
Author:     Evan Hanson <evhan@foldling.org>
AuthorDate: Thu Oct 9 07:08:59 2014 +1300
Commit:     Peter Bex <peter.bex@xs4all.nl>
CommitDate: Sat Oct 11 14:35:53 2014 +0200

    Avoid invalid specializations for multi-valued foreign-primitives
    
    The foreign-primitive form may return multiple values with the C_values
    function, but its expansion is always declared to return a (single)
    undefined value. This triggers invalid ##sys#c-w-v specializations for
    single-valued producers where multiple values may in fact result.
    
    This fixes that declaration so that multiple values are expected when no
    return type is specified.
    
    Signed-off-by: Peter Bex <peter.bex@xs4all.nl>
    
    Conflicts:
            chicken-ffi-syntax.scm

diff --git a/NEWS b/NEWS
index 16094661..227fefba 100644
--- a/NEWS
+++ b/NEWS
@@ -67,6 +67,8 @@
 - Foreign function interface
   - The foreign type specifier "scheme-pointer" now accepts an optional
     C pointer type (thanks to Moritz Heidkamp and Kristian Lein-Mathisen).
+  - Type hinting for foreign-primitives now allows returning multiple
+    values when no return type has been specified.
 
 - Build system
   - MANDIR was renamed to MAN1DIR and TOPMANDIR was renamed to MANDIR
diff --git a/chicken-ffi-syntax.scm b/chicken-ffi-syntax.scm
index af02739a..d3fc79b9 100644
--- a/chicken-ffi-syntax.scm
+++ b/chicken-ffi-syntax.scm
@@ -213,13 +213,15 @@
   (lambda (form r c)
     (##sys#check-syntax 'foreign-primitive form '(_ _ . _))
     (let* ((hasrtype (and (pair? (cddr form)) (not (string? (caddr form)))))
-	   (rtype (or (and hasrtype (##sys#strip-syntax (cadr form))) 'void))
+	   (rtype (and hasrtype (##sys#strip-syntax (cadr form))))
 	   (args (##sys#strip-syntax (if hasrtype (caddr form) (cadr form))))
 	   (argtypes (map car args)))
       `(##core#the (procedure
 		    ,(map (cut chicken.compiler.support#foreign-type->scrutiny-type <> 'arg)
 			  argtypes)
-		    ,(chicken.compiler.support#foreign-type->scrutiny-type rtype 'result))
+		    ,@(if (not rtype)
+			  '* ; special case for C_values(...)
+			  (list (chicken.compiler.support#foreign-type->scrutiny-type rtype 'result))))
 		   #f
 		   (##core#foreign-primitive ,@(cdr form)))))))
 
diff --git a/manual/Accessing external objects b/manual/Accessing external objects
index 2fcec623..23107026 100644
--- a/manual/Accessing external objects	
+++ b/manual/Accessing external objects	
@@ -167,13 +167,13 @@ function to call Scheme functions and allocate Scheme data-objects. See [[Callba
 
 <macro>(foreign-primitive [RETURNTYPE] ((ARGTYPE VARIABLE) ...) STRING ...)</macro>
 
-This is also similar to {{foreign-lambda*}} but the code will be executed
-in a ''primitive'' CPS context, which means it will not actually return, but
-call its continuation on exit. This means that code inside this form may
-allocate Scheme data on the C stack (the ''nursery'') with {{C_alloc}}
-(see below). If the {{RETURNTYPE}} is omitted it defaults to {{void}}.
-You can return multiple values inside the body of the {{foreign-primitive}}
-form by calling this C function:
+This is also similar to {{foreign-lambda*}} but the code will be
+executed in a ''primitive'' CPS context, which means it will not
+actually return, but call its continuation on exit. This means that code
+inside this form may allocate Scheme data on the C stack (the
+''nursery'') with {{C_alloc}} (see below). You can return multiple
+values inside the body of the {{foreign-primitive}} form by calling this
+C function:
 
 <enscript highlight=scheme>
 C_values(N + 2, C_SCHEME_UNDEFINED, C_k, X1, ...)
diff --git a/tests/specialization-test-1.scm b/tests/specialization-test-1.scm
index 37e8d6bb..344e4451 100644
--- a/tests/specialization-test-1.scm
+++ b/tests/specialization-test-1.scm
@@ -46,5 +46,14 @@ return n;}
 
 (assert (null? (the (or undefined *) (list))))
 
+;; Ensure a foreign-primitive returning multiple values with C_values()
+;; isn't specialized to a single result.
+(let ((result (receive ((foreign-primitive ()
+			  "C_values(4,"
+			  "         C_SCHEME_UNDEFINED,"
+			  "         C_k,"
+			  "         C_fix(1),"
+			  "         C_fix(2));")))))
+  (assert (equal? '(1 2) result)))
 
 )
Trap