LOOP fails to catch the duplicate variables bindings in some cases
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Fix Released
|
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:
; (SB-LOOP:
; #:LOOP-
; (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-
; (DECLARE (IGNORE #:LOOP-
; (SB-LOOP:
; (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 |
Changed in sbcl: | |
assignee: | Roman Marynchak (roman-marynchak) → nobody |
status: | In Progress → Triaged |
Changed in sbcl: | |
status: | Fix Committed → Fix Released |
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} >:
A) OF-TYPE FLOAT = '(3.0
4.0) RETURN.
duplicated variable A in a LOOP binding
current LOOP context: WITH (A B) OF-TYPE FLOAT = '(1.0 2.0) AND (C
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.