Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning nested closures causes external compiler error #16534

Open
Ryan1729 opened this issue Dec 31, 2020 · 1 comment
Open

Returning nested closures causes external compiler error #16534

Ryan1729 opened this issue Dec 31, 2020 · 1 comment
Labels
const `const x=expr` or `static: stmt`

Comments

@Ryan1729
Copy link

Ryan1729 commented Dec 31, 2020

Attempting to compile the following examples involving procs that return procs that capture variables, result in gcc errors.

Example

type
    Spell = proc(state: var bool)

proc requirePlayer(
    spellMaker: proc(field: bool): Spell,
): Spell =
    return proc(state: var bool) =
        (spellMaker(state))(state)

const spell*: Spell =
    requirePlayer(
        proc(field: bool): Spell =
        return proc(state: var bool) =
            discard
    )

var state = true

spell(state)

Current Output

/home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c:126:89: error: ‘T2_’ undeclared here (not in a function)
  126 | N_LIB_PRIVATE NIM_CONST tyProc__dNfqZotHSSZhQq1OsUK9aUw spell__plx15GbDYaoiAnEXuLH2aA = T2_;
      |                                                                                         ^~~
/home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c: In function ‘NimMainModule’:
/home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c:253:67: error: incompatible types when assigning to type ‘void *’ from type ‘tyObject_Env_nested_closuresdotnim_requirePlayer___v19a3PTYtzd9bI9c06OC6xp1Q’ {aka ‘struct tyObject_Env_nested_closuresdotnim_requirePlayer___v19a3PTYtzd9bI9c06OC6xp1Q’}
  253 |  T2_.ClP_0 = colonanonymous___JQcKraBLv4N8RwRRwgzeLg; T2_.ClE_0 = T1_;
      |                                                                   ^~~
Error: execution of an external compiler program 'gcc -c  -w -fmax-errors=3   -I/home/ryan/code/not_my_code/Nim/lib -I/home/ryan/code/nim/nested-closures-bug-repro -o /home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c.o /home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c' failed with exit code: 1

Expected Output

The program compiles successfully, or an error message explaining why this cannot be done.

Example

Here's a slightly longer example that hopefully makes the motivation for wanting to do this clearer.

import options

type
    Player = bool
    State = tuple
        playerOption: Option[Player]

    Spell = proc(state: var State)

proc requirePlayer(
    spellMaker: proc(player: Player): Spell,
): Spell =
    return proc(state: var State) =
        if state.playerOption.isSome:
            (spellMaker(state.playerOption.get))(state)

const spell*: Spell =
    requirePlayer(
        proc(player: Player): Spell =
        return proc(state: var State) =
            # somthing that relies on Player here
            discard
    )

var state = (playerOption: some(true))

spell(state)

Current Output

/home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c:302:88: error: ‘T2_’ undeclared here (not in a function)
  302 | N_LIB_PRIVATE NIM_CONST tyProc__dcDH7r0MeN4B247epLRPAA spell__plx15GbDYaoiAnEXuLH2aA = T2_;
      |                                                                                        ^~~
/home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c: In function ‘NimMainModule’:
/home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c:608:68: error: incompatible types when assigning to type ‘void *’ from type ‘tyObject_Env_nested_closuresdotnim_requirePlayer___yo9bXRRNccA4vMqvRdMx4AA’ {aka ‘struct tyObject_Env_nested_closuresdotnim_requirePlayer___yo9bXRRNccA4vMqvRdMx4AA’}
  608 |  T2_.ClP_0 = colonanonymous___zXdvcEgKPo8T8h9axX05B4w; T2_.ClE_0 = T1_;
      |                                                                    ^~~
Error: execution of an external compiler program 'gcc -c  -w -fmax-errors=3   -I/home/ryan/code/not_my_code/Nim/lib -I/home/ryan/code/nim/nested-closures-bug-repro -o /home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c.o /home/ryan/.cache/nim/nested_closures_d/@mnested_closures.nim.c' failed with exit code: 1

Expected Output

The program compiles successfully, or an error message explaining why this cannot be done.

Additional Information

The posted output is from this version:

Nim Compiler Version 1.5.1 [Linux: amd64]
Compiled at 2020-12-31
Copyright (c) 2006-2020 by Andreas Rumpf

git hash: 5fb56a3b2c83b62d72c72a9d56ef1333671bc2b6
active boot switches: -d:release

But the problem happens with this version as well:

Nim Compiler Version 1.4.0 [Linux: amd64]
Compiled at 2020-10-18
Copyright (c) 2006-2020 by Andreas Rumpf

git hash: bdcd87afca238a0a7b2c70971827cf9172817b12
active boot switches: -d:release
@metagn
Copy link
Collaborator

metagn commented Jan 1, 2021

If you change const to let or if you wrap the code after it in static: then there is no error. No difference between var bool and bool. Is Nim supposed to support const procs at all? This compiles:

type Spell = proc (state: bool)

proc requirePlayer(): Spell =
  return proc (state: bool) =
    discard

const spell = requirePlayer()

var state = true

spell(state)

But a simple example like this doesn't:

proc foo() = discard

const bar = foo

bar()

In case you don't know, const is for constants evaluated at compile time while let is runtime. If you want to use your compile time closure value at runtime, then Nim would have to generate code for it, which seems to cause problems such as this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
const `const x=expr` or `static: stmt`
Projects
None yet
Development

No branches or pull requests

2 participants