Skip to content
Closed
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
2 changes: 1 addition & 1 deletion src/libponyc/ast/frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ bool frame_push(typecheck_t* t, ast_t* ast)
{
case TK_TYPEPARAM:
{
AST_GET_CHILDREN(parent, id, constraint, def_type);
AST_GET_CHILDREN(parent, id, unbounded_type_params, constraint, def_type);

if(constraint == ast)
{
Expand Down
3 changes: 3 additions & 0 deletions src/libponyc/ast/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,11 @@ static const lextoken_t abstract[] =
{ "branch", TK_LITERALBRANCH },
{ "opliteral", TK_OPERATORLITERAL },

{ "_", TK_UNDERSCORE },
{ "typeparams", TK_TYPEPARAMS },
{ "typeparam", TK_TYPEPARAM },
{ "unboundtypeparams", TK_UNBOUNDTYPEPARAMS },
{ "unboundtypeparam", TK_UNBOUNDTYPEPARAM },
{ "valueformalparam", TK_VALUEFORMALPARAM },
{ "params", TK_PARAMS },
{ "param", TK_PARAM },
Expand Down
20 changes: 19 additions & 1 deletion src/libponyc/ast/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,28 @@ DEF(typearg);
RULE("type argument", type, typeargliteral, typeargconst);
DONE();

// ID [COLON type] [ASSIGN typearg]
// UNDERSCORE
DEF(underscore);
AST_NODE(TK_UNBOUNDTYPEPARAM);
TOKEN("_", TK_ID);
IF(TK_COLON, RULE("type constraint", type));
IF(TK_ASSIGN, RULE("default type argument", typearg));
DONE();

// LSQUARE UNDERSCORE {COMMA UNDERSCORE} RSQUARE
DEF(unboundtypeparams);
AST_NODE(TK_UNBOUNDTYPEPARAMS);
SKIP(NULL, TK_LSQUARE, TK_LSQUARE_NEW);
RULE("underscore", underscore);
WHILE(TK_COMMA, RULE("underscore", underscore));
TERMINATE("higher kinded type arguments", TK_RSQUARE);
DONE();

// ID [UNDERSCORE {COMMA UNDERSCORE}] [COLON type] [ASSIGN typearg]
DEF(typeparam);
AST_NODE(TK_TYPEPARAM);
TOKEN("name", TK_ID);
OPT RULE("higher kinded type parameters", unboundtypeparams);
IF(TK_COLON, RULE("type constraint", type));
IF(TK_ASSIGN, RULE("default type argument", typearg));
DONE();
Expand Down
3 changes: 3 additions & 0 deletions src/libponyc/ast/token.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ const char* token_print(token_t* token)
return token->printed;
}

case TK_UNDERSCORE:
return "_";

case TK_LEX_ERROR:
return "LEX_ERROR";

Expand Down
3 changes: 3 additions & 0 deletions src/libponyc/ast/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef enum token_id
TK_LSQUARE,
TK_RSQUARE,
TK_BACKSLASH,
TK_UNDERSCORE,

TK_COMMA,
TK_ARROW,
Expand Down Expand Up @@ -240,6 +241,8 @@ typedef enum token_id
TK_PACKAGEREF,
TK_TYPEREF,
TK_TYPEPARAMREF,
TK_UNBOUNDTYPEPARAM,
TK_UNBOUNDTYPEPARAMS,
TK_NEWREF,
TK_NEWBEREF,
TK_BEREF,
Expand Down
11 changes: 11 additions & 0 deletions src/libponyc/ast/treecheckdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,20 @@ RULE(method,

RULE(type_params, ONE_OR_MORE(type_param), TK_TYPEPARAMS);

RULE(unboundtypeparam,
CHILD(id)
CHILD(type, none) // Constraint
CHILD(type, none), // Default
TK_UNBOUNDTYPEPARAM);

RULE(unboundtypeparams,
ONE_OR_MORE(unboundtypeparam),
TK_UNBOUNDTYPEPARAMS);

RULE(type_param,
HAS_DATA // Original typeparam definition
CHILD(id)
CHILD(unboundtypeparams, none)
CHILD(type, none) // Constraint
CHILD(type, none), // Default
TK_TYPEPARAM);
Expand Down
4 changes: 2 additions & 2 deletions src/libponyc/expr/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ static void find_possible_element_types(pass_opt_t* opt, ast_t* ast,
{
ast_t* def = (ast_t*)ast_data(ast);
pony_assert(ast_id(def) == TK_TYPEPARAM);
find_possible_element_types(opt, ast_childidx(def, 1), list);
find_possible_element_types(opt, ast_childidx(def, 2), list);
return;
}

Expand Down Expand Up @@ -217,7 +217,7 @@ static void find_possible_iterator_element_types(pass_opt_t* opt, ast_t* ast,
{
ast_t* def = (ast_t*)ast_data(ast);
pony_assert(ast_id(def) == TK_TYPEPARAM);
find_possible_iterator_element_types(opt, ast_childidx(def, 1), list);
find_possible_iterator_element_types(opt, ast_childidx(def, 2), list);
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/expr/literal.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ static int uifset_formal_param(pass_opt_t* opt, ast_t* type_param_ref,
pony_assert(ast_id(type_param) == TK_TYPEPARAM);
pony_assert(chain != NULL);

ast_t* constraint = ast_childidx(type_param, 1);
ast_t* constraint = ast_childidx(type_param, 2);
pony_assert(constraint != NULL);

// If the constraint is not a subtype of (Real[A] & Number) then there are no
Expand Down
7 changes: 0 additions & 7 deletions src/libponyc/pass/names.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,6 @@ static bool names_typeparam(pass_opt_t* opt, ast_t** astp, ast_t* def)
AST_GET_CHILDREN(ast, package, id, typeargs, cap, ephemeral);
pony_assert(ast_id(package) == TK_NONE);

if(ast_id(typeargs) != TK_NONE)
{
ast_error(opt->check.errors, typeargs,
"can't qualify a type parameter with type arguments");
return false;
}

if(ast_id(ast) == TK_NOMINAL) {
ast_t* module = ast_nearest(ast, TK_MODULE);
if(module && ast_get(module, ast_name(id), 0)) {
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/pass/sugar.c
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ static ast_result_t sugar_entity(pass_opt_t* opt, ast_t* ast, bool add_create,

static ast_result_t sugar_typeparam(ast_t* ast)
{
AST_GET_CHILDREN(ast, id, constraint);
AST_GET_CHILDREN(ast, id, unbound_type_param, constraint);

if(ast_id(constraint) == TK_NONE)
{
Expand Down
2 changes: 1 addition & 1 deletion src/libponyc/type/lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static deferred_reification_t* lookup_typeparam(pass_opt_t* opt, ast_t* from,
ast_t* orig, ast_t* type, const char* name, bool errors, bool allow_private)
{
ast_t* def = (ast_t*)ast_data(type);
ast_t* constraint = ast_childidx(def, 1);
ast_t* constraint = ast_childidx(def, 2);
ast_t* constraint_def = (ast_t*)ast_data(constraint);

if(def == constraint_def)
Expand Down
4 changes: 2 additions & 2 deletions src/libponyc/type/reify.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors,

while(typeparam != NULL)
{
ast_t* defarg = ast_childidx(typeparam, 2);
ast_t* defarg = ast_childidx(typeparam, 3);

if(ast_id(defarg) == TK_NONE)
break;
Expand Down Expand Up @@ -424,7 +424,7 @@ bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs,
}

// Reify the constraint.
ast_t* constraint = ast_childidx(typeparam, 1);
ast_t* constraint = ast_childidx(typeparam, 2);
ast_t* r_constraint = reify(constraint, typeparams, typeargs, opt,
true);

Expand Down
3 changes: 2 additions & 1 deletion src/libponyc/type/sanitise.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ static void collect_type_param(ast_t* orig_param, ast_t* params, ast_t* args)
pony_assert(orig_param != NULL);

// Get original type parameter info
AST_GET_CHILDREN(orig_param, id, constraint, deflt);
AST_GET_CHILDREN(orig_param, id, unbound_type_params, constraint, deflt);
const char* name = ast_name(id);

constraint = sanitise_type(constraint);
Expand All @@ -21,6 +21,7 @@ static void collect_type_param(ast_t* orig_param, ast_t* params, ast_t* args)
BUILD(new_param, orig_param,
NODE(TK_TYPEPARAM,
ID(name)
TREE(unbound_type_params)
TREE(constraint)
NONE));

Expand Down
4 changes: 2 additions & 2 deletions src/libponyc/type/subtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ static bool is_reified_fun_sub_fun(ast_t* sub, ast_t* super,

while((sub_typeparam != NULL) && (super_typeparam != NULL))
{
ast_t* sub_constraint = ast_childidx(sub_typeparam, 1);
ast_t* super_constraint = ast_childidx(super_typeparam, 1);
ast_t* sub_constraint = ast_childidx(sub_typeparam, 2);
ast_t* super_constraint = ast_childidx(super_typeparam, 2);

if(!is_x_sub_x(super_constraint, sub_constraint, CHECK_CAP_EQ, errorf,
opt))
Expand Down
8 changes: 6 additions & 2 deletions src/libponyc/type/typeparam.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,10 @@ static token_id cap_from_constraint(ast_t* type)
case TK_TYPEPARAMREF:
return cap_from_constraint(typeparam_constraint(type));

// TODO: fix this!
case TK_UNBOUNDTYPEPARAM:
return cap_from_constraint(typeparam_constraint(type));

default: {}
}

Expand Down Expand Up @@ -503,7 +507,7 @@ ast_t* typeparam_constraint(ast_t* typeparamref)
{
pony_assert(ast_id(typeparamref) == TK_TYPEPARAMREF);
ast_t* def = (ast_t*)ast_data(typeparamref);
ast_t* constraint = ast_childidx(def, 1);
ast_t* constraint = ast_childidx(def, 2);
astlist_t* def_list = astlist_push(NULL, def);

while(ast_id(constraint) == TK_TYPEPARAMREF)
Expand All @@ -517,7 +521,7 @@ ast_t* typeparam_constraint(ast_t* typeparamref)
}

def_list = astlist_push(def_list, constraint_def);
constraint = ast_childidx(constraint_def, 1);
constraint = ast_childidx(constraint_def, 2);
}

astlist_free(def_list);
Expand Down
13 changes: 13 additions & 0 deletions test/libponyc/badpony.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ TEST_F(BadPonyTest, TypeParamMissingForTypeInProvidesList)
TEST_ERRORS_1(src, "not enough type arguments");
}

TEST_F(BadPonyTest, HKTMustBeReturnedReified)
{
const char* src =
"trait Foo[F[_]]\n"
" fun f[A](): F // F has not been exhaustively parameterized and thus cannot be reified. Should be F[A]\n"

"actor Main\n"
"new create(env: Env) => None";


TEST_ERRORS_1(src, "not enough type arguments");
}

TEST_F(BadPonyTest, TupleIndexIsZero)
{
// From issue #397
Expand Down
14 changes: 14 additions & 0 deletions test/libponyc/parse_entity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ TEST_F(ParseEntityTest, ActorMinimal)
}


TEST_F(ParseEntityTest, ActorMinimalGeneric)
{
const char* src = "actor Foo[A]";

TEST_COMPILE(src);
}

TEST_F(ParseEntityTest, ActorMinimalHKT)
{
const char* src = "actor Foo[F[_]]";

TEST_COMPILE(src);
}

TEST_F(ParseEntityTest, ActorCApi)
{
const char* src = "actor @ Foo";
Expand Down
12 changes: 12 additions & 0 deletions test/libponyc/scope.cc
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ TEST_F(ScopeTest, TypeParam)
}


TEST_F(ScopeTest, HigherKindedTypeParamMethod)
{
const char* src = "actor A fun foo[F[_]]() => None";

TEST_COMPILE(src);

ast_t* foo = lookup_member("A", "foo");
ASSERT_ID(TK_FUN, foo);
ASSERT_ID(TK_TYPEPARAM, lookup_in(foo, "F"));
ASSERT_EQ(1, ref_count(package, "F"));
}

TEST_F(ScopeTest, Local)
{
const char* src = "actor A fun foo() => var bar: U32 = 3";
Expand Down