| ... | @@ -13,8 +13,6 @@ | ... | @@ -13,8 +13,6 @@ |
| 13 | | 13 | |
| 14 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 14 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 15 | TypeTableEntry *expected_type, AstNode *node); | 15 | TypeTableEntry *expected_type, AstNode *node); |
| 16 | static void eval_const_expr(CodeGen *g, BlockContext *context, | | |
| 17 | AstNode *node, ConstExprValue *out_val); | | |
| 18 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, | 16 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, |
| 19 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); | 17 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); |
| 20 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); | 18 | static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); |
| ... | @@ -158,20 +156,6 @@ static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) { | ... | @@ -158,20 +156,6 @@ static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) { |
| 158 | return get_int_type(g, false, num_lit_bit_count(get_number_literal_kind_unsigned(x))); | 156 | return get_int_type(g, false, num_lit_bit_count(get_number_literal_kind_unsigned(x))); |
| 159 | } | 157 | } |
| 160 | | 158 | |
| 161 | static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) { | | |
| 162 | if (child_type->meta_parent) { | | |
| 163 | return child_type->meta_parent; | | |
| 164 | } else { | | |
| 165 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType); | | |
| 166 | buf_resize(&entry->name, 0); | | |
| 167 | buf_appendf(&entry->name, "(%s declaration)", buf_ptr(&child_type->name)); | | |
| 168 | | | |
| 169 | entry->data.meta_type.child_type = child_type; | | |
| 170 | child_type->meta_parent = entry; | | |
| 171 | return entry; | | |
| 172 | } | | |
| 173 | } | | |
| 174 | | | |
| 175 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { | 159 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 176 | assert(child_type->id != TypeTableEntryIdInvalid); | 160 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 177 | TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; | 161 | TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; |
| ... | @@ -327,301 +311,36 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry | ... | @@ -327,301 +311,36 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry |
| 327 | } | 311 | } |
| 328 | } | 312 | } |
| 329 | | 313 | |
| 330 | // like analyze expression, but expects a type. creates an error if resulting type is | 314 | // If the node does not have a constant expression value with a metatype, generates an error |
| 331 | // not a meta type. unwraps it if it is. | 315 | // and returns invalid type. Otherwise, returns the type of the constant expression value. |
| 332 | static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 316 | // Must be called after analyze_expression on the same node. |
| 333 | AstNode *node) | 317 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 334 | { | 318 | Expr *expr = get_resolved_expr(node); |
| 335 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, node); | 319 | assert(expr->type_entry); |
| 336 | if (type_entry->id == TypeTableEntryIdInvalid) { | 320 | if (expr->type_entry->id == TypeTableEntryIdInvalid) { |
| 337 | return type_entry; | 321 | return g->builtin_types.entry_invalid; |
| 338 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | 322 | } else if (expr->type_entry->id == TypeTableEntryIdMetaType) { |
| 339 | return type_entry->data.meta_type.child_type; | 323 | // OK |
| 340 | } else { | 324 | } else { |
| 341 | add_node_error(g, first_executing_node(node), | 325 | add_node_error(g, node, buf_sprintf("expected type, found expression")); |
| 342 | buf_sprintf("expected type, found expression")); | | |
| 343 | get_resolved_expr(node)->type_entry = g->builtin_types.entry_invalid; | | |
| 344 | return g->builtin_types.entry_invalid; | 326 | return g->builtin_types.entry_invalid; |
| 345 | } | 327 | } |
| 346 | } | | |
| 347 | | | |
| 348 | static void eval_const_expr_bin_op(CodeGen *g, BlockContext *context, | | |
| 349 | AstNode *node, ConstExprValue *out_val) | | |
| 350 | { | | |
| 351 | AstNode *op1_node = node->data.bin_op_expr.op1; | | |
| 352 | AstNode *op2_node = node->data.bin_op_expr.op2; | | |
| 353 | ConstExprValue op1_val = {0}; | | |
| 354 | ConstExprValue op2_val = {0}; | | |
| 355 | eval_const_expr(g, context, op1_node, &op1_val); | | |
| 356 | eval_const_expr(g, context, op2_node, &op2_val); | | |
| 357 | | | |
| 358 | if (!op1_val.ok || !op2_val.ok) { | | |
| 359 | return; | | |
| 360 | } | | |
| 361 | | 328 | |
| 362 | TypeTableEntry *op1_type = get_resolved_expr(op1_node)->type_entry; | 329 | ConstExprValue *const_val = &expr->const_val; |
| 363 | TypeTableEntry *op2_type = get_resolved_expr(op2_node)->type_entry; | 330 | if (!const_val->ok) { |
| 364 | | 331 | add_node_error(g, node, buf_sprintf("unable to resolve constant expression")); |
| 365 | // TODO complete more of this function instead of returning invalid | 332 | return g->builtin_types.entry_invalid; |
| 366 | // returning invalid makes the "unable to evaluate constant expression" error | | |
| 367 | | | |
| 368 | switch (node->data.bin_op_expr.bin_op) { | | |
| 369 | case BinOpTypeCmpNotEq: | | |
| 370 | { | | |
| 371 | if (op1_type->id == TypeTableEntryIdInt && | | |
| 372 | op2_type->id == TypeTableEntryIdInt) | | |
| 373 | { | | |
| 374 | out_val->data.x_bool = (op1_val.data.x_uint == op2_val.data.x_uint); | | |
| 375 | out_val->ok = true; | | |
| 376 | } | | |
| 377 | break; | | |
| 378 | } | | |
| 379 | case BinOpTypeCmpLessThan: | | |
| 380 | { | | |
| 381 | if (op1_type->id == TypeTableEntryIdInt && | | |
| 382 | op2_type->id == TypeTableEntryIdInt) | | |
| 383 | { | | |
| 384 | if (op1_type->data.integral.is_signed && | | |
| 385 | op2_type->data.integral.is_signed) | | |
| 386 | { | | |
| 387 | out_val->data.x_bool = (op1_val.data.x_int < op2_val.data.x_int); | | |
| 388 | out_val->ok = true; | | |
| 389 | } else if (!op1_type->data.integral.is_signed && | | |
| 390 | !op2_type->data.integral.is_signed) | | |
| 391 | { | | |
| 392 | out_val->data.x_bool = (op1_val.data.x_uint < op2_val.data.x_uint); | | |
| 393 | out_val->ok = true; | | |
| 394 | } | | |
| 395 | } | | |
| 396 | break; | | |
| 397 | } | | |
| 398 | case BinOpTypeMod: | | |
| 399 | { | | |
| 400 | if (op1_type->id == TypeTableEntryIdInt && | | |
| 401 | op2_type->id == TypeTableEntryIdInt) | | |
| 402 | { | | |
| 403 | if (op1_type->data.integral.is_signed && | | |
| 404 | op2_type->data.integral.is_signed) | | |
| 405 | { | | |
| 406 | out_val->data.x_int = op1_val.data.x_int % op2_val.data.x_int; | | |
| 407 | out_val->ok = true; | | |
| 408 | } else if (!op1_type->data.integral.is_signed && | | |
| 409 | !op2_type->data.integral.is_signed) | | |
| 410 | { | | |
| 411 | out_val->data.x_uint = op1_val.data.x_uint % op2_val.data.x_uint; | | |
| 412 | out_val->ok = true; | | |
| 413 | } | | |
| 414 | } | | |
| 415 | break; | | |
| 416 | } | | |
| 417 | case BinOpTypeBoolOr: | | |
| 418 | case BinOpTypeBoolAnd: | | |
| 419 | case BinOpTypeCmpEq: | | |
| 420 | case BinOpTypeCmpGreaterThan: | | |
| 421 | case BinOpTypeCmpLessOrEq: | | |
| 422 | case BinOpTypeCmpGreaterOrEq: | | |
| 423 | case BinOpTypeBinOr: | | |
| 424 | case BinOpTypeBinXor: | | |
| 425 | case BinOpTypeBinAnd: | | |
| 426 | case BinOpTypeBitShiftLeft: | | |
| 427 | case BinOpTypeBitShiftRight: | | |
| 428 | case BinOpTypeAdd: | | |
| 429 | case BinOpTypeSub: | | |
| 430 | case BinOpTypeMult: | | |
| 431 | case BinOpTypeDiv: | | |
| 432 | case BinOpTypeUnwrapMaybe: | | |
| 433 | break; | | |
| 434 | case BinOpTypeInvalid: | | |
| 435 | case BinOpTypeAssign: | | |
| 436 | case BinOpTypeAssignTimes: | | |
| 437 | case BinOpTypeAssignDiv: | | |
| 438 | case BinOpTypeAssignMod: | | |
| 439 | case BinOpTypeAssignPlus: | | |
| 440 | case BinOpTypeAssignMinus: | | |
| 441 | case BinOpTypeAssignBitShiftLeft: | | |
| 442 | case BinOpTypeAssignBitShiftRight: | | |
| 443 | case BinOpTypeAssignBitAnd: | | |
| 444 | case BinOpTypeAssignBitXor: | | |
| 445 | case BinOpTypeAssignBitOr: | | |
| 446 | case BinOpTypeAssignBoolAnd: | | |
| 447 | case BinOpTypeAssignBoolOr: | | |
| 448 | zig_unreachable(); | | |
| 449 | } | | |
| 450 | } | | |
| 451 | | | |
| 452 | static void eval_const_expr_builtin(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) { | | |
| 453 | switch (node->data.fn_call_expr.builtin_fn->id) { | | |
| 454 | case BuiltinFnIdInvalid: | | |
| 455 | zig_unreachable(); | | |
| 456 | case BuiltinFnIdAddWithOverflow: | | |
| 457 | case BuiltinFnIdSubWithOverflow: | | |
| 458 | case BuiltinFnIdMulWithOverflow: | | |
| 459 | case BuiltinFnIdMemcpy: | | |
| 460 | case BuiltinFnIdMemset: | | |
| 461 | break; | | |
| 462 | case BuiltinFnIdSizeof: | | |
| 463 | { | | |
| 464 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | | |
| 465 | TypeTableEntry *target_type = unwrapped_node_type(type_node); | | |
| 466 | out_val->data.x_uint = target_type->size_in_bits / 8; | | |
| 467 | out_val->ok = true; | | |
| 468 | break; | | |
| 469 | } | | |
| 470 | case BuiltinFnIdMaxValue: | | |
| 471 | case BuiltinFnIdMinValue: | | |
| 472 | zig_panic("TODO eval_const_expr_fn_call max/min value"); | | |
| 473 | case BuiltinFnIdValueCount: | | |
| 474 | zig_panic("TODO eval_const_expr_fn_call value_count"); | | |
| 475 | case BuiltinFnIdTypeof: | | |
| 476 | // TODO | | |
| 477 | out_val->ok = true; | | |
| 478 | break; | | |
| 479 | } | | |
| 480 | } | | |
| 481 | | | |
| 482 | static void eval_const_expr_fn_call_known(CodeGen *g, BlockContext *context, | | |
| 483 | AstNode *node, ConstExprValue *out_val) | | |
| 484 | { | | |
| 485 | // currently no functions can be constant expression evaluated, | | |
| 486 | // so we do nothing | | |
| 487 | } | | |
| 488 | | | |
| 489 | static void eval_const_expr_fn_call_cast(CodeGen *g, BlockContext *context, | | |
| 490 | AstNode *node, ConstExprValue *out_val) | | |
| 491 | { | | |
| 492 | assert(node->type == NodeTypeFnCallExpr); | | |
| 493 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); | | |
| 494 | Cast *cast = &node->data.fn_call_expr.cast; | | |
| 495 | switch (cast->op) { | | |
| 496 | case CastOpNothing: | | |
| 497 | case CastOpPtrToInt: | | |
| 498 | case CastOpPointerReinterpret: | | |
| 499 | case CastOpIntWidenOrShorten: | | |
| 500 | { | | |
| 501 | eval_const_expr(g, context, expr_node, out_val); | | |
| 502 | break; | | |
| 503 | } | | |
| 504 | case CastOpMaybeWrap: | | |
| 505 | { | | |
| 506 | ConstExprValue *child_val = allocate<ConstExprValue>(1); | | |
| 507 | eval_const_expr(g, context, expr_node, child_val); | | |
| 508 | if (!child_val->ok) { | | |
| 509 | return; | | |
| 510 | } | | |
| 511 | out_val->data.x_maybe.child_val = child_val; | | |
| 512 | out_val->data.x_maybe.is_null = false; | | |
| 513 | out_val->ok = true; | | |
| 514 | break; | | |
| 515 | } | | |
| 516 | case CastOpToUnknownSizeArray: | | |
| 517 | zig_panic("TODO eval_const_expr CastOpToUnknownSizeArray"); | | |
| 518 | } | 333 | } |
| 519 | } | | |
| 520 | | 334 | |
| 521 | static void eval_const_expr_fn_call(CodeGen *g, BlockContext *context, | 335 | return const_val->data.x_type; |
| 522 | AstNode *node, ConstExprValue *out_val) | | |
| 523 | { | | |
| 524 | if (node->data.fn_call_expr.is_builtin) { | | |
| 525 | return eval_const_expr_builtin(g, context, node, out_val); | | |
| 526 | } | | |
| 527 | if (node->data.fn_call_expr.fn_entry) { | | |
| 528 | return eval_const_expr_fn_call_known(g, context, node, out_val); | | |
| 529 | } | | |
| 530 | return eval_const_expr_fn_call_cast(g, context, node, out_val); | | |
| 531 | } | 336 | } |
| 532 | | 337 | |
| 533 | static void eval_const_expr_prefix_op_expr(CodeGen *g, BlockContext *context, AstNode *node, | 338 | // Calls analyze_expression on node, and then resolve_type. |
| 534 | ConstExprValue *out_val) | 339 | static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 340 | AstNode *node) |
| 535 | { | 341 | { |
| 536 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; | 342 | analyze_expression(g, import, context, nullptr, node); |
| 537 | switch (node->data.prefix_op_expr.prefix_op) { | 343 | return resolve_type(g, node); |
| 538 | case PrefixOpInvalid: | | |
| 539 | zig_unreachable(); | | |
| 540 | case PrefixOpBoolNot: | | |
| 541 | { | | |
| 542 | eval_const_expr(g, context, expr_node, out_val); | | |
| 543 | if (out_val->ok) { | | |
| 544 | out_val->data.x_bool = !out_val->data.x_bool; | | |
| 545 | } | | |
| 546 | break; | | |
| 547 | } | | |
| 548 | case PrefixOpBinNot: | | |
| 549 | break; | | |
| 550 | case PrefixOpNegation: | | |
| 551 | break; | | |
| 552 | case PrefixOpAddressOf: | | |
| 553 | { | | |
| 554 | if (get_resolved_expr(node)->type_entry->id == TypeTableEntryIdMetaType) { | | |
| 555 | eval_const_expr(g, context, expr_node, out_val); | | |
| 556 | } | | |
| 557 | break; | | |
| 558 | } | | |
| 559 | case PrefixOpConstAddressOf: | | |
| 560 | break; | | |
| 561 | case PrefixOpDereference: | | |
| 562 | break; | | |
| 563 | case PrefixOpMaybe: | | |
| 564 | break; | | |
| 565 | } | | |
| 566 | } | | |
| 567 | | | |
| 568 | static void eval_const_expr(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) { | | |
| 569 | switch (node->type) { | | |
| 570 | case NodeTypeNumberLiteral: | | |
| 571 | { | | |
| 572 | if (is_num_lit_unsigned(node->data.number_literal.kind)) { | | |
| 573 | out_val->data.x_uint = node->data.number_literal.data.x_uint; | | |
| 574 | out_val->ok = true; | | |
| 575 | } else if (is_num_lit_float(node->data.number_literal.kind)) { | | |
| 576 | out_val->data.x_uint = node->data.number_literal.data.x_float; | | |
| 577 | out_val->ok = true; | | |
| 578 | } | | |
| 579 | break; | | |
| 580 | } | | |
| 581 | case NodeTypeBoolLiteral: | | |
| 582 | out_val->data.x_uint = node->data.bool_literal.value ? 1 : 0; | | |
| 583 | out_val->ok = true; | | |
| 584 | break; | | |
| 585 | case NodeTypeNullLiteral: | | |
| 586 | out_val->data.x_maybe.is_null = true; | | |
| 587 | out_val->ok = true; | | |
| 588 | break; | | |
| 589 | case NodeTypeBinOpExpr: | | |
| 590 | eval_const_expr_bin_op(g, context, node, out_val); | | |
| 591 | break; | | |
| 592 | case NodeTypeSymbol: | | |
| 593 | { | | |
| 594 | VariableTableEntry *var = node->data.symbol_expr.variable; | | |
| 595 | if (var) { | | |
| 596 | if (var->is_const) { | | |
| 597 | AstNode *decl_node = var->decl_node; | | |
| 598 | if (decl_node->type == NodeTypeVariableDeclaration) { | | |
| 599 | AstNode *expr_node = decl_node->data.variable_declaration.expr; | | |
| 600 | if (expr_node) { | | |
| 601 | BlockContext *next_context = get_resolved_expr(expr_node)->block_context; | | |
| 602 | eval_const_expr(g, next_context, expr_node, out_val); | | |
| 603 | } | | |
| 604 | } | | |
| 605 | } | | |
| 606 | } else if (node->data.symbol_expr.meta_type) { | | |
| 607 | out_val->ok = true; | | |
| 608 | } else if (node->data.symbol_expr.fn_entry) { | | |
| 609 | out_val->ok = true; | | |
| 610 | out_val->data.x_fn = node->data.symbol_expr.fn_entry; | | |
| 611 | } else { | | |
| 612 | zig_unreachable(); | | |
| 613 | } | | |
| 614 | break; | | |
| 615 | } | | |
| 616 | case NodeTypeFnCallExpr: | | |
| 617 | eval_const_expr_fn_call(g, context, node, out_val); | | |
| 618 | break; | | |
| 619 | case NodeTypePrefixOpExpr: | | |
| 620 | eval_const_expr_prefix_op_expr(g, context, node, out_val); | | |
| 621 | break; | | |
| 622 | default: | | |
| 623 | break; | | |
| 624 | } | | |
| 625 | } | 344 | } |
| 626 | | 345 | |
| 627 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, | 346 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, |
| ... | @@ -662,9 +381,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -662,9 +381,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 662 | | 381 | |
| 663 | fn_table_entry->type_entry = fn_type; | 382 | fn_table_entry->type_entry = fn_type; |
| 664 | | 383 | |
| 665 | Buf *name = &node->data.fn_proto.name; | | |
| 666 | buf_resize(&fn_type->name, 0); | 384 | buf_resize(&fn_type->name, 0); |
| 667 | buf_appendf(&fn_type->name, "fn %s(", buf_ptr(name)); | 385 | buf_appendf(&fn_type->name, "fn("); |
| 668 | for (int i = 0; i < param_count; i += 1) { | 386 | for (int i = 0; i < param_count; i += 1) { |
| 669 | AstNode *child = node->data.fn_proto.params.at(i); | 387 | AstNode *child = node->data.fn_proto.params.at(i); |
| 670 | assert(child->type == NodeTypeParamDecl); | 388 | assert(child->type == NodeTypeParamDecl); |
| ... | @@ -672,8 +390,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t | ... | @@ -672,8 +390,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 672 | child->data.param_decl.type); | 390 | child->data.param_decl.type); |
| 673 | fn_table_entry->type_entry->data.fn.param_types[i] = type_entry; | 391 | fn_table_entry->type_entry->data.fn.param_types[i] = type_entry; |
| 674 | | 392 | |
| 675 | buf_appendf(&fn_type->name, "%s : %s", | 393 | buf_appendf(&fn_type->name, "%s", buf_ptr(&type_entry->name)); |
| 676 | buf_ptr(&child->data.param_decl.name), buf_ptr(&type_entry->name)); | | |
| 677 | | 394 | |
| 678 | if (i + 1 < param_count) { | 395 | if (i + 1 < param_count) { |
| 679 | buf_appendf(&fn_type->name, ", "); | 396 | buf_appendf(&fn_type->name, ", "); |
| ... | @@ -1212,13 +929,14 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) { | ... | @@ -1212,13 +929,14 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) { |
| 1212 | } | 929 | } |
| 1213 | | 930 | |
| 1214 | static TypeTableEntry *unwrapped_node_type(AstNode *node) { | 931 | static TypeTableEntry *unwrapped_node_type(AstNode *node) { |
| 1215 | TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry; | 932 | Expr *expr = get_resolved_expr(node); |
| 1216 | if (meta_type_entry->id == TypeTableEntryIdInvalid) { | 933 | if (expr->type_entry->id == TypeTableEntryIdInvalid) { |
| 1217 | return meta_type_entry; | 934 | return expr->type_entry; |
| 1218 | } else { | | |
| 1219 | assert(meta_type_entry->id == TypeTableEntryIdMetaType); | | |
| 1220 | return meta_type_entry->data.meta_type.child_type; | | |
| 1221 | } | 935 | } |
| | 936 | assert(expr->type_entry->id == TypeTableEntryIdMetaType); |
| | 937 | ConstExprValue *const_val = &expr->const_val; |
| | 938 | assert(const_val->ok); |
| | 939 | return const_val->data.x_type; |
| 1222 | } | 940 | } |
| 1223 | | 941 | |
| 1224 | static TypeTableEntry *get_return_type(BlockContext *context) { | 942 | static TypeTableEntry *get_return_type(BlockContext *context) { |
| ... | @@ -1704,8 +1422,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -1704,8 +1422,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1704 | AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; | 1422 | AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; |
| 1705 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node); | 1423 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node); |
| 1706 | | 1424 | |
| 1707 | TypeTableEntry *return_type; | | |
| 1708 | | | |
| 1709 | if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && | 1425 | if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && |
| 1710 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) | 1426 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) |
| 1711 | { | 1427 | { |
| ... | @@ -1716,40 +1432,45 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -1716,40 +1432,45 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1716 | | 1432 | |
| 1717 | node->data.field_access_expr.type_struct_field = get_struct_field(bare_struct_type, field_name); | 1433 | node->data.field_access_expr.type_struct_field = get_struct_field(bare_struct_type, field_name); |
| 1718 | if (node->data.field_access_expr.type_struct_field) { | 1434 | if (node->data.field_access_expr.type_struct_field) { |
| 1719 | return_type = node->data.field_access_expr.type_struct_field->type_entry; | 1435 | return node->data.field_access_expr.type_struct_field->type_entry; |
| 1720 | } else { | 1436 | } else { |
| 1721 | add_node_error(g, node, | 1437 | add_node_error(g, node, |
| 1722 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name))); | 1438 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&struct_type->name))); |
| 1723 | return_type = g->builtin_types.entry_invalid; | 1439 | return g->builtin_types.entry_invalid; |
| 1724 | } | 1440 | } |
| 1725 | } else if (struct_type->id == TypeTableEntryIdArray) { | 1441 | } else if (struct_type->id == TypeTableEntryIdArray) { |
| 1726 | Buf *name = &node->data.field_access_expr.field_name; | 1442 | Buf *name = &node->data.field_access_expr.field_name; |
| 1727 | if (buf_eql_str(name, "len")) { | 1443 | if (buf_eql_str(name, "len")) { |
| 1728 | return_type = g->builtin_types.entry_usize; | 1444 | return g->builtin_types.entry_usize; |
| 1729 | } else if (buf_eql_str(name, "ptr")) { | 1445 | } else if (buf_eql_str(name, "ptr")) { |
| 1730 | // TODO determine whether the pointer should be const | 1446 | // TODO determine whether the pointer should be const |
| 1731 | return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false); | 1447 | return get_pointer_to_type(g, struct_type->data.array.child_type, false); |
| 1732 | } else { | 1448 | } else { |
| 1733 | add_node_error(g, node, | 1449 | add_node_error(g, node, |
| 1734 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), | 1450 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), |
| 1735 | buf_ptr(&struct_type->name))); | 1451 | buf_ptr(&struct_type->name))); |
| 1736 | return_type = g->builtin_types.entry_invalid; | 1452 | return g->builtin_types.entry_invalid; |
| | 1453 | } |
| | 1454 | } else if (struct_type->id == TypeTableEntryIdMetaType) { |
| | 1455 | TypeTableEntry *enum_type = resolve_type(g, struct_expr_node); |
| | 1456 | |
| | 1457 | if (enum_type->id == TypeTableEntryIdInvalid) { |
| | 1458 | return g->builtin_types.entry_invalid; |
| | 1459 | } else if (enum_type->id == TypeTableEntryIdEnum) { |
| | 1460 | Buf *field_name = &node->data.field_access_expr.field_name; |
| | 1461 | return analyze_enum_value_expr(g, import, context, node, nullptr, enum_type, field_name); |
| | 1462 | } else { |
| | 1463 | add_node_error(g, node, |
| | 1464 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); |
| | 1465 | return g->builtin_types.entry_invalid; |
| 1737 | } | 1466 | } |
| 1738 | } else if (struct_type->id == TypeTableEntryIdMetaType && | | |
| 1739 | struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) | | |
| 1740 | { | | |
| 1741 | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; | | |
| 1742 | Buf *field_name = &node->data.field_access_expr.field_name; | | |
| 1743 | return_type = analyze_enum_value_expr(g, import, context, node, nullptr, enum_type, field_name); | | |
| 1744 | } else { | 1467 | } else { |
| 1745 | if (struct_type->id != TypeTableEntryIdInvalid) { | 1468 | if (struct_type->id != TypeTableEntryIdInvalid) { |
| 1746 | add_node_error(g, node, | 1469 | add_node_error(g, node, |
| 1747 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); | 1470 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); |
| 1748 | } | 1471 | } |
| 1749 | return_type = g->builtin_types.entry_invalid; | 1472 | return g->builtin_types.entry_invalid; |
| 1750 | } | 1473 | } |
| 1751 | | | |
| 1752 | return return_type; | | |
| 1753 | } | 1474 | } |
| 1754 | | 1475 | |
| 1755 | static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1476 | static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -1826,6 +1547,52 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -1826,6 +1547,52 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i |
| 1826 | return return_type; | 1547 | return return_type; |
| 1827 | } | 1548 | } |
| 1828 | | 1549 | |
| | 1550 | static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type) { |
| | 1551 | Expr *expr = get_resolved_expr(node); |
| | 1552 | expr->const_val.ok = true; |
| | 1553 | expr->const_val.data.x_type = type; |
| | 1554 | return g->builtin_types.entry_type; |
| | 1555 | } |
| | 1556 | |
| | 1557 | static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) { |
| | 1558 | Expr *expr = get_resolved_expr(node); |
| | 1559 | Expr *other_expr = get_resolved_expr(other); |
| | 1560 | expr->const_val = other_expr->const_val; |
| | 1561 | return other_expr->type_entry; |
| | 1562 | } |
| | 1563 | |
| | 1564 | static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) { |
| | 1565 | Expr *expr = get_resolved_expr(node); |
| | 1566 | expr->const_val.ok = true; |
| | 1567 | expr->const_val.data.x_fn = fn; |
| | 1568 | return fn->type_entry; |
| | 1569 | } |
| | 1570 | |
| | 1571 | static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) { |
| | 1572 | Expr *expr = get_resolved_expr(node); |
| | 1573 | expr->const_val.ok = true; |
| | 1574 | expr->const_val.data.x_bool = value; |
| | 1575 | return g->builtin_types.entry_bool; |
| | 1576 | } |
| | 1577 | |
| | 1578 | static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node, TypeTableEntry *type) { |
| | 1579 | Expr *expr = get_resolved_expr(node); |
| | 1580 | expr->const_val.ok = true; |
| | 1581 | expr->const_val.data.x_maybe = nullptr; |
| | 1582 | return type; |
| | 1583 | } |
| | 1584 | |
| | 1585 | static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node, |
| | 1586 | TypeTableEntry *expected_type, uint64_t x) |
| | 1587 | { |
| | 1588 | Expr *expr = get_resolved_expr(node); |
| | 1589 | expr->const_val.ok = true; |
| | 1590 | expr->const_val.data.x_uint = x; |
| | 1591 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, x); |
| | 1592 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); |
| | 1593 | return resolved_type ? resolved_type : num_lit_type; |
| | 1594 | } |
| | 1595 | |
| 1829 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1596 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1830 | TypeTableEntry *expected_type, AstNode *node) | 1597 | TypeTableEntry *expected_type, AstNode *node) |
| 1831 | { | 1598 | { |
| ... | @@ -1833,28 +1600,33 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -1833,28 +1600,33 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 1833 | | 1600 | |
| 1834 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); | 1601 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); |
| 1835 | if (primitive_table_entry) { | 1602 | if (primitive_table_entry) { |
| 1836 | TypeTableEntry *meta_type = get_meta_type(g, primitive_table_entry->value); | 1603 | return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value); |
| 1837 | node->data.symbol_expr.meta_type = meta_type; | | |
| 1838 | return meta_type; | | |
| 1839 | } | 1604 | } |
| 1840 | | 1605 | |
| 1841 | VariableTableEntry *var = find_variable(context, variable_name); | 1606 | VariableTableEntry *var = find_variable(context, variable_name); |
| 1842 | if (var) { | 1607 | if (var) { |
| 1843 | node->data.symbol_expr.variable = var; | 1608 | node->data.symbol_expr.variable = var; |
| | 1609 | if (var->is_const) { |
| | 1610 | AstNode *decl_node = var->decl_node; |
| | 1611 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| | 1612 | AstNode *expr_node = decl_node->data.variable_declaration.expr; |
| | 1613 | ConstExprValue *const_val = &get_resolved_expr(expr_node)->const_val; |
| | 1614 | if (const_val->ok) { |
| | 1615 | return resolve_expr_const_val_as_other_expr(g, node, expr_node); |
| | 1616 | } |
| | 1617 | } |
| | 1618 | } |
| 1844 | return var->type; | 1619 | return var->type; |
| 1845 | } | 1620 | } |
| 1846 | | 1621 | |
| 1847 | TypeTableEntry *container_type = find_container(context, variable_name); | 1622 | TypeTableEntry *container_type = find_container(context, variable_name); |
| 1848 | if (container_type) { | 1623 | if (container_type) { |
| 1849 | TypeTableEntry *meta_type = get_meta_type(g, container_type); | 1624 | return resolve_expr_const_val_as_type(g, node, container_type); |
| 1850 | node->data.symbol_expr.meta_type = meta_type; | | |
| 1851 | return meta_type; | | |
| 1852 | } | 1625 | } |
| 1853 | | 1626 | |
| 1854 | auto fn_table_entry = import->fn_table.maybe_get(variable_name); | 1627 | auto fn_table_entry = import->fn_table.maybe_get(variable_name); |
| 1855 | if (fn_table_entry) { | 1628 | if (fn_table_entry) { |
| 1856 | node->data.symbol_expr.fn_entry = fn_table_entry->value; | 1629 | return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value); |
| 1857 | return node->data.symbol_expr.fn_entry->type_entry; | | |
| 1858 | } | 1630 | } |
| 1859 | | 1631 | |
| 1860 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); | 1632 | add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| ... | @@ -1990,10 +1762,148 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc | ... | @@ -1990,10 +1762,148 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc |
| 1990 | return expected_rhs_type; | 1762 | return expected_rhs_type; |
| 1991 | } | 1763 | } |
| 1992 | | 1764 | |
| | 1765 | static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) { |
| | 1766 | if (bin_op == BinOpTypeBoolOr) { |
| | 1767 | return a || b; |
| | 1768 | } else if (bin_op == BinOpTypeBoolAnd) { |
| | 1769 | return a && b; |
| | 1770 | } else { |
| | 1771 | zig_unreachable(); |
| | 1772 | } |
| | 1773 | } |
| | 1774 | |
| | 1775 | static bool eval_bool_bin_op_signed(int64_t a, BinOpType bin_op, int64_t b) { |
| | 1776 | if (bin_op == BinOpTypeCmpEq) { |
| | 1777 | return a == b; |
| | 1778 | } else if (bin_op == BinOpTypeCmpNotEq) { |
| | 1779 | return a != b; |
| | 1780 | } else if (bin_op == BinOpTypeCmpLessThan) { |
| | 1781 | return a < b; |
| | 1782 | } else if (bin_op == BinOpTypeCmpGreaterThan) { |
| | 1783 | return a > b; |
| | 1784 | } else if (bin_op == BinOpTypeCmpLessOrEq) { |
| | 1785 | return a <= b; |
| | 1786 | } else if (bin_op == BinOpTypeCmpGreaterOrEq) { |
| | 1787 | return a >= b; |
| | 1788 | } else { |
| | 1789 | zig_unreachable(); |
| | 1790 | } |
| | 1791 | } |
| | 1792 | |
| | 1793 | static bool eval_bool_bin_op_unsigned(uint64_t a, BinOpType bin_op, uint64_t b) { |
| | 1794 | if (bin_op == BinOpTypeCmpEq) { |
| | 1795 | return a == b; |
| | 1796 | } else if (bin_op == BinOpTypeCmpNotEq) { |
| | 1797 | return a != b; |
| | 1798 | } else if (bin_op == BinOpTypeCmpLessThan) { |
| | 1799 | return a < b; |
| | 1800 | } else if (bin_op == BinOpTypeCmpGreaterThan) { |
| | 1801 | return a > b; |
| | 1802 | } else if (bin_op == BinOpTypeCmpLessOrEq) { |
| | 1803 | return a <= b; |
| | 1804 | } else if (bin_op == BinOpTypeCmpGreaterOrEq) { |
| | 1805 | return a >= b; |
| | 1806 | } else { |
| | 1807 | zig_unreachable(); |
| | 1808 | } |
| | 1809 | } |
| | 1810 | |
| | 1811 | static bool eval_bool_bin_op_float(double a, BinOpType bin_op, double b) { |
| | 1812 | if (bin_op == BinOpTypeCmpEq) { |
| | 1813 | return a == b; |
| | 1814 | } else if (bin_op == BinOpTypeCmpNotEq) { |
| | 1815 | return a != b; |
| | 1816 | } else if (bin_op == BinOpTypeCmpLessThan) { |
| | 1817 | return a < b; |
| | 1818 | } else if (bin_op == BinOpTypeCmpGreaterThan) { |
| | 1819 | return a > b; |
| | 1820 | } else if (bin_op == BinOpTypeCmpLessOrEq) { |
| | 1821 | return a <= b; |
| | 1822 | } else if (bin_op == BinOpTypeCmpGreaterOrEq) { |
| | 1823 | return a >= b; |
| | 1824 | } else { |
| | 1825 | zig_unreachable(); |
| | 1826 | } |
| | 1827 | } |
| | 1828 | |
| | 1829 | static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 1830 | AstNode *node) |
| | 1831 | { |
| | 1832 | assert(node->type == NodeTypeBinOpExpr); |
| | 1833 | BinOpType bin_op_type = node->data.bin_op_expr.bin_op; |
| | 1834 | |
| | 1835 | AstNode *op1 = node->data.bin_op_expr.op1; |
| | 1836 | AstNode *op2 = node->data.bin_op_expr.op2; |
| | 1837 | TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, op1); |
| | 1838 | TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, op2); |
| | 1839 | |
| | 1840 | TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node, |
| | 1841 | op1, op2, op1_type, op2_type); |
| | 1842 | |
| | 1843 | if (resolved_type->id == TypeTableEntryIdInvalid) { |
| | 1844 | return g->builtin_types.entry_invalid; |
| | 1845 | } |
| | 1846 | |
| | 1847 | ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val; |
| | 1848 | ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val; |
| | 1849 | if (!op1_val->ok || !op2_val->ok) { |
| | 1850 | return g->builtin_types.entry_bool; |
| | 1851 | } |
| | 1852 | |
| | 1853 | bool answer; |
| | 1854 | if (resolved_type->id == TypeTableEntryIdInt) { |
| | 1855 | if (op1_type->data.integral.is_signed && |
| | 1856 | op2_type->data.integral.is_signed) |
| | 1857 | { |
| | 1858 | answer = eval_bool_bin_op_signed(op1_val->data.x_int, bin_op_type, op2_val->data.x_int); |
| | 1859 | } else if (!op1_type->data.integral.is_signed && |
| | 1860 | !op2_type->data.integral.is_signed) |
| | 1861 | { |
| | 1862 | answer = eval_bool_bin_op_unsigned(op1_val->data.x_uint, bin_op_type, op2_val->data.x_uint); |
| | 1863 | } else { |
| | 1864 | zig_unreachable(); |
| | 1865 | } |
| | 1866 | } else if (resolved_type->id == TypeTableEntryIdFloat) { |
| | 1867 | answer = eval_bool_bin_op_float(op1_val->data.x_float, bin_op_type, op2_val->data.x_float); |
| | 1868 | } else { |
| | 1869 | zig_unreachable(); |
| | 1870 | } |
| | 1871 | |
| | 1872 | return resolve_expr_const_val_as_bool(g, node, answer); |
| | 1873 | } |
| | 1874 | |
| | 1875 | static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 1876 | AstNode *node) |
| | 1877 | { |
| | 1878 | assert(node->type == NodeTypeBinOpExpr); |
| | 1879 | BinOpType bin_op_type = node->data.bin_op_expr.bin_op; |
| | 1880 | |
| | 1881 | AstNode *op1 = node->data.bin_op_expr.op1; |
| | 1882 | AstNode *op2 = node->data.bin_op_expr.op2; |
| | 1883 | TypeTableEntry *op1_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op1); |
| | 1884 | TypeTableEntry *op2_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op2); |
| | 1885 | |
| | 1886 | if (op1_type->id == TypeTableEntryIdInvalid || |
| | 1887 | op2_type->id == TypeTableEntryIdInvalid) |
| | 1888 | { |
| | 1889 | return g->builtin_types.entry_invalid; |
| | 1890 | } |
| | 1891 | |
| | 1892 | ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val; |
| | 1893 | ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val; |
| | 1894 | if (!op1_val->ok || !op2_val->ok) { |
| | 1895 | return g->builtin_types.entry_bool; |
| | 1896 | } |
| | 1897 | |
| | 1898 | bool answer = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op_type, op2_val->data.x_bool); |
| | 1899 | return resolve_expr_const_val_as_bool(g, node, answer); |
| | 1900 | } |
| | 1901 | |
| 1993 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1902 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1994 | TypeTableEntry *expected_type, AstNode *node) | 1903 | TypeTableEntry *expected_type, AstNode *node) |
| 1995 | { | 1904 | { |
| 1996 | switch (node->data.bin_op_expr.bin_op) { | 1905 | BinOpType bin_op_type = node->data.bin_op_expr.bin_op; |
| | 1906 | switch (bin_op_type) { |
| 1997 | case BinOpTypeAssign: | 1907 | case BinOpTypeAssign: |
| 1998 | case BinOpTypeAssignTimes: | 1908 | case BinOpTypeAssignTimes: |
| 1999 | case BinOpTypeAssignDiv: | 1909 | case BinOpTypeAssignDiv: |
| ... | @@ -2025,25 +1935,14 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2025,25 +1935,14 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 2025 | } | 1935 | } |
| 2026 | case BinOpTypeBoolOr: | 1936 | case BinOpTypeBoolOr: |
| 2027 | case BinOpTypeBoolAnd: | 1937 | case BinOpTypeBoolAnd: |
| 2028 | analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.bin_op_expr.op1); | 1938 | return analyze_logic_bin_op_expr(g, import, context, node); |
| 2029 | analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.bin_op_expr.op2); | | |
| 2030 | return g->builtin_types.entry_bool; | | |
| 2031 | case BinOpTypeCmpEq: | 1939 | case BinOpTypeCmpEq: |
| 2032 | case BinOpTypeCmpNotEq: | 1940 | case BinOpTypeCmpNotEq: |
| 2033 | case BinOpTypeCmpLessThan: | 1941 | case BinOpTypeCmpLessThan: |
| 2034 | case BinOpTypeCmpGreaterThan: | 1942 | case BinOpTypeCmpGreaterThan: |
| 2035 | case BinOpTypeCmpLessOrEq: | 1943 | case BinOpTypeCmpLessOrEq: |
| 2036 | case BinOpTypeCmpGreaterOrEq: | 1944 | case BinOpTypeCmpGreaterOrEq: |
| 2037 | { | 1945 | return analyze_bool_bin_op_expr(g, import, context, node); |
| 2038 | AstNode *op1 = node->data.bin_op_expr.op1; | | |
| 2039 | AstNode *op2 = node->data.bin_op_expr.op2; | | |
| 2040 | TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1); | | |
| 2041 | TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2); | | |
| 2042 | | | |
| 2043 | resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type); | | |
| 2044 | | | |
| 2045 | return g->builtin_types.entry_bool; | | |
| 2046 | } | | |
| 2047 | case BinOpTypeBinOr: | 1946 | case BinOpTypeBinOr: |
| 2048 | case BinOpTypeBinXor: | 1947 | case BinOpTypeBinXor: |
| 2049 | case BinOpTypeBinAnd: | 1948 | case BinOpTypeBinAnd: |
| ... | @@ -2178,30 +2077,41 @@ static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -2178,30 +2077,41 @@ static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *i |
| 2178 | { | 2077 | { |
| 2179 | assert(node->type == NodeTypeNullLiteral); | 2078 | assert(node->type == NodeTypeNullLiteral); |
| 2180 | | 2079 | |
| 2181 | if (expected_type) { | 2080 | if (!expected_type) { |
| 2182 | assert(expected_type->id == TypeTableEntryIdMaybe); | | |
| 2183 | | | |
| 2184 | node->data.null_literal.resolved_struct_val_expr.type_entry = expected_type; | | |
| 2185 | node->data.null_literal.resolved_struct_val_expr.source_node = node; | | |
| 2186 | block_context->struct_val_expr_alloca_list.append(&node->data.null_literal.resolved_struct_val_expr); | | |
| 2187 | | | |
| 2188 | return expected_type; | | |
| 2189 | } else { | | |
| 2190 | add_node_error(g, node, | 2081 | add_node_error(g, node, |
| 2191 | buf_sprintf("unable to determine null type")); | 2082 | buf_sprintf("unable to determine null type")); |
| 2192 | return g->builtin_types.entry_invalid; | 2083 | return g->builtin_types.entry_invalid; |
| 2193 | } | 2084 | } |
| | 2085 | |
| | 2086 | assert(expected_type->id == TypeTableEntryIdMaybe); |
| | 2087 | |
| | 2088 | node->data.null_literal.resolved_struct_val_expr.type_entry = expected_type; |
| | 2089 | node->data.null_literal.resolved_struct_val_expr.source_node = node; |
| | 2090 | block_context->struct_val_expr_alloca_list.append(&node->data.null_literal.resolved_struct_val_expr); |
| | 2091 | |
| | 2092 | return resolve_expr_const_val_as_null(g, node, expected_type); |
| 2194 | } | 2093 | } |
| 2195 | | 2094 | |
| 2196 | static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, | 2095 | static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, |
| 2197 | BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) | 2096 | BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) |
| 2198 | { | 2097 | { |
| 2199 | TypeTableEntry *num_lit_type = g->num_lit_types[node->data.number_literal.kind]; | | |
| 2200 | if (node->data.number_literal.overflow) { | 2098 | if (node->data.number_literal.overflow) { |
| 2201 | add_node_error(g, node, | 2099 | add_node_error(g, node, buf_sprintf("number literal too large to be represented in any type")); |
| 2202 | buf_sprintf("number literal too large to be represented in any type")); | | |
| 2203 | return g->builtin_types.entry_invalid; | 2100 | return g->builtin_types.entry_invalid; |
| 2204 | } else if (expected_type) { | 2101 | } |
| | 2102 | |
| | 2103 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| | 2104 | const_val->ok = true; |
| | 2105 | if (is_num_lit_unsigned(node->data.number_literal.kind)) { |
| | 2106 | const_val->data.x_uint = node->data.number_literal.data.x_uint; |
| | 2107 | } else if (is_num_lit_float(node->data.number_literal.kind)) { |
| | 2108 | const_val->data.x_float = node->data.number_literal.data.x_float; |
| | 2109 | } else { |
| | 2110 | zig_unreachable(); |
| | 2111 | } |
| | 2112 | |
| | 2113 | TypeTableEntry *num_lit_type = g->num_lit_types[node->data.number_literal.kind]; |
| | 2114 | if (expected_type) { |
| 2205 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); | 2115 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); |
| 2206 | assert(!codegen_num_lit->resolved_type); | 2116 | assert(!codegen_num_lit->resolved_type); |
| 2207 | TypeTableEntry *after_implicit_cast_resolved_type = | 2117 | TypeTableEntry *after_implicit_cast_resolved_type = |
| ... | @@ -2235,18 +2145,17 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, | ... | @@ -2235,18 +2145,17 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, |
| 2235 | return g->builtin_types.entry_invalid; | 2145 | return g->builtin_types.entry_invalid; |
| 2236 | } | 2146 | } |
| 2237 | | 2147 | |
| 2238 | ConstExprValue const_val = {0}; | 2148 | ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val; |
| 2239 | eval_const_expr(g, context, size_node, &const_val); | 2149 | if (const_val->ok) { |
| 2240 | | 2150 | return resolve_expr_const_val_as_type(g, node, |
| 2241 | if (const_val.ok) { | 2151 | get_array_type(g, import, child_type, const_val->data.x_uint)); |
| 2242 | return get_meta_type(g, get_array_type(g, import, child_type, const_val.data.x_uint)); | | |
| 2243 | } else { | 2152 | } else { |
| 2244 | add_node_error(g, size_node, | 2153 | add_node_error(g, size_node, buf_create_from_str("unable to resolve constant expression")); |
| 2245 | buf_create_from_str("unable to resolve constant expression")); | | |
| 2246 | return g->builtin_types.entry_invalid; | 2154 | return g->builtin_types.entry_invalid; |
| 2247 | } | 2155 | } |
| 2248 | } else { | 2156 | } else { |
| 2249 | return get_meta_type(g, get_unknown_size_array_type(g, import, child_type, node->data.array_type.is_const)); | 2157 | return resolve_expr_const_val_as_type(g, node, |
| | 2158 | get_unknown_size_array_type(g, import, child_type, node->data.array_type.is_const)); |
| 2250 | } | 2159 | } |
| 2251 | } | 2160 | } |
| 2252 | | 2161 | |
| ... | @@ -2271,11 +2180,9 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2271,11 +2180,9 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, |
| 2271 | } else { | 2180 | } else { |
| 2272 | // if the condition is a simple constant expression and there are no break statements | 2181 | // if the condition is a simple constant expression and there are no break statements |
| 2273 | // then the return type is unreachable | 2182 | // then the return type is unreachable |
| 2274 | ConstExprValue const_val = {0}; | 2183 | ConstExprValue *const_val = &get_resolved_expr(condition_node)->const_val; |
| 2275 | eval_const_expr(g, context, condition_node, &const_val); | 2184 | if (const_val->ok) { |
| 2276 | | 2185 | if (const_val->data.x_bool) { |
| 2277 | if (const_val.ok) { | | |
| 2278 | if (const_val.data.x_bool) { | | |
| 2279 | node->data.while_expr.condition_always_true = true; | 2186 | node->data.while_expr.condition_always_true = true; |
| 2280 | if (!node->data.while_expr.contains_break) { | 2187 | if (!node->data.while_expr.contains_break) { |
| 2281 | expr_return_type = g->builtin_types.entry_unreachable; | 2188 | expr_return_type = g->builtin_types.entry_unreachable; |
| ... | @@ -2360,19 +2267,23 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -2360,19 +2267,23 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 2360 | } | 2267 | } |
| 2361 | | 2268 | |
| 2362 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2269 | static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2363 | AstNode *node, const char *err_format) | 2270 | AstNode *node, const char *err_format, bool is_max) |
| 2364 | { | 2271 | { |
| 2365 | assert(node->type == NodeTypeFnCallExpr); | 2272 | assert(node->type == NodeTypeFnCallExpr); |
| 2366 | assert(node->data.fn_call_expr.params.length == 1); | 2273 | assert(node->data.fn_call_expr.params.length == 1); |
| 2367 | | 2274 | |
| 2368 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | 2275 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 2369 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | 2276 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 2370 | if (type_entry->id == TypeTableEntryIdInt || | 2277 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2371 | type_entry->id == TypeTableEntryIdFloat || | 2278 | return g->builtin_types.entry_invalid; |
| 2372 | type_entry->id == TypeTableEntryIdBool || | 2279 | } else if (type_entry->id == TypeTableEntryIdInt) { |
| 2373 | type_entry->id == TypeTableEntryIdInvalid) | 2280 | // TODO const expr eval for min/max int |
| 2374 | { | | |
| 2375 | return type_entry; | 2281 | return type_entry; |
| | 2282 | } else if (type_entry->id == TypeTableEntryIdFloat) { |
| | 2283 | // TODO const expr eval for min/max float |
| | 2284 | return type_entry; |
| | 2285 | } else if (type_entry->id == TypeTableEntryIdBool) { |
| | 2286 | return resolve_expr_const_val_as_bool(g, node, is_max); |
| 2376 | } else { | 2287 | } else { |
| 2377 | add_node_error(g, node, | 2288 | add_node_error(g, node, |
| 2378 | buf_sprintf(err_format, buf_ptr(&type_entry->name))); | 2289 | buf_sprintf(err_format, buf_ptr(&type_entry->name))); |
| ... | @@ -2380,8 +2291,46 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor | ... | @@ -2380,8 +2291,46 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor |
| 2380 | } | 2291 | } |
| 2381 | } | 2292 | } |
| 2382 | | 2293 | |
| | 2294 | static void eval_const_expr_implicit_cast(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| | 2295 | AstNode *node, Cast *cast, AstNode *expr_node) |
| | 2296 | { |
| | 2297 | switch (cast->op) { |
| | 2298 | case CastOpNothing: |
| | 2299 | case CastOpPtrToInt: |
| | 2300 | case CastOpIntWidenOrShorten: |
| | 2301 | case CastOpPointerReinterpret: |
| | 2302 | { |
| | 2303 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; |
| | 2304 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| | 2305 | if (other_val != const_val) { |
| | 2306 | *const_val = *other_val; |
| | 2307 | } |
| | 2308 | break; |
| | 2309 | } |
| | 2310 | case CastOpToUnknownSizeArray: |
| | 2311 | // TODO eval const expr |
| | 2312 | break; |
| | 2313 | case CastOpMaybeWrap: |
| | 2314 | { |
| | 2315 | ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val; |
| | 2316 | ConstExprValue *const_val = &get_resolved_expr(node)->const_val; |
| | 2317 | if (!other_val->ok) { |
| | 2318 | break; |
| | 2319 | } else if (const_val == other_val) { |
| | 2320 | ConstExprValue *new_val = allocate<ConstExprValue>(1); |
| | 2321 | memcpy(new_val, other_val, sizeof(ConstExprValue)); |
| | 2322 | other_val = new_val; |
| | 2323 | } |
| | 2324 | |
| | 2325 | const_val->data.x_maybe = other_val; |
| | 2326 | const_val->ok = true; |
| | 2327 | break; |
| | 2328 | } |
| | 2329 | } |
| | 2330 | } |
| | 2331 | |
| 2383 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2332 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2384 | AstNode *node, TypeTableEntry *invoke_type_entry) | 2333 | AstNode *node) |
| 2385 | { | 2334 | { |
| 2386 | assert(node->type == NodeTypeFnCallExpr); | 2335 | assert(node->type == NodeTypeFnCallExpr); |
| 2387 | | 2336 | |
| ... | @@ -2394,7 +2343,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -2394,7 +2343,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2394 | } | 2343 | } |
| 2395 | | 2344 | |
| 2396 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); | 2345 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); |
| 2397 | TypeTableEntry *wanted_type = invoke_type_entry->data.meta_type.child_type; | 2346 | TypeTableEntry *wanted_type = resolve_type(g, fn_ref_expr); |
| 2398 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node); | 2347 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node); |
| 2399 | | 2348 | |
| 2400 | if (wanted_type->id == TypeTableEntryIdInvalid || | 2349 | if (wanted_type->id == TypeTableEntryIdInvalid || |
| ... | @@ -2411,11 +2360,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -2411,11 +2360,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2411 | actual_type->id == TypeTableEntryIdPointer) | 2360 | actual_type->id == TypeTableEntryIdPointer) |
| 2412 | { | 2361 | { |
| 2413 | cast->op = CastOpPtrToInt; | 2362 | cast->op = CastOpPtrToInt; |
| | 2363 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2414 | return wanted_type; | 2364 | return wanted_type; |
| 2415 | } else if (wanted_type->id == TypeTableEntryIdInt && | 2365 | } else if (wanted_type->id == TypeTableEntryIdInt && |
| 2416 | actual_type->id == TypeTableEntryIdInt) | 2366 | actual_type->id == TypeTableEntryIdInt) |
| 2417 | { | 2367 | { |
| 2418 | cast->op = CastOpIntWidenOrShorten; | 2368 | cast->op = CastOpIntWidenOrShorten; |
| | 2369 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2419 | return wanted_type; | 2370 | return wanted_type; |
| 2420 | } else if (wanted_type->id == TypeTableEntryIdStruct && | 2371 | } else if (wanted_type->id == TypeTableEntryIdStruct && |
| 2421 | wanted_type->data.structure.is_unknown_size_array && | 2372 | wanted_type->data.structure.is_unknown_size_array && |
| ... | @@ -2424,6 +2375,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -2424,6 +2375,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2424 | { | 2375 | { |
| 2425 | cast->op = CastOpToUnknownSizeArray; | 2376 | cast->op = CastOpToUnknownSizeArray; |
| 2426 | context->cast_expr_alloca_list.append(cast); | 2377 | context->cast_expr_alloca_list.append(cast); |
| | 2378 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2427 | return wanted_type; | 2379 | return wanted_type; |
| 2428 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && | 2380 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && |
| 2429 | num_lit_fits_in_other_type(g, actual_type, wanted_type)) | 2381 | num_lit_fits_in_other_type(g, actual_type, wanted_type)) |
| ... | @@ -2432,11 +2384,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B | ... | @@ -2432,11 +2384,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2432 | assert(!codegen_num_lit->resolved_type); | 2384 | assert(!codegen_num_lit->resolved_type); |
| 2433 | codegen_num_lit->resolved_type = wanted_type; | 2385 | codegen_num_lit->resolved_type = wanted_type; |
| 2434 | cast->op = CastOpNothing; | 2386 | cast->op = CastOpNothing; |
| | 2387 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2435 | return wanted_type; | 2388 | return wanted_type; |
| 2436 | } else if (actual_type->id == TypeTableEntryIdPointer && | 2389 | } else if (actual_type->id == TypeTableEntryIdPointer && |
| 2437 | wanted_type->id == TypeTableEntryIdPointer) | 2390 | wanted_type->id == TypeTableEntryIdPointer) |
| 2438 | { | 2391 | { |
| 2439 | cast->op = CastOpPointerReinterpret; | 2392 | cast->op = CastOpPointerReinterpret; |
| | 2393 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2440 | return wanted_type; | 2394 | return wanted_type; |
| 2441 | } else { | 2395 | } else { |
| 2442 | add_node_error(g, node, | 2396 | add_node_error(g, node, |
| ... | @@ -2457,165 +2411,160 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -2457,165 +2411,160 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 2457 | | 2411 | |
| 2458 | auto entry = g->builtin_fn_table.maybe_get(name); | 2412 | auto entry = g->builtin_fn_table.maybe_get(name); |
| 2459 | | 2413 | |
| 2460 | if (entry) { | 2414 | if (!entry) { |
| 2461 | BuiltinFnEntry *builtin_fn = entry->value; | 2415 | add_node_error(g, node, |
| 2462 | int actual_param_count = node->data.fn_call_expr.params.length; | 2416 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); |
| | 2417 | return g->builtin_types.entry_invalid; |
| | 2418 | } |
| 2463 | | 2419 | |
| 2464 | node->data.fn_call_expr.builtin_fn = builtin_fn; | 2420 | BuiltinFnEntry *builtin_fn = entry->value; |
| | 2421 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 2465 | | 2422 | |
| 2466 | if (builtin_fn->param_count != actual_param_count) { | 2423 | node->data.fn_call_expr.builtin_fn = builtin_fn; |
| 2467 | add_node_error(g, node, | | |
| 2468 | buf_sprintf("expected %d arguments, got %d", | | |
| 2469 | builtin_fn->param_count, actual_param_count)); | | |
| 2470 | return g->builtin_types.entry_invalid; | | |
| 2471 | } | | |
| 2472 | | 2424 | |
| 2473 | switch (builtin_fn->id) { | 2425 | if (builtin_fn->param_count != actual_param_count) { |
| 2474 | case BuiltinFnIdInvalid: | 2426 | add_node_error(g, node, |
| 2475 | zig_unreachable(); | 2427 | buf_sprintf("expected %d arguments, got %d", |
| 2476 | case BuiltinFnIdAddWithOverflow: | 2428 | builtin_fn->param_count, actual_param_count)); |
| 2477 | case BuiltinFnIdSubWithOverflow: | 2429 | return g->builtin_types.entry_invalid; |
| 2478 | case BuiltinFnIdMulWithOverflow: | 2430 | } |
| 2479 | { | | |
| 2480 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | | |
| 2481 | TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node); | | |
| 2482 | if (int_type->id == TypeTableEntryIdInvalid) { | | |
| 2483 | return g->builtin_types.entry_bool; | | |
| 2484 | } else if (int_type->id == TypeTableEntryIdInt) { | | |
| 2485 | AstNode *op1_node = node->data.fn_call_expr.params.at(1); | | |
| 2486 | AstNode *op2_node = node->data.fn_call_expr.params.at(2); | | |
| 2487 | AstNode *result_node = node->data.fn_call_expr.params.at(3); | | |
| 2488 | | | |
| 2489 | analyze_expression(g, import, context, int_type, op1_node); | | |
| 2490 | analyze_expression(g, import, context, int_type, op2_node); | | |
| 2491 | analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false), | | |
| 2492 | result_node); | | |
| 2493 | } else { | | |
| 2494 | add_node_error(g, type_node, | | |
| 2495 | buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name))); | | |
| 2496 | } | | |
| 2497 | | 2431 | |
| | 2432 | switch (builtin_fn->id) { |
| | 2433 | case BuiltinFnIdInvalid: |
| | 2434 | zig_unreachable(); |
| | 2435 | case BuiltinFnIdAddWithOverflow: |
| | 2436 | case BuiltinFnIdSubWithOverflow: |
| | 2437 | case BuiltinFnIdMulWithOverflow: |
| | 2438 | { |
| | 2439 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| | 2440 | TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node); |
| | 2441 | if (int_type->id == TypeTableEntryIdInvalid) { |
| 2498 | return g->builtin_types.entry_bool; | 2442 | return g->builtin_types.entry_bool; |
| | 2443 | } else if (int_type->id == TypeTableEntryIdInt) { |
| | 2444 | AstNode *op1_node = node->data.fn_call_expr.params.at(1); |
| | 2445 | AstNode *op2_node = node->data.fn_call_expr.params.at(2); |
| | 2446 | AstNode *result_node = node->data.fn_call_expr.params.at(3); |
| | 2447 | |
| | 2448 | analyze_expression(g, import, context, int_type, op1_node); |
| | 2449 | analyze_expression(g, import, context, int_type, op2_node); |
| | 2450 | analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false), |
| | 2451 | result_node); |
| | 2452 | } else { |
| | 2453 | add_node_error(g, type_node, |
| | 2454 | buf_sprintf("expected integer type, got '%s'", buf_ptr(&int_type->name))); |
| 2499 | } | 2455 | } |
| 2500 | case BuiltinFnIdMemcpy: | | |
| 2501 | { | | |
| 2502 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); | | |
| 2503 | AstNode *src_node = node->data.fn_call_expr.params.at(1); | | |
| 2504 | AstNode *len_node = node->data.fn_call_expr.params.at(2); | | |
| 2505 | TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); | | |
| 2506 | TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node); | | |
| 2507 | analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); | | |
| 2508 | | | |
| 2509 | if (dest_type->id != TypeTableEntryIdInvalid && | | |
| 2510 | dest_type->id != TypeTableEntryIdPointer) | | |
| 2511 | { | | |
| 2512 | add_node_error(g, dest_node, | | |
| 2513 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name))); | | |
| 2514 | } | | |
| 2515 | | | |
| 2516 | if (src_type->id != TypeTableEntryIdInvalid && | | |
| 2517 | src_type->id != TypeTableEntryIdPointer) | | |
| 2518 | { | | |
| 2519 | add_node_error(g, src_node, | | |
| 2520 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&src_type->name))); | | |
| 2521 | } | | |
| 2522 | | 2456 | |
| 2523 | if (dest_type->id == TypeTableEntryIdPointer && | 2457 | // TODO constant expression evaluation |
| 2524 | src_type->id == TypeTableEntryIdPointer) | | |
| 2525 | { | | |
| 2526 | uint64_t dest_align_bits = dest_type->data.pointer.child_type->align_in_bits; | | |
| 2527 | uint64_t src_align_bits = src_type->data.pointer.child_type->align_in_bits; | | |
| 2528 | if (dest_align_bits != src_align_bits) { | | |
| 2529 | add_node_error(g, dest_node, buf_sprintf( | | |
| 2530 | "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64, | | |
| 2531 | buf_ptr(&dest_type->name), dest_align_bits / 8, | | |
| 2532 | buf_ptr(&src_type->name), src_align_bits / 8)); | | |
| 2533 | } | | |
| 2534 | } | | |
| 2535 | | 2458 | |
| 2536 | return builtin_fn->return_type; | 2459 | return g->builtin_types.entry_bool; |
| 2537 | } | 2460 | } |
| 2538 | case BuiltinFnIdMemset: | 2461 | case BuiltinFnIdMemcpy: |
| | 2462 | { |
| | 2463 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| | 2464 | AstNode *src_node = node->data.fn_call_expr.params.at(1); |
| | 2465 | AstNode *len_node = node->data.fn_call_expr.params.at(2); |
| | 2466 | TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); |
| | 2467 | TypeTableEntry *src_type = analyze_expression(g, import, context, nullptr, src_node); |
| | 2468 | analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); |
| | 2469 | |
| | 2470 | if (dest_type->id != TypeTableEntryIdInvalid && |
| | 2471 | dest_type->id != TypeTableEntryIdPointer) |
| 2539 | { | 2472 | { |
| 2540 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); | 2473 | add_node_error(g, dest_node, |
| 2541 | AstNode *char_node = node->data.fn_call_expr.params.at(1); | 2474 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name))); |
| 2542 | AstNode *len_node = node->data.fn_call_expr.params.at(2); | | |
| 2543 | TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); | | |
| 2544 | analyze_expression(g, import, context, builtin_fn->param_types[1], char_node); | | |
| 2545 | analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); | | |
| 2546 | | | |
| 2547 | if (dest_type->id != TypeTableEntryIdInvalid && | | |
| 2548 | dest_type->id != TypeTableEntryIdPointer) | | |
| 2549 | { | | |
| 2550 | add_node_error(g, dest_node, | | |
| 2551 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name))); | | |
| 2552 | } | | |
| 2553 | | | |
| 2554 | return builtin_fn->return_type; | | |
| 2555 | } | 2475 | } |
| 2556 | case BuiltinFnIdSizeof: | 2476 | |
| | 2477 | if (src_type->id != TypeTableEntryIdInvalid && |
| | 2478 | src_type->id != TypeTableEntryIdPointer) |
| 2557 | { | 2479 | { |
| 2558 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | 2480 | add_node_error(g, src_node, |
| 2559 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | 2481 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&src_type->name))); |
| 2560 | if (type_entry->id == TypeTableEntryIdInvalid) { | 2482 | } |
| 2561 | return g->builtin_types.entry_invalid; | | |
| 2562 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { | | |
| 2563 | add_node_error(g, first_executing_node(type_node), | | |
| 2564 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); | | |
| 2565 | return g->builtin_types.entry_invalid; | | |
| 2566 | } else { | | |
| 2567 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; | | |
| 2568 | | 2483 | |
| 2569 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); | 2484 | if (dest_type->id == TypeTableEntryIdPointer && |
| 2570 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | 2485 | src_type->id == TypeTableEntryIdPointer) |
| 2571 | return resolved_type ? resolved_type : num_lit_type; | 2486 | { |
| | 2487 | uint64_t dest_align_bits = dest_type->data.pointer.child_type->align_in_bits; |
| | 2488 | uint64_t src_align_bits = src_type->data.pointer.child_type->align_in_bits; |
| | 2489 | if (dest_align_bits != src_align_bits) { |
| | 2490 | add_node_error(g, dest_node, buf_sprintf( |
| | 2491 | "misaligned memcpy, '%s' has alignment '%" PRIu64 ", '%s' has alignment %" PRIu64, |
| | 2492 | buf_ptr(&dest_type->name), dest_align_bits / 8, |
| | 2493 | buf_ptr(&src_type->name), src_align_bits / 8)); |
| 2572 | } | 2494 | } |
| 2573 | } | 2495 | } |
| 2574 | case BuiltinFnIdMaxValue: | | |
| 2575 | return analyze_min_max_value(g, import, context, node, "no max value available for type '%s'"); | | |
| 2576 | case BuiltinFnIdMinValue: | | |
| 2577 | return analyze_min_max_value(g, import, context, node, "no min value available for type '%s'"); | | |
| 2578 | case BuiltinFnIdValueCount: | | |
| 2579 | { | | |
| 2580 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | | |
| 2581 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); | | |
| 2582 | | 2496 | |
| 2583 | if (type_entry->id == TypeTableEntryIdInvalid) { | 2497 | return builtin_fn->return_type; |
| 2584 | return type_entry; | 2498 | } |
| 2585 | } else if (type_entry->id == TypeTableEntryIdEnum) { | 2499 | case BuiltinFnIdMemset: |
| 2586 | uint64_t value_count = type_entry->data.enumeration.field_count; | 2500 | { |
| | 2501 | AstNode *dest_node = node->data.fn_call_expr.params.at(0); |
| | 2502 | AstNode *char_node = node->data.fn_call_expr.params.at(1); |
| | 2503 | AstNode *len_node = node->data.fn_call_expr.params.at(2); |
| | 2504 | TypeTableEntry *dest_type = analyze_expression(g, import, context, nullptr, dest_node); |
| | 2505 | analyze_expression(g, import, context, builtin_fn->param_types[1], char_node); |
| | 2506 | analyze_expression(g, import, context, builtin_fn->param_types[2], len_node); |
| | 2507 | |
| | 2508 | if (dest_type->id != TypeTableEntryIdInvalid && |
| | 2509 | dest_type->id != TypeTableEntryIdPointer) |
| | 2510 | { |
| | 2511 | add_node_error(g, dest_node, |
| | 2512 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name))); |
| | 2513 | } |
| 2587 | | 2514 | |
| 2588 | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, value_count); | 2515 | return builtin_fn->return_type; |
| 2589 | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); | 2516 | } |
| 2590 | return resolved_type ? resolved_type : num_lit_type; | 2517 | case BuiltinFnIdSizeof: |
| | 2518 | { |
| | 2519 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| | 2520 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| | 2521 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| | 2522 | return g->builtin_types.entry_invalid; |
| | 2523 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { |
| | 2524 | add_node_error(g, first_executing_node(type_node), |
| | 2525 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); |
| | 2526 | return g->builtin_types.entry_invalid; |
| | 2527 | } else { |
| | 2528 | uint64_t size_in_bytes = type_entry->size_in_bits / 8; |
| | 2529 | return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, size_in_bytes); |
| | 2530 | } |
| | 2531 | } |
| | 2532 | case BuiltinFnIdMaxValue: |
| | 2533 | return analyze_min_max_value(g, import, context, node, |
| | 2534 | "no max value available for type '%s'", true); |
| | 2535 | case BuiltinFnIdMinValue: |
| | 2536 | return analyze_min_max_value(g, import, context, node, |
| | 2537 | "no min value available for type '%s'", false); |
| | 2538 | case BuiltinFnIdValueCount: |
| | 2539 | { |
| | 2540 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| | 2541 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 2591 | | 2542 | |
| 2592 | } else { | 2543 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2593 | add_node_error(g, node, | 2544 | return type_entry; |
| 2594 | buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name))); | 2545 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 2595 | return g->builtin_types.entry_invalid; | 2546 | uint64_t value_count = type_entry->data.enumeration.field_count; |
| 2596 | } | 2547 | return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, value_count); |
| | 2548 | } else { |
| | 2549 | add_node_error(g, node, |
| | 2550 | buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name))); |
| | 2551 | return g->builtin_types.entry_invalid; |
| 2597 | } | 2552 | } |
| 2598 | case BuiltinFnIdTypeof: | 2553 | } |
| 2599 | { | 2554 | case BuiltinFnIdTypeof: |
| 2600 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); | 2555 | { |
| 2601 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); | 2556 | AstNode *expr_node = node->data.fn_call_expr.params.at(0); |
| | 2557 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); |
| 2602 | | 2558 | |
| 2603 | if (type_entry->id == TypeTableEntryIdInvalid) { | 2559 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2604 | return g->builtin_types.entry_invalid; | 2560 | return g->builtin_types.entry_invalid; |
| 2605 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | 2561 | } else { |
| 2606 | add_node_error(g, node, buf_sprintf("expected expression, got type")); | 2562 | return resolve_expr_const_val_as_type(g, node, type_entry); |
| 2607 | } else { | | |
| 2608 | return get_meta_type(g, type_entry); | | |
| 2609 | } | | |
| 2610 | } | 2563 | } |
| | 2564 | } |
| 2611 | | 2565 | |
| 2612 | } | | |
| 2613 | zig_unreachable(); | | |
| 2614 | } else { | | |
| 2615 | add_node_error(g, node, | | |
| 2616 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); | | |
| 2617 | return g->builtin_types.entry_invalid; | | |
| 2618 | } | 2566 | } |
| | 2567 | zig_unreachable(); |
| 2619 | } | 2568 | } |
| 2620 | | 2569 | |
| 2621 | static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2570 | static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| ... | @@ -2707,30 +2656,35 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -2707,30 +2656,35 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2707 | } | 2656 | } |
| 2708 | } else if (struct_type->id == TypeTableEntryIdInvalid) { | 2657 | } else if (struct_type->id == TypeTableEntryIdInvalid) { |
| 2709 | return struct_type; | 2658 | return struct_type; |
| 2710 | } else if (struct_type->id == TypeTableEntryIdMetaType && | 2659 | } else if (struct_type->id == TypeTableEntryIdMetaType) { |
| 2711 | struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) | 2660 | TypeTableEntry *enum_type = resolve_type(g, first_param_expr); |
| 2712 | { | 2661 | |
| 2713 | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; | 2662 | if (enum_type->id == TypeTableEntryIdInvalid) { |
| 2714 | Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; | 2663 | return g->builtin_types.entry_invalid; |
| 2715 | int param_count = node->data.fn_call_expr.params.length; | 2664 | } else if (enum_type->id == TypeTableEntryIdEnum) { |
| 2716 | if (param_count > 1) { | 2665 | Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; |
| 2717 | add_node_error(g, first_executing_node(node->data.fn_call_expr.params.at(1)), | 2666 | int param_count = node->data.fn_call_expr.params.length; |
| 2718 | buf_sprintf("enum values accept only one parameter")); | 2667 | if (param_count > 1) { |
| 2719 | return enum_type; | 2668 | add_node_error(g, first_executing_node(node->data.fn_call_expr.params.at(1)), |
| 2720 | } else { | 2669 | buf_sprintf("enum values accept only one parameter")); |
| 2721 | AstNode *value_node; | 2670 | return enum_type; |
| 2722 | if (param_count == 1) { | | |
| 2723 | value_node = node->data.fn_call_expr.params.at(0); | | |
| 2724 | } else { | 2671 | } else { |
| 2725 | value_node = nullptr; | 2672 | AstNode *value_node; |
| 2726 | } | 2673 | if (param_count == 1) { |
| | 2674 | value_node = node->data.fn_call_expr.params.at(0); |
| | 2675 | } else { |
| | 2676 | value_node = nullptr; |
| | 2677 | } |
| 2727 | | 2678 | |
| 2728 | return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node, | 2679 | return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node, |
| 2729 | enum_type, field_name); | 2680 | enum_type, field_name); |
| | 2681 | } |
| | 2682 | } else { |
| | 2683 | add_node_error(g, first_param_expr, buf_sprintf("member reference base type not struct or enum")); |
| | 2684 | return g->builtin_types.entry_invalid; |
| 2730 | } | 2685 | } |
| 2731 | } else { | 2686 | } else { |
| 2732 | add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, | 2687 | add_node_error(g, first_param_expr, buf_sprintf("member reference base type not struct or enum")); |
| 2733 | buf_sprintf("member reference base type not struct or enum")); | | |
| 2734 | return g->builtin_types.entry_invalid; | 2688 | return g->builtin_types.entry_invalid; |
| 2735 | } | 2689 | } |
| 2736 | } | 2690 | } |
| ... | @@ -2742,18 +2696,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -2742,18 +2696,17 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2742 | | 2696 | |
| 2743 | // use constant expression evaluator to figure out the function at compile time. | 2697 | // use constant expression evaluator to figure out the function at compile time. |
| 2744 | // otherwise we treat this as a function pointer. | 2698 | // otherwise we treat this as a function pointer. |
| 2745 | ConstExprValue const_val = {0}; | 2699 | ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val; |
| 2746 | eval_const_expr(g, context, fn_ref_expr, &const_val); | | |
| 2747 | | 2700 | |
| 2748 | if (!const_val.ok) { | 2701 | if (!const_val->ok) { |
| 2749 | add_node_error(g, node, buf_sprintf("function pointers not yet supported")); | 2702 | add_node_error(g, node, buf_sprintf("function pointers not yet supported")); |
| 2750 | return g->builtin_types.entry_invalid; | 2703 | return g->builtin_types.entry_invalid; |
| 2751 | } | 2704 | } |
| 2752 | | 2705 | |
| 2753 | if (invoke_type_entry->id == TypeTableEntryIdMetaType) { | 2706 | if (invoke_type_entry->id == TypeTableEntryIdMetaType) { |
| 2754 | return analyze_cast_expr(g, import, context, node, invoke_type_entry); | 2707 | return analyze_cast_expr(g, import, context, node); |
| 2755 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { | 2708 | } else if (invoke_type_entry->id == TypeTableEntryIdFn) { |
| 2756 | return analyze_fn_call_raw(g, import, context, expected_type, node, const_val.data.x_fn, nullptr); | 2709 | return analyze_fn_call_raw(g, import, context, expected_type, node, const_val->data.x_fn, nullptr); |
| 2757 | } else { | 2710 | } else { |
| 2758 | add_node_error(g, fn_ref_expr, | 2711 | add_node_error(g, fn_ref_expr, |
| 2759 | buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); | 2712 | buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); |
| ... | @@ -2764,18 +2717,31 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -2764,18 +2717,31 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 2764 | static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2717 | static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2765 | TypeTableEntry *expected_type, AstNode *node) | 2718 | TypeTableEntry *expected_type, AstNode *node) |
| 2766 | { | 2719 | { |
| 2767 | switch (node->data.prefix_op_expr.prefix_op) { | 2720 | PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; |
| | 2721 | AstNode *expr_node = node->data.prefix_op_expr.primary_expr; |
| | 2722 | switch (prefix_op) { |
| 2768 | case PrefixOpInvalid: | 2723 | case PrefixOpInvalid: |
| 2769 | zig_unreachable(); | 2724 | zig_unreachable(); |
| 2770 | case PrefixOpBoolNot: | 2725 | case PrefixOpBoolNot: |
| 2771 | analyze_expression(g, import, context, g->builtin_types.entry_bool, | 2726 | { |
| 2772 | node->data.prefix_op_expr.primary_expr); | 2727 | TypeTableEntry *type_entry = analyze_expression(g, import, context, g->builtin_types.entry_bool, |
| 2773 | return g->builtin_types.entry_bool; | 2728 | expr_node); |
| | 2729 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| | 2730 | return g->builtin_types.entry_bool; |
| | 2731 | } |
| | 2732 | |
| | 2733 | ConstExprValue *target_const_val = &get_resolved_expr(expr_node)->const_val; |
| | 2734 | if (!target_const_val->ok) { |
| | 2735 | return g->builtin_types.entry_bool; |
| | 2736 | } |
| | 2737 | |
| | 2738 | bool answer = target_const_val->data.x_bool; |
| | 2739 | return resolve_expr_const_val_as_bool(g, node, answer); |
| | 2740 | } |
| 2774 | case PrefixOpBinNot: | 2741 | case PrefixOpBinNot: |
| 2775 | { | 2742 | { |
| 2776 | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; | | |
| 2777 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, | 2743 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, |
| 2778 | operand_node); | 2744 | expr_node); |
| 2779 | if (expr_type->id == TypeTableEntryIdInvalid) { | 2745 | if (expr_type->id == TypeTableEntryIdInvalid) { |
| 2780 | return expr_type; | 2746 | return expr_type; |
| 2781 | } else if (expr_type->id == TypeTableEntryIdInt || | 2747 | } else if (expr_type->id == TypeTableEntryIdInt || |
| ... | @@ -2784,16 +2750,15 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo | ... | @@ -2784,16 +2750,15 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2784 | { | 2750 | { |
| 2785 | return expr_type; | 2751 | return expr_type; |
| 2786 | } else { | 2752 | } else { |
| 2787 | add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'", | 2753 | add_node_error(g, expr_node, buf_sprintf("invalid binary not type: '%s'", |
| 2788 | buf_ptr(&expr_type->name))); | 2754 | buf_ptr(&expr_type->name))); |
| 2789 | return g->builtin_types.entry_invalid; | 2755 | return g->builtin_types.entry_invalid; |
| 2790 | } | 2756 | } |
| 2791 | } | 2757 | } |
| 2792 | case PrefixOpNegation: | 2758 | case PrefixOpNegation: |
| 2793 | { | 2759 | { |
| 2794 | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; | | |
| 2795 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, | 2760 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, |
| 2796 | operand_node); | 2761 | expr_node); |
| 2797 | if (expr_type->id == TypeTableEntryIdInvalid) { | 2762 | if (expr_type->id == TypeTableEntryIdInvalid) { |
| 2798 | return expr_type; | 2763 | return expr_type; |
| 2799 | } else if (expr_type->id == TypeTableEntryIdInt && | 2764 | } else if (expr_type->id == TypeTableEntryIdInt && |
| ... | @@ -2805,7 +2770,6 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo | ... | @@ -2805,7 +2770,6 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2805 | } else if (expr_type->id == TypeTableEntryIdNumberLiteral) { | 2770 | } else if (expr_type->id == TypeTableEntryIdNumberLiteral) { |
| 2806 | return expr_type; | 2771 | return expr_type; |
| 2807 | } else { | 2772 | } else { |
| 2808 | BREAKPOINT; | | |
| 2809 | add_node_error(g, node, buf_sprintf("invalid negation type: '%s'", | 2773 | add_node_error(g, node, buf_sprintf("invalid negation type: '%s'", |
| 2810 | buf_ptr(&expr_type->name))); | 2774 | buf_ptr(&expr_type->name))); |
| 2811 | return g->builtin_types.entry_invalid; | 2775 | return g->builtin_types.entry_invalid; |
| ... | @@ -2814,20 +2778,23 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo | ... | @@ -2814,20 +2778,23 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2814 | case PrefixOpAddressOf: | 2778 | case PrefixOpAddressOf: |
| 2815 | case PrefixOpConstAddressOf: | 2779 | case PrefixOpConstAddressOf: |
| 2816 | { | 2780 | { |
| 2817 | bool is_const = (node->data.prefix_op_expr.prefix_op == PrefixOpConstAddressOf); | 2781 | bool is_const = (prefix_op == PrefixOpConstAddressOf); |
| 2818 | | 2782 | |
| 2819 | TypeTableEntry *child_type = analyze_lvalue(g, import, context, | 2783 | TypeTableEntry *child_type = analyze_lvalue(g, import, context, |
| 2820 | node->data.prefix_op_expr.primary_expr, LValPurposeAddressOf, is_const); | 2784 | expr_node, LValPurposeAddressOf, is_const); |
| 2821 | | 2785 | |
| 2822 | if (child_type->id == TypeTableEntryIdInvalid) { | 2786 | if (child_type->id == TypeTableEntryIdInvalid) { |
| 2823 | return g->builtin_types.entry_invalid; | 2787 | return g->builtin_types.entry_invalid; |
| 2824 | } else if (child_type->id == TypeTableEntryIdMetaType) { | 2788 | } else if (child_type->id == TypeTableEntryIdMetaType) { |
| 2825 | TypeTableEntry *meta_child_type = child_type->data.meta_type.child_type; | 2789 | TypeTableEntry *meta_type = analyze_type_expr(g, import, context, expr_node); |
| 2826 | if (meta_child_type->id == TypeTableEntryIdUnreachable) { | 2790 | if (meta_type->id == TypeTableEntryIdInvalid) { |
| 2827 | add_node_error(g, node, | 2791 | return g->builtin_types.entry_invalid; |
| 2828 | buf_create_from_str("pointer to unreachable not allowed")); | 2792 | } else if (meta_type->id == TypeTableEntryIdUnreachable) { |
| | 2793 | add_node_error(g, node, buf_create_from_str("pointer to unreachable not allowed")); |
| | 2794 | return g->builtin_types.entry_invalid; |
| 2829 | } else { | 2795 | } else { |
| 2830 | return get_meta_type(g, get_pointer_to_type(g, meta_child_type, is_const)); | 2796 | return resolve_expr_const_val_as_type(g, node, |
| | 2797 | get_pointer_to_type(g, meta_type, is_const)); |
| 2831 | } | 2798 | } |
| 2832 | } else { | 2799 | } else { |
| 2833 | return get_pointer_to_type(g, child_type, is_const); | 2800 | return get_pointer_to_type(g, child_type, is_const); |
| ... | @@ -2835,14 +2802,13 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo | ... | @@ -2835,14 +2802,13 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2835 | } | 2802 | } |
| 2836 | case PrefixOpDereference: | 2803 | case PrefixOpDereference: |
| 2837 | { | 2804 | { |
| 2838 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, | 2805 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); |
| 2839 | node->data.prefix_op_expr.primary_expr); | | |
| 2840 | if (type_entry->id == TypeTableEntryIdInvalid) { | 2806 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2841 | return type_entry; | 2807 | return type_entry; |
| 2842 | } else if (type_entry->id == TypeTableEntryIdPointer) { | 2808 | } else if (type_entry->id == TypeTableEntryIdPointer) { |
| 2843 | return type_entry->data.pointer.child_type; | 2809 | return type_entry->data.pointer.child_type; |
| 2844 | } else { | 2810 | } else { |
| 2845 | add_node_error(g, node->data.prefix_op_expr.primary_expr, | 2811 | add_node_error(g, expr_node, |
| 2846 | buf_sprintf("indirection requires pointer operand ('%s' invalid)", | 2812 | buf_sprintf("indirection requires pointer operand ('%s' invalid)", |
| 2847 | buf_ptr(&type_entry->name))); | 2813 | buf_ptr(&type_entry->name))); |
| 2848 | return g->builtin_types.entry_invalid; | 2814 | return g->builtin_types.entry_invalid; |
| ... | @@ -2850,24 +2816,25 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo | ... | @@ -2850,24 +2816,25 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2850 | } | 2816 | } |
| 2851 | case PrefixOpMaybe: | 2817 | case PrefixOpMaybe: |
| 2852 | { | 2818 | { |
| 2853 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, | 2819 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); |
| 2854 | node->data.prefix_op_expr.primary_expr); | | |
| 2855 | | 2820 | |
| 2856 | if (type_entry->id == TypeTableEntryIdInvalid) { | 2821 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2857 | return type_entry; | 2822 | return type_entry; |
| 2858 | } else if (type_entry->id == TypeTableEntryIdMetaType) { | 2823 | } else if (type_entry->id == TypeTableEntryIdMetaType) { |
| 2859 | TypeTableEntry *child_type = type_entry->data.meta_type.child_type; | 2824 | TypeTableEntry *meta_type = resolve_type(g, expr_node); |
| 2860 | if (child_type->id == TypeTableEntryIdUnreachable) { | 2825 | if (meta_type->id == TypeTableEntryIdInvalid) { |
| | 2826 | return g->builtin_types.entry_invalid; |
| | 2827 | } else if (meta_type->id == TypeTableEntryIdUnreachable) { |
| 2861 | add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed")); | 2828 | add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed")); |
| 2862 | return g->builtin_types.entry_invalid; | 2829 | return g->builtin_types.entry_invalid; |
| 2863 | } else { | 2830 | } else { |
| 2864 | return get_meta_type(g, get_maybe_type(g, child_type)); | 2831 | return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type)); |
| 2865 | } | 2832 | } |
| 2866 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { | 2833 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 2867 | add_node_error(g, node->data.prefix_op_expr.primary_expr, | 2834 | add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in maybe type")); |
| 2868 | buf_sprintf("unable to wrap unreachable in maybe type")); | | |
| 2869 | return g->builtin_types.entry_invalid; | 2835 | return g->builtin_types.entry_invalid; |
| 2870 | } else { | 2836 | } else { |
| | 2837 | // TODO eval const expr |
| 2871 | return get_maybe_type(g, type_entry); | 2838 | return get_maybe_type(g, type_entry); |
| 2872 | } | 2839 | } |
| 2873 | } | 2840 | } |
| ... | @@ -3023,7 +2990,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -3023,7 +2990,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3023 | return_type = g->builtin_types.entry_u8; | 2990 | return_type = g->builtin_types.entry_u8; |
| 3024 | break; | 2991 | break; |
| 3025 | case NodeTypeBoolLiteral: | 2992 | case NodeTypeBoolLiteral: |
| 3026 | return_type = g->builtin_types.entry_bool; | 2993 | return_type = resolve_expr_const_val_as_bool(g, node, node->data.bool_literal.value); |
| 3027 | break; | 2994 | break; |
| 3028 | | 2995 | |
| 3029 | case NodeTypeNullLiteral: | 2996 | case NodeTypeNullLiteral: |
| ... | @@ -3066,10 +3033,29 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -3066,10 +3033,29 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3066 | assert(return_type); | 3033 | assert(return_type); |
| 3067 | resolve_type_compatibility(g, context, node, expected_type, return_type); | 3034 | resolve_type_compatibility(g, context, node, expected_type, return_type); |
| 3068 | | 3035 | |
| 3069 | get_resolved_expr(node)->type_entry = return_type; | 3036 | Expr *expr = get_resolved_expr(node); |
| 3070 | get_resolved_expr(node)->block_context = context; | 3037 | expr->type_entry = return_type; |
| | 3038 | expr->block_context = context; |
| 3071 | | 3039 | |
| 3072 | return return_type; | 3040 | if (expr->type_entry->id == TypeTableEntryIdUnreachable) { |
| | 3041 | return expr->type_entry; |
| | 3042 | } |
| | 3043 | |
| | 3044 | /* |
| | 3045 | Cast *cast_node = &expr->implicit_cast; |
| | 3046 | if (cast_node->after_type) { |
| | 3047 | eval_const_expr_implicit_cast(g, import, context, node, cast_node, node); |
| | 3048 | expr->type_entry = cast_node->after_type; |
| | 3049 | } |
| | 3050 | */ |
| | 3051 | |
| | 3052 | Cast *cast_node = &expr->implicit_maybe_cast; |
| | 3053 | if (cast_node->after_type) { |
| | 3054 | eval_const_expr_implicit_cast(g, import, context, node, cast_node, node); |
| | 3055 | expr->type_entry = cast_node->after_type; |
| | 3056 | } |
| | 3057 | |
| | 3058 | return expr->type_entry; |
| 3073 | } | 3059 | } |
| 3074 | | 3060 | |
| 3075 | static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { | 3061 | static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { |