From 6907951f1eebcc9053ccfbe32a30dc704e790747 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 22 Sep 2016 13:34:14 +0100 Subject: [PATCH] Fix type info generation The problem: entry's index != entry->value in info_type_map But I was assuming this --- code/demo.odin | 68 ++++++++++++++++++++++++++------------ core/fmt.odin | 10 ++++-- src/checker/checker.cpp | 2 ++ src/checker/expr.cpp | 72 +++++++++++++++++++++++++++-------------- src/checker/type.cpp | 3 +- src/codegen/codegen.cpp | 7 ++-- src/codegen/ssa.cpp | 8 +++++ 7 files changed, 119 insertions(+), 51 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 19d997c33..4311ec213 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -8,7 +8,7 @@ main :: proc() { // bounds_checking() // type_introspection() // any_type() - crazy_introspection() + // crazy_introspection() // namespaces_and_files() // miscellany() } @@ -143,25 +143,51 @@ bounds_checking :: proc() { } type_introspection :: proc() { + { + info: ^Type_Info + x: int - info: ^Type_Info - x: int + info = type_info(int) // by type + info = type_info_of_val(x) // by value + // See: runtime.odin - info = type_info(int) // by type - info = type_info(x) // by value - // See: runtime.odin + match type i : info { + case Type_Info.Integer: + fmt.println("integer!") + case Type_Info.Float: + fmt.println("float!") + default: + fmt.println("potato!") + } - match type i : info { - case Type_Info.Integer: - fmt.println("integer!") - case Type_Info.Float: - fmt.println("float!") - default: - fmt.println("potato!") + // Unsafe cast + integer_info := info as ^Type_Info.Integer } - // Unsafe cast - integer_info := info as ^Type_Info.Integer + { + Vector2 :: struct { x, y: f32 } + Vector3 :: struct { x, y, z: f32 } + + v1: Vector2 + v2: Vector3 + v3: Vector3 + + t1 := type_info_of_val(v1) + t2 := type_info_of_val(v2) + t3 := type_info_of_val(v3) + + fmt.println() + fmt.print("Type of v1 is:\n\t", t1) + // fmt.fprint_type(os.stdout, t1) + + fmt.println() + fmt.print("Type of v2 is:\n\t") + fmt.fprint_type(os.stdout, t2) + + fmt.println("\n") + fmt.println("t1 == t2:", t1 == t2) + fmt.println("t2 == t3:", t2 == t3) + } } any_type :: proc() { @@ -174,14 +200,17 @@ any_type :: proc() { a = x a = y a = z - a = a + a = a // This the "identity" type, it doesn't get converted + + a = 123 // Literals are copied onto the stack first // any has two members // data - rawptr to the data // type_info - pointer to the type info fmt.println(x, y, z) - // See: Implementation + // See: fmt.odin + // For variadic any procedures in action } crazy_introspection :: proc() { @@ -204,6 +233,7 @@ crazy_introspection :: proc() { fmt.println(s) fmt.println(f) + // See: runtime.odin } @@ -225,9 +255,7 @@ crazy_introspection :: proc() { name := (fruit_ti as ^Type_Info.Named).name // Unsafe casts info := type_info_base(fruit_ti) as ^Type_Info.Enum // Unsafe casts - fmt.printf("% :: enum ", name); - fmt.fprint_type(os.stdout, info.base) - fmt.printf(" {\n") + fmt.printf("% :: enum % {", name, info.base); for i := 0; i < info.values.count; i++ { fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]) } diff --git a/core/fmt.odin b/core/fmt.odin index 98aa2c227..faeb98016 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -419,11 +419,15 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { print_bool_to_buffer(buf, v) case Pointer: - v := null; if arg.data != null { - v = (arg.data as ^rawptr)^ + if arg.type_info == type_info(^Type_Info) { + print_type_to_buffer(buf, (arg.data as ^^Type_Info)^) + } else { + print_pointer_to_buffer(buf, (arg.data as ^rawptr)^) + } + } else { + print_pointer_to_buffer(buf, null) } - print_pointer_to_buffer(buf, v) case Enum: value: i64 = 0 diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index bb093de0d..ea246dba0 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -142,6 +142,7 @@ enum BuiltinProcId { BuiltinProc_type_of_val, BuiltinProc_type_info, + BuiltinProc_type_info_of_val, BuiltinProc_compile_assert, BuiltinProc_assert, @@ -186,6 +187,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("type_of_val"), 1, false, Expr_Expr}, {STR_LIT("type_info"), 1, false, Expr_Expr}, + {STR_LIT("type_info_of_val"), 1, false, Expr_Expr}, {STR_LIT("compile_assert"), 1, false, Expr_Stmt}, {STR_LIT("assert"), 1, false, Expr_Stmt}, diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 9dd761ec6..6bc21157b 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -1072,6 +1072,13 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c type = o.type; goto end; } + } else if (e->kind == AstNode_UnaryExpr) { + ast_node(ue, UnaryExpr, e); + if (ue->op.kind == Token_Pointer) { + type = make_type_pointer(c->allocator, check_type(c, ue->expr)); + set_base_type(named_type, type); + goto end; + } } err_str = expr_to_string(e); @@ -2241,10 +2248,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_size_of: { // size_of :: proc(Type) -> int - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *type = op.type; - if (type == NULL || op.mode == Addressing_Builtin) { + Type *type = check_type(c, ce->args[0]); + if (type == NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `size_of`"); return false; } @@ -2269,10 +2274,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_align_of: { // align_of :: proc(Type) -> int - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *type = op.type; - if (type == NULL || op.mode == Addressing_Builtin) { + Type *type = check_type(c, ce->args[0]); + if (type == NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `align_of`"); return false; } @@ -2296,10 +2299,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_offset_of: { // offset_val :: proc(Type, field) -> int Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *type = get_base_type(op.type); - AstNode *field_arg = unparen_expr(ce->args[1]); - if (type != NULL || op.mode == Addressing_Builtin) { + Type *type = get_base_type(check_type(c, ce->args[0])); + if (type != NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`"); return false; } @@ -2307,6 +2308,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) error(ast_node_token(ce->args[0]), "Expected a structure type for `offset_of`"); return false; } + + AstNode *field_arg = unparen_expr(ce->args[1]); if (field_arg == NULL || field_arg->kind != AstNode_Ident) { error(ast_node_token(field_arg), "Expected an identifier for field argument"); @@ -2377,19 +2380,34 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case BuiltinProc_type_info: { - // type_info :: proc(val_or_type) -> ^Type_Info - operand->mode = Addressing_Value; - operand->type = t_type_info_ptr; - - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - if (op.type == NULL || op.type == t_invalid || operand->mode == Addressing_Builtin) { - error(ast_node_token(op.expr), "Invalid argument to `type_info`"); + // type_info :: proc(Type) -> ^Type_Info + AstNode *expr = ce->args[0]; + Type *type = check_type(c, expr); + if (type == NULL || type == t_invalid) { + error(ast_node_token(expr), "Invalid argument to `type_info`"); return false; } - add_type_info_type(c, op.type); + add_type_info_type(c, type); + + operand->mode = Addressing_Value; + operand->type = t_type_info_ptr; } break; + case BuiltinProc_type_info_of_val: { + // type_info_of_val :: proc(val: Type) -> ^Type_Info + AstNode *expr = ce->args[0]; + + check_assignment(c, operand, NULL, make_string("argument of `type_info_of_val`")); + if (operand->mode == Addressing_Invalid || operand->mode == Addressing_Builtin) + return false; + add_type_info_type(c, operand->type); + + operand->mode = Addressing_Value; + operand->type = t_type_info_ptr; + } break; + + + case BuiltinProc_compile_assert: // compile_assert :: proc(cond: bool) @@ -3379,18 +3397,21 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(ue, UnaryExpr, node); check_expr(c, o, ue->expr); - if (o->mode == Addressing_Invalid) + if (o->mode == Addressing_Invalid) { goto error; + } check_unary_expr(c, o, ue->op, node); - if (o->mode == Addressing_Invalid) + if (o->mode == Addressing_Invalid) { goto error; + } case_end; case_ast_node(be, BinaryExpr, node); check_binary_expr(c, o, node); - if (o->mode == Addressing_Invalid) + if (o->mode == Addressing_Invalid) { goto error; + } case_end; @@ -3402,8 +3423,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(ie, IndexExpr, node); check_expr(c, o, ie->expr); - if (o->mode == Addressing_Invalid) + if (o->mode == Addressing_Invalid) { goto error; + } b32 valid = false; i64 max_count = -1; diff --git a/src/checker/type.cpp b/src/checker/type.cpp index ae415b3d5..085e7c61e 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -1062,7 +1062,8 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { if (max < size) max = size; } - return align_formula(max, s.max_align) + type_size_of(s, allocator, t_int); + // NOTE(bill): Align to int + return align_formula(max, s.word_size) + type_size_of(s, allocator, t_int); } break; case TypeRecord_RawUnion: { diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index e021069b2..4a4a7da46 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -302,9 +302,12 @@ void ssa_gen_tree(ssaGen *s) { }; - gb_for_array(entry_index, info->type_info_map.entries) { - auto *entry = &info->type_info_map.entries[entry_index]; + gb_for_array(type_info_map_index, info->type_info_map.entries) { + auto *entry = &info->type_info_map.entries[type_info_map_index]; Type *t = cast(Type *)cast(uintptr)entry->key.key; + t = default_type(t); + isize entry_index = entry->value; + ssaValue *tag = NULL; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 959e3faf8..66d00ed0f 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -1327,6 +1327,8 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se isize ssa_type_info_index(CheckerInfo *info, Type *type) { + type = default_type(type); + isize entry_index = -1; HashKey key = hash_pointer(type); auto *found_entry_index = map_get(&info->type_info_map, key); @@ -1763,6 +1765,8 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg data = ssa_add_local_generated(proc, src_type); ssa_emit_store(proc, data, value); } + GB_ASSERT(is_type_pointer(ssa_type(data))); + GB_ASSERT(is_type_typed(src_type)); data = ssa_emit_conv(proc, data, t_rawptr); @@ -2157,6 +2161,10 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); return ssa_type_info(proc, t); } break; + case BuiltinProc_type_info_of_val: { + Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); + return ssa_type_info(proc, t); + } break; case BuiltinProc_new: { ssa_emit_comment(proc, make_string("new"));