authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-25 17:25:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-29 22:14:09-07:00
log651dc31247c2f637925ed6a6e92c8bc1a19efd5c
tree7e75713d6c4c9b5dfc8783759b5ed60b5e9e71bf
parent1f7ec741fa5b1d9ba3826e06a8a8a0feec58876f

implement null as a literal type


8 files changed, 76 insertions(+), 35 deletions(-)

CMakeLists.txt+1
......@@ -202,6 +202,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}
202202install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}")
203203install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
204204install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")
205install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}")
205206install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}")
206207install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
207208install(FILES "${CMAKE_SOURCE_DIR}/std/endian.zig" DESTINATION "${ZIG_STD_DEST}")
src/all_types.hpp+3-3
......@@ -394,6 +394,7 @@ enum CastOp {
394394 CastOpWidenOrShorten,
395395 CastOpToUnknownSizeArray,
396396 CastOpMaybeWrap,
397 CastOpNullToMaybe,
397398 CastOpErrorWrap,
398399 CastOpPureErrorWrap,
399400 CastOpPointerReinterpret,
......@@ -692,19 +693,16 @@ struct AstNodeContainerInitExpr {
692693
693694struct AstNodeNullLiteral {
694695 // populated by semantic analyzer
695 StructValExprCodeGen resolved_struct_val_expr;
696696 Expr resolved_expr;
697697};
698698
699699struct AstNodeUndefinedLiteral {
700700 // populated by semantic analyzer
701 StructValExprCodeGen resolved_struct_val_expr;
702701 Expr resolved_expr;
703702};
704703
705704struct AstNodeZeroesLiteral {
706705 // populated by semantic analyzer
707 StructValExprCodeGen resolved_struct_val_expr;
708706 Expr resolved_expr;
709707};
710708
......@@ -989,6 +987,7 @@ enum TypeTableEntryId {
989987 TypeTableEntryIdNumLitFloat,
990988 TypeTableEntryIdNumLitInt,
991989 TypeTableEntryIdUndefLit,
990 TypeTableEntryIdNullLit,
992991 TypeTableEntryIdMaybe,
993992 TypeTableEntryIdErrorUnion,
994993 TypeTableEntryIdPureError,
......@@ -1228,6 +1227,7 @@ struct CodeGen {
12281227 TypeTableEntry *entry_num_lit_int;
12291228 TypeTableEntry *entry_num_lit_float;
12301229 TypeTableEntry *entry_undef;
1230 TypeTableEntry *entry_null;
12311231 TypeTableEntry *entry_pure_error;
12321232 TypeTableEntry *entry_os_enum;
12331233 TypeTableEntry *entry_arch_enum;
src/analyze.cpp+35-28
......@@ -237,6 +237,7 @@ static bool type_is_complete(TypeTableEntry *type_entry) {
237237 case TypeTableEntryIdNumLitFloat:
238238 case TypeTableEntryIdNumLitInt:
239239 case TypeTableEntryIdUndefLit:
240 case TypeTableEntryIdNullLit:
240241 case TypeTableEntryIdMaybe:
241242 case TypeTableEntryIdErrorUnion:
242243 case TypeTableEntryIdPureError:
......@@ -925,6 +926,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
925926 case TypeTableEntryIdNumLitFloat:
926927 case TypeTableEntryIdNumLitInt:
927928 case TypeTableEntryIdUndefLit:
929 case TypeTableEntryIdNullLit:
928930 case TypeTableEntryIdNamespace:
929931 case TypeTableEntryIdGenericFn:
930932 fn_proto->skip = true;
......@@ -963,6 +965,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
963965 case TypeTableEntryIdNumLitFloat:
964966 case TypeTableEntryIdNumLitInt:
965967 case TypeTableEntryIdUndefLit:
968 case TypeTableEntryIdNullLit:
966969 case TypeTableEntryIdUnreachable:
967970 case TypeTableEntryIdNamespace:
968971 case TypeTableEntryIdGenericFn:
......@@ -1912,6 +1915,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
19121915 case TypeTableEntryIdNumLitFloat:
19131916 case TypeTableEntryIdNumLitInt:
19141917 case TypeTableEntryIdUndefLit:
1918 case TypeTableEntryIdNullLit:
19151919 case TypeTableEntryIdNamespace:
19161920 case TypeTableEntryIdGenericFn:
19171921 return false;
......@@ -2167,6 +2171,13 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
21672171 return true;
21682172 }
21692173
2174 // implicit conversion from null literal to maybe type
2175 if (expected_type->id == TypeTableEntryIdMaybe &&
2176 actual_type->id == TypeTableEntryIdNullLit)
2177 {
2178 return true;
2179 }
2180
21702181 // implicit conversion from error child type to error type
21712182 if (expected_type->id == TypeTableEntryIdErrorUnion &&
21722183 types_match_with_implicit_cast(g, expected_type->data.error.child_type, actual_type,
......@@ -2971,13 +2982,6 @@ static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node,
29712982 return g->builtin_types.entry_bool;
29722983}
29732984
2974static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node, TypeTableEntry *type) {
2975 Expr *expr = get_resolved_expr(node);
2976 expr->const_val.ok = true;
2977 expr->const_val.data.x_maybe = nullptr;
2978 return type;
2979}
2980
29812985static TypeTableEntry *resolve_expr_const_val_as_non_null(CodeGen *g, AstNode *node,
29822986 TypeTableEntry *type, ConstExprValue *other_val)
29832987{
......@@ -3358,6 +3362,7 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
33583362 case TypeTableEntryIdArray:
33593363 case TypeTableEntryIdStruct:
33603364 case TypeTableEntryIdUndefLit:
3365 case TypeTableEntryIdNullLit:
33613366 case TypeTableEntryIdMaybe:
33623367 case TypeTableEntryIdErrorUnion:
33633368 case TypeTableEntryIdUnion:
......@@ -3916,26 +3921,17 @@ static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *i
39163921{
39173922 assert(node->type == NodeTypeNullLiteral);
39183923
3919 if (!expected_type) {
3920 add_node_error(g, node, buf_sprintf("unable to determine null type"));
3921 return g->builtin_types.entry_invalid;
3922 }
3923
3924 if (expected_type->id != TypeTableEntryIdMaybe) {
3925 add_node_error(g, node,
3926 buf_sprintf("expected maybe type, got '%s'", buf_ptr(&expected_type->name)));
3927 return g->builtin_types.entry_invalid;
3928 }
3929
3930 node->data.null_literal.resolved_struct_val_expr.type_entry = expected_type;
3931 node->data.null_literal.resolved_struct_val_expr.source_node = node;
3924 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
3925 const_val->ok = true;
39323926
3933 return resolve_expr_const_val_as_null(g, node, expected_type);
3927 return g->builtin_types.entry_null;
39343928}
39353929
39363930static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
39373931 TypeTableEntry *expected_type, AstNode *node)
39383932{
3933 assert(node->type == NodeTypeUndefinedLiteral);
3934
39393935 Expr *expr = get_resolved_expr(node);
39403936 ConstExprValue *const_val = &expr->const_val;
39413937
......@@ -4519,6 +4515,14 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
45194515 }
45204516 }
45214517
4518 // explicit cast from null literal to maybe type
4519 if (wanted_type->id == TypeTableEntryIdMaybe &&
4520 actual_type->id == TypeTableEntryIdNullLit)
4521 {
4522 get_resolved_expr(node)->return_knowledge = ReturnKnowledgeKnownNull;
4523 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpNullToMaybe, true);
4524 }
4525
45224526 // explicit cast from child type of error type to error type
45234527 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
45244528 if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
......@@ -5203,6 +5207,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
52035207 case TypeTableEntryIdNumLitFloat:
52045208 case TypeTableEntryIdNumLitInt:
52055209 case TypeTableEntryIdUndefLit:
5210 case TypeTableEntryIdNullLit:
52065211 case TypeTableEntryIdNamespace:
52075212 case TypeTableEntryIdGenericFn:
52085213 add_node_error(g, expr_node,
......@@ -6252,13 +6257,12 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
62526257 if (resolved_type->id == TypeTableEntryIdInvalid) {
62536258 return resolved_type;
62546259 } else if (resolved_type->id == TypeTableEntryIdErrorUnion) {
6255 TypeTableEntry *return_type = context->fn_entry->type_entry->data.fn.fn_type_id.return_type;
6256 if (return_type->id != TypeTableEntryIdErrorUnion &&
6257 return_type->id != TypeTableEntryIdPureError)
6260 if (expected_return_type->id != TypeTableEntryIdErrorUnion &&
6261 expected_return_type->id != TypeTableEntryIdPureError)
62586262 {
62596263 ErrorMsg *msg = add_node_error(g, node,
62606264 buf_sprintf("%%return statement in function with return type '%s'",
6261 buf_ptr(&return_type->name)));
6265 buf_ptr(&expected_return_type->name)));
62626266 AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
62636267 add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
62646268 }
......@@ -6283,11 +6287,10 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
62836287 if (resolved_type->id == TypeTableEntryIdInvalid) {
62846288 return resolved_type;
62856289 } else if (resolved_type->id == TypeTableEntryIdMaybe) {
6286 TypeTableEntry *return_type = context->fn_entry->type_entry->data.fn.fn_type_id.return_type;
6287 if (return_type->id != TypeTableEntryIdMaybe) {
6290 if (expected_return_type->id != TypeTableEntryIdMaybe) {
62886291 ErrorMsg *msg = add_node_error(g, node,
62896292 buf_sprintf("?return statement in function with return type '%s'",
6290 buf_ptr(&return_type->name)));
6293 buf_ptr(&expected_return_type->name)));
62916294 AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
62926295 add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
62936296 }
......@@ -7227,6 +7230,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
72277230 case TypeTableEntryIdNumLitFloat:
72287231 case TypeTableEntryIdNumLitInt:
72297232 case TypeTableEntryIdUndefLit:
7233 case TypeTableEntryIdNullLit:
72307234 case TypeTableEntryIdNamespace:
72317235 case TypeTableEntryIdGenericFn:
72327236 zig_unreachable();
......@@ -7335,6 +7339,8 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
73357339 return hash_ptr(const_val->data.x_ptr.ptr);
73367340 case TypeTableEntryIdUndefLit:
73377341 return 162837799;
7342 case TypeTableEntryIdNullLit:
7343 return 844854567;
73387344 case TypeTableEntryIdArray:
73397345 // TODO better hashing algorithm
73407346 return 1166190605;
......@@ -7428,6 +7434,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
74287434 case TypeTableEntryIdNumLitFloat:
74297435 case TypeTableEntryIdNumLitInt:
74307436 case TypeTableEntryIdUndefLit:
7437 case TypeTableEntryIdNullLit:
74317438 case TypeTableEntryIdUnreachable:
74327439 case TypeTableEntryIdMetaType:
74337440 case TypeTableEntryIdVoid:
src/codegen.cpp+10
......@@ -875,6 +875,9 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
875875
876876 return cast_expr->tmp_ptr;
877877 }
878 case CastOpNullToMaybe:
879 // handled by constant expression evaluator
880 zig_unreachable();
878881 case CastOpErrorWrap:
879882 {
880883 assert(wanted_type->id == TypeTableEntryIdErrorUnion);
......@@ -3806,6 +3809,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
38063809 case TypeTableEntryIdNumLitFloat:
38073810 case TypeTableEntryIdNumLitInt:
38083811 case TypeTableEntryIdUndefLit:
3812 case TypeTableEntryIdNullLit:
38093813 case TypeTableEntryIdVoid:
38103814 case TypeTableEntryIdNamespace:
38113815 case TypeTableEntryIdGenericFn:
......@@ -4311,6 +4315,12 @@ static void define_builtin_types(CodeGen *g) {
43114315 entry->deep_const = true;
43124316 g->builtin_types.entry_undef = entry;
43134317 }
4318 {
4319 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNullLit);
4320 buf_init_from_str(&entry->name, "(null)");
4321 entry->deep_const = true;
4322 g->builtin_types.entry_null = entry;
4323 }
43144324
43154325 for (int int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
43164326 int size_in_bits = int_sizes_in_bits[int_size_i];
src/eval.cpp+6
......@@ -45,6 +45,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
4545 zig_panic("TODO");
4646 case TypeTableEntryIdUndefLit:
4747 zig_panic("TODO");
48 case TypeTableEntryIdNullLit:
49 zig_panic("TODO");
4850 case TypeTableEntryIdMaybe:
4951 zig_panic("TODO");
5052 case TypeTableEntryIdErrorUnion:
......@@ -650,6 +652,10 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
650652 const_val->data.x_maybe = other_val;
651653 const_val->ok = true;
652654 break;
655 case CastOpNullToMaybe:
656 const_val->data.x_maybe = nullptr;
657 const_val->ok = true;
658 break;
653659 case CastOpErrorWrap:
654660 const_val->data.x_err.err = nullptr;
655661 const_val->data.x_err.payload = other_val;
std/debug.zig+5-3
......@@ -40,7 +40,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
4040
4141 %return out_stream.printInt(usize, return_address);
4242 %return out_stream.printf(" -> ");
43 %return out_stream.printInt(u64, debug_info_offset);
43 %return out_stream.printInt(u64, compile_unit_offset);
4444 %return out_stream.printf("\n");
4545 maybe_fp = *(&const ?&const u8)(fp);
4646 }
......@@ -82,7 +82,8 @@ fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {
8282}
8383
8484fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {
85 const aranges = ?return st.aranges;
85 // TODO ability to implicitly cast null to %?T
86 const aranges = st.aranges ?? return (?u64)(null);
8687
8788 %return st.elf.seekToSection(aranges);
8889
......@@ -129,7 +130,8 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {
129130 if (address == 0 && length == 0) break;
130131
131132 if (target_address >= address && target_address < address + length) {
132 return debug_info_offset;
133 // TODO ability to implicitly cast T to %?T
134 return (?u64)(debug_info_offset);
133135 }
134136 }
135137 }
test/cases/maybe_return.zig created+15
......@@ -0,0 +1,15 @@
1const assert = @import("std").debug.assert;
2
3#attribute("test")
4fn maybeReturn() {
5 assert(??foo(1235));
6 assert(if (const _ ?= foo(null)) false else true);
7 assert(!??foo(1234));
8}
9
10// TODO add another function with static_eval_enable(true)
11#static_eval_enable(false)
12fn foo(x: ?i32) -> ?bool {
13 const value = ?return x;
14 return value > 1234;
15}
test/run_tests.cpp+1-1
......@@ -1211,7 +1211,7 @@ fn derp(){}
12111211
12121212 add_compile_fail_case("assign null to non-nullable pointer", R"SOURCE(
12131213const a: &u8 = null;
1214 )SOURCE", 1, ".tmp_source.zig:2:16: error: expected maybe type, got '&u8'");
1214 )SOURCE", 1, ".tmp_source.zig:2:16: error: expected type '&u8', got '(null)'");
12151215
12161216 add_compile_fail_case("indexing an array of size zero", R"SOURCE(
12171217const array = []u8{};