| ... | ... | @@ -13,8 +13,6 @@ |
| 13 | 13 | |
| 14 | 14 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 15 | 15 | TypeTableEntry *expected_type, AstNode *node); |
| 16 | | static void eval_const_expr(CodeGen *g, BlockContext *context, |
| 17 | | AstNode *node, ConstExprValue *out_val); |
| 18 | 16 | static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, |
| 19 | 17 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node); |
| 20 | 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 | 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 | 159 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 176 | 160 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 177 | 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 | 311 | } |
| 328 | 312 | } |
| 329 | 313 | |
| 330 | | // like analyze expression, but expects a type. creates an error if resulting type is |
| 331 | | // not a meta type. unwraps it if it is. |
| 332 | | static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 333 | | AstNode *node) |
| 334 | | { |
| 335 | | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, node); |
| 336 | | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 337 | | return type_entry; |
| 338 | | } else if (type_entry->id == TypeTableEntryIdMetaType) { |
| 339 | | return type_entry->data.meta_type.child_type; |
| 314 | // If the node does not have a constant expression value with a metatype, generates an error |
| 315 | // and returns invalid type. Otherwise, returns the type of the constant expression value. |
| 316 | // Must be called after analyze_expression on the same node. |
| 317 | static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 318 | Expr *expr = get_resolved_expr(node); |
| 319 | assert(expr->type_entry); |
| 320 | if (expr->type_entry->id == TypeTableEntryIdInvalid) { |
| 321 | return g->builtin_types.entry_invalid; |
| 322 | } else if (expr->type_entry->id == TypeTableEntryIdMetaType) { |
| 323 | // OK |
| 340 | 324 | } else { |
| 341 | | add_node_error(g, first_executing_node(node), |
| 342 | | buf_sprintf("expected type, found expression")); |
| 343 | | get_resolved_expr(node)->type_entry = g->builtin_types.entry_invalid; |
| 325 | add_node_error(g, node, buf_sprintf("expected type, found expression")); |
| 344 | 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; |
| 363 | | TypeTableEntry *op2_type = get_resolved_expr(op2_node)->type_entry; |
| 364 | | |
| 365 | | // TODO complete more of this function instead of returning 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"); |
| 329 | ConstExprValue *const_val = &expr->const_val; |
| 330 | if (!const_val->ok) { |
| 331 | add_node_error(g, node, buf_sprintf("unable to resolve constant expression")); |
| 332 | return g->builtin_types.entry_invalid; |
| 518 | 333 | } |
| 519 | | } |
| 520 | 334 | |
| 521 | | static void eval_const_expr_fn_call(CodeGen *g, BlockContext *context, |
| 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); |
| 335 | return const_val->data.x_type; |
| 531 | 336 | } |
| 532 | 337 | |
| 533 | | static void eval_const_expr_prefix_op_expr(CodeGen *g, BlockContext *context, AstNode *node, |
| 534 | | ConstExprValue *out_val) |
| 338 | // Calls analyze_expression on node, and then resolve_type. |
| 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; |
| 537 | | switch (node->data.prefix_op_expr.prefix_op) { |
| 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 | | } |
| 342 | analyze_expression(g, import, context, nullptr, node); |
| 343 | return resolve_type(g, node); |
| 625 | 344 | } |
| 626 | 345 | |
| 627 | 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 | 381 | |
| 663 | 382 | fn_table_entry->type_entry = fn_type; |
| 664 | 383 | |
| 665 | | Buf *name = &node->data.fn_proto.name; |
| 666 | 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 | 386 | for (int i = 0; i < param_count; i += 1) { |
| 669 | 387 | AstNode *child = node->data.fn_proto.params.at(i); |
| 670 | 388 | assert(child->type == NodeTypeParamDecl); |
| ... | ... | @@ -672,8 +390,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 672 | 390 | child->data.param_decl.type); |
| 673 | 391 | fn_table_entry->type_entry->data.fn.param_types[i] = type_entry; |
| 674 | 392 | |
| 675 | | buf_appendf(&fn_type->name, "%s : %s", |
| 676 | | buf_ptr(&child->data.param_decl.name), buf_ptr(&type_entry->name)); |
| 393 | buf_appendf(&fn_type->name, "%s", buf_ptr(&type_entry->name)); |
| 677 | 394 | |
| 678 | 395 | if (i + 1 < param_count) { |
| 679 | 396 | buf_appendf(&fn_type->name, ", "); |
| ... | ... | @@ -1212,13 +929,14 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) { |
| 1212 | 929 | } |
| 1213 | 930 | |
| 1214 | 931 | static TypeTableEntry *unwrapped_node_type(AstNode *node) { |
| 1215 | | TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry; |
| 1216 | | if (meta_type_entry->id == TypeTableEntryIdInvalid) { |
| 1217 | | return meta_type_entry; |
| 1218 | | } else { |
| 1219 | | assert(meta_type_entry->id == TypeTableEntryIdMetaType); |
| 1220 | | return meta_type_entry->data.meta_type.child_type; |
| 932 | Expr *expr = get_resolved_expr(node); |
| 933 | if (expr->type_entry->id == TypeTableEntryIdInvalid) { |
| 934 | return expr->type_entry; |
| 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 | 942 | static TypeTableEntry *get_return_type(BlockContext *context) { |
| ... | ... | @@ -1704,8 +1422,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1704 | 1422 | AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; |
| 1705 | 1423 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node); |
| 1706 | 1424 | |
| 1707 | | TypeTableEntry *return_type; |
| 1708 | | |
| 1709 | 1425 | if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && |
| 1710 | 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 | 1432 | |
| 1717 | 1433 | node->data.field_access_expr.type_struct_field = get_struct_field(bare_struct_type, field_name); |
| 1718 | 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 | 1436 | } else { |
| 1721 | 1437 | add_node_error(g, node, |
| 1722 | 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 | 1441 | } else if (struct_type->id == TypeTableEntryIdArray) { |
| 1726 | 1442 | Buf *name = &node->data.field_access_expr.field_name; |
| 1727 | 1443 | if (buf_eql_str(name, "len")) { |
| 1728 | | return_type = g->builtin_types.entry_usize; |
| 1444 | return g->builtin_types.entry_usize; |
| 1729 | 1445 | } else if (buf_eql_str(name, "ptr")) { |
| 1730 | 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 | 1448 | } else { |
| 1733 | 1449 | add_node_error(g, node, |
| 1734 | 1450 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), |
| 1735 | 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 | 1467 | } else { |
| 1745 | 1468 | if (struct_type->id != TypeTableEntryIdInvalid) { |
| 1746 | 1469 | add_node_error(g, node, |
| 1747 | 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 | 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 | 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 | 1596 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1830 | 1597 | TypeTableEntry *expected_type, AstNode *node) |
| 1831 | 1598 | { |
| ... | ... | @@ -1833,28 +1600,33 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, |
| 1833 | 1600 | |
| 1834 | 1601 | auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); |
| 1835 | 1602 | if (primitive_table_entry) { |
| 1836 | | TypeTableEntry *meta_type = get_meta_type(g, primitive_table_entry->value); |
| 1837 | | node->data.symbol_expr.meta_type = meta_type; |
| 1838 | | return meta_type; |
| 1603 | return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value); |
| 1839 | 1604 | } |
| 1840 | 1605 | |
| 1841 | 1606 | VariableTableEntry *var = find_variable(context, variable_name); |
| 1842 | 1607 | if (var) { |
| 1843 | 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 | 1619 | return var->type; |
| 1845 | 1620 | } |
| 1846 | 1621 | |
| 1847 | 1622 | TypeTableEntry *container_type = find_container(context, variable_name); |
| 1848 | 1623 | if (container_type) { |
| 1849 | | TypeTableEntry *meta_type = get_meta_type(g, container_type); |
| 1850 | | node->data.symbol_expr.meta_type = meta_type; |
| 1851 | | return meta_type; |
| 1624 | return resolve_expr_const_val_as_type(g, node, container_type); |
| 1852 | 1625 | } |
| 1853 | 1626 | |
| 1854 | 1627 | auto fn_table_entry = import->fn_table.maybe_get(variable_name); |
| 1855 | 1628 | if (fn_table_entry) { |
| 1856 | | node->data.symbol_expr.fn_entry = fn_table_entry->value; |
| 1857 | | return node->data.symbol_expr.fn_entry->type_entry; |
| 1629 | return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value); |
| 1858 | 1630 | } |
| 1859 | 1631 | |
| 1860 | 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 | 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 | 1902 | static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1994 | 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 | 1907 | case BinOpTypeAssign: |
| 1998 | 1908 | case BinOpTypeAssignTimes: |
| 1999 | 1909 | case BinOpTypeAssignDiv: |
| ... | ... | @@ -2025,25 +1935,14 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 2025 | 1935 | } |
| 2026 | 1936 | case BinOpTypeBoolOr: |
| 2027 | 1937 | case BinOpTypeBoolAnd: |
| 2028 | | analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.bin_op_expr.op1); |
| 2029 | | analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.bin_op_expr.op2); |
| 2030 | | return g->builtin_types.entry_bool; |
| 1938 | return analyze_logic_bin_op_expr(g, import, context, node); |
| 2031 | 1939 | case BinOpTypeCmpEq: |
| 2032 | 1940 | case BinOpTypeCmpNotEq: |
| 2033 | 1941 | case BinOpTypeCmpLessThan: |
| 2034 | 1942 | case BinOpTypeCmpGreaterThan: |
| 2035 | 1943 | case BinOpTypeCmpLessOrEq: |
| 2036 | 1944 | case BinOpTypeCmpGreaterOrEq: |
| 2037 | | { |
| 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 | | } |
| 1945 | return analyze_bool_bin_op_expr(g, import, context, node); |
| 2047 | 1946 | case BinOpTypeBinOr: |
| 2048 | 1947 | case BinOpTypeBinXor: |
| 2049 | 1948 | case BinOpTypeBinAnd: |
| ... | ... | @@ -2178,30 +2077,41 @@ static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *i |
| 2178 | 2077 | { |
| 2179 | 2078 | assert(node->type == NodeTypeNullLiteral); |
| 2180 | 2079 | |
| 2181 | | 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 { |
| 2080 | if (!expected_type) { |
| 2190 | 2081 | add_node_error(g, node, |
| 2191 | 2082 | buf_sprintf("unable to determine null type")); |
| 2192 | 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 | 2095 | static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, |
| 2197 | 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 | 2098 | if (node->data.number_literal.overflow) { |
| 2201 | | add_node_error(g, node, |
| 2202 | | buf_sprintf("number literal too large to be represented in any type")); |
| 2099 | add_node_error(g, node, buf_sprintf("number literal too large to be represented in any type")); |
| 2203 | 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 | 2115 | NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node); |
| 2206 | 2116 | assert(!codegen_num_lit->resolved_type); |
| 2207 | 2117 | TypeTableEntry *after_implicit_cast_resolved_type = |
| ... | ... | @@ -2235,18 +2145,17 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, |
| 2235 | 2145 | return g->builtin_types.entry_invalid; |
| 2236 | 2146 | } |
| 2237 | 2147 | |
| 2238 | | ConstExprValue const_val = {0}; |
| 2239 | | eval_const_expr(g, context, size_node, &const_val); |
| 2240 | | |
| 2241 | | if (const_val.ok) { |
| 2242 | | return get_meta_type(g, get_array_type(g, import, child_type, const_val.data.x_uint)); |
| 2148 | ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val; |
| 2149 | if (const_val->ok) { |
| 2150 | return resolve_expr_const_val_as_type(g, node, |
| 2151 | get_array_type(g, import, child_type, const_val->data.x_uint)); |
| 2243 | 2152 | } else { |
| 2244 | | add_node_error(g, size_node, |
| 2245 | | buf_create_from_str("unable to resolve constant expression")); |
| 2153 | add_node_error(g, size_node, buf_create_from_str("unable to resolve constant expression")); |
| 2246 | 2154 | return g->builtin_types.entry_invalid; |
| 2247 | 2155 | } |
| 2248 | 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 | 2180 | } else { |
| 2272 | 2181 | // if the condition is a simple constant expression and there are no break statements |
| 2273 | 2182 | // then the return type is unreachable |
| 2274 | | ConstExprValue const_val = {0}; |
| 2275 | | eval_const_expr(g, context, condition_node, &const_val); |
| 2276 | | |
| 2277 | | if (const_val.ok) { |
| 2278 | | if (const_val.data.x_bool) { |
| 2183 | ConstExprValue *const_val = &get_resolved_expr(condition_node)->const_val; |
| 2184 | if (const_val->ok) { |
| 2185 | if (const_val->data.x_bool) { |
| 2279 | 2186 | node->data.while_expr.condition_always_true = true; |
| 2280 | 2187 | if (!node->data.while_expr.contains_break) { |
| 2281 | 2188 | expr_return_type = g->builtin_types.entry_unreachable; |
| ... | ... | @@ -2360,19 +2267,23 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, |
| 2360 | 2267 | } |
| 2361 | 2268 | |
| 2362 | 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 | 2272 | assert(node->type == NodeTypeFnCallExpr); |
| 2366 | 2273 | assert(node->data.fn_call_expr.params.length == 1); |
| 2367 | 2274 | |
| 2368 | 2275 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 2369 | 2276 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 2370 | | if (type_entry->id == TypeTableEntryIdInt || |
| 2371 | | type_entry->id == TypeTableEntryIdFloat || |
| 2372 | | type_entry->id == TypeTableEntryIdBool || |
| 2373 | | type_entry->id == TypeTableEntryIdInvalid) |
| 2374 | | { |
| 2277 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2278 | return g->builtin_types.entry_invalid; |
| 2279 | } else if (type_entry->id == TypeTableEntryIdInt) { |
| 2280 | // TODO const expr eval for min/max int |
| 2375 | 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 | 2287 | } else { |
| 2377 | 2288 | add_node_error(g, node, |
| 2378 | 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 | 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 | 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 | 2335 | assert(node->type == NodeTypeFnCallExpr); |
| 2387 | 2336 | |
| ... | ... | @@ -2394,7 +2343,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2394 | 2343 | } |
| 2395 | 2344 | |
| 2396 | 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 | 2347 | TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node); |
| 2399 | 2348 | |
| 2400 | 2349 | if (wanted_type->id == TypeTableEntryIdInvalid || |
| ... | ... | @@ -2411,11 +2360,13 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2411 | 2360 | actual_type->id == TypeTableEntryIdPointer) |
| 2412 | 2361 | { |
| 2413 | 2362 | cast->op = CastOpPtrToInt; |
| 2363 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2414 | 2364 | return wanted_type; |
| 2415 | 2365 | } else if (wanted_type->id == TypeTableEntryIdInt && |
| 2416 | 2366 | actual_type->id == TypeTableEntryIdInt) |
| 2417 | 2367 | { |
| 2418 | 2368 | cast->op = CastOpIntWidenOrShorten; |
| 2369 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2419 | 2370 | return wanted_type; |
| 2420 | 2371 | } else if (wanted_type->id == TypeTableEntryIdStruct && |
| 2421 | 2372 | wanted_type->data.structure.is_unknown_size_array && |
| ... | ... | @@ -2424,6 +2375,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 2424 | 2375 | { |
| 2425 | 2376 | cast->op = CastOpToUnknownSizeArray; |
| 2426 | 2377 | context->cast_expr_alloca_list.append(cast); |
| 2378 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2427 | 2379 | return wanted_type; |
| 2428 | 2380 | } else if (actual_type->id == TypeTableEntryIdNumberLiteral && |
| 2429 | 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 | 2384 | assert(!codegen_num_lit->resolved_type); |
| 2433 | 2385 | codegen_num_lit->resolved_type = wanted_type; |
| 2434 | 2386 | cast->op = CastOpNothing; |
| 2387 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2435 | 2388 | return wanted_type; |
| 2436 | 2389 | } else if (actual_type->id == TypeTableEntryIdPointer && |
| 2437 | 2390 | wanted_type->id == TypeTableEntryIdPointer) |
| 2438 | 2391 | { |
| 2439 | 2392 | cast->op = CastOpPointerReinterpret; |
| 2393 | eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); |
| 2440 | 2394 | return wanted_type; |
| 2441 | 2395 | } else { |
| 2442 | 2396 | add_node_error(g, node, |
| ... | ... | @@ -2457,165 +2411,160 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 2457 | 2411 | |
| 2458 | 2412 | auto entry = g->builtin_fn_table.maybe_get(name); |
| 2459 | 2413 | |
| 2460 | | if (entry) { |
| 2461 | | BuiltinFnEntry *builtin_fn = entry->value; |
| 2462 | | int actual_param_count = node->data.fn_call_expr.params.length; |
| 2414 | if (!entry) { |
| 2415 | add_node_error(g, node, |
| 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) { |
| 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 | | } |
| 2423 | node->data.fn_call_expr.builtin_fn = builtin_fn; |
| 2472 | 2424 | |
| 2473 | | switch (builtin_fn->id) { |
| 2474 | | case BuiltinFnIdInvalid: |
| 2475 | | zig_unreachable(); |
| 2476 | | case BuiltinFnIdAddWithOverflow: |
| 2477 | | case BuiltinFnIdSubWithOverflow: |
| 2478 | | case BuiltinFnIdMulWithOverflow: |
| 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 | | } |
| 2425 | if (builtin_fn->param_count != actual_param_count) { |
| 2426 | add_node_error(g, node, |
| 2427 | buf_sprintf("expected %d arguments, got %d", |
| 2428 | builtin_fn->param_count, actual_param_count)); |
| 2429 | return g->builtin_types.entry_invalid; |
| 2430 | } |
| 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 | 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 && |
| 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 | | } |
| 2457 | // TODO constant expression evaluation |
| 2535 | 2458 | |
| 2536 | | return builtin_fn->return_type; |
| 2537 | | } |
| 2538 | | case BuiltinFnIdMemset: |
| 2459 | return g->builtin_types.entry_bool; |
| 2460 | } |
| 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); |
| 2541 | | AstNode *char_node = node->data.fn_call_expr.params.at(1); |
| 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; |
| 2473 | add_node_error(g, dest_node, |
| 2474 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&dest_type->name))); |
| 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); |
| 2559 | | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 2560 | | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 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; |
| 2480 | add_node_error(g, src_node, |
| 2481 | buf_sprintf("expected pointer argument, got '%s'", buf_ptr(&src_type->name))); |
| 2482 | } |
| 2568 | 2483 | |
| 2569 | | TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes); |
| 2570 | | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); |
| 2571 | | return resolved_type ? resolved_type : num_lit_type; |
| 2484 | if (dest_type->id == TypeTableEntryIdPointer && |
| 2485 | src_type->id == TypeTableEntryIdPointer) |
| 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) { |
| 2584 | | return type_entry; |
| 2585 | | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 2586 | | uint64_t value_count = type_entry->data.enumeration.field_count; |
| 2497 | return builtin_fn->return_type; |
| 2498 | } |
| 2499 | case BuiltinFnIdMemset: |
| 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); |
| 2589 | | TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type); |
| 2590 | | return resolved_type ? resolved_type : num_lit_type; |
| 2515 | return builtin_fn->return_type; |
| 2516 | } |
| 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 { |
| 2593 | | add_node_error(g, node, |
| 2594 | | buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name))); |
| 2595 | | return g->builtin_types.entry_invalid; |
| 2596 | | } |
| 2543 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2544 | return type_entry; |
| 2545 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 2546 | uint64_t value_count = type_entry->data.enumeration.field_count; |
| 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: |
| 2599 | | { |
| 2600 | | AstNode *expr_node = node->data.fn_call_expr.params.at(0); |
| 2601 | | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); |
| 2553 | } |
| 2554 | case BuiltinFnIdTypeof: |
| 2555 | { |
| 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) { |
| 2604 | | return g->builtin_types.entry_invalid; |
| 2605 | | } else if (type_entry->id == TypeTableEntryIdMetaType) { |
| 2606 | | add_node_error(g, node, buf_sprintf("expected expression, got type")); |
| 2607 | | } else { |
| 2608 | | return get_meta_type(g, type_entry); |
| 2609 | | } |
| 2559 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2560 | return g->builtin_types.entry_invalid; |
| 2561 | } else { |
| 2562 | return resolve_expr_const_val_as_type(g, node, type_entry); |
| 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 | 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 | 2656 | } |
| 2708 | 2657 | } else if (struct_type->id == TypeTableEntryIdInvalid) { |
| 2709 | 2658 | return struct_type; |
| 2710 | | } else if (struct_type->id == TypeTableEntryIdMetaType && |
| 2711 | | struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) |
| 2712 | | { |
| 2713 | | TypeTableEntry *enum_type = struct_type->data.meta_type.child_type; |
| 2714 | | Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; |
| 2715 | | int param_count = node->data.fn_call_expr.params.length; |
| 2716 | | if (param_count > 1) { |
| 2717 | | add_node_error(g, first_executing_node(node->data.fn_call_expr.params.at(1)), |
| 2718 | | buf_sprintf("enum values accept only one parameter")); |
| 2719 | | return enum_type; |
| 2720 | | } else { |
| 2721 | | AstNode *value_node; |
| 2722 | | if (param_count == 1) { |
| 2723 | | value_node = node->data.fn_call_expr.params.at(0); |
| 2659 | } else if (struct_type->id == TypeTableEntryIdMetaType) { |
| 2660 | TypeTableEntry *enum_type = resolve_type(g, first_param_expr); |
| 2661 | |
| 2662 | if (enum_type->id == TypeTableEntryIdInvalid) { |
| 2663 | return g->builtin_types.entry_invalid; |
| 2664 | } else if (enum_type->id == TypeTableEntryIdEnum) { |
| 2665 | Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name; |
| 2666 | int param_count = node->data.fn_call_expr.params.length; |
| 2667 | if (param_count > 1) { |
| 2668 | add_node_error(g, first_executing_node(node->data.fn_call_expr.params.at(1)), |
| 2669 | buf_sprintf("enum values accept only one parameter")); |
| 2670 | return enum_type; |
| 2724 | 2671 | } else { |
| 2725 | | value_node = nullptr; |
| 2726 | | } |
| 2672 | AstNode *value_node; |
| 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, |
| 2729 | | enum_type, field_name); |
| 2679 | return analyze_enum_value_expr(g, import, context, fn_ref_expr, value_node, |
| 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 | 2686 | } else { |
| 2732 | | add_node_error(g, fn_ref_expr->data.field_access_expr.struct_expr, |
| 2733 | | buf_sprintf("member reference base type not struct or enum")); |
| 2687 | add_node_error(g, first_param_expr, buf_sprintf("member reference base type not struct or enum")); |
| 2734 | 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 | 2696 | |
| 2743 | 2697 | // use constant expression evaluator to figure out the function at compile time. |
| 2744 | 2698 | // otherwise we treat this as a function pointer. |
| 2745 | | ConstExprValue const_val = {0}; |
| 2746 | | eval_const_expr(g, context, fn_ref_expr, &const_val); |
| 2699 | ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val; |
| 2747 | 2700 | |
| 2748 | | if (!const_val.ok) { |
| 2701 | if (!const_val->ok) { |
| 2749 | 2702 | add_node_error(g, node, buf_sprintf("function pointers not yet supported")); |
| 2750 | 2703 | return g->builtin_types.entry_invalid; |
| 2751 | 2704 | } |
| 2752 | 2705 | |
| 2753 | 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 | 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 | 2710 | } else { |
| 2758 | 2711 | add_node_error(g, fn_ref_expr, |
| 2759 | 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 | 2717 | static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2765 | 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 | 2723 | case PrefixOpInvalid: |
| 2769 | 2724 | zig_unreachable(); |
| 2770 | 2725 | case PrefixOpBoolNot: |
| 2771 | | analyze_expression(g, import, context, g->builtin_types.entry_bool, |
| 2772 | | node->data.prefix_op_expr.primary_expr); |
| 2773 | | return g->builtin_types.entry_bool; |
| 2726 | { |
| 2727 | TypeTableEntry *type_entry = analyze_expression(g, import, context, 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 | 2741 | case PrefixOpBinNot: |
| 2775 | 2742 | { |
| 2776 | | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; |
| 2777 | 2743 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, |
| 2778 | | operand_node); |
| 2744 | expr_node); |
| 2779 | 2745 | if (expr_type->id == TypeTableEntryIdInvalid) { |
| 2780 | 2746 | return expr_type; |
| 2781 | 2747 | } else if (expr_type->id == TypeTableEntryIdInt || |
| ... | ... | @@ -2784,16 +2750,15 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2784 | 2750 | { |
| 2785 | 2751 | return expr_type; |
| 2786 | 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 | 2754 | buf_ptr(&expr_type->name))); |
| 2789 | 2755 | return g->builtin_types.entry_invalid; |
| 2790 | 2756 | } |
| 2791 | 2757 | } |
| 2792 | 2758 | case PrefixOpNegation: |
| 2793 | 2759 | { |
| 2794 | | AstNode *operand_node = node->data.prefix_op_expr.primary_expr; |
| 2795 | 2760 | TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, |
| 2796 | | operand_node); |
| 2761 | expr_node); |
| 2797 | 2762 | if (expr_type->id == TypeTableEntryIdInvalid) { |
| 2798 | 2763 | return expr_type; |
| 2799 | 2764 | } else if (expr_type->id == TypeTableEntryIdInt && |
| ... | ... | @@ -2805,7 +2770,6 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2805 | 2770 | } else if (expr_type->id == TypeTableEntryIdNumberLiteral) { |
| 2806 | 2771 | return expr_type; |
| 2807 | 2772 | } else { |
| 2808 | | BREAKPOINT; |
| 2809 | 2773 | add_node_error(g, node, buf_sprintf("invalid negation type: '%s'", |
| 2810 | 2774 | buf_ptr(&expr_type->name))); |
| 2811 | 2775 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -2814,20 +2778,23 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2814 | 2778 | case PrefixOpAddressOf: |
| 2815 | 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 | 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 | 2786 | if (child_type->id == TypeTableEntryIdInvalid) { |
| 2823 | 2787 | return g->builtin_types.entry_invalid; |
| 2824 | 2788 | } else if (child_type->id == TypeTableEntryIdMetaType) { |
| 2825 | | TypeTableEntry *meta_child_type = child_type->data.meta_type.child_type; |
| 2826 | | if (meta_child_type->id == TypeTableEntryIdUnreachable) { |
| 2827 | | add_node_error(g, node, |
| 2828 | | buf_create_from_str("pointer to unreachable not allowed")); |
| 2789 | TypeTableEntry *meta_type = analyze_type_expr(g, import, context, expr_node); |
| 2790 | if (meta_type->id == TypeTableEntryIdInvalid) { |
| 2791 | return g->builtin_types.entry_invalid; |
| 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 | 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 | 2799 | } else { |
| 2833 | 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 | 2802 | } |
| 2836 | 2803 | case PrefixOpDereference: |
| 2837 | 2804 | { |
| 2838 | | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, |
| 2839 | | node->data.prefix_op_expr.primary_expr); |
| 2805 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); |
| 2840 | 2806 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2841 | 2807 | return type_entry; |
| 2842 | 2808 | } else if (type_entry->id == TypeTableEntryIdPointer) { |
| 2843 | 2809 | return type_entry->data.pointer.child_type; |
| 2844 | 2810 | } else { |
| 2845 | | add_node_error(g, node->data.prefix_op_expr.primary_expr, |
| 2811 | add_node_error(g, expr_node, |
| 2846 | 2812 | buf_sprintf("indirection requires pointer operand ('%s' invalid)", |
| 2847 | 2813 | buf_ptr(&type_entry->name))); |
| 2848 | 2814 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -2850,24 +2816,25 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo |
| 2850 | 2816 | } |
| 2851 | 2817 | case PrefixOpMaybe: |
| 2852 | 2818 | { |
| 2853 | | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, |
| 2854 | | node->data.prefix_op_expr.primary_expr); |
| 2819 | TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node); |
| 2855 | 2820 | |
| 2856 | 2821 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 2857 | 2822 | return type_entry; |
| 2858 | 2823 | } else if (type_entry->id == TypeTableEntryIdMetaType) { |
| 2859 | | TypeTableEntry *child_type = type_entry->data.meta_type.child_type; |
| 2860 | | if (child_type->id == TypeTableEntryIdUnreachable) { |
| 2824 | TypeTableEntry *meta_type = resolve_type(g, expr_node); |
| 2825 | if (meta_type->id == TypeTableEntryIdInvalid) { |
| 2826 | return g->builtin_types.entry_invalid; |
| 2827 | } else if (meta_type->id == TypeTableEntryIdUnreachable) { |
| 2861 | 2828 | add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed")); |
| 2862 | 2829 | return g->builtin_types.entry_invalid; |
| 2863 | 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 | 2833 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 2867 | | add_node_error(g, node->data.prefix_op_expr.primary_expr, |
| 2868 | | buf_sprintf("unable to wrap unreachable in maybe type")); |
| 2834 | add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in maybe type")); |
| 2869 | 2835 | return g->builtin_types.entry_invalid; |
| 2870 | 2836 | } else { |
| 2837 | // TODO eval const expr |
| 2871 | 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 | 2990 | return_type = g->builtin_types.entry_u8; |
| 3024 | 2991 | break; |
| 3025 | 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 | 2994 | break; |
| 3028 | 2995 | |
| 3029 | 2996 | case NodeTypeNullLiteral: |
| ... | ... | @@ -3066,10 +3033,29 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3066 | 3033 | assert(return_type); |
| 3067 | 3034 | resolve_type_compatibility(g, context, node, expected_type, return_type); |
| 3068 | 3035 | |
| 3069 | | get_resolved_expr(node)->type_entry = return_type; |
| 3070 | | get_resolved_expr(node)->block_context = context; |
| 3036 | Expr *expr = get_resolved_expr(node); |
| 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 | 3061 | static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { |