Skip to content

Commit 1001b4c

Browse files
Benoit VeySeanTAllen
Benoit Vey
authored andcommitted
Change semantics of break with no value
break statements without a value will now generate their value from the else branch of the loop instead of being implict break None. The for loop has been changed. It will now break out of the loop instead of continuing with the following iterations if Iterator.next errors. This is for performance reasons with range check elimination. Closes ponylang#1156.
1 parent 34e6a99 commit 1001b4c

File tree

7 files changed

+58
-39
lines changed

7 files changed

+58
-39
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ All notable changes to the Pony compiler and standard library will be documented
1414

1515
### Changed
1616

17+
- `break` without a value now generates its value from the `else` branch of a loop instead of being an implicit `break None`.
18+
- The `for` loop will now break out of the loop instead of continuing with the following iterations if `Iterator.next` errors.
19+
1720
## [0.6.0] - 2016-10-20
1821

1922
### Fixed

src/libponyc/codegen/codegen.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,7 @@ void codegen_pushscope(compile_t* c, ast_t* ast)
970970

971971
frame->fun = frame->prev->fun;
972972
frame->break_target = frame->prev->break_target;
973+
frame->break_novalue_target = frame->prev->break_novalue_target;
973974
frame->continue_target = frame->prev->continue_target;
974975
frame->invoke_target = frame->prev->invoke_target;
975976
frame->di_file = frame->prev->di_file;
@@ -1065,12 +1066,13 @@ LLVMMetadataRef codegen_discope(compile_t* c)
10651066
}
10661067

10671068
void codegen_pushloop(compile_t* c, LLVMBasicBlockRef continue_target,
1068-
LLVMBasicBlockRef break_target)
1069+
LLVMBasicBlockRef break_target, LLVMBasicBlockRef break_novalue_target)
10691070
{
10701071
compile_frame_t* frame = push_frame(c);
10711072

10721073
frame->fun = frame->prev->fun;
10731074
frame->break_target = break_target;
1075+
frame->break_novalue_target = break_novalue_target;
10741076
frame->continue_target = continue_target;
10751077
frame->invoke_target = frame->prev->invoke_target;
10761078
frame->di_file = frame->prev->di_file;
@@ -1088,6 +1090,7 @@ void codegen_pushtry(compile_t* c, LLVMBasicBlockRef invoke_target)
10881090

10891091
frame->fun = frame->prev->fun;
10901092
frame->break_target = frame->prev->break_target;
1093+
frame->break_novalue_target = frame->prev->break_novalue_target;
10911094
frame->continue_target = frame->prev->continue_target;
10921095
frame->invoke_target = invoke_target;
10931096
frame->di_file = frame->prev->di_file;

src/libponyc/codegen/codegen.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ typedef struct compile_frame_t
6969
LLVMValueRef ctx;
7070

7171
LLVMBasicBlockRef break_target;
72+
LLVMBasicBlockRef break_novalue_target;
7273
LLVMBasicBlockRef continue_target;
7374
LLVMBasicBlockRef invoke_target;
7475

@@ -218,7 +219,7 @@ LLVMMetadataRef codegen_difile(compile_t* c);
218219
LLVMMetadataRef codegen_discope(compile_t* c);
219220

220221
void codegen_pushloop(compile_t* c, LLVMBasicBlockRef continue_target,
221-
LLVMBasicBlockRef break_target);
222+
LLVMBasicBlockRef break_target, LLVMBasicBlockRef break_novalue_target);
222223

223224
void codegen_poploop(compile_t* c);
224225

src/libponyc/codegen/gencontrol.c

+31-23
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ LLVMValueRef gen_while(compile_t* c, ast_t* ast)
182182
}
183183

184184
// Push the loop status.
185-
codegen_pushloop(c, init_block, post_block);
185+
codegen_pushloop(c, init_block, post_block, else_block);
186186

187187
// init
188188
// This jumps either to the body or the else clause. This is not evaluated
@@ -300,7 +300,7 @@ LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)
300300
}
301301

302302
// Push the loop status.
303-
codegen_pushloop(c, cond_block, post_block);
303+
codegen_pushloop(c, cond_block, post_block, else_block);
304304

305305
// Body.
306306
LLVMPositionBuilderAtEnd(c->builder, body_block);
@@ -383,33 +383,41 @@ LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)
383383
LLVMValueRef gen_break(compile_t* c, ast_t* ast)
384384
{
385385
ast_t* body = ast_child(ast);
386-
ast_t* body_type = ast_type(body);
387386

388-
// Get the break target.
389-
LLVMBasicBlockRef target = c->frame->break_target;
387+
LLVMBasicBlockRef target;
390388

391-
// Get the phi node.
392-
LLVMValueRef post_phi = LLVMGetFirstInstruction(target);
393-
bool needed = (post_phi != NULL) && LLVMIsAPHINode(post_phi);
389+
if(ast_id(body) == TK_NONE)
390+
{
391+
target = c->frame->break_novalue_target;
392+
} else {
393+
ast_t* body_type = ast_type(body);
394394

395-
// Build the break expression.
396-
LLVMValueRef value = gen_expr(c, body);
395+
// Get the break target.
396+
target = c->frame->break_target;
397397

398-
if(needed)
399-
{
400-
// Cast it to the phi type if we need to.
401-
LLVMTypeRef phi_type = LLVMTypeOf(post_phi);
402-
value = gen_assign_cast(c, phi_type, value, body_type);
403-
}
398+
// Get the phi node.
399+
LLVMValueRef post_phi = LLVMGetFirstInstruction(target);
400+
bool needed = (post_phi != NULL) && LLVMIsAPHINode(post_phi);
404401

405-
if(value == NULL)
406-
return NULL;
402+
// Build the break expression.
403+
LLVMValueRef value = gen_expr(c, body);
407404

408-
// Add break value to the post block phi node.
409-
if(needed)
410-
{
411-
LLVMBasicBlockRef insert_block = LLVMGetInsertBlock(c->builder);
412-
LLVMAddIncoming(post_phi, &value, &insert_block, 1);
405+
if(needed)
406+
{
407+
// Cast it to the phi type if we need to.
408+
LLVMTypeRef phi_type = LLVMTypeOf(post_phi);
409+
value = gen_assign_cast(c, phi_type, value, body_type);
410+
}
411+
412+
if(value == NULL)
413+
return NULL;
414+
415+
// Add break value to the post block phi node.
416+
if(needed)
417+
{
418+
LLVMBasicBlockRef insert_block = LLVMGetInsertBlock(c->builder);
419+
LLVMAddIncoming(post_phi, &value, &insert_block, 1);
420+
}
413421
}
414422

415423
// Jump to the break target.

src/libponyc/expr/control.c

+13-8
Original file line numberDiff line numberDiff line change
@@ -393,17 +393,22 @@ bool expr_break(pass_opt_t* opt, ast_t* ast)
393393
// Add type to loop.
394394
ast_t* body = ast_child(ast);
395395

396-
if(is_control_type(ast_type(body)))
396+
if(ast_id(body) != TK_NONE)
397397
{
398-
ast_error(opt->check.errors, body,
399-
"break value cannot be a control statement");
400-
return false;
401-
}
398+
if(is_control_type(ast_type(body)))
399+
{
400+
ast_error(opt->check.errors, body,
401+
"break value cannot be a control statement");
402+
return false;
403+
}
402404

403-
ast_t* loop_type = ast_type(t->frame->loop);
405+
ast_t* loop_type = ast_type(t->frame->loop);
404406

405-
loop_type = control_type_add_branch(opt, loop_type, body);
406-
ast_settype(t->frame->loop, loop_type);
407+
// If there is no body the break will jump to the else branch, whose type
408+
// has already been added to the loop type.
409+
loop_type = control_type_add_branch(opt, loop_type, body);
410+
ast_settype(t->frame->loop, loop_type);
411+
}
407412

408413
return true;
409414
}

src/libponyc/pass/sugar.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ static ast_result_t sugar_for(pass_opt_t* opt, ast_t** astp)
496496
NONE
497497
NODE(TK_DOT, NODE(TK_REFERENCE, ID(iter_name)) ID("next"))))
498498
NODE(TK_SEQ, AST_SCOPE
499-
NODE(TK_CONTINUE, NONE))
499+
NODE(TK_BREAK, NONE))
500500
NONE));
501501

502502
sugar_try(try_next);
@@ -1413,8 +1413,7 @@ ast_result_t pass_sugar(ast_t** astp, pass_opt_t* options)
14131413
case TK_NEW: return sugar_new(options, ast);
14141414
case TK_BE: return sugar_be(options, ast);
14151415
case TK_FUN: return sugar_fun(options, ast);
1416-
case TK_RETURN:
1417-
case TK_BREAK: return sugar_return(options, ast);
1416+
case TK_RETURN: return sugar_return(options, ast);
14181417
case TK_IF:
14191418
case TK_MATCH:
14201419
case TK_WHILE:

test/libponyc/sugar.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ TEST_F(SugarTest, ForWithoutElse)
602602
" let i = $try_no_check\n"
603603
" $1.next()\n"
604604
" else\n"
605-
" continue\n"
605+
" break\n"
606606
" then\n"
607607
" None\n"
608608
" end\n"
@@ -633,7 +633,7 @@ TEST_F(SugarTest, ForWithElse)
633633
" let i = $try_no_check\n"
634634
" $1.next()\n"
635635
" else\n"
636-
" continue\n"
636+
" break\n"
637637
" then\n"
638638
" None\n"
639639
" end\n"
@@ -664,7 +664,7 @@ TEST_F(SugarTest, MultiIteratorFor)
664664
" (let i, let j) = $try_no_check\n"
665665
" $1.next()\n"
666666
" else\n"
667-
" continue\n"
667+
" break\n"
668668
" then\n"
669669
" None\n"
670670
" end\n"

0 commit comments

Comments
 (0)