Skip to content

Commit

Permalink
Refactor: Add the refer pass to the compiler. (#1715)
Browse files Browse the repository at this point in the history
This PR extracts a significant chunk of the work done in the expr pass (short for "expression type check pass") to a new pass called refer (short for "reference resolution pass"), which runs just before the expr pass.

The goal is to reduce the complexity of the expr pass, so that it is easier to maintain, and easier to add new features too, like the many features we'd like to add to improve type inference for lambdas, type parameters, etc.
  • Loading branch information
jemc authored Apr 21, 2017
1 parent b71af17 commit e84506d
Show file tree
Hide file tree
Showing 44 changed files with 1,999 additions and 1,460 deletions.
2 changes: 1 addition & 1 deletion src/libponyc/ast/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ enum
AST_ORPHAN = 0x10,
AST_INHERIT_FLAGS = (AST_FLAG_CAN_ERROR | AST_FLAG_CAN_SEND |
AST_FLAG_MIGHT_SEND | AST_FLAG_RECURSE_1 | AST_FLAG_RECURSE_2),
AST_ALL_FLAGS = 0x7FFFF
AST_ALL_FLAGS = 0x1FFFFF
};


Expand Down
2 changes: 2 additions & 0 deletions src/libponyc/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ enum
AST_FLAG_RECURSE_2 = 0x10000,
AST_FLAG_DONE_2 = 0x20000,
AST_FLAG_ERROR_2 = 0x40000,
AST_FLAG_JUMPS_AWAY = 0x80000, // Jumps away (control flow) without a value.
AST_FLAG_INCOMPLETE = 0x100000, // Not all fields of `this` are defined yet.
};

DECLARE_LIST(astlist, astlist_t, ast_t);
Expand Down
1 change: 1 addition & 0 deletions src/libponyc/ast/lexer.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ static const lextoken_t abstract[] =
{ "funref", TK_FUNREF },
{ "fvarref", TK_FVARREF },
{ "fletref", TK_FLETREF },
{ "tupleelemref", TK_TUPLEELEMREF },
{ "embedref", TK_EMBEDREF },
{ "varref", TK_VARREF },
{ "letref", TK_LETREF },
Expand Down
1 change: 1 addition & 0 deletions src/libponyc/ast/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ typedef enum token_id
TK_FVARREF,
TK_FLETREF,
TK_EMBEDREF,
TK_TUPLEELEMREF,
TK_VARREF,
TK_LETREF,
TK_PARAMREF,
Expand Down
15 changes: 8 additions & 7 deletions src/libponyc/ast/treecheckdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ GROUP(expr,
if_expr, ifdef, whileloop, repeat, for_loop, with, match, try_expr, lambda,
array_literal, object_literal, int_literal, float_literal, string,
bool_literal, id, rawseq, package_ref, location,
this_ref, ref, fun_ref, type_ref, flet_ref, field_ref, local_ref);
this_ref, ref, fun_ref, type_ref, field_ref, tuple_elem_ref, local_ref);

RULE(local,
HAS_TYPE(type)
Expand Down Expand Up @@ -380,21 +380,22 @@ RULE(fun_ref,

RULE(type_ref,
HAS_TYPE(type)
CHILD(expr)
OPTIONAL(id, type_args),
CHILD(package_ref, none)
CHILD(id, none)
CHILD(type_args, none),
TK_TYPEREF);

RULE(field_ref,
HAS_TYPE(type)
CHILD(expr)
CHILD(id),
TK_FVARREF, TK_EMBEDREF);
TK_FVARREF, TK_FLETREF, TK_EMBEDREF);

RULE(flet_ref,
RULE(tuple_elem_ref,
HAS_TYPE(type)
CHILD(expr)
CHILD(id, int_literal), // Int for tuple element access
TK_FLETREF);
CHILD(int_literal),
TK_TUPLEELEMREF);

RULE(local_ref,
HAS_TYPE(type)
Expand Down
24 changes: 12 additions & 12 deletions src/libponyc/codegen/gencontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ LLVMValueRef gen_if(compile_t* c, ast_t* ast)
// We will have no type if both branches have return statements.
reach_type_t* phi_type = NULL;

if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
phi_type = reach_type(c->reach, type);

LLVMValueRef c_value = gen_expr(c, cond);
Expand All @@ -68,7 +68,7 @@ LLVMValueRef gen_if(compile_t* c, ast_t* ast)
LLVMBasicBlockRef post_block = NULL;

// If both branches return, we have no post block.
if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
post_block = codegen_block(c, "if_post");

LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, "");
Expand Down Expand Up @@ -130,7 +130,7 @@ LLVMValueRef gen_if(compile_t* c, ast_t* ast)
}

// If both sides return, we return a sentinel value.
if(is_control_type(type))
if(ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
return GEN_NOVALUE;

// Continue in the post block.
Expand Down Expand Up @@ -163,7 +163,7 @@ LLVMValueRef gen_while(compile_t* c, ast_t* ast)

reach_type_t* phi_type = NULL;

if(needed && !is_control_type(type))
if(needed && !ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
phi_type = reach_type(c->reach, type);

LLVMBasicBlockRef init_block = codegen_block(c, "while_init");
Expand All @@ -175,7 +175,7 @@ LLVMValueRef gen_while(compile_t* c, ast_t* ast)
// start the post block so that a break can modify the phi node
LLVMValueRef phi = GEN_NOTNEEDED;

if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
{
// Start the post block so that a break can modify the phi node.
post_block = codegen_block(c, "while_post");
Expand Down Expand Up @@ -254,7 +254,7 @@ LLVMValueRef gen_while(compile_t* c, ast_t* ast)
LLVMBuildBr(c->builder, post_block);
}

if(is_control_type(type))
if(ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
return GEN_NOVALUE;

// post
Expand Down Expand Up @@ -285,7 +285,7 @@ LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)

reach_type_t* phi_type = NULL;

if(needed && !is_control_type(type))
if(needed && !ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
phi_type = reach_type(c->reach, type);

LLVMBasicBlockRef body_block = codegen_block(c, "repeat_body");
Expand All @@ -297,7 +297,7 @@ LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)
// start the post block so that a break can modify the phi node
LLVMValueRef phi = GEN_NOTNEEDED;

if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
{
// Start the post block so that a break can modify the phi node.
post_block = codegen_block(c, "repeat_post");
Expand Down Expand Up @@ -372,7 +372,7 @@ LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)
LLVMBuildBr(c->builder, post_block);
}

if(is_control_type(type))
if(ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
return GEN_NOVALUE;

// post
Expand Down Expand Up @@ -498,14 +498,14 @@ LLVMValueRef gen_try(compile_t* c, ast_t* ast)
reach_type_t* phi_type = NULL;

// We will have no type if both branches have return statements.
if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
phi_type = reach_type(c->reach, type);

LLVMBasicBlockRef block = LLVMGetInsertBlock(c->builder);
LLVMBasicBlockRef else_block = codegen_block(c, "try_else");
LLVMBasicBlockRef post_block = NULL;

if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
post_block = codegen_block(c, "try_post");

// Keep a reference to the else block.
Expand Down Expand Up @@ -579,7 +579,7 @@ LLVMValueRef gen_try(compile_t* c, ast_t* ast)
}

// If both sides return, we return a sentinel value.
if(is_control_type(type))
if(ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
return GEN_NOVALUE;

// Continue in the post block.
Expand Down
4 changes: 4 additions & 0 deletions src/libponyc/codegen/genexpr.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ LLVMValueRef gen_expr(compile_t* c, ast_t* ast)
ret = gen_fieldload(c, ast);
break;

case TK_TUPLEELEMREF:
ret = gen_tupleelemptr(c, ast);
break;

case TK_EMBEDREF:
ret = gen_fieldembed(c, ast);
break;
Expand Down
6 changes: 3 additions & 3 deletions src/libponyc/codegen/genmatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,10 +729,10 @@ LLVMValueRef gen_match(compile_t* c, ast_t* ast)
ast_t* type = ast_type(ast);
AST_GET_CHILDREN(ast, match_expr, cases, else_expr);

// We will have no type if all case have control types.
// We will have no type if all cases jump away.
LLVMTypeRef phi_type = NULL;

if(needed && !is_control_type(type))
if(needed && !ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
{
reach_type_t* t_phi = reach_type(c->reach, type);
phi_type = t_phi->use_type;
Expand All @@ -751,7 +751,7 @@ LLVMValueRef gen_match(compile_t* c, ast_t* ast)

LLVMValueRef phi = GEN_NOVALUE;

if(!is_control_type(type))
if(!ast_checkflag(ast, AST_FLAG_JUMPS_AWAY))
{
// Start the post block so that a case can modify the phi node.
post_block = codegen_block(c, "match_post");
Expand Down
8 changes: 8 additions & 0 deletions src/libponyc/codegen/genoperator.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,14 @@ static LLVMValueRef assign_rvalue(compile_t* c, ast_t* left, ast_t* r_type,
return assign_field(c, l_value, r_value, p_type, r_type);
}

case TK_TUPLEELEMREF:
{
// The result is the previous value of the tuple element.
LLVMValueRef l_value = gen_tupleelemptr(c, left);
ast_t* p_type = ast_type(ast_child(left));
return assign_field(c, l_value, r_value, p_type, r_type);
}

case TK_EMBEDREF:
{
// Do nothing. The embed field was already passed as the receiver.
Expand Down
81 changes: 40 additions & 41 deletions src/libponyc/codegen/genreference.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ LLVMValueRef gen_this(compile_t* c, ast_t* ast)

LLVMValueRef gen_param(compile_t* c, ast_t* ast)
{
ast_t* def = ast_get(ast, ast_name(ast_child(ast)), NULL);
ast_t* def = (ast_t*)ast_data(ast);
pony_assert(def != NULL);
int index = (int)ast_index(def);

return LLVMGetParam(codegen_fun(c), index + 1);
Expand All @@ -55,41 +56,20 @@ LLVMValueRef gen_param(compile_t* c, ast_t* ast)
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value,
ast_t* l_type, ast_t* right)
{
switch(ast_id(l_type))
{
case TK_NOMINAL:
{
pony_assert(ast_id(right) == TK_ID);

ast_t* def = (ast_t*)ast_data(l_type);
ast_t* field = ast_get(def, ast_name(right), NULL);
int index = (int)ast_index(field);
pony_assert(ast_id(l_type) == TK_NOMINAL);
pony_assert(ast_id(right) == TK_ID);

if(ast_id(def) != TK_STRUCT)
index++;
ast_t* def = (ast_t*)ast_data(l_type);
ast_t* field = ast_get(def, ast_name(right), NULL);
int index = (int)ast_index(field);

if(ast_id(def) == TK_ACTOR)
index++;

return LLVMBuildStructGEP(c->builder, l_value, index, "");
}

case TK_TUPLETYPE:
{
pony_assert(ast_id(right) == TK_INT);
int index = (int)ast_int(right)->low;

return LLVMBuildExtractValue(c->builder, l_value, index, "");
}
if(ast_id(def) != TK_STRUCT)
index++;

case TK_ARROW:
return make_fieldptr(c, l_value, ast_childidx(l_type, 1), right);
if(ast_id(def) == TK_ACTOR)
index++;

default: {}
}

pony_assert(0);
return NULL;
return LLVMBuildStructGEP(c->builder, l_value, index, "");
}

LLVMValueRef gen_fieldptr(compile_t* c, ast_t* ast)
Expand All @@ -115,20 +95,17 @@ LLVMValueRef gen_fieldload(compile_t* c, ast_t* ast)
if(field == NULL)
return NULL;

pony_assert((ast_id(l_type) == TK_NOMINAL) || (ast_id(l_type) == TK_TUPLETYPE));
pony_assert(ast_id(l_type) == TK_NOMINAL);

// Don't load if we're reading from a tuple.
if(ast_id(l_type) != TK_TUPLETYPE)
{
field = LLVMBuildLoad(c->builder, field, "");
LLVMValueRef metadata = tbaa_metadata_for_type(c, l_type);
const char id[] = "tbaa";
LLVMSetMetadata(field, LLVMGetMDKindID(id, sizeof(id) - 1), metadata);
}
field = LLVMBuildLoad(c->builder, field, "");
LLVMValueRef metadata = tbaa_metadata_for_type(c, l_type);
const char id[] = "tbaa";
LLVMSetMetadata(field, LLVMGetMDKindID(id, sizeof(id) - 1), metadata);

return field;
}


LLVMValueRef gen_fieldembed(compile_t* c, ast_t* ast)
{
LLVMValueRef field = gen_fieldptr(c, ast);
Expand All @@ -139,6 +116,28 @@ LLVMValueRef gen_fieldembed(compile_t* c, ast_t* ast)
return field;
}

static LLVMValueRef make_tupleelemptr(compile_t* c, LLVMValueRef l_value,
ast_t* l_type, ast_t* right)
{
pony_assert(ast_id(l_type) == TK_TUPLETYPE);
int index = (int)ast_int(right)->low;

return LLVMBuildExtractValue(c->builder, l_value, index, "");
}

LLVMValueRef gen_tupleelemptr(compile_t* c, ast_t* ast)
{
AST_GET_CHILDREN(ast, left, right);

LLVMValueRef l_value = gen_expr(c, left);

if(l_value == NULL)
return NULL;

ast_t* l_type = ast_type(left);
return make_tupleelemptr(c, l_value, l_type, right);
}

LLVMValueRef gen_tuple(compile_t* c, ast_t* ast)
{
ast_t* child = ast_child(ast);
Expand Down
2 changes: 2 additions & 0 deletions src/libponyc/codegen/genreference.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ LLVMValueRef gen_fieldload(compile_t* c, ast_t* ast);

LLVMValueRef gen_fieldembed(compile_t* c, ast_t* ast);

LLVMValueRef gen_tupleelemptr(compile_t* c, ast_t* ast);

LLVMValueRef gen_tuple(compile_t* c, ast_t* ast);

LLVMValueRef gen_localdecl(compile_t* c, ast_t* ast);
Expand Down
13 changes: 7 additions & 6 deletions src/libponyc/expr/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../pkg/package.h"
#include "../pass/names.h"
#include "../pass/expr.h"
#include "../pass/refer.h"
#include "../type/alias.h"
#include "../type/assemble.h"
#include "../type/subtype.h"
Expand All @@ -28,16 +29,15 @@ bool expr_array(pass_opt_t* opt, ast_t** astp)

for(ast_t* ele = ast_child(elements); ele != NULL; ele = ast_sibling(ele))
{
ast_t* c_type = ast_type(ele);

if(is_control_type(c_type))
if(ast_checkflag(ele, AST_FLAG_JUMPS_AWAY))
{
ast_error(opt->check.errors, ele,
"can't use an expression without a value in an array constructor");
"an array can't contain an expression that jumps away with no value");
ast_free_unattached(type);
return false;
}

ast_t* c_type = ast_type(ele);
if(is_typecheck_error(c_type))
return false;

Expand Down Expand Up @@ -102,8 +102,9 @@ bool expr_array(pass_opt_t* opt, ast_t** astp)
NONE
TREE(dot)));

if(!expr_reference(opt, &ref) ||
!expr_qualify(opt, &qualify) ||
if(!refer_reference(opt, &ref) ||
!refer_qualify(opt, qualify) ||
!expr_typeref(opt, &qualify) ||
!expr_dot(opt, &dot) ||
!expr_call(opt, &call)
)
Expand Down
Loading

0 comments on commit e84506d

Please sign in to comment.