| ... | @@ -54,6 +54,26 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) | ... | @@ -54,6 +54,26 @@ static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) |
| 54 | } | 54 | } |
| 55 | } | 55 | } |
| 56 | | 56 | |
| | 57 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| | 58 | TypeTableEntry **parent_pointer = is_const ? |
| | 59 | &child_type->pointer_const_parent : |
| | 60 | &child_type->pointer_mut_parent; |
| | 61 | const char *const_or_mut_str = is_const ? "const" : "mut"; |
| | 62 | if (*parent_pointer) { |
| | 63 | return *parent_pointer; |
| | 64 | } else { |
| | 65 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); |
| | 66 | entry->type_ref = LLVMPointerType(child_type->type_ref, 0); |
| | 67 | buf_resize(&entry->name, 0); |
| | 68 | buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type->name)); |
| | 69 | entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type, |
| | 70 | g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name)); |
| | 71 | g->type_table.put(&entry->name, entry); |
| | 72 | *parent_pointer = entry; |
| | 73 | return entry; |
| | 74 | } |
| | 75 | } |
| | 76 | |
| 57 | static void resolve_type(CodeGen *g, AstNode *node) { | 77 | static void resolve_type(CodeGen *g, AstNode *node) { |
| 58 | assert(!node->codegen_node); | 78 | assert(!node->codegen_node); |
| 59 | node->codegen_node = allocate<CodeGenNode>(1); | 79 | node->codegen_node = allocate<CodeGenNode>(1); |
| ... | @@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) { | ... | @@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) { |
| 75 | case AstNodeTypeTypePointer: | 95 | case AstNodeTypeTypePointer: |
| 76 | { | 96 | { |
| 77 | resolve_type(g, node->data.type.child_type); | 97 | resolve_type(g, node->data.type.child_type); |
| 78 | TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node; | 98 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; |
| 79 | if (child_type_node->entry == g->builtin_types.entry_unreachable) { | 99 | if (child_type == g->builtin_types.entry_unreachable) { |
| 80 | add_node_error(g, node, | 100 | add_node_error(g, node, |
| 81 | buf_create_from_str("pointer to unreachable not allowed")); | 101 | buf_create_from_str("pointer to unreachable not allowed")); |
| 82 | } | 102 | } |
| 83 | TypeTableEntry **parent_pointer = node->data.type.is_const ? | 103 | type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); |
| 84 | &child_type_node->entry->pointer_const_parent : | | |
| 85 | &child_type_node->entry->pointer_mut_parent; | | |
| 86 | const char *const_or_mut_str = node->data.type.is_const ? "const" : "mut"; | | |
| 87 | if (*parent_pointer) { | | |
| 88 | type_node->entry = *parent_pointer; | | |
| 89 | } else { | | |
| 90 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | | |
| 91 | entry->type_ref = LLVMPointerType(child_type_node->entry->type_ref, 0); | | |
| 92 | buf_resize(&entry->name, 0); | | |
| 93 | buf_appendf(&entry->name, "*%s %s", const_or_mut_str, buf_ptr(&child_type_node->entry->name)); | | |
| 94 | entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type_node->entry->di_type, | | |
| 95 | g->pointer_size_bytes * 8, g->pointer_size_bytes * 8, buf_ptr(&entry->name)); | | |
| 96 | g->type_table.put(&entry->name, entry); | | |
| 97 | type_node->entry = entry; | | |
| 98 | *parent_pointer = entry; | | |
| 99 | } | | |
| 100 | break; | 104 | break; |
| 101 | } | 105 | } |
| 102 | } | 106 | } |
| ... | @@ -284,23 +288,26 @@ static TypeTableEntry * get_return_type(BlockContext *context) { | ... | @@ -284,23 +288,26 @@ static TypeTableEntry * get_return_type(BlockContext *context) { |
| 284 | } | 288 | } |
| 285 | | 289 | |
| 286 | static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) { | 290 | static void check_type_compatibility(CodeGen *g, AstNode *node, TypeTableEntry *expected_type, TypeTableEntry *actual_type) { |
| | 291 | if (expected_type == nullptr) |
| | 292 | return; // anything will do |
| 287 | if (expected_type == actual_type) | 293 | if (expected_type == actual_type) |
| 288 | return; // good | 294 | return; // match |
| 289 | if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid) | 295 | if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid) |
| 290 | return; // already complained | 296 | return; // already complained |
| 291 | if (actual_type == g->builtin_types.entry_unreachable) | 297 | if (actual_type == g->builtin_types.entry_unreachable) |
| 292 | return; // TODO: is this true? | 298 | return; // TODO: is this true? |
| 293 | | 299 | |
| 294 | // TODO better error message | 300 | // TODO better error message |
| 295 | add_node_error(g, node, buf_sprintf("type mismatch.")); | 301 | add_node_error(g, node, buf_sprintf("type mismatch. expected %s. got %s", buf_ptr(&expected_type->name), buf_ptr(&actual_type->name))); |
| 296 | } | 302 | } |
| 297 | | 303 | |
| 298 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { | 304 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { |
| | 305 | TypeTableEntry *return_type = nullptr; |
| 299 | switch (node->type) { | 306 | switch (node->type) { |
| 300 | case NodeTypeBlock: | 307 | case NodeTypeBlock: |
| 301 | { | 308 | { |
| 302 | // TODO: nested block scopes | 309 | // TODO: nested block scopes |
| 303 | TypeTableEntry *return_type = g->builtin_types.entry_void; | 310 | return_type = g->builtin_types.entry_void; |
| 304 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | 311 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 305 | AstNode *child = node->data.block.statements.at(i); | 312 | AstNode *child = node->data.block.statements.at(i); |
| 306 | if (return_type == g->builtin_types.entry_unreachable) { | 313 | if (return_type == g->builtin_types.entry_unreachable) { |
| ... | @@ -310,7 +317,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -310,7 +317,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 310 | } | 317 | } |
| 311 | return_type = analyze_expression(g, import, context, nullptr, child); | 318 | return_type = analyze_expression(g, import, context, nullptr, child); |
| 312 | } | 319 | } |
| 313 | return return_type; | 320 | break; |
| 314 | } | 321 | } |
| 315 | | 322 | |
| 316 | case NodeTypeReturnExpr: | 323 | case NodeTypeReturnExpr: |
| ... | @@ -330,7 +337,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -330,7 +337,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 330 | } | 337 | } |
| 331 | | 338 | |
| 332 | check_type_compatibility(g, node, expected_return_type, actual_return_type); | 339 | check_type_compatibility(g, node, expected_return_type, actual_return_type); |
| 333 | return g->builtin_types.entry_unreachable; | 340 | return_type = g->builtin_types.entry_unreachable; |
| | 341 | break; |
| 334 | } | 342 | } |
| 335 | | 343 | |
| 336 | case NodeTypeBinOpExpr: | 344 | case NodeTypeBinOpExpr: |
| ... | @@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 338 | // TODO: think about expected types | 346 | // TODO: think about expected types |
| 339 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1); | 347 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1); |
| 340 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2); | 348 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op2); |
| 341 | return expected_type; | 349 | return_type = expected_type; |
| | 350 | break; |
| 342 | } | 351 | } |
| 343 | | 352 | |
| 344 | case NodeTypeFnCallExpr: | 353 | case NodeTypeFnCallExpr: |
| ... | @@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 358 | analyze_expression(g, import, context, nullptr, child); | 367 | analyze_expression(g, import, context, nullptr, child); |
| 359 | } | 368 | } |
| 360 | | 369 | |
| 361 | return g->builtin_types.entry_invalid; | 370 | return_type = g->builtin_types.entry_invalid; |
| 362 | } else { | 371 | } else { |
| 363 | FnTableEntry *fn_table_entry = entry->value; | 372 | FnTableEntry *fn_table_entry = entry->value; |
| 364 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | 373 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| ... | @@ -388,21 +397,23 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -388,21 +397,23 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 388 | analyze_expression(g, import, context, expected_param_type, child); | 397 | analyze_expression(g, import, context, expected_param_type, child); |
| 389 | } | 398 | } |
| 390 | | 399 | |
| 391 | TypeTableEntry *return_type = fn_proto->return_type->codegen_node->data.type_node.entry; | 400 | return_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| 392 | check_type_compatibility(g, node, expected_type, return_type); | | |
| 393 | return return_type; | | |
| 394 | } | 401 | } |
| | 402 | break; |
| 395 | } | 403 | } |
| 396 | | 404 | |
| 397 | case NodeTypeNumberLiteral: | 405 | case NodeTypeNumberLiteral: |
| 398 | // TODO: generic literal int type | 406 | // TODO: generic literal int type |
| 399 | return g->builtin_types.entry_i32; | 407 | return_type = g->builtin_types.entry_i32; |
| | 408 | break; |
| 400 | | 409 | |
| 401 | case NodeTypeStringLiteral: | 410 | case NodeTypeStringLiteral: |
| 402 | zig_panic("TODO: string literal"); | 411 | return_type = g->builtin_types.entry_string_literal; |
| | 412 | break; |
| 403 | | 413 | |
| 404 | case NodeTypeUnreachable: | 414 | case NodeTypeUnreachable: |
| 405 | return g->builtin_types.entry_unreachable; | 415 | return_type = g->builtin_types.entry_unreachable; |
| | 416 | break; |
| 406 | | 417 | |
| 407 | case NodeTypeSymbol: | 418 | case NodeTypeSymbol: |
| 408 | // look up symbol in symbol table | 419 | // look up symbol in symbol table |
| ... | @@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 423 | case NodeTypeUse: | 434 | case NodeTypeUse: |
| 424 | zig_unreachable(); | 435 | zig_unreachable(); |
| 425 | } | 436 | } |
| 426 | zig_unreachable(); | 437 | assert(return_type); |
| | 438 | check_type_compatibility(g, node, expected_type, return_type); |
| | 439 | return return_type; |
| 427 | } | 440 | } |
| 428 | | 441 | |
| 429 | static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { | 442 | static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { |