authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-07 22:19:00-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-07 22:41:58-04:00
logf0b6dac1f2d37ea9eff0116bec34e9b2be9f3ce7
treecb119ae6c6ce4d1a5022b02a5013e763fdc2aa30
parentb65203f5736199bdc8d98d27728be5e92a17d565

add implicit casts from `*[N]T`

* to `[]T` * to `[*]T` See #770

4 files changed, 163 insertions(+), 2 deletions(-)

src/all_types.hpp+1
...@@ -583,6 +583,7 @@ enum CastOp {...@@ -583,6 +583,7 @@ enum CastOp {
583 CastOpNumLitToConcrete,583 CastOpNumLitToConcrete,
584 CastOpErrSet,584 CastOpErrSet,
585 CastOpBitCast,585 CastOpBitCast,
586 CastOpPtrOfArrayToSlice,
586};587};
587588
588struct AstNodeFnCallExpr {589struct AstNodeFnCallExpr {
src/codegen.cpp+24-2
...@@ -2530,7 +2530,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -2530,7 +2530,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
2530 assert(wanted_type->data.structure.is_slice);2530 assert(wanted_type->data.structure.is_slice);
2531 assert(actual_type->id == TypeTableEntryIdArray);2531 assert(actual_type->id == TypeTableEntryIdArray);
25322532
2533 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;2533 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
2534 TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;2534 TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
25352535
25362536
...@@ -2576,6 +2576,29 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -2576,6 +2576,29 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
2576 return expr_val;2576 return expr_val;
2577 case CastOpBitCast:2577 case CastOpBitCast:
2578 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");2578 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
2579 case CastOpPtrOfArrayToSlice: {
2580 assert(cast_instruction->tmp_ptr);
2581 assert(actual_type->id == TypeTableEntryIdPointer);
2582 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
2583 assert(array_type->id == TypeTableEntryIdArray);
2584
2585 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
2586 slice_ptr_index, "");
2587 LLVMValueRef indices[] = {
2588 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
2589 LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
2590 };
2591 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
2592 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
2593
2594 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
2595 slice_len_index, "");
2596 LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
2597 array_type->data.array.len, false);
2598 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
2599
2600 return cast_instruction->tmp_ptr;
2601 }
2579 }2602 }
2580 zig_unreachable();2603 zig_unreachable();
2581}2604}
...@@ -3815,7 +3838,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst...@@ -3815,7 +3838,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
3815 } else {3838 } else {
3816 end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);3839 end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
3817 }3840 }
3818
3819 if (want_runtime_safety) {3841 if (want_runtime_safety) {
3820 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);3842 add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
3821 if (instruction->end) {3843 if (instruction->end) {
src/ir.cpp+122
...@@ -108,6 +108,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -108,6 +108,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
108static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);108static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
109static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);109static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
110static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);110static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
111static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align);
111112
112ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {113ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
113 assert(const_val->type->id == TypeTableEntryIdPointer);114 assert(const_val->type->id == TypeTableEntryIdPointer);
...@@ -8024,6 +8025,33 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -8024,6 +8025,33 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
8024 }8025 }
8025 }8026 }
80268027
8028 // implicit *[N]T to [*]T
8029 if (expected_type->id == TypeTableEntryIdPointer &&
8030 expected_type->data.pointer.ptr_len == PtrLenUnknown &&
8031 actual_type->id == TypeTableEntryIdPointer &&
8032 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8033 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
8034 types_match_const_cast_only(ira, expected_type->data.pointer.child_type,
8035 actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8036 {
8037 return ImplicitCastMatchResultYes;
8038 }
8039
8040 // implicit *[N]T to []T
8041 if (is_slice(expected_type) &&
8042 actual_type->id == TypeTableEntryIdPointer &&
8043 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8044 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
8045 {
8046 TypeTableEntry *slice_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
8047 assert(slice_ptr_type->id == TypeTableEntryIdPointer);
8048 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
8049 actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
8050 {
8051 return ImplicitCastMatchResultYes;
8052 }
8053 }
8054
8027 // implicit [N]T to ?[]const T8055 // implicit [N]T to ?[]const T
8028 if (expected_type->id == TypeTableEntryIdMaybe &&8056 if (expected_type->id == TypeTableEntryIdMaybe &&
8029 is_slice(expected_type->data.maybe.child_type) &&8057 is_slice(expected_type->data.maybe.child_type) &&
...@@ -8699,6 +8727,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -8699,6 +8727,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
8699 zig_unreachable();8727 zig_unreachable();
8700 case CastOpErrSet:8728 case CastOpErrSet:
8701 case CastOpBitCast:8729 case CastOpBitCast:
8730 case CastOpPtrOfArrayToSlice:
8702 zig_panic("TODO");8731 zig_panic("TODO");
8703 case CastOpNoop:8732 case CastOpNoop:
8704 {8733 {
...@@ -8786,6 +8815,63 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8786,6 +8815,63 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
8786 }8815 }
8787}8816}
87888817
8818static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, IrInstruction *source_instr,
8819 IrInstruction *value, TypeTableEntry *wanted_type)
8820{
8821 assert(value->value.type->id == TypeTableEntryIdPointer);
8822 wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
8823
8824 if (instr_is_comptime(value)) {
8825 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
8826 if (pointee->special != ConstValSpecialRuntime) {
8827 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8828 source_instr->source_node, wanted_type);
8829 result->value.type = wanted_type;
8830 result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
8831 result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
8832 result->value.data.x_ptr.data.base_array.array_val = pointee;
8833 result->value.data.x_ptr.data.base_array.elem_index = 0;
8834 result->value.data.x_ptr.data.base_array.is_cstr = false;
8835 return result;
8836 }
8837 }
8838
8839 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
8840 wanted_type, value, CastOpBitCast);
8841 result->value.type = wanted_type;
8842 return result;
8843}
8844
8845static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
8846 IrInstruction *value, TypeTableEntry *wanted_type)
8847{
8848 wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
8849
8850 if (instr_is_comptime(value)) {
8851 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
8852 if (pointee->special != ConstValSpecialRuntime) {
8853 assert(value->value.type->id == TypeTableEntryIdPointer);
8854 TypeTableEntry *array_type = value->value.type->data.pointer.child_type;
8855 assert(is_slice(wanted_type));
8856 bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
8857
8858 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8859 source_instr->source_node, wanted_type);
8860 init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
8861 result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
8862 value->value.data.x_ptr.mut;
8863 result->value.type = wanted_type;
8864 return result;
8865 }
8866 }
8867
8868 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
8869 wanted_type, value, CastOpPtrOfArrayToSlice);
8870 result->value.type = wanted_type;
8871 ir_add_alloca(ira, result, wanted_type);
8872 return result;
8873}
8874
8789static bool is_container(TypeTableEntry *type) {8875static bool is_container(TypeTableEntry *type) {
8790 return type->id == TypeTableEntryIdStruct ||8876 return type->id == TypeTableEntryIdStruct ||
8791 type->id == TypeTableEntryIdEnum ||8877 type->id == TypeTableEntryIdEnum ||
...@@ -9937,6 +10023,35 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -9937,6 +10023,35 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
9937 }10023 }
9938 }10024 }
993910025
10026 // explicit *[N]T to [*]T
10027 if (wanted_type->id == TypeTableEntryIdPointer &&
10028 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
10029 actual_type->id == TypeTableEntryIdPointer &&
10030 actual_type->data.pointer.ptr_len == PtrLenSingle &&
10031 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
10032 actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
10033 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
10034 actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10035 {
10036 return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
10037 }
10038
10039 // explicit *[N]T to []T
10040 if (is_slice(wanted_type) &&
10041 actual_type->id == TypeTableEntryIdPointer &&
10042 actual_type->data.pointer.ptr_len == PtrLenSingle &&
10043 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
10044 {
10045 TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
10046 assert(slice_ptr_type->id == TypeTableEntryIdPointer);
10047 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
10048 actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
10049 {
10050 return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
10051 }
10052 }
10053
10054
9940 // explicit cast from child type of maybe type to maybe type10055 // explicit cast from child type of maybe type to maybe type
9941 if (wanted_type->id == TypeTableEntryIdMaybe) {10056 if (wanted_type->id == TypeTableEntryIdMaybe) {
9942 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;10057 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
...@@ -13150,6 +13265,13 @@ static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, ui...@@ -13150,6 +13265,13 @@ static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, ui
13150 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);13265 ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
13151}13266}
1315213267
13268static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align) {
13269 assert(is_slice(slice_type));
13270 TypeTableEntry *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
13271 new_align);
13272 return get_slice_type(g, ptr_type);
13273}
13274
13153static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrLen ptr_len) {13275static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrLen ptr_len) {
13154 assert(ptr_type->id == TypeTableEntryIdPointer);13276 assert(ptr_type->id == TypeTableEntryIdPointer);
13155 return get_pointer_to_type_extra(g,13277 return get_pointer_to_type_extra(g,
test/cases/cast.zig+16
...@@ -384,3 +384,19 @@ test "const slice widen cast" {...@@ -384,3 +384,19 @@ test "const slice widen cast" {
384384
385 assert(@bitCast(u32, bytes) == 0x12121212);385 assert(@bitCast(u32, bytes) == 0x12121212);
386}386}
387
388test "single-item pointer of array to slice and to unknown length pointer" {
389 testCastPtrOfArrayToSliceAndPtr();
390 comptime testCastPtrOfArrayToSliceAndPtr();
391}
392
393fn testCastPtrOfArrayToSliceAndPtr() void {
394 var array = "ao" ++ "eu"; // TODO https://github.com/ziglang/zig/issues/1076
395 const x: [*]u8 = &array;
396 x[0] += 1;
397 assert(mem.eql(u8, array[0..], "boeu"));
398 const y: []u8 = &array;
399 y[0] += 1;
400 assert(mem.eql(u8, array[0..], "coeu"));
401}
402