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

Lambda lift breaks recursive let definitions #111

Closed
gschare opened this issue Sep 22, 2022 · 11 comments
Closed

Lambda lift breaks recursive let definitions #111

gschare opened this issue Sep 22, 2022 · 11 comments
Assignees
Labels
bug Something isn't working

Comments

@gschare
Copy link

gschare commented Sep 22, 2022

In regression-tests/tests/hello13.ssl, the following function for printing a list of characters fails to compile. It complains that the puts__ variable is unbound, the error presumably originating when it is recursively called.

puts_ putc s =
  let puts__ ss =
        match ss
          Cons c s = putc c
                     puts__ s
          Nil = ()
  puts__ s

// TypeError (ErrorMsg "Unbound variable: Var (VarId puts__) (Type [])")

We should allow recursive nested functions a la Haskell. This could be achieved by adding the name to the environment at the moment it is declared, like letrec bindings in Racket or OCaml, but I'm not sure if would be negative consequences to that. We could also add an explicit rec keyword like those languages do, but the result might be aesthetically subpar.

See also #30 -- seems related.

@sedwards-lab
Copy link
Contributor

This is definitely a bug since top-level definitions can handle recursion and the local ones should, too. This may be a bug in the type checker. The question is why it's not working for local definitions yet working for top-level definitions. Is the type error being generated before or after lambda-lifting?

@j-hui j-hui self-assigned this Sep 22, 2022
@j-hui
Copy link
Contributor

j-hui commented Sep 22, 2022

I'll look into it

@j-hui
Copy link
Contributor

j-hui commented Sep 22, 2022

I can't reproduce the TypeError shown. In fact, the code snippet shown was originally commented out; if I use that definition it, passes the typecheck, and only fails later on at the Codgen stage:

$ cat regression-tests/tests/hello13.ssl
putc_ (cout : &Int) c =
  after 1, cout <- c
  wait cout

eof_ (cout : &Int) _ =
  after 1, cout <- 0
  wait cout

type String
  Cons Int String
  Nil

/*
// old workaround definition
puts_ putc s =
  match s
    Cons c ss = putc c
                puts_ putc ss
    Nil = ()
*/

puts_ putc s =
  let puts__ ss =
        match ss
          Cons c s = putc c
                     puts__ s
          Nil = ()
  puts__ s

// Previously commented out, used to throw this error:
// TypeError (ErrorMsg "Unbound variable: Var (VarId puts__) (Type [])")

main cin cout =
  let putc = putc_ cout
  let puts = puts_ putc
  let eof = eof_ cout
  let hello = Cons 72 (Cons 101 (Cons 108 (Cons 108
                (Cons 111 (Cons 49 (Cons 51 (Cons 10 Nil)))))))
  puts hello
  eof ()

$ sslc regression-tests/tests/hello13.ssl
UnexpectedError (ErrorMsg "Pattern match failure in do expression at src/Codegen/Codegen.hs:529:3-8")

@gschare
Copy link
Author

gschare commented Sep 22, 2022

I tested using the regression-tests/runtests.sh script:

$ ./runtests.sh -k tests/hello13.ssl
hello13...FAILED
  failed: stack exec sslc -- tests/hello13.ssl > out/hello13.c
make -C ../lib/ssm build/libssm.a 1>&2
PLATFORM is simulation
# Valgrind is not available; compiling without it.
make: `build/libssm.a' is up to date.

###### Testing hello13
stack exec sslc -- tests/hello13.ssl > out/hello13.c
TypeError (ErrorMsg "Unbound variable: Var (VarId puts__) (Type [])")
###### FAILED

@j-hui
Copy link
Contributor

j-hui commented Sep 22, 2022

@gschare did you modify hello13.ssl in any way? Also, can you confirm that you have the latest build of sslc?

@j-hui
Copy link
Contributor

j-hui commented Sep 22, 2022

For what it's worth, I'm able to get the following output, right before Codegen:

puts__puts___anon0 (putc : (Int32 -> a1)) (puts__ : (String -> ())) (ss : String) -> () =
  __drop (
    __drop (
      __drop (
        match ss
          Cons __pat_anon0 __pat_anon1 = __drop (
                                           __dup (__pat_anon0)
                                           __drop (
                                             __dup (__pat_anon1)
                                             let s = __dup (__pat_anon1)
                                             __drop (
                                               let c = __dup (__pat_anon0)
                                               __drop (
                                                 let anon0_underscore = __dup (putc) (__dup (c))
                                                 __drop (
                                                   __dup (puts__) (__dup (s))
                                                 ) anon0_underscore
                                               ) c
                                             ) s
                                           ) __pat_anon1
                                         ) __pat_anon0
          Nil  = ()
      ) ss
    ) puts__
  ) putc

puts_ (putc : (Int32 -> a1)) (s : String) -> () =
  __drop (
    __drop (
      let puts__ = __dup (puts__puts___anon0) (__dup (putc)) (__dup (puts__))
      __drop (
        __dup (puts__) (__dup (s))
      ) puts__
    ) s
  ) putc

I suspect this line is what's causing the issue:

      let puts__ = __dup (puts__puts___anon0) (__dup (putc)) (__dup (puts__))

I'm not totally sure how that's being generated

@sedwards-lab
Copy link
Contributor

Yes. Please make sure you're on the main branch, at the head (git pull) and have run stack build (runtests.sh doesn't automatically build the compiler)

@gschare
Copy link
Author

gschare commented Sep 22, 2022

@gschare did you modify hello13.ssl in any way? Also, can you confirm that you have the latest build of sslc?

My bad, I hadn't pulled the latest commits. Now I get the same error as you. I did the same modification you did to hello13.ssl, uncommenting the second definition of puts_ and commenting out the old one.

$ ./runtests.sh -k tests/hello13.ssl
hello13...FAILED
  failed: stack exec sslc -- tests/hello13.ssl > out/hello13.c
make -C ../lib/ssm clean 1>&2
PLATFORM is simulation
# Valgrind is not available; compiling without it.
rm -rf build
make -C ../lib/ssm EXTRA_CFLAGS="-DCONFIG_MEM_STATS" build/libssm.a 1>&2
PLATFORM is simulation
# Valgrind is not available; compiling without it.
mkdir -p build
cc -g -Iinclude -O -Wall -pedantic -DCONFIG_MEM_STATS -std=c99 -c -o build/ssm-closure.o src/ssm-closure.c
cc -g -Iinclude -O -Wall -pedantic -DCONFIG_MEM_STATS -std=c99 -c -o build/ssm-mem.o src/ssm-mem.c
cc -g -Iinclude -O -Wall -pedantic -DCONFIG_MEM_STATS -std=c99 -c -o build/ssm-scheduler.o src/ssm-scheduler.c
cc -g -Iinclude -O -Wall -pedantic -DCONFIG_MEM_STATS -std=c99 -c -o build/ssm-top-act.o src/ssm-top-act.c
rm -f build/libssm.a
ar -cr build/libssm.a build/ssm-closure.o build/ssm-mem.o build/ssm-scheduler.o build/ssm-top-act.o

###### Testing hello13
stack exec sslc -- tests/hello13.ssl > out/hello13.c
UnexpectedError (ErrorMsg "Pattern match failure in do expression at src/Codegen/Codegen.hs:529:3-8")
###### FAILED

@j-hui
Copy link
Contributor

j-hui commented Sep 22, 2022

Scratch that, I think the problem comes from lambda lifting. From --dump-ir-typed (before lambda-lifting):

puts_ (putc : (Int32 -> a1)) (s : String) -> () =
  let puts__ = puts__puts___anon0 putc puts__
  puts__ s

It's not correctly handling the identifiers of recursive functions, which it believs is captured by closure.

@j-hui
Copy link
Contributor

j-hui commented Sep 22, 2022 via email

@j-hui j-hui changed the title Allow recursive let functions Lambda lift breaks recursive let definitions Oct 17, 2022
@j-hui j-hui added the bug Something isn't working label Apr 18, 2023
@j-hui
Copy link
Contributor

j-hui commented Apr 29, 2023

Closed by #152

@j-hui j-hui closed this as completed Apr 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants