Fix closures in methods.

A local name inside a method should always resolve to a self send even
if there is a local variable with that name outside of the method.
This commit is contained in:
Bob Nystrom
2015-10-05 07:44:51 -07:00
parent e968b4bf98
commit 24cbb7f399
4 changed files with 29 additions and 33 deletions

View File

@ -1230,9 +1230,13 @@ static int addUpvalue(Compiler* compiler, bool isLocal, int index)
// not close over local variables.
static int findUpvalue(Compiler* compiler, const char* name, int length)
{
// If we are at a method boundary or the top level, we didn't find it.
if (compiler->parent == NULL || compiler->enclosingClass != NULL) return -1;
// If we are at the top level, we didn't find it.
if (compiler->parent == NULL) return -1;
// If we hit the method boundary (and the name isn't a static field), then
// stop looking for it. We'll instead treat it as a self send.
if (name[0] != '_' && compiler->parent->enclosingClass != NULL) return -1;
// See if it's a local variable in the immediately enclosing function.
int local = resolveLocal(compiler->parent, name, length);
if (local != -1)

View File

@ -1,17 +0,0 @@
// TODO: Is this right? Shouldn't it resolve to this.local?
var foo = null
{
var local = "local"
class Foo {
construct new() {}
method {
System.print(local)
}
}
foo = Foo.new()
}
foo.method // expect: local

View File

@ -1,13 +0,0 @@
// TODO: Is this right? Shouldn't it resolve to this.local?
{
var local = "local"
class Foo {
construct new() {}
method {
System.print(local)
}
}
Foo.new().method // expect: local
}

View File

@ -0,0 +1,22 @@
{
var foo = "variable"
class Foo {
construct new() {}
foo { "method" }
method {
System.print(foo)
}
static foo { "class method" }
static classMethod {
System.print(foo)
}
}
Foo.new().method // expect: method
Foo.classMethod // expect: class method
}