authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-03 13:55:50-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-03 13:55:50-04:00
loga1359ac3abbb83f30719f596180f1e923da3a8f2
tree194da04d4f7cf3be9795e8d2edab96ac1c1a31af
parent9daf0140e5a78802fd294bce8a9019f59bd89b61
parent4bae87764fc455f4df8b9d96be856921b0dd97db
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'rbscott-comptime-union-init'


6 files changed, 208 insertions(+), 28 deletions(-)

doc/langref.html.in+17
......@@ -5065,6 +5065,12 @@ test "@intToPtr for pointer to zero bit type" {
50655065 {#header_close#}
50665066 {#header_close#}
50675067
5068 {#header_open|Result Location Semantics#}
5069 <p>
5070 <a href="https://github.com/ziglang/zig/issues/2809">TODO add documentation for this</a>
5071 </p>
5072 {#header_close#}
5073
50685074 {#header_open|comptime#}
50695075 <p>
50705076 Zig places importance on the concept of whether an expression is known at compile-time.
......@@ -7809,6 +7815,17 @@ pub const TypeInfo = union(TypeId) {
78097815
78107816 {#header_close#}
78117817
7818 {#header_open|@unionInit#}
7819 <pre>{#syntax#}@unionInit(comptime Union: type, comptime active_field_name: []const u8, init_expr) Union{#endsyntax#}</pre>
7820 <p>
7821 This is the same thing as {#link|union#} initialization syntax, except that the field name is a
7822 {#link|comptime#}-known value rather than an identifier token.
7823 </p>
7824 <p>
7825 {#syntax#}@unionInit{#endsyntax#} forwards its {#link|result location|Result Location Semantics#} to {#syntax#}init_expr{#endsyntax#}.
7826 </p>
7827 {#header_close#}
7828
78127829 {#header_open|@Vector#}
78137830 <pre>{#syntax#}@Vector(comptime len: u32, comptime ElemType: type) type{#endsyntax#}</pre>
78147831 <p>
src/all_types.hpp+11
......@@ -1509,6 +1509,7 @@ enum BuiltinFnId {
15091509 BuiltinFnIdAtomicRmw,
15101510 BuiltinFnIdAtomicLoad,
15111511 BuiltinFnIdHasDecl,
1512 BuiltinFnIdUnionInit,
15121513};
15131514
15141515struct BuiltinFnEntry {
......@@ -2359,6 +2360,7 @@ enum IrInstructionId {
23592360 IrInstructionIdAllocaGen,
23602361 IrInstructionIdEndExpr,
23612362 IrInstructionIdPtrOfArrayToSlice,
2363 IrInstructionIdUnionInitNamedField,
23622364};
23632365
23642366struct IrInstruction {
......@@ -3603,6 +3605,15 @@ struct IrInstructionAssertNonNull {
36033605 IrInstruction *target;
36043606};
36053607
3608struct IrInstructionUnionInitNamedField {
3609 IrInstruction base;
3610
3611 IrInstruction *union_type;
3612 IrInstruction *field_name;
3613 IrInstruction *field_result_loc;
3614 IrInstruction *result_loc;
3615};
3616
36063617struct IrInstructionHasDecl {
36073618 IrInstruction base;
36083619
src/codegen.cpp+2
......@@ -5635,6 +5635,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
56355635 case IrInstructionIdRef:
56365636 case IrInstructionIdBitCastSrc:
56375637 case IrInstructionIdTestErrSrc:
5638 case IrInstructionIdUnionInitNamedField:
56385639 zig_unreachable();
56395640
56405641 case IrInstructionIdDeclVarGen:
......@@ -7419,6 +7420,7 @@ static void define_builtin_fns(CodeGen *g) {
74197420 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
74207421 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
74217422 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
7423 create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);
74227424}
74237425
74247426static const char *bool_to_str(bool b) {
src/ir.cpp+127-27
......@@ -198,6 +198,9 @@ static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *
198198 IrInstruction *base_ptr, bool initializing);
199199static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
200200 IrInstruction *ptr, IrInstruction *uncasted_value);
201static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
202 IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
203 LVal lval, ResultLoc *parent_result_loc);
201204
202205static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
203206 assert(get_src_ptr_type(const_val->type) != nullptr);
......@@ -1089,6 +1092,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEndExpr *) {
10891092 return IrInstructionIdEndExpr;
10901093}
10911094
1095static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedField *) {
1096 return IrInstructionIdUnionInitNamedField;
1097}
1098
10921099template<typename T>
10931100static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
10941101 T *special_instruction = allocate<T>(1);
......@@ -1352,12 +1359,13 @@ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *s
13521359}
13531360
13541361static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node,
1355 IrInstruction *container_ptr, IrInstruction *field_name_expr)
1362 IrInstruction *container_ptr, IrInstruction *field_name_expr, bool initializing)
13561363{
13571364 IrInstructionFieldPtr *instruction = ir_build_instruction<IrInstructionFieldPtr>(irb, scope, source_node);
13581365 instruction->container_ptr = container_ptr;
13591366 instruction->field_name_buffer = nullptr;
13601367 instruction->field_name_expr = field_name_expr;
1368 instruction->initializing = initializing;
13611369
13621370 ir_ref_instruction(container_ptr, irb->current_basic_block);
13631371 ir_ref_instruction(field_name_expr, irb->current_basic_block);
......@@ -3324,6 +3332,24 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
33243332 return &instruction->base;
33253333}
33263334
3335static IrInstruction *ir_build_union_init_named_field(IrBuilder *irb, Scope *scope, AstNode *source_node,
3336 IrInstruction *union_type, IrInstruction *field_name, IrInstruction *field_result_loc, IrInstruction *result_loc)
3337{
3338 IrInstructionUnionInitNamedField *instruction = ir_build_instruction<IrInstructionUnionInitNamedField>(irb, scope, source_node);
3339 instruction->union_type = union_type;
3340 instruction->field_name = field_name;
3341 instruction->field_result_loc = field_result_loc;
3342 instruction->result_loc = result_loc;
3343
3344 ir_ref_instruction(union_type, irb->current_basic_block);
3345 ir_ref_instruction(field_name, irb->current_basic_block);
3346 ir_ref_instruction(field_result_loc, irb->current_basic_block);
3347 if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
3348
3349 return &instruction->base;
3350}
3351
3352
33273353static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction,
33283354 ZigType *result_type, IrInstruction *vector, IrInstruction *result_loc)
33293355{
......@@ -5110,7 +5136,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
51105136 if (arg1_value == irb->codegen->invalid_instruction)
51115137 return arg1_value;
51125138
5113 IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, arg0_value, arg1_value);
5139 IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node,
5140 arg0_value, arg1_value, false);
51145141
51155142 if (lval == LValPtr)
51165143 return ptr_instruction;
......@@ -5651,6 +5678,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
56515678 IrInstruction *has_decl = ir_build_has_decl(irb, scope, node, arg0_value, arg1_value);
56525679 return ir_lval_wrap(irb, scope, has_decl, lval, result_loc);
56535680 }
5681 case BuiltinFnIdUnionInit:
5682 {
5683 AstNode *union_type_node = node->data.fn_call_expr.params.at(0);
5684 IrInstruction *union_type_inst = ir_gen_node(irb, union_type_node, scope);
5685 if (union_type_inst == irb->codegen->invalid_instruction)
5686 return union_type_inst;
5687
5688 AstNode *name_node = node->data.fn_call_expr.params.at(1);
5689 IrInstruction *name_inst = ir_gen_node(irb, name_node, scope);
5690 if (name_inst == irb->codegen->invalid_instruction)
5691 return name_inst;
5692
5693 AstNode *init_node = node->data.fn_call_expr.params.at(2);
5694
5695 return ir_gen_union_init_expr(irb, scope, node, union_type_inst, name_inst, init_node,
5696 lval, result_loc);
5697 }
56545698 }
56555699 zig_unreachable();
56565700}
......@@ -5929,6 +5973,31 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
59295973 zig_unreachable();
59305974}
59315975
5976static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node,
5977 IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node,
5978 LVal lval, ResultLoc *parent_result_loc)
5979{
5980 IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, source_node, parent_result_loc, union_type);
5981 IrInstruction *field_ptr = ir_build_field_ptr_instruction(irb, scope, source_node, container_ptr,
5982 field_name, true);
5983
5984 ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
5985 result_loc_inst->base.id = ResultLocIdInstruction;
5986 result_loc_inst->base.source_instruction = field_ptr;
5987 ir_ref_instruction(field_ptr, irb->current_basic_block);
5988 ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
5989
5990 IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone,
5991 &result_loc_inst->base);
5992 if (expr_value == irb->codegen->invalid_instruction)
5993 return expr_value;
5994
5995 IrInstruction *init_union = ir_build_union_init_named_field(irb, scope, source_node, union_type,
5996 field_name, field_ptr, container_ptr);
5997
5998 return ir_lval_wrap(irb, scope, init_union, lval, parent_result_loc);
5999}
6000
59326001static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
59336002 ResultLoc *parent_result_loc)
59346003{
......@@ -19408,32 +19477,21 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe
1940819477 return ir_get_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
1940919478}
1941019479
19411static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
19412 ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields,
19413 IrInstruction *result_loc)
19480static IrInstruction *ir_analyze_union_init(IrAnalyze *ira, IrInstruction *source_instruction,
19481 AstNode *field_source_node, ZigType *union_type, Buf *field_name, IrInstruction *field_result_loc,
19482 IrInstruction *result_loc)
1941419483{
1941519484 Error err;
19416 assert(container_type->id == ZigTypeIdUnion);
19417
19418 if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
19419 return ira->codegen->invalid_instruction;
19420
19421 if (instr_field_count != 1) {
19422 ir_add_error(ira, instruction,
19423 buf_sprintf("union initialization expects exactly one field"));
19424 return ira->codegen->invalid_instruction;
19425 }
19485 assert(union_type->id == ZigTypeIdUnion);
1942619486
19427 IrInstructionContainerInitFieldsField *field = &fields[0];
19428 IrInstruction *field_result_loc = field->result_loc->child;
19429 if (type_is_invalid(field_result_loc->value.type))
19487 if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
1943019488 return ira->codegen->invalid_instruction;
1943119489
19432 TypeUnionField *type_field = find_union_type_field(container_type, field->name);
19490 TypeUnionField *type_field = find_union_type_field(union_type, field_name);
1943319491 if (type_field == nullptr) {
19434 ir_add_error_node(ira, field->source_node,
19492 ir_add_error_node(ira, field_source_node,
1943519493 buf_sprintf("no member named '%s' in union '%s'",
19436 buf_ptr(field->name), buf_ptr(&container_type->name)));
19494 buf_ptr(field_name), buf_ptr(&union_type->name)));
1943719495 return ira->codegen->invalid_instruction;
1943819496 }
1943919497
......@@ -19450,12 +19508,12 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
1945019508 }
1945119509 }
1945219510
19453 bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope)
19454 || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes;
19511 bool is_comptime = ir_should_inline(ira->new_irb.exec, source_instruction->scope)
19512 || type_requires_comptime(ira->codegen, union_type) == ReqCompTimeYes;
1945519513
19456 IrInstruction *result = ir_get_deref(ira, instruction, result_loc, nullptr);
19514 IrInstruction *result = ir_get_deref(ira, source_instruction, result_loc, nullptr);
1945719515 if (is_comptime && !instr_is_comptime(result)) {
19458 ir_add_error(ira, field->result_loc,
19516 ir_add_error(ira, field_result_loc,
1945919517 buf_sprintf("unable to evaluate constant expression"));
1946019518 return ira->codegen->invalid_instruction;
1946119519 }
......@@ -19468,8 +19526,18 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
1946819526{
1946919527 Error err;
1947019528 if (container_type->id == ZigTypeIdUnion) {
19471 return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count,
19472 fields, result_loc);
19529 if (instr_field_count != 1) {
19530 ir_add_error(ira, instruction,
19531 buf_sprintf("union initialization expects exactly one field"));
19532 return ira->codegen->invalid_instruction;
19533 }
19534 IrInstructionContainerInitFieldsField *field = &fields[0];
19535 IrInstruction *field_result_loc = field->result_loc->child;
19536 if (type_is_invalid(field_result_loc->value.type))
19537 return ira->codegen->invalid_instruction;
19538
19539 return ir_analyze_union_init(ira, instruction, field->source_node, container_type, field->name,
19540 field_result_loc, result_loc);
1947319541 }
1947419542 if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) {
1947519543 ir_add_error(ira, instruction,
......@@ -25326,6 +25394,35 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst
2532625394 return instruction->result_loc_bit_cast->parent->gen_instruction;
2532725395}
2532825396
25397static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *ira,
25398 IrInstructionUnionInitNamedField *instruction)
25399{
25400 ZigType *union_type = ir_resolve_type(ira, instruction->union_type->child);
25401 if (type_is_invalid(union_type))
25402 return ira->codegen->invalid_instruction;
25403
25404 if (union_type->id != ZigTypeIdUnion) {
25405 ir_add_error(ira, instruction->union_type,
25406 buf_sprintf("non-union type '%s' passed to @unionInit", buf_ptr(&union_type->name)));
25407 return ira->codegen->invalid_instruction;
25408 }
25409
25410 Buf *field_name = ir_resolve_str(ira, instruction->field_name->child);
25411 if (field_name == nullptr)
25412 return ira->codegen->invalid_instruction;
25413
25414 IrInstruction *field_result_loc = instruction->field_result_loc->child;
25415 if (type_is_invalid(field_result_loc->value.type))
25416 return ira->codegen->invalid_instruction;
25417
25418 IrInstruction *result_loc = instruction->result_loc->child;
25419 if (type_is_invalid(result_loc->value.type))
25420 return ira->codegen->invalid_instruction;
25421
25422 return ir_analyze_union_init(ira, &instruction->base, instruction->base.source_node,
25423 union_type, field_name, field_result_loc, result_loc);
25424}
25425
2532925426static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
2533025427 switch (instruction->id) {
2533125428 case IrInstructionIdInvalid:
......@@ -25641,6 +25738,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2564125738 return ir_analyze_instruction_end_expr(ira, (IrInstructionEndExpr *)instruction);
2564225739 case IrInstructionIdBitCastSrc:
2564325740 return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction);
25741 case IrInstructionIdUnionInitNamedField:
25742 return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)instruction);
2564425743 }
2564525744 zig_unreachable();
2564625745}
......@@ -25794,6 +25893,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2579425893 case IrInstructionIdCast:
2579525894 case IrInstructionIdContainerInitList:
2579625895 case IrInstructionIdContainerInitFields:
25896 case IrInstructionIdUnionInitNamedField:
2579725897 case IrInstructionIdFieldPtr:
2579825898 case IrInstructionIdElemPtr:
2579925899 case IrInstructionIdVarPtr:
src/ir_print.cpp+15
......@@ -1626,6 +1626,18 @@ static void ir_print_undeclared_ident(IrPrint *irp, IrInstructionUndeclaredIdent
16261626 fprintf(irp->f, "@undeclaredIdent(%s)", buf_ptr(instruction->name));
16271627}
16281628
1629static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInitNamedField *instruction) {
1630 fprintf(irp->f, "@unionInit(");
1631 ir_print_other_instruction(irp, instruction->union_type);
1632 fprintf(irp->f, ", ");
1633 ir_print_other_instruction(irp, instruction->field_name);
1634 fprintf(irp->f, ", ");
1635 ir_print_other_instruction(irp, instruction->field_result_loc);
1636 fprintf(irp->f, ", ");
1637 ir_print_other_instruction(irp, instruction->result_loc);
1638 fprintf(irp->f, ")");
1639}
1640
16291641static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
16301642 ir_print_prefix(irp, instruction);
16311643 switch (instruction->id) {
......@@ -2132,6 +2144,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
21322144 case IrInstructionIdEndExpr:
21332145 ir_print_end_expr(irp, (IrInstructionEndExpr *)instruction);
21342146 break;
2147 case IrInstructionIdUnionInitNamedField:
2148 ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction);
2149 break;
21352150 }
21362151 fprintf(irp->f, "\n");
21372152}
test/stage1/behavior/union.zig+36-1
......@@ -416,9 +416,44 @@ test "return union init with void payload" {
416416 two: u32,
417417 };
418418 fn func() Outer {
419 return Outer{ .state = State{ .one = {} }};
419 return Outer{ .state = State{ .one = {} } };
420420 }
421421 };
422422 S.entry();
423423 comptime S.entry();
424424}
425
426test "@unionInit can modify a union type" {
427 const UnionInitEnum = union(enum) {
428 Boolean: bool,
429 Byte: u8,
430 };
431
432 var value: UnionInitEnum = undefined;
433
434 value = @unionInit(UnionInitEnum, "Boolean", true);
435 expect(value.Boolean == true);
436 value.Boolean = false;
437 expect(value.Boolean == false);
438
439 value = @unionInit(UnionInitEnum, "Byte", 2);
440 expect(value.Byte == 2);
441 value.Byte = 3;
442 expect(value.Byte == 3);
443}
444
445test "@unionInit can modify a pointer value" {
446 const UnionInitEnum = union(enum) {
447 Boolean: bool,
448 Byte: u8,
449 };
450
451 var value: UnionInitEnum = undefined;
452 var value_ptr = &value;
453
454 value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
455 expect(value.Boolean == true);
456
457 value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
458 expect(value.Byte == 2);
459}