authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-06 23:21:31-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-08 15:57:24-05:00
log2a6fbbd8fba30b8d24aa966606372f595c102d55
tree1cdb0d029de60a63d3bba24520aa8665536ba65c
parent6d28b28ccc689e6bf8849b1d39e969e8da760999
signaturelock-open Commit is signed but in an unrecognized format.

introduce `@as` builtin for type coercion

This commit also hooks up type coercion (previously called implicit casting) into the result location mechanism, and additionally hooks up variable declarations, maintaining the property that: var a: T = b; is semantically equivalent to: var a = @as(T, b); See #1757

4 files changed, 175 insertions(+), 64 deletions(-)

src/all_types.hpp+17-8
......@@ -48,6 +48,7 @@ struct ResultLoc;
4848struct ResultLocPeer;
4949struct ResultLocPeerParent;
5050struct ResultLocBitCast;
51struct ResultLocCast;
5152struct ResultLocReturn;
5253
5354enum PtrLen {
......@@ -1691,6 +1692,7 @@ enum BuiltinFnId {
16911692 BuiltinFnIdFrameType,
16921693 BuiltinFnIdFrameHandle,
16931694 BuiltinFnIdFrameSize,
1695 BuiltinFnIdAs,
16941696};
16951697
16961698struct BuiltinFnEntry {
......@@ -3458,6 +3460,13 @@ struct IrInstructionPtrCastGen {
34583460 bool safety_check_on;
34593461};
34603462
3463struct IrInstructionImplicitCast {
3464 IrInstruction base;
3465
3466 IrInstruction *operand;
3467 ResultLocCast *result_loc_cast;
3468};
3469
34613470struct IrInstructionBitCastSrc {
34623471 IrInstruction base;
34633472
......@@ -3823,14 +3832,6 @@ struct IrInstructionEndExpr {
38233832 ResultLoc *result_loc;
38243833};
38253834
3826struct IrInstructionImplicitCast {
3827 IrInstruction base;
3828
3829 IrInstruction *dest_type;
3830 IrInstruction *target;
3831 ResultLoc *result_loc;
3832};
3833
38343835// This one is for writing through the result pointer.
38353836struct IrInstructionResolveResult {
38363837 IrInstruction base;
......@@ -3928,6 +3929,7 @@ enum ResultLocId {
39283929 ResultLocIdPeerParent,
39293930 ResultLocIdInstruction,
39303931 ResultLocIdBitCast,
3932 ResultLocIdCast,
39313933};
39323934
39333935// Additions to this struct may need to be handled in
......@@ -3995,6 +3997,13 @@ struct ResultLocBitCast {
39953997 ResultLoc *parent;
39963998};
39973999
4000// The source_instruction is the destination type
4001struct ResultLocCast {
4002 ResultLoc base;
4003
4004 ResultLoc *parent;
4005};
4006
39984007static const size_t slice_ptr_index = 0;
39994008static const size_t slice_len_index = 1;
40004009
src/codegen.cpp+1
......@@ -8070,6 +8070,7 @@ static void define_builtin_fns(CodeGen *g) {
80708070 create_builtin_fn(g, BuiltinFnIdFrameType, "Frame", 1);
80718071 create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
80728072 create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
8073 create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
80738074}
80748075
80758076static const char *bool_to_str(bool b) {
src/ir.cpp+142-48
......@@ -200,6 +200,8 @@ static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNo
200200static void ir_reset_result(ResultLoc *result_loc);
201201static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name,
202202 Scope *scope, AstNode *source_node, Buf *out_bare_name);
203static ResultLocCast *ir_build_cast_result_loc(IrBuilder *irb, IrInstruction *dest_type,
204 ResultLoc *parent_result_loc);
203205
204206static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
205207 assert(get_src_ptr_type(const_val->type) != nullptr);
......@@ -2766,6 +2768,18 @@ static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *sourc
27662768 return &instruction->base;
27672769}
27682770
2771static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
2772 IrInstruction *operand, ResultLocCast *result_loc_cast)
2773{
2774 IrInstructionImplicitCast *instruction = ir_build_instruction<IrInstructionImplicitCast>(irb, scope, source_node);
2775 instruction->operand = operand;
2776 instruction->result_loc_cast = result_loc_cast;
2777
2778 ir_ref_instruction(operand, irb->current_basic_block);
2779
2780 return &instruction->base;
2781}
2782
27692783static IrInstruction *ir_build_bit_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
27702784 IrInstruction *operand, ResultLocBitCast *result_loc_bit_cast)
27712785{
......@@ -3063,20 +3077,6 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode
30633077 return &instruction->base;
30643078}
30653079
3066static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
3067 IrInstruction *dest_type, IrInstruction *target, ResultLoc *result_loc)
3068{
3069 IrInstructionImplicitCast *instruction = ir_build_instruction<IrInstructionImplicitCast>(irb, scope, source_node);
3070 instruction->dest_type = dest_type;
3071 instruction->target = target;
3072 instruction->result_loc = result_loc;
3073
3074 ir_ref_instruction(dest_type, irb->current_basic_block);
3075 ir_ref_instruction(target, irb->current_basic_block);
3076
3077 return &instruction->base;
3078}
3079
30803080static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstNode *source_node,
30813081 ResultLoc *result_loc, IrInstruction *ty)
30823082{
......@@ -5374,6 +5374,24 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
53745374 IrInstruction *bitcast = ir_build_bit_cast_src(irb, scope, arg1_node, arg1_value, result_loc_bit_cast);
53755375 return ir_lval_wrap(irb, scope, bitcast, lval, result_loc);
53765376 }
5377 case BuiltinFnIdAs:
5378 {
5379 AstNode *dest_type_node = node->data.fn_call_expr.params.at(0);
5380 IrInstruction *dest_type = ir_gen_node(irb, dest_type_node, scope);
5381 if (dest_type == irb->codegen->invalid_instruction)
5382 return dest_type;
5383
5384 ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, dest_type, result_loc);
5385
5386 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
5387 IrInstruction *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone,
5388 &result_loc_cast->base);
5389 if (arg1_value == irb->codegen->invalid_instruction)
5390 return arg1_value;
5391
5392 IrInstruction *result = ir_build_implicit_cast(irb, scope, node, arg1_value, result_loc_cast);
5393 return ir_lval_wrap(irb, scope, result, lval, result_loc);
5394 }
53775395 case BuiltinFnIdIntToPtr:
53785396 {
53795397 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -6214,6 +6232,20 @@ static ResultLocVar *ir_build_var_result_loc(IrBuilder *irb, IrInstruction *allo
62146232 return result_loc_var;
62156233}
62166234
6235static ResultLocCast *ir_build_cast_result_loc(IrBuilder *irb, IrInstruction *dest_type,
6236 ResultLoc *parent_result_loc)
6237{
6238 ResultLocCast *result_loc_cast = allocate<ResultLocCast>(1);
6239 result_loc_cast->base.id = ResultLocIdCast;
6240 result_loc_cast->base.source_instruction = dest_type;
6241 ir_ref_instruction(dest_type, irb->current_basic_block);
6242 result_loc_cast->parent = parent_result_loc;
6243
6244 ir_build_reset_result(irb, dest_type->scope, dest_type->source_node, &result_loc_cast->base);
6245
6246 return result_loc_cast;
6247}
6248
62176249static void build_decl_var_and_init(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var,
62186250 IrInstruction *init, const char *name_hint, IrInstruction *is_comptime)
62196251{
......@@ -6282,7 +6314,15 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
62826314
62836315 // Create a result location for the initialization expression.
62846316 ResultLocVar *result_loc_var = ir_build_var_result_loc(irb, alloca, var);
6285 ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr;
6317 ResultLoc *init_result_loc;
6318 ResultLocCast *result_loc_cast;
6319 if (type_instruction != nullptr) {
6320 result_loc_cast = ir_build_cast_result_loc(irb, type_instruction, &result_loc_var->base);
6321 init_result_loc = &result_loc_cast->base;
6322 } else {
6323 result_loc_cast = nullptr;
6324 init_result_loc = &result_loc_var->base;
6325 }
62866326
62876327 Scope *init_scope = is_comptime_scalar ?
62886328 create_comptime_scope(irb->codegen, variable_declaration->expr, scope) : scope;
......@@ -6298,9 +6338,8 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
62986338 if (init_value == irb->codegen->invalid_instruction)
62996339 return irb->codegen->invalid_instruction;
63006340
6301 if (type_instruction != nullptr) {
6302 IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value,
6303 &result_loc_var->base);
6341 if (result_loc_cast != nullptr) {
6342 IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, init_value, result_loc_cast);
63046343 ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base);
63056344 }
63066345
......@@ -15435,6 +15474,7 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe
1543515474 case ResultLocIdNone:
1543615475 case ResultLocIdVar:
1543715476 case ResultLocIdBitCast:
15477 case ResultLocIdCast:
1543815478 return nullptr;
1543915479 case ResultLocIdInstruction:
1544015480 return result_loc->source_instruction->child->value.type;
......@@ -15489,6 +15529,7 @@ static bool ir_result_has_type(ResultLoc *result_loc) {
1548915529 case ResultLocIdReturn:
1549015530 case ResultLocIdInstruction:
1549115531 case ResultLocIdBitCast:
15532 case ResultLocIdCast:
1549215533 return true;
1549315534 case ResultLocIdVar:
1549415535 return reinterpret_cast<ResultLocVar *>(result_loc)->var->decl_node->data.variable_declaration.type != nullptr;
......@@ -15668,6 +15709,61 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe
1566815709 result_loc->resolved_loc = parent_result_loc;
1566915710 return result_loc->resolved_loc;
1567015711 }
15712 case ResultLocIdCast: {
15713 ResultLocCast *result_cast = reinterpret_cast<ResultLocCast *>(result_loc);
15714 ZigType *dest_type = ir_resolve_type(ira, result_cast->base.source_instruction->child);
15715 if (type_is_invalid(dest_type))
15716 return ira->codegen->invalid_instruction;
15717
15718 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, dest_type, value_type,
15719 result_cast->base.source_instruction->source_node, false);
15720 if (const_cast_result.id == ConstCastResultIdInvalid)
15721 return ira->codegen->invalid_instruction;
15722 if (const_cast_result.id != ConstCastResultIdOk) {
15723 // We will not be able to provide a result location for this value. Allow the
15724 // code to create a new result location and then type coerce to the old one.
15725 return nullptr;
15726 }
15727
15728 // In this case we can pointer cast the result location.
15729 IrInstruction *casted_value;
15730 if (value != nullptr) {
15731 casted_value = ir_implicit_cast(ira, value, dest_type);
15732 } else {
15733 casted_value = nullptr;
15734 }
15735
15736 if (casted_value == nullptr || type_is_invalid(casted_value->value.type)) {
15737 return casted_value;
15738 }
15739
15740 IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_cast->parent,
15741 dest_type, casted_value, force_runtime, non_null_comptime, true);
15742 if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) ||
15743 parent_result_loc->value.type->id == ZigTypeIdUnreachable)
15744 {
15745 return parent_result_loc;
15746 }
15747 ZigType *parent_ptr_type = parent_result_loc->value.type;
15748 assert(parent_ptr_type->id == ZigTypeIdPointer);
15749 if ((err = type_resolve(ira->codegen, parent_ptr_type->data.pointer.child_type,
15750 ResolveStatusAlignmentKnown)))
15751 {
15752 return ira->codegen->invalid_instruction;
15753 }
15754 uint64_t parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type);
15755 if ((err = type_resolve(ira->codegen, value_type, ResolveStatusAlignmentKnown))) {
15756 return ira->codegen->invalid_instruction;
15757 }
15758 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value_type,
15759 parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle,
15760 parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero);
15761
15762 result_loc->written = true;
15763 result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc,
15764 ptr_type, result_cast->base.source_instruction, false);
15765 return result_loc->resolved_loc;
15766 }
1567115767 case ResultLocIdBitCast: {
1567215768 ResultLocBitCast *result_bit_cast = reinterpret_cast<ResultLocBitCast *>(result_loc);
1567315769 ZigType *dest_type = ir_resolve_type(ira, result_bit_cast->base.source_instruction->child);
......@@ -15790,18 +15886,6 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s
1579015886 return result_loc;
1579115887}
1579215888
15793static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrInstructionImplicitCast *instruction) {
15794 ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
15795 if (type_is_invalid(dest_type))
15796 return ira->codegen->invalid_instruction;
15797
15798 IrInstruction *target = instruction->target->child;
15799 if (type_is_invalid(target->value.type))
15800 return ira->codegen->invalid_instruction;
15801
15802 return ir_implicit_cast_with_result(ira, target, dest_type, instruction->result_loc);
15803}
15804
1580515889static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) {
1580615890 ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child);
1580715891 if (type_is_invalid(implicit_elem_type))
......@@ -15864,6 +15948,7 @@ static void ir_reset_result(ResultLoc *result_loc) {
1586415948 case ResultLocIdNone:
1586515949 case ResultLocIdInstruction:
1586615950 case ResultLocIdBitCast:
15951 case ResultLocIdCast:
1586715952 break;
1586815953 }
1586915954}
......@@ -16903,25 +16988,14 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
1690316988
1690416989 if (is_comptime || instr_is_comptime(fn_ref)) {
1690516990 if (fn_ref->value.type->id == ZigTypeIdMetaType) {
16906 ZigType *dest_type = ir_resolve_type(ira, fn_ref);
16907 if (type_is_invalid(dest_type))
16991 ZigType *ty = ir_resolve_type(ira, fn_ref);
16992 if (ty == nullptr)
1690816993 return ira->codegen->invalid_instruction;
16909
16910 size_t actual_param_count = call_instruction->arg_count;
16911
16912 if (actual_param_count != 1) {
16913 ir_add_error_node(ira, call_instruction->base.source_node,
16914 buf_sprintf("cast expression expects exactly one parameter"));
16915 return ira->codegen->invalid_instruction;
16916 }
16917
16918 IrInstruction *arg = call_instruction->args[0]->child;
16919
16920 IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg,
16921 call_instruction->result_loc);
16922 if (type_is_invalid(cast_instruction->value.type))
16923 return ira->codegen->invalid_instruction;
16924 return ir_finish_anal(ira, cast_instruction);
16994 ErrorMsg *msg = ir_add_error_node(ira, fn_ref->source_node,
16995 buf_sprintf("type '%s' not a function", buf_ptr(&ty->name)));
16996 add_error_note(ira->codegen, msg, call_instruction->base.source_node,
16997 buf_sprintf("use @as builtin for type coercion"));
16998 return ira->codegen->invalid_instruction;
1692516999 } else if (fn_ref->value.type->id == ZigTypeIdFn) {
1692617000 ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref);
1692717001 ZigType *fn_type = fn_table_entry ? fn_table_entry->type_entry : fn_ref->value.type;
......@@ -25958,6 +26032,26 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct
2595826032 return ir_const_void(ira, &instruction->base);
2595926033}
2596026034
26035static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrInstructionImplicitCast *instruction) {
26036 IrInstruction *operand = instruction->operand->child;
26037 if (type_is_invalid(operand->value.type))
26038 return operand;
26039
26040 IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base,
26041 &instruction->result_loc_cast->base, operand->value.type, operand, false, false, true);
26042 if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)))
26043 return result_loc;
26044
26045 if (instruction->result_loc_cast->parent->gen_instruction != nullptr) {
26046 return instruction->result_loc_cast->parent->gen_instruction;
26047 }
26048
26049 ZigType *dest_type = ir_resolve_type(ira, instruction->result_loc_cast->base.source_instruction->child);
26050 if (type_is_invalid(dest_type))
26051 return ira->codegen->invalid_instruction;
26052 return ir_implicit_cast(ira, operand, dest_type);
26053}
26054
2596126055static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInstructionBitCastSrc *instruction) {
2596226056 IrInstruction *operand = instruction->operand->child;
2596326057 if (type_is_invalid(operand->value.type))
src/ir_print.cpp+15-8
......@@ -601,6 +601,12 @@ static void ir_print_result_loc_bit_cast(IrPrint *irp, ResultLocBitCast *result_
601601 fprintf(irp->f, ")");
602602}
603603
604static void ir_print_result_loc_cast(IrPrint *irp, ResultLocCast *result_loc_cast) {
605 fprintf(irp->f, "cast(ty=");
606 ir_print_other_instruction(irp, result_loc_cast->base.source_instruction);
607 fprintf(irp->f, ")");
608}
609
604610static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
605611 switch (result_loc->id) {
606612 case ResultLocIdInvalid:
......@@ -619,6 +625,8 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
619625 return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc);
620626 case ResultLocIdBitCast:
621627 return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc);
628 case ResultLocIdCast:
629 return ir_print_result_loc_cast(irp, (ResultLocCast *)result_loc);
622630 case ResultLocIdPeerParent:
623631 fprintf(irp->f, "peer_parent");
624632 return;
......@@ -1484,6 +1492,13 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
14841492 fprintf(irp->f, ")");
14851493}
14861494
1495static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *instruction) {
1496 fprintf(irp->f, "@implicitCast(");
1497 ir_print_other_instruction(irp, instruction->operand);
1498 fprintf(irp->f, ")result=");
1499 ir_print_result_loc(irp, &instruction->result_loc_cast->base);
1500}
1501
14871502static void ir_print_bit_cast_src(IrPrint *irp, IrInstructionBitCastSrc *instruction) {
14881503 fprintf(irp->f, "@bitCast(");
14891504 ir_print_other_instruction(irp, instruction->operand);
......@@ -1739,14 +1754,6 @@ static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instructio
17391754 fprintf(irp->f, ")");
17401755}
17411756
1742static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *instruction) {
1743 fprintf(irp->f, "@implicitCast(");
1744 ir_print_other_instruction(irp, instruction->dest_type);
1745 fprintf(irp->f, ",");
1746 ir_print_other_instruction(irp, instruction->target);
1747 fprintf(irp->f, ")");
1748}
1749
17501757static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *instruction) {
17511758 fprintf(irp->f, "ResolveResult(");
17521759 ir_print_result_loc(irp, instruction->result_loc);