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

Replace type variables in a single sweep during reification. #3664

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 95 additions & 72 deletions src/libponyc/type/reify.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,68 @@
#include "../../libponyrt/mem/pool.h"
#include "ponyassert.h"

static void reify_typeparamref(ast_t** astp, ast_t* typeparam, ast_t* typearg)
static ast_t* find_typearg(pass_opt_t* opt, ast_t* ast, ast_t* typeparams, ast_t* typeargs)
{
ast_t* ast = *astp;
pony_assert(ast_id(ast) == TK_TYPEPARAMREF);
pony_assert(ast_id(typeparam) == TK_TYPEPARAM);
ast_t* ref_def = NULL;
switch(ast_id(ast))
{
case TK_REFERENCE:
ref_def = ast_get(ast, ast_name(ast_child(ast)), NULL);
if(ref_def == NULL)
return NULL;

break;

case TK_TYPEPARAMREF:
ref_def = (ast_t*)ast_data(ast);
pony_assert(ref_def != NULL);
break;

default:
pony_assert(0);
}

// Iterate pairwise through the typeparams and typeargs,
// until we find the one corresponding to this ref
ast_t* typeparam = ast_child(typeparams);
ast_t* typearg = ast_child(typeargs);

while((typeparam != NULL) && (typearg != NULL))
{
ast_t* param_def = (ast_t*)ast_data(typeparam);
pony_assert(param_def != NULL);

if(ref_def == param_def)
return typearg;

if(ast_id(ast) == TK_TYPEPARAMREF)
{
AST_GET_CHILDREN(param_def, param_name, param_constraint);
AST_GET_CHILDREN(ref_def, ref_name, ref_constraint);

if(ast_name(ref_name) == ast_name(param_name))
{
if((ast_id(param_constraint) == TK_TYPEPARAMREF) ||
is_subtype(ref_constraint, param_constraint, NULL, opt))
return typearg;
}
}

ast_t* ref_def = (ast_t*)ast_data(ast);
// Not the type variable we are looking for, move on to next
typeparam = ast_sibling(typeparam);
typearg = ast_sibling(typearg);
}

// We can't compare ref_def and typeparam, as they could be a copy or
// a iftype shadowing. However, their data points back to the original
// typeparam definition, which can be compared.
ref_def = (ast_t*)ast_data(ref_def);
typeparam = (ast_t*)ast_data(typeparam);
return NULL;
}

pony_assert(ref_def != NULL);
pony_assert(typeparam != NULL);
static void reify_typeparamref(pass_opt_t* opt, ast_t** astp, ast_t* typeparams, ast_t* typeargs)
{
ast_t* ast = *astp;
pony_assert(ast_id(ast) == TK_TYPEPARAMREF);

if(ref_def != typeparam)
ast_t* typearg = find_typearg(opt, ast, typeparams, typeargs);
if (typearg == NULL)
return;

// Keep ephemerality.
Expand Down Expand Up @@ -84,23 +128,13 @@ static void reify_arrow(ast_t** astp)
ast_replace(astp, r_type);
}

static void reify_reference(ast_t** astp, ast_t* typeparam, ast_t* typearg)
static void reify_reference(pass_opt_t* opt, ast_t** astp, ast_t* typeparams, ast_t* typeargs)
{
ast_t* ast = *astp;
pony_assert(ast_id(ast) == TK_REFERENCE);

const char* name = ast_name(ast_child(ast));

sym_status_t status;
ast_t* ref_def = ast_get(ast, name, &status);

if(ref_def == NULL)
return;

ast_t* param_def = (ast_t*)ast_data(typeparam);
pony_assert(param_def != NULL);

if(ref_def != param_def)
ast_t* typearg = find_typearg(opt, ast, typeparams, typeargs);
if (typearg == NULL)
return;

ast_setid(ast, TK_TYPEREF);
Expand All @@ -109,39 +143,6 @@ static void reify_reference(ast_t** astp, ast_t* typeparam, ast_t* typearg)
ast_settype(ast, typearg);
}

static void reify_one(pass_opt_t* opt, ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
ast_t* ast = *astp;
ast_t* child = ast_child(ast);

while(child != NULL)
{
reify_one(opt, &child, typeparam, typearg);
child = ast_sibling(child);
}

ast_t* type = ast_type(ast);

if(type != NULL)
reify_one(opt, &type, typeparam, typearg);

switch(ast_id(ast))
{
case TK_TYPEPARAMREF:
reify_typeparamref(astp, typeparam, typearg);
break;

case TK_ARROW:
reify_arrow(astp);
break;

case TK_REFERENCE:
reify_reference(astp, typeparam, typearg);
break;

default: {}
}
}

bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors,
pass_opt_t* opt)
Expand Down Expand Up @@ -201,6 +202,40 @@ bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors,
return true;
}

static void reify_ast(ast_t** astp, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt)
{
ast_t* ast = *astp;
ast_t* child = ast_child(ast);

while(child != NULL)
{
reify_ast(&child, typeparams, typeargs, opt);
child = ast_sibling(child);
}

ast_t* type = ast_type(ast);

if(type != NULL)
reify_ast(&type, typeparams, typeargs, opt);

switch(ast_id(ast))
{
case TK_TYPEPARAMREF:
reify_typeparamref(opt, astp, typeparams, typeargs);
break;

case TK_ARROW:
reify_arrow(astp);
break;

case TK_REFERENCE:
reify_reference(opt, astp, typeparams, typeargs);
break;

default: {}
}
}

ast_t* reify(ast_t* ast, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt,
bool duplicate)
{
Expand All @@ -220,19 +255,7 @@ ast_t* reify(ast_t* ast, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt,
else
r_ast = ast;

// Iterate pairwise through the typeparams and typeargs.
ast_t* typeparam = ast_child(typeparams);
ast_t* typearg = ast_child(typeargs);

while((typeparam != NULL) && (typearg != NULL))
{
reify_one(opt, &r_ast, typeparam, typearg);
typeparam = ast_sibling(typeparam);
typearg = ast_sibling(typearg);
}

pony_assert(typeparam == NULL);
pony_assert(typearg == NULL);
reify_ast(&r_ast, typeparams, typeargs, opt);
return r_ast;
}

Expand Down
24 changes: 24 additions & 0 deletions test/libponyc/type_params.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include <gtest/gtest.h>
#include <platform.h>

#include <ast/ast.h>

#include "util.h"

#define TEST_COMPILE(src) DO(test_compile(src, "expr"))
#define TEST_ERROR(src) DO(test_error(src, "expr"))
#define TEST_EQUIV(src, expect) DO(test_equiv(src, "expr", expect, "expr"))

class TypeParamsTest : public PassTest
{};

TEST_F(TypeParamsTest, ReifySimultaneously)
{
// From issue #1870
const char* src =
"interface State[S, I, O]\n"
" fun val apply(state: S, input: I): (S, O)\n"
" fun val bind[O2](next: State[S, O, O2]): State[S, I, O2]\n";

TEST_COMPILE(src);
}
Loading