diff options
Diffstat (limited to 'src/check_expr.c')
| -rw-r--r-- | src/check_expr.c | 477 |
1 files changed, 157 insertions, 320 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index 3b58dc904..687f4ebea 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -265,8 +265,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } - - if (type == NULL) { return; } @@ -1030,7 +1028,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ } o->mode = Addressing_Variable; if (e->Variable.is_immutable) { - o->mode = Addressing_Value; + o->mode = Addressing_Immutable; } break; @@ -1073,7 +1071,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { } Operand o = {0}; if (e->kind == AstNode_UnaryExpr && - e->UnaryExpr.op.kind == Token_Question) { + e->UnaryExpr.op.kind == Token_Ellipsis) { return -1; } @@ -1115,12 +1113,13 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { return 0; } -Type *make_map_tuple_type(gbAllocator a, Type *value) { +Type *make_optional_ok_type(gbAllocator a, Type *value) { + bool typed = true; Type *t = make_type_tuple(a); t->Tuple.variables = gb_alloc_array(a, Entity *, 2); t->Tuple.variable_count = 2; t->Tuple.variables[0] = make_entity_field(a, NULL, blank_token, value, false, 0); - t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, t_bool, false, 1); + t->Tuple.variables[1] = make_entity_field(a, NULL, blank_token, typed ? t_bool : t_untyped_bool, false, 1); return t; } @@ -1221,7 +1220,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { type->Map.generated_struct_type = generated_struct_type; } - type->Map.lookup_result_type = make_map_tuple_type(a, value); + type->Map.lookup_result_type = make_optional_ok_type(a, value); // error_node(node, "`map` types are not yet implemented"); } @@ -1929,6 +1928,76 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { x->mode = Addressing_Value; } + +String check_down_cast_name(Type *dst_, Type *src_) { + String result = {0}; + Type *dst = type_deref(dst_); + Type *src = type_deref(src_); + Type *dst_s = base_type(dst); + GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s)); + for (isize i = 0; i < dst_s->Record.field_count; i++) { + Entity *f = dst_s->Record.fields[i]; + GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); + if (f->flags & EntityFlag_Anonymous) { + if (are_types_identical(f->type, src_)) { + return f->token.string; + } + if (are_types_identical(type_deref(f->type), src_)) { + return f->token.string; + } + + if (!is_type_pointer(f->type)) { + result = check_down_cast_name(f->type, src_); + if (result.len > 0) { + return result; + } + } + } + } + + return result; +} + +Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) { + GB_ASSERT(node->kind == AstNode_BinaryExpr); + ast_node(be, BinaryExpr, node); + GB_ASSERT(is_type_pointer(ptr->type)); + GB_ASSERT(is_type_integer(offset->type)); + GB_ASSERT(op == Token_Add || op == Token_Sub); + + Operand operand = {0}; + operand.mode = Addressing_Value; + operand.type = ptr->type; + operand.expr = node; + + if (base_type(ptr->type) == t_rawptr) { + gbString str = type_to_string(ptr->type); + error_node(node, "Invalid pointer type for pointer arithmetic: `%s`", str); + gb_string_free(str); + operand.mode = Addressing_Invalid; + return operand; + } + + + if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) { + i64 elem_size = type_size_of(c->allocator, ptr->type); + i64 ptr_val = ptr->value.value_pointer; + i64 offset_val = exact_value_to_integer(offset->value).value_integer; + i64 new_ptr_val = ptr_val; + if (op == Token_Add) { + new_ptr_val += elem_size*offset_val; + } else { + new_ptr_val -= elem_size*offset_val; + } + operand.mode = Addressing_Constant; + operand.value = make_exact_value_pointer(new_ptr_val); + } + + return operand; +} + + + bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { if (check_is_assignable_to(c, operand, y)) { return true; @@ -1968,10 +2037,21 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { // Cast between pointers if (is_type_pointer(src) && is_type_pointer(dst)) { + Type *s = base_type(type_deref(src)); + if (is_type_union(s)) { + // NOTE(bill): Should the error be here?! + // NOTE(bill): This error should suppress the next casting error as it's at the same position + gbString xs = type_to_string(x); + gbString ys = type_to_string(y); + error_node(operand->expr, "Cannot cast from a union pointer `%s` to `%s`, try using `union_cast` or cast to a `rawptr`", xs, ys); + gb_string_free(ys); + gb_string_free(xs); + return false; + } return true; } - // (u)int <-> pointer + // (u)int <-> rawptr if (is_type_int_or_uint(src) && is_type_rawptr(dst)) { return true; } @@ -2006,75 +2086,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { return false; } -String check_down_cast_name(Type *dst_, Type *src_) { - String result = {0}; - Type *dst = type_deref(dst_); - Type *src = type_deref(src_); - Type *dst_s = base_type(dst); - GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s)); - for (isize i = 0; i < dst_s->Record.field_count; i++) { - Entity *f = dst_s->Record.fields[i]; - GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); - if (f->flags & EntityFlag_Anonymous) { - if (are_types_identical(f->type, src_)) { - return f->token.string; - } - if (are_types_identical(type_deref(f->type), src_)) { - return f->token.string; - } - - if (!is_type_pointer(f->type)) { - result = check_down_cast_name(f->type, src_); - if (result.len > 0) { - return result; - } - } - } - } - - return result; -} - -Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offset, AstNode *node) { - GB_ASSERT(node->kind == AstNode_BinaryExpr); - ast_node(be, BinaryExpr, node); - GB_ASSERT(is_type_pointer(ptr->type)); - GB_ASSERT(is_type_integer(offset->type)); - GB_ASSERT(op == Token_Add || op == Token_Sub); - - Operand operand = {0}; - operand.mode = Addressing_Value; - operand.type = ptr->type; - operand.expr = node; - - if (base_type(ptr->type) == t_rawptr) { - gbString str = type_to_string(ptr->type); - error_node(node, "Invalid pointer type for pointer arithmetic: `%s`", str); - gb_string_free(str); - operand.mode = Addressing_Invalid; - return operand; - } - - - if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) { - i64 elem_size = type_size_of(c->allocator, ptr->type); - i64 ptr_val = ptr->value.value_pointer; - i64 offset_val = exact_value_to_integer(offset->value).value_integer; - i64 new_ptr_val = ptr_val; - if (op == Token_Add) { - new_ptr_val += elem_size*offset_val; - } else { - new_ptr_val -= elem_size*offset_val; - } - operand.mode = Addressing_Constant; - operand.value = make_exact_value_pointer(new_ptr_val); - } - - return operand; -} - - -void check_conversion(Checker *c, Operand *x, Type *type) { +void check_cast(Checker *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; bool can_convert = false; @@ -2714,7 +2726,9 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h break; case Entity_Variable: // TODO(bill): This is the rule I need? - if (sel.indirect || operand->mode != Addressing_Value) { + if (operand->mode == Addressing_Immutable) { + // Okay + } else if (sel.indirect || operand->mode != Addressing_Value) { operand->mode = Addressing_Variable; } else { operand->mode = Addressing_Value; @@ -3819,17 +3833,16 @@ int valid_proc_and_score_cmp(void const *a, void const *b) { typedef Array(Operand) ArrayOperand; -void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray args, bool allow_map_ok) { - for_array(i, args) { +bool check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, AstNodeArray rhs, bool allow_ok) { + bool optional_ok = false; + for_array(i, rhs) { Operand o = {0}; - check_multi_expr(c, &o, args.e[i]); + check_multi_expr(c, &o, rhs.e[i]); if (o.type == NULL || o.type->kind != Type_Tuple) { - if (o.mode == Addressing_MapIndex && - allow_map_ok && - lhs_count == 2 && - args.count == 1) { - Type *tuple = make_map_tuple_type(c->allocator, o.type); + if (allow_ok && lhs_count == 2 && rhs.count == 1 && + (o.mode == Addressing_MapIndex || o.mode == Addressing_OptionalOk)) { + Type *tuple = make_optional_ok_type(c->allocator, o.type); add_type_and_value(&c->info, o.expr, o.mode, tuple, o.value); Operand val = o; @@ -3839,9 +3852,11 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, ok.type = t_bool; array_add(operands, val); array_add(operands, ok); - continue; + + optional_ok = true; + } else { + array_add(operands, o); } - array_add(operands, o); } else { TypeTuple *tuple = &o.type->Tuple; for (isize j = 0; j < tuple->variable_count; j++) { @@ -3850,6 +3865,8 @@ void check_unpack_arguments(Checker *c, isize lhs_count, ArrayOperand *operands, } } } + + return optional_ok; } Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { @@ -3998,7 +4015,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { case 1: check_expr(c, operand, ce->args.e[0]); if (operand->mode != Addressing_Invalid) { - check_conversion(c, operand, t); + check_cast(c, operand, t); } break; } @@ -4097,8 +4114,19 @@ void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { } } -bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { - t = base_type(type_deref(t)); +void check_set_mode_with_indirection(Operand *o, bool indirection) { + if (o->mode != Addressing_Immutable) { + if (indirection) { + o->mode = Addressing_Variable; + } else if (o->mode != Addressing_Variable && + o->mode != Addressing_Constant) { + o->mode = Addressing_Value; + } + } +} + +bool check_set_index_data(Operand *o, Type *type, bool indirection, i64 *max_count) { + Type *t = base_type(type_deref(type)); switch (t->kind) { case Type_Basic: @@ -4106,9 +4134,7 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { if (o->mode == Addressing_Constant) { *max_count = o->value.value_string.len; } - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t_u8; return true; } @@ -4116,69 +4142,33 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) { case Type_Array: *max_count = t->Array.count; - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t->Array.elem; return true; case Type_Vector: *max_count = t->Vector.count; - if (o->mode != Addressing_Variable) { - o->mode = Addressing_Value; - } + check_set_mode_with_indirection(o, indirection); o->type = t->Vector.elem; return true; case Type_Slice: o->type = t->Slice.elem; - o->mode = Addressing_Variable; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Variable; + } return true; case Type_DynamicArray: o->type = t->DynamicArray.elem; - o->mode = Addressing_Variable; + check_set_mode_with_indirection(o, indirection); return true; } return false; } - -bool check_is_giving(AstNode *node, AstNode **give_expr) { - switch (node->kind) { - case_ast_node(es, ExprStmt, node); - if (es->expr->kind == AstNode_GiveExpr) { - if (give_expr) *give_expr = es->expr; - return true; - } - case_end; - - case_ast_node(ge, GiveExpr, node); - if (give_expr) *give_expr = node; - return true; - case_end; - - case_ast_node(be, BlockExpr, node); - // Iterate backwards - for (isize n = be->stmts.count-1; n >= 0; n--) { - AstNode *stmt = be->stmts.e[n]; - if (stmt->kind == AstNode_EmptyStmt) { - continue; - } - if (stmt->kind == AstNode_ExprStmt && stmt->ExprStmt.expr->kind == AstNode_GiveExpr) { - if (give_expr) *give_expr = stmt->ExprStmt.expr; - return true; - } - } - case_end; - } - - if (give_expr) *give_expr = NULL; - return false; -} - ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { ExprKind kind = Expr_Stmt; @@ -4280,177 +4270,30 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->type = type; case_end; - case_ast_node(ge, GiveExpr, node); - if (c->proc_stack.count == 0) { - error_node(node, "A give expression is only allowed within a procedure"); - goto error; - } - - if (ge->results.count == 0) { - error_node(node, "`give` has no results"); - goto error; - } - - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - - Array(Operand) operands; - array_init_reserve(&operands, c->tmp_allocator, 2*ge->results.count); - - for_array(i, ge->results) { - AstNode *rhs = ge->results.e[i]; - Operand o = {0}; - check_multi_expr(c, &o, rhs); - if (!is_operand_value(o)) { - error_node(rhs, "Expected a value for a `give`"); - continue; - } - if (o.type->kind != Type_Tuple) { - array_add(&operands, o); - } else { - TypeTuple *tuple = &o.type->Tuple; - for (isize j = 0; j < tuple->variable_count; j++) { - o.type = tuple->variables[j]->type; - array_add(&operands, o); - } - } - } - - if (operands.count == 0) { - error_node(node, "`give` has no value"); - gb_temp_arena_memory_end(tmp); - goto error; - } else if (operands.count == 1) { - Operand operand = operands.e[0]; - Type *th = type_hint != NULL ? type_hint : c->context.type_hint; - if (th != NULL) { - convert_to_typed(c, &operand, th, 0); - } - // IMPORTANT NOTE(bill): This type could be untyped!!! - o->type = default_type(operand.type); - o->mode = Addressing_Value; - } else { - Type *tuple = make_type_tuple(c->allocator); - - Entity **variables = gb_alloc_array(c->allocator, Entity *, operands.count); - isize variable_index = 0; - for_array(i, operands) { - Operand operand = operands.e[i]; - // Type *type = default_type(operand.type); - Type *type = operand.type; - switch (operand.mode) { - case Addressing_Constant: - variables[variable_index++] = make_entity_constant(c->allocator, NULL, empty_token, type, operand.value); - break; - default: - variables[variable_index++] = make_entity_param(c->allocator, NULL, empty_token, type, false, true); - break; - } - } - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = operands.count; - - o->type = tuple; - o->mode = Addressing_Value; - } - gb_temp_arena_memory_end(tmp); - case_end; - - case_ast_node(be, BlockExpr, node); + case_ast_node(te, TernaryExpr, node); if (c->proc_stack.count == 0) { - error_node(node, "A block expression is only allowed within a procedure"); + error_node(node, "A ternary expression is only allowed within a procedure"); goto error; } - - for (isize i = be->stmts.count-1; i >= 0; i--) { - if (be->stmts.e[i]->kind != AstNode_EmptyStmt) { - break; - } - be->stmts.count--; - } - - if (be->stmts.count == 0) { - error_node(node, "Empty block expression"); - goto error; - } - - CheckerContext prev_context = c->context; - c->context.type_hint = type_hint; - check_open_scope(c, node); - check_stmt_list(c, be->stmts, Stmt_GiveAllowed); - check_close_scope(c); - - c->context = prev_context; - - AstNode *give_node = NULL; - if (!check_is_giving(node, &give_node) || give_node == NULL) { - error_node(node, "Missing give statement at end of block expression"); - goto error; - } - - GB_ASSERT(give_node != NULL && give_node->kind == AstNode_GiveExpr); - be->give_node = give_node; - - Type *type = type_of_expr(&c->info, give_node); - if (type == NULL) { - goto error; - } else if (type == t_invalid) { - o->type = t_invalid; - o->mode = Addressing_Invalid; - } else { - o->type = type; - o->mode = Addressing_Value; - } - case_end; - - case_ast_node(ie, IfExpr, node); - if (c->proc_stack.count == 0) { - error_node(node, "An if expression is only allowed within a procedure"); - goto error; - } - - check_open_scope(c, node); - - if (ie->init != NULL) { - check_stmt(c, ie->init, 0); - } - Operand operand = {Addressing_Invalid}; - check_expr(c, &operand, ie->cond); + check_expr(c, &operand, te->cond); if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) { - error_node(ie->cond, "Non-boolean condition in if expression"); + error_node(te->cond, "Non-boolean condition in if expression"); } Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - Type *if_type = NULL; - Type *else_type = NULL; - if (type_hint) { - gb_printf_err("here\n"); - } - check_expr_with_type_hint(c, &x, ie->body, type_hint); - if_type = x.type; - - if (ie->else_expr != NULL) { - switch (ie->else_expr->kind) { - case AstNode_IfExpr: - case AstNode_BlockExpr: - check_expr_with_type_hint(c, &y, ie->else_expr, if_type); - else_type = y.type; - break; - default: - error_node(ie->else_expr, "Invalid else expression in if expression"); - break; - } + check_expr_with_type_hint(c, &x, te->x, type_hint); + + if (te->y != NULL) { + check_expr_with_type_hint(c, &y, te->y, type_hint); } else { - error_node(ie->else_expr, "An if expression must have an else expression"); - check_close_scope(c); + error_node(node, "A ternary expression must have an else clause"); goto error; } - check_close_scope(c); - - if (if_type == NULL || if_type == t_invalid || - else_type == NULL || else_type == t_invalid) { + if (x.type == NULL || x.type == t_invalid || + y.type == NULL || y.type == t_invalid) { goto error; } @@ -4465,16 +4308,16 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } - if (!are_types_identical(if_type, else_type)) { - gbString its = type_to_string(if_type); - gbString ets = type_to_string(else_type); - error_node(node, "Mismatched types in if expression, %s vs %s", its, ets); + if (!are_types_identical(x.type, y.type)) { + gbString its = type_to_string(x.type); + gbString ets = type_to_string(y.type); + error_node(node, "Mismatched types in ternary expression, %s vs %s", its, ets); gb_string_free(ets); gb_string_free(its); goto error; } - o->type = if_type; + o->type = x.type; o->mode = Addressing_Value; case_end; @@ -4489,7 +4332,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != NULL) { AstNode *count = cl->type->ArrayType.count; if (count->kind == AstNode_UnaryExpr && - count->UnaryExpr.op.kind == Token_Question) { + count->UnaryExpr.op.kind == Token_Ellipsis) { type = make_type_array(c->allocator, check_type(c, cl->type->ArrayType.elem), -1); is_to_be_determined_array_count = true; } @@ -4820,7 +4663,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } switch (ce->token.kind) { case Token_cast: - check_conversion(c, o, t); + check_cast(c, o, t); break; case Token_transmute: { if (o->mode == Addressing_Constant) { @@ -4913,16 +4756,11 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } - Entity **variables = gb_alloc_array(c->allocator, Entity *, 2); - variables[0] = make_entity_param(c->allocator, NULL, empty_token, t, false, true); - variables[1] = make_entity_param(c->allocator, NULL, empty_token, t_bool, false, true); - - Type *tuple = make_type_tuple(c->allocator); - tuple->Tuple.variables = variables; - tuple->Tuple.variable_count = 2; + add_type_info_type(c, o->type); + add_type_info_type(c, t); - o->type = tuple; - o->mode = Addressing_Value; + o->type = t; + o->mode = Addressing_OptionalOk; } break; case Token_down_cast: { if (o->mode == Addressing_Constant) { @@ -5023,6 +4861,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } Type *t = base_type(type_deref(o->type)); + bool is_ptr = is_type_pointer(o->type); bool is_const = o->mode == Addressing_Constant; if (is_type_map(t)) { @@ -5039,7 +4878,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } i64 max_count = -1; - bool valid = check_set_index_data(o, t, &max_count); + bool valid = check_set_index_data(o, t, is_ptr, &max_count); if (is_const) { valid = false; @@ -5048,7 +4887,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint if (!valid && (is_type_struct(t) || is_type_raw_union(t))) { Entity *found = find_using_index_expr(t); if (found != NULL) { - valid = check_set_index_data(o, found->type, &max_count); + valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count); } } @@ -5125,7 +4964,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint goto error; } - o->mode = Addressing_Value; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Value; + } i64 indices[2] = {0}; AstNode *nodes[2] = {se->low, se->high}; @@ -5173,7 +5014,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } else { Type *t = base_type(o->type); if (t->kind == Type_Pointer) { - o->mode = Addressing_Variable; + if (o->mode != Addressing_Immutable) { + o->mode = Addressing_Variable; + } o->type = t->Pointer.elem; } else { gbString str = expr_to_string(o->expr); @@ -5354,12 +5197,6 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "}"); case_end; - case_ast_node(be, BlockExpr, node); - str = gb_string_appendc(str, "block expression"); - case_end; - case_ast_node(ie, IfExpr, node); - str = gb_string_appendc(str, "if expression"); - case_end; case_ast_node(te, TagExpr, node); str = gb_string_appendc(str, "#"); |