ooc-lang / rock

:ocean: self-hosted ooc compiler that generates c99
http://ooc-lang.org/
MIT License
403 stars 40 forks source link

Variables in nested closures #864

Closed emilwestergren closed 9 years ago

emilwestergren commented 9 years ago

Should it be possible to create a closure inside another closure? Because it is in that case not possible to use variables created in the parent closure in the child closure.

Example code:

func1 := func {
    a := 1
    b := 2
    func2 := func { println((a + b) toString()) }
    func2()
}
func1()

fails with:

NestedClosureTest.ooc: In function ‘test_sdk_NestedClosureTest_load’:
NestedClosureTest.ooc:3:13: error: ‘a’ undeclared (first use in this function)
  a := 1
             ^
NestedClosureTest.ooc:3:13: note: each undeclared identifier is reported only once for each function it appears in
NestedClosureTest.ooc:4:13: error: ‘b’ undeclared (first use in this function)
  b := 2
             ^
NestedClosureTest.ooc: In function ‘test_sdk_NestedClosureTest____test_sdk_NestedClosureTest_test_sdk_NestedClosureTest_closure4’:
NestedClosureTest.ooc:3:23: error: ‘a’ redeclared as different kind of symbol
  a := 1
                       ^
NestedClosureTest.ooc:8:117: note: previous definition of ‘a’ was here
 func1()
                                                                                                                     ^
NestedClosureTest.ooc:4:23: error: ‘b’ redeclared as different kind of symbol
  b := 2
                       ^
NestedClosureTest.ooc:8:138: note: previous definition of ‘b’ was here
 func1()
horasal commented 9 years ago

Things messed up when variable appears. line no.104,105 cause this problem. Here we are generating unnecessary context __vvv_ctx5.

101         __vvv_ctx5 = lang_Memory__gc_malloc(((lang_types__Class*)__vvv_vvv_closure4_ctx_class())->size);
102         #line 1 "/home/housezet/.ooc_libs/mcs/test/rock/vvv.ooc"
103         (*(__vvv_ctx5)) = (__vvv_vvv_closure4_ctx) {
104             a,
105             b
106         };
107         __vvv_closure6 = (lang_types__Closure) {
108             vvv____vvv_vvv_closure4_thunk,
109             __vvv_ctx5
110         };
horasal commented 9 years ago

It seems to be a bug in VariableDecl -> captureInUpstreamClosures -> intermediateScopeIndex W should also check if var is defined in parent closure.

horasal commented 9 years ago

A related problem(UNRESOLVED):

main: func{
    ret := 1
    1 times(|| 2 times(|| ret += 1))
    ret toString() println()
}

Expect: 3 Got: 1

because rock generate &(&ret) in nested closure...

fasterthanlime commented 9 years ago

My example (for the original issue, not #882)

func1 := func {
    a := 1
    b := 2
    func2 := func {
        "#{a + b}" println()
    }
    func2()
}
func1()

Note that if you change func1 := to func1: it doesn't happen. Looks like isDefined doesn't do the right thing..