| ... | ... | @@ -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 | 77 | static void resolve_type(CodeGen *g, AstNode *node) { |
| 58 | 78 | assert(!node->codegen_node); |
| 59 | 79 | node->codegen_node = allocate<CodeGenNode>(1); |
| ... | ... | @@ -75,28 +95,12 @@ static void resolve_type(CodeGen *g, AstNode *node) { |
| 75 | 95 | case AstNodeTypeTypePointer: |
| 76 | 96 | { |
| 77 | 97 | resolve_type(g, node->data.type.child_type); |
| 78 | | TypeNode *child_type_node = &node->data.type.child_type->codegen_node->data.type_node; |
| 79 | | if (child_type_node->entry == g->builtin_types.entry_unreachable) { |
| 98 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; |
| 99 | if (child_type == g->builtin_types.entry_unreachable) { |
| 80 | 100 | add_node_error(g, node, |
| 81 | 101 | buf_create_from_str("pointer to unreachable not allowed")); |
| 82 | 102 | } |
| 83 | | TypeTableEntry **parent_pointer = 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 | | } |
| 103 | type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); |
| 100 | 104 | break; |
| 101 | 105 | } |
| 102 | 106 | } |
| ... | ... | @@ -284,23 +288,26 @@ static TypeTableEntry * get_return_type(BlockContext *context) { |
| 284 | 288 | } |
| 285 | 289 | |
| 286 | 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 | 293 | if (expected_type == actual_type) |
| 288 | | return; // good |
| 294 | return; // match |
| 289 | 295 | if (expected_type == g->builtin_types.entry_invalid || actual_type == g->builtin_types.entry_invalid) |
| 290 | 296 | return; // already complained |
| 291 | 297 | if (actual_type == g->builtin_types.entry_unreachable) |
| 292 | 298 | return; // TODO: is this true? |
| 293 | 299 | |
| 294 | 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 | 304 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { |
| 305 | TypeTableEntry *return_type = nullptr; |
| 299 | 306 | switch (node->type) { |
| 300 | 307 | case NodeTypeBlock: |
| 301 | 308 | { |
| 302 | 309 | // TODO: nested block scopes |
| 303 | | TypeTableEntry *return_type = g->builtin_types.entry_void; |
| 310 | return_type = g->builtin_types.entry_void; |
| 304 | 311 | for (int i = 0; i < node->data.block.statements.length; i += 1) { |
| 305 | 312 | AstNode *child = node->data.block.statements.at(i); |
| 306 | 313 | if (return_type == g->builtin_types.entry_unreachable) { |
| ... | ... | @@ -310,7 +317,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 310 | 317 | } |
| 311 | 318 | return_type = analyze_expression(g, import, context, nullptr, child); |
| 312 | 319 | } |
| 313 | | return return_type; |
| 320 | break; |
| 314 | 321 | } |
| 315 | 322 | |
| 316 | 323 | case NodeTypeReturnExpr: |
| ... | ... | @@ -330,7 +337,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 330 | 337 | } |
| 331 | 338 | |
| 332 | 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 | 344 | case NodeTypeBinOpExpr: |
| ... | ... | @@ -338,7 +346,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 338 | 346 | // TODO: think about expected types |
| 339 | 347 | analyze_expression(g, import, context, expected_type, node->data.bin_op_expr.op1); |
| 340 | 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 | 353 | case NodeTypeFnCallExpr: |
| ... | ... | @@ -358,7 +367,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 358 | 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 | 371 | } else { |
| 363 | 372 | FnTableEntry *fn_table_entry = entry->value; |
| 364 | 373 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| ... | ... | @@ -388,21 +397,23 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 388 | 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; |
| 392 | | check_type_compatibility(g, node, expected_type, return_type); |
| 393 | | return return_type; |
| 400 | return_type = fn_proto->return_type->codegen_node->data.type_node.entry; |
| 394 | 401 | } |
| 402 | break; |
| 395 | 403 | } |
| 396 | 404 | |
| 397 | 405 | case NodeTypeNumberLiteral: |
| 398 | 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 | 410 | case NodeTypeStringLiteral: |
| 402 | | zig_panic("TODO: string literal"); |
| 411 | return_type = g->builtin_types.entry_string_literal; |
| 412 | break; |
| 403 | 413 | |
| 404 | 414 | case NodeTypeUnreachable: |
| 405 | | return g->builtin_types.entry_unreachable; |
| 415 | return_type = g->builtin_types.entry_unreachable; |
| 416 | break; |
| 406 | 417 | |
| 407 | 418 | case NodeTypeSymbol: |
| 408 | 419 | // look up symbol in symbol table |
| ... | ... | @@ -423,7 +434,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 423 | 434 | case NodeTypeUse: |
| 424 | 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 | 442 | static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { |