diff --git a/src/libponyc/ast/ast.c b/src/libponyc/ast/ast.c index 043bd37bda..27937037a6 100644 --- a/src/libponyc/ast/ast.c +++ b/src/libponyc/ast/ast.c @@ -56,6 +56,13 @@ struct ast_t uint32_t flags; }; +static bool ast_cmp(ast_t* a, ast_t* b) +{ + return a == b; +} + +DEFINE_LIST(astlist, astlist_t, ast_t, ast_cmp, NULL); + static const char in[] = " "; static const size_t in_len = 2; static size_t width = 80; diff --git a/src/libponyc/ast/ast.h b/src/libponyc/ast/ast.h index 0aa6d45036..4f5fd5d963 100644 --- a/src/libponyc/ast/ast.h +++ b/src/libponyc/ast/ast.h @@ -45,6 +45,7 @@ enum AST_FLAG_ERROR_2 = 0x40000, }; +DECLARE_LIST(astlist, astlist_t, ast_t); ast_t* ast_new(token_t* t, token_id id); ast_t* ast_blank(token_id id); diff --git a/src/libponyc/type/typeparam.c b/src/libponyc/type/typeparam.c index f847a2ffd8..78cd771cd8 100644 --- a/src/libponyc/type/typeparam.c +++ b/src/libponyc/type/typeparam.c @@ -500,17 +500,23 @@ ast_t* typeparam_constraint(ast_t* typeparamref) assert(ast_id(typeparamref) == TK_TYPEPARAMREF); ast_t* def = (ast_t*)ast_data(typeparamref); ast_t* constraint = ast_childidx(def, 1); + astlist_t* def_list = astlist_push(NULL, def); - while((constraint != NULL) && (ast_id(constraint) == TK_TYPEPARAMREF)) + while(ast_id(constraint) == TK_TYPEPARAMREF) { ast_t* constraint_def = (ast_t*)ast_data(constraint); - if(constraint_def == def) - return NULL; + if(astlist_find(def_list, constraint_def)) + { + constraint = NULL; + break; + } + def_list = astlist_push(def_list, constraint_def); constraint = ast_childidx(constraint_def, 1); } + astlist_free(def_list); return constraint; } diff --git a/test/libponyc/type_check_bind.cc b/test/libponyc/type_check_bind.cc new file mode 100644 index 0000000000..f488aa1ead --- /dev/null +++ b/test/libponyc/type_check_bind.cc @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include "util.h" + +#define TEST_COMPILE(src) DO(test_compile(src, "expr")) + +class BindTest: public PassTest +{}; + + +TEST_F(BindTest, RecursiveConstraintIsUnbound) +{ + const char* src = + "class C1[A, B: A]\n" + " var x: B\n" + " new create(x': B) => x = consume x'\n"; + + TEST_COMPILE(src); + ast_t* x = lookup_member("C1", "x"); + ASSERT_EQ(NULL, typeparam_constraint(ast_type(x))); +}