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 procedures with different noSideEffect pragmas #14216

Closed
adelq opened this issue May 4, 2020 · 4 comments · Fixed by #20733
Closed

Returning procedures with different noSideEffect pragmas #14216

adelq opened this issue May 4, 2020 · 4 comments · Fixed by #20733

Comments

@adelq
Copy link
Contributor

adelq commented May 4, 2020

I am trying to write a procedure that returns different procedures conditionally, and one variant of the procedure returned happens to have no side effects and the other does not. This is unexpected behavior since both returned procedure variants adhere to the procedure signature ((int) -> void) but because one of them gets annotated with the {.noSideEffects.} pragma, the other variant is rejected as well. The following code should reproduce the error:

Example

import sugar

proc makeAdder(a: int): (int) -> void =
  proc discard_adder(x: int) {.closure.} =
    discard a + x

  proc echo_adder(x: int) {.closure.} =
    echo("printing from adder")

  if a > 0:
    discard_adder
  else:
    echo_adder

let newAdder = makeAdder(0)
newAdder(5)

Current Output

Error: type mismatch: got <proc (x: int){.closure, gcsafe, locks: 0.}> but expected 'proc (x: int){.closure, noSideEffect, gcsafe, locks: 0.}'

Expected Output

printing from adder

Possible Solution

  • Adding a pragma that is the inverse of the {.noSideEffects.} pragma such that a function can be marked as potentially having side effects.
  • Using the loosest annotation rather than the strictest annotation for the {.noSideEffects.} pragma when determining procedure return pragmas.

Additional Information

$ nim -v
Nim Compiler Version 1.2.0
@cooldome
Copy link
Member

cooldome commented May 4, 2020

This works:

import sugar

proc makeAdder(a: int): (int) -> void =
  proc discard_adder(x: int) {.closure.} =
    discard a + x

  proc echo_adder(x: int) {.closure.} =
    echo("printing from adder")

  if a > 0:
    result = discard_adder
  else:
    result = echo_adder

let newAdder = makeAdder(0)
newAdder(5)

The issue is that if a > 0: x else: y needs to return one type. Nim struggles a bit.

@adelq
Copy link
Contributor Author

adelq commented May 4, 2020

Thanks, that worked perfectly.

@adelq adelq closed this as completed May 4, 2020
@Clyybber
Copy link
Contributor

Clyybber commented May 4, 2020

The original snippet should still work though :)

@Clyybber Clyybber reopened this May 4, 2020
@adelq
Copy link
Contributor Author

adelq commented May 5, 2020

I think this is actually the same bug as #12642, because re-ordering the branches of the if statement makes it compile correctly. This bug has been present since v0.15.0 and is currently present in v1.2.0.

ringabout added a commit that referenced this issue Nov 2, 2022
ringabout added a commit that referenced this issue Nov 2, 2022
capocasa pushed a commit to capocasa/Nim that referenced this issue Mar 31, 2023
narimiran pushed a commit that referenced this issue Apr 25, 2023
(cherry picked from commit 87f7f50)
narimiran pushed a commit that referenced this issue Apr 25, 2023
(cherry picked from commit 87f7f50)
bung87 pushed a commit to bung87/Nim that referenced this issue Jul 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants