Steel Bank Common Lisp

LOOP fails to catch the duplicate variables bindings in some cases

Reported by Roman Marynchak on 2010-09-22
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
SBCL
Low
Unassigned

Bug Description

The slightly modified example from CLHS demonstrates the problem in SBCL 1.0.42:

 (loop with (a b) of-type float = '(1.0 2.0)
          and (c a) of-type float = '(3.0 4.0)
       return (list a b c))

CLISP and Lispworks do not have this issue - they both say about the duplicate binding in LOOP and throw the error.

But in SBCL's REPL it yields:

* (loop with (a b) of-type float = '(1.0 2.0)
          and (c a) of-type float = '(3.0 4.0)
       return (list a b c))
; in: LAMBDA NIL
; (SB-LOOP::LOOP-DESTRUCTURING-BIND (C A) #:LOOP-DESTRUCTURE-604
; (SB-LOOP::LOOP-DESTRUCTURING-BIND (A B)
; #:LOOP-DESTRUCTURE-603
; (DECLARE
; (TYPE
; FLOAT
; A)
; (TYPE
; FLOAT
; C)
; (TYPE
; FLOAT
; B)
; (TYPE
; FLOAT
; A))
; (SB-LOOP::LOOP-BODY
; NIL NIL
; ((RETURN-FROM
; NIL
; #))
; NIL
; NIL)))
; --> DESTRUCTURING-BIND LET LET*
; ==>
; (LET* ((C (CAR #:WHOLE1))
; (A (CAR (CDR #:WHOLE1)))
; (#:LOOP-IGNORED-VAR-0 (CDR (CDR #:WHOLE1))))
; (DECLARE (IGNORE #:LOOP-IGNORED-VAR-0))
; (SB-LOOP::LOOP-DESTRUCTURING-BIND (A B) #:LOOP-DESTRUCTURE-603
; (DECLARE (TYPE FLOAT A)
; (TYPE FLOAT C)
; (TYPE FLOAT B)
; (TYPE FLOAT A))
; (SB-LOOP::LOOP-BODY NIL NIL
; ((RETURN-FROM NIL #))
; NIL NIL)))
;
; caught STYLE-WARNING:
; The variable A is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition

(1.0 2.0 3.0)
*

The right behavior here is to signal the error. CLHS (section 6.1.1.7) says that "An error of type program-error is signaled (at macro expansion time) if the same variable is bound twice in any variable-binding clause of a single loop expression. Such variables include local variables, iteration control variables, and variables found by destructuring."

Changed in sbcl:
importance: Undecided → Low
status: New → Triaged
Changed in sbcl:
assignee: nobody → Roman Marynchak (roman-marynchak)
status: Triaged → In Progress

There is a simple patch. Before declaring a variable, we check whether its name is already used within the loop. To do that, we analyze *loop-declarations* list contents. Variables which are initialized by destructuring are described by the sublists in that list. Every sublist has a variable name as a last element.

The regression tests is coming soon. Current behavior with the fix:

* (loop with (a b) of-type float = '(1.0 2.0)
          and (c a) of-type float = '(3.0 4.0)
       return (list a b c))

debugger invoked on a SB-INT:SIMPLE-PROGRAM-ERROR in thread #<THREAD
                                                              "initial thread" RUNNING
                                                              {A9E6861}>:
  duplicated variable A in a LOOP binding
current LOOP context: WITH (A B) OF-TYPE FLOAT = '(1.0 2.0) AND (C
                                                                 A) OF-TYPE FLOAT = '(3.0
                                                                                      4.0) RETURN.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

The attachment contains a regression test. Note that a 'successful' variant of the similar example (where A is not duplicated) is already present in loop.pure.lisp.

tags: added: loop review

I have just found that this patch is not applicable on the current LOOP, so I'm removing the review tag. But I will try to find the acceptable solution later.

tags: removed: review
Paul Khuong (pvk) on 2013-07-22
Changed in sbcl:
assignee: Roman Marynchak (roman-marynchak) → nobody
status: In Progress → Triaged
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers