Skip to content

Commit

Permalink
Fix support for recursive constraints in iftype conditions.
Browse files Browse the repository at this point in the history
By defining the shadowing TK_TYPEPARAM on the entire iftype clause, which
contains both the constraint and the body, the appropriate definition
of the type variable is used when it appears in the constraint.

Fixes #1960
  • Loading branch information
plietar committed Jun 12, 2017
1 parent 344bbac commit 36946f8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 5 deletions.
10 changes: 5 additions & 5 deletions src/libponyc/pass/scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,22 +203,22 @@ static ast_result_t scope_iftype_clause(pass_opt_t* opt, ast_t* ast)
{
pony_assert(ast_id(ast) == TK_IFTYPE_CLAUSE);

AST_GET_CHILDREN(ast, subtype, supertype, body);
AST_GET_CHILDREN(ast, subtype, supertype);

ast_t* typeparams = ast_from(ast, TK_TYPEPARAMS);

switch(ast_id(subtype))
{
case TK_NOMINAL:
{
ast_t* typeparam = make_iftype_typeparam(opt, subtype, supertype, body);
ast_t* typeparam = make_iftype_typeparam(opt, subtype, supertype, ast);
if(typeparam == NULL)
{
ast_free_unattached(typeparams);
return AST_ERROR;
}

if(!set_scope(opt, body, ast_child(typeparam), typeparam, true))
if(!set_scope(opt, ast, ast_child(typeparam), typeparam, true))
{
ast_free_unattached(typeparams);
return AST_ERROR;
Expand Down Expand Up @@ -253,14 +253,14 @@ static ast_result_t scope_iftype_clause(pass_opt_t* opt, ast_t* ast)
while(sub_child != NULL)
{
ast_t* typeparam = make_iftype_typeparam(opt, sub_child, super_child,
body);
ast);
if(typeparam == NULL)
{
ast_free_unattached(typeparams);
return AST_ERROR;
}

if(!set_scope(opt, body, ast_child(typeparam), typeparam, true))
if(!set_scope(opt, ast, ast_child(typeparam), typeparam, true))
{
ast_free_unattached(typeparams);
return AST_ERROR;
Expand Down
51 changes: 51 additions & 0 deletions test/libponyc/iftype.cc
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,57 @@ TEST_F(IftypeTest, UnconstrainedTypeparam)
TEST_COMPILE(src);
}

TEST_F(IftypeTest, RecursiveConstraint)
{
const char* src =
"trait T[X: T[X] #any]\n"
" fun tag m(): X\n"

"class val C is T[C]\n"
" fun tag m(): C => C.create()\n"

"actor Main\n"
" new create(env: Env) =>\n"
" foo[C](C)\n"

" fun foo[A](x': A) =>\n"
" var x = x'\n"
" iftype A <: T[A] then\n"
" x = x.m()\n"
" end";

TEST_COMPILE(src);
}


TEST_F(IftypeTest, Tuple_MutuallyRecursiveConstraint)
{
const char* src =
"trait T[X]\n"
" fun tag m(): X\n"

"class val C is T[D]\n"
" fun tag m(): D => D.create()\n"

"class val D is T[C]\n"
" fun tag m(): C => C.create()\n"

"actor Main\n"
" new create(env: Env) =>\n"
" foo[C,D](C, D)\n"

" fun foo[A, B](x': A, y': B) =>\n"
" var x = x'\n"
" var y = y'\n"
" iftype (A, B) <: (T[B], T[A]) then\n"
" x = y.m()\n"
" y = x.m()\n"
" end";

TEST_COMPILE(src);
}


TEST_F(IftypeTest, NestedCond)
{
const char* src =
Expand Down

0 comments on commit 36946f8

Please sign in to comment.