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

Use symbol table from definition scope when looking up references from default method bodies #4027

Merged
merged 14 commits into from
Feb 22, 2022
7 changes: 7 additions & 0 deletions .release-notes/4027.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Use symbol table from definition scope when looking up references from default method bodies

Previously, symbols from default method bodies were only looked up in the local scope of the file into which they were included. This resulted in compilation errors if said symbol wasn't available in the local scope.

Issues [#3737](https://github.com/ponylang/ponyc/issues/3737) and [#2150](https://github.com/ponylang/ponyc/issues/2150) were both examples of this problem.

We've updated definition lookup to check if the enclosing method is provided by a trait or interface and if it is, to also check to definition scope for any needed symbols.
27 changes: 27 additions & 0 deletions src/libponyc/ast/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1892,6 +1892,33 @@ void ast_extract_children(ast_t* parent, size_t child_count,
}
}

ast_t* ast_get_provided_symbol_definition(ast_t* ast,
const char* name, sym_status_t* status)
{
// The definition isn't in the local scope. let's check to see if our
// parent has a provided method body from a trait or interface. If yes,
// then we will find our definition.
ast_t* def = NULL;
bool found = false;

while(ast != NULL && !found)
{
if((ast_id(ast) == TK_FUN) || (ast_id(ast) == TK_BE))
{
// Methods with defaults provided by a trait/interface store the ast
// of the provided body in the ast data.
ast_t* body_donor = (ast_t *)ast_data(ast);
if (body_donor != NULL)
def = ast_get(body_donor, name, status);
found = true;
}

ast = ast_parent(ast);
}

return def;
}

static void ast_signature_serialise_trace(pony_ctx_t* ctx, void* object)
{
ast_t* ast = (ast_t*)object;
Expand Down
3 changes: 3 additions & 0 deletions src/libponyc/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ void ast_extract_children(ast_t* parent, size_t child_count,
children); \
}

ast_t* ast_get_provided_symbol_definition(ast_t* ast,
const char* name, sym_status_t* status);

pony_type_t* ast_signature_pony_type();

pony_type_t* ast_nominal_pkg_id_signature_pony_type();
Expand Down
3 changes: 3 additions & 0 deletions src/libponyc/pass/names.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,9 @@ bool names_nominal(pass_opt_t* opt, ast_t* scope, ast_t** astp, bool expr)
}

ast_t* def = ast_get(r_scope, name, NULL);
if(def == NULL)
def = ast_get_provided_symbol_definition(ast, name, NULL);

bool r = true;

if(def == NULL)
Expand Down
5 changes: 3 additions & 2 deletions src/libponyc/pass/refer.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,10 @@ bool refer_reference(pass_opt_t* opt, ast_t** astp)
return true;
}

// Everything we reference must be in scope, so we can use ast_get for lookup.
sym_status_t status;
ast_t* def = ast_get(ast, ast_name(ast_child(ast)), &status);
ast_t* def = ast_get(ast, name, &status);
if(def == NULL)
def = ast_get_provided_symbol_definition(ast, name, &status);

// If nothing was found, we fail, but also try to suggest an alternate name.
if(def == NULL)
Expand Down
8 changes: 8 additions & 0 deletions test/libponyc-run/regression-2150/bar.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Bar[T: Stringable #read] is Foo[T]
let _t: T

new create(t: T) =>
_t = t

fun foo(): this->T =>
_t
7 changes: 7 additions & 0 deletions test/libponyc-run/regression-2150/foo.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use "debug"

trait Foo[T: Stringable #read]
fun foo(): this->T

fun bar() =>
Debug.out(foo().string())
4 changes: 4 additions & 0 deletions test/libponyc-run/regression-2150/main.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
actor Main
new create(env: Env) =>
let b = Bar[I32](123)
b.bar()
4 changes: 4 additions & 0 deletions test/libponyc-run/regression-3737/lib/lib.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
primitive LibPrimitive

trait LibTrait
fun foo(): LibPrimitive => LibPrimitive
5 changes: 5 additions & 0 deletions test/libponyc-run/regression-3737/main.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use l = "./lib"

actor Main is l.LibTrait
new create(env: Env) =>
None