nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.58k stars 1.47k forks source link

collect leaking scope, and maybe another bug #19287

Open nblaxall opened 2 years ago

nblaxall commented 2 years ago

This was tested on https://play.nim-lang.org/#ix=3Jnf and also on my laptop (Nim Compiler Version 1.6.2 [MacOSX: amd64])

Sugar's collect seems to leak scope, plus maybe another bug to do with if/else's in collect:

Example

import std/sugar

let a = collect:
  let n = 2
  for i in 1..9:
    n * i
echo a  # @[2, 4, 6, 8, 10, 12, 14, 16, 18]

echo n  # 2 ... leaks out of scope :(

let b = collect:
  #let n = 1  # Error: redefinition of 'n' :(
  let m = 2
  for i in 1..9:
    m * i
echo b  # @[2, 4, 6, 8, 10, 12, 14, 16, 18]

let c = collect:
  let o = 2
  for i in 1..9:
    if o == 2: o
    else: 0  # works
echo c  # @[2, 2, 2, 2, 2, 2, 2, 2, 2]

let d = collect:
  let p = 2
  if p == 2:
    for i in 1..9: i
  else:
    for i in 1..9: i * p  # breaks
echo d  # expected should be: @[1, 2, 3, 4, 5, 6, 7, 8, 9]

here is the output of https://play.nim-lang.org/#ix=3Jnf:

Hint: used config file '/playground/nim/config/nim.cfg' [Conf] Hint: used config file '/playground/nim/config/config.nims' [Conf] ............................................................. /usercode/in.nim(25, 9) template/generic instantiation of collect from here /usercode/in.nim(30, 22) Error: expression 'i * p' is of type 'int' and has to be used (or discarded)

ghost commented 2 years ago

Scope leakage fixed in https://github.com/nim-lang/Nim/pull/19288

About this:

let d = collect:
  let p = 2
  if p == 2:
    for i in 1..9: i
  else:
    for i in 1..9: i * p  # breaks

I'm not really sure if this is supposed to work as-is. You can make it work by changing the code so that if is inside the loop:

let d = collect:
  let p = 2
  for i in 1..9:
    if p == 2: 
      i
    else:
      i * p