diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-01-15 12:00:13 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-01-15 12:00:13 +0000 |
| commit | 6fe25badf067d63c79999814f46be0ac79a39ef8 (patch) | |
| tree | f16c268add842c56c82a95f5be19e117ea27c088 /src/check_expr.c | |
| parent | c29d433e381a4505045fccc02f2d00fafcc7f32f (diff) | |
Bug fix: comparisons with shifts
Diffstat (limited to 'src/check_expr.c')
| -rw-r--r-- | src/check_expr.c | 324 |
1 files changed, 100 insertions, 224 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index c52d463f2..eee69ee45 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -28,143 +28,11 @@ gb_inline Type *check_type(Checker *c, AstNode *expression) { -typedef struct DelayedEntity { - AstNode * ident; - Entity * entity; - DeclInfo * decl; -} DelayedEntity; - -typedef struct DelayedOtherFields { - Entity **other_fields; - isize other_field_count; - isize other_field_index; - - MapEntity *entity_map; -} DelayedOtherFields; - -typedef Array(DelayedEntity) DelayedEntities; - -void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntities *delayed_entities, DelayedOtherFields *dof); - -void check_local_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, DelayedEntities *delayed_entities, DelayedOtherFields *dof) { - Operand operand = {Addressing_Invalid}; - check_expr(c, &operand, ws->cond); - if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) { - error_node(ws->cond, "Non-boolean condition in `when` statement"); - } - if (operand.mode != Addressing_Constant) { - error_node(ws->cond, "Non-constant condition in `when` statement"); - } - if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) { - error_node(ws->cond, "Invalid body for `when` statement"); - } else { - if (operand.value.kind == ExactValue_Bool && - operand.value.value_bool) { - check_local_collect_entities(c, ws->body->BlockStmt.stmts, delayed_entities, dof); - } else if (ws->else_stmt) { - switch (ws->else_stmt->kind) { - case AstNode_BlockStmt: - check_local_collect_entities(c, ws->else_stmt->BlockStmt.stmts, delayed_entities, dof); - break; - case AstNode_WhenStmt: - check_local_collect_entities_from_when_stmt(c, &ws->else_stmt->WhenStmt, delayed_entities, dof); - break; - default: - error_node(ws->else_stmt, "Invalid `else` statement in `when` statement"); - break; - } - } - } -} - -// NOTE(bill): The `dof` is for use within records -void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntities *delayed_entities, DelayedOtherFields *dof) { - for_array(i, nodes) { - AstNode *node = nodes.e[i]; - switch (node->kind) { - case_ast_node(ws, WhenStmt, node); - // Will be handled later - case_end; - - case_ast_node(vd, ValueDecl, node); - if (vd->is_var) { - // NOTE(bill): Handled later - } else { - for_array(i, vd->names) { - AstNode *name = vd->names.e[i]; - if (name->kind != AstNode_Ident) { - error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind])); - continue; - } - - AstNode *init = NULL; - if (i < vd->values.count) { - init = vd->values.e[i]; - } - - DeclInfo *d = make_declaration_info(c->allocator, c->context.scope); - Entity *e = NULL; - - AstNode *up_init = unparen_expr(init); - if (init != NULL && is_ast_node_type(up_init)) { - e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL); - d->type_expr = init; - d->init_expr = init; - } else if (init != NULL && up_init->kind == AstNode_ProcLit) { - e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags); - d->proc_lit = init; - } else { - e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0}); - d->type_expr = vd->type; - d->init_expr = init; - } - GB_ASSERT(e != NULL); - e->identifier = name; - - add_entity_and_decl_info(c, name, e, d); - - DelayedEntity delay = {name, e, d}; - array_add(delayed_entities, delay); - } - - check_arity_match(c, vd); - } - case_end; -#if 0 - case_ast_node(pd, ProcDecl, node); - if (!ast_node_expect(pd->name, AstNode_Ident)) { - break; - } - - Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL); - e->identifier = pd->name; - - DeclInfo *d = make_declaration_info(c->allocator, e->scope); - d->proc_lit = node; - - add_entity_and_decl_info(c, pd->name, e, d); - check_entity_decl(c, e, d, NULL, NULL); - case_end; -#endif - } - } - - // NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something - // declared after this stmt in source - for_array(i, nodes) { - AstNode *node = nodes.e[i]; - switch (node->kind) { - case_ast_node(ws, WhenStmt, node); - check_local_collect_entities_from_when_stmt(c, ws, delayed_entities, dof); - case_end; - } - } -} - -void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size, DelayedOtherFields *dof) { +void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) { + GB_ASSERT(!c->context.scope->is_file); DelayedEntities delayed_entities; array_init_reserve(&delayed_entities, heap_allocator(), reserve_size); - check_local_collect_entities(c, nodes, &delayed_entities, dof); + check_collect_entities(c, nodes, NULL, &delayed_entities); for_array(i, delayed_entities) { DelayedEntity delayed = delayed_entities.e[i]; @@ -462,7 +330,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Type *type = check_type_extra(c, f->type, NULL); - if (f->is_using) { + if (f->flags&FieldFlag_using) { if (f->names.count > 1) { error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type"); } @@ -476,7 +344,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Token name_token = name->Ident; - Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->is_using, cast(i32)field_index); + Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->flags&FieldFlag_using, cast(i32)field_index); e->identifier = name; if (str_eq(name_token.string, str_lit("_"))) { fields[field_index++] = e; @@ -495,7 +363,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, } - if (f->is_using) { + if (f->flags&FieldFlag_using) { Type *t = base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t) && f->names.count >= 1 && @@ -843,7 +711,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v for_array(j, p->names) { AstNode *name = p->names.e[j]; if (ast_node_expect(name, AstNode_Ident)) { - Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->is_using); + Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->flags&FieldFlag_using); add_entity(c, scope, name, param); variables[variable_index++] = param; } @@ -966,25 +834,15 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { o->type = t_invalid; return; } - #if 0 - if (e->Variable.param) { - o->mode = Addressing_Value; - } else { - o->mode = Addressing_Variable; - } - #else o->mode = Addressing_Variable; if (e->Variable.is_immutable) { o->mode = Addressing_Value; } - #endif break; case Entity_TypeName: { o->mode = Addressing_Type; -#if 1 - // TODO(bill): Fix cyclical dependancy checker -#endif + // TODO(bill): Fix cyclical dependancy checker } break; case Entity_Procedure: @@ -1028,7 +886,7 @@ i64 check_array_count(Checker *c, AstNode *e) { } return 0; } - Type *type = base_type(base_enum_type(o.type)); + Type *type = base_type(o.type); if (is_type_untyped(type) || is_type_integer(type)) { if (o.value.kind == ExactValue_Integer) { i64 count = o.value.value_integer; @@ -1252,7 +1110,7 @@ end: bool check_unary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly - Type *type = base_type(base_enum_type(base_vector_type(o->type))); + Type *type = base_type(base_vector_type(o->type)); gbString str = NULL; switch (op.kind) { case Token_Add: @@ -1288,7 +1146,7 @@ bool check_unary_op(Checker *c, Operand *o, Token op) { bool check_binary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly - Type *type = base_type(base_enum_type(base_vector_type(o->type))); + Type *type = base_type(base_vector_type(o->type)); switch (op.kind) { case Token_Sub: case Token_SubEq: @@ -1359,6 +1217,7 @@ bool check_binary_op(Checker *c, Operand *o, Token op) { return true; } + bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) { if (in_value.kind == ExactValue_Invalid) { // NOTE(bill): There's already been an error @@ -1389,7 +1248,6 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa } i64 imax = (1ll << (s-1ll)); - switch (type->Basic.kind) { case Basic_i8: case Basic_i16: @@ -1581,16 +1439,15 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { o->mode = Addressing_Value; } -void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - +void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) { gbString err_str = NULL; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); if (check_is_assignable_to(c, x, y->type) || check_is_assignable_to(c, y, x->type)) { Type *err_type = x->type; bool defined = false; - switch (op.kind) { + switch (op) { case Token_CmpEq: case Token_NotEq: defined = is_type_comparable(x->type); @@ -1615,7 +1472,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { if (!defined) { gbString type_string = type_to_string(err_type); err_str = gb_string_make(c->tmp_allocator, - gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(op.string), type_string)); + gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(token_strings[op]), type_string)); gb_string_free(type_string); } } else { @@ -1633,7 +1490,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { } else { if (x->mode == Addressing_Constant && y->mode == Addressing_Constant) { - x->value = make_exact_value_bool(compare_exact_values(op.kind, x->value, y->value)); + x->value = make_exact_value_bool(compare_exact_values(op, x->value, y->value)); } else { x->mode = Addressing_Value; @@ -1650,8 +1507,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { if (err_str != NULL) { gb_string_free(err_str); - }; - + } gb_temp_arena_memory_end(tmp); } @@ -1665,7 +1521,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { } bool x_is_untyped = is_type_untyped(x->type); - if (!(is_type_integer(base_enum_type(x->type)) || (x_is_untyped && x_val.kind == ExactValue_Integer))) { + if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) { gbString err_str = expr_to_string(x->expr); error_node(node, "Shifted operand `%s` must be an integer", err_str); gb_string_free(err_str); @@ -1673,7 +1529,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { return; } - if (is_type_unsigned(base_enum_type(y->type))) { + if (is_type_unsigned(y->type)) { } else if (is_type_untyped(y->type)) { convert_to_typed(c, y, t_untyped_integer, 0); @@ -1702,7 +1558,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { } u64 amount = cast(u64)y_val.value_integer; - if (amount > 1074) { + if (amount > 64) { gbString err_str = expr_to_string(y->expr); error_node(node, "Shift amount too large: `%s`", err_str); gb_string_free(err_str); @@ -1710,7 +1566,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { return; } - if (!is_type_integer(base_enum_type(x->type))) { + if (!is_type_integer(x->type)) { // NOTE(bill): It could be an untyped float but still representable // as an integer x->type = t_untyped_integer; @@ -1719,17 +1575,19 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { x->value = exact_value_shift(be->op.kind, x_val, make_exact_value_integer(amount)); if (is_type_typed(x->type)) { - check_is_expressible(c, x, base_type(base_enum_type(x->type))); + check_is_expressible(c, x, base_type(x->type)); } return; } + TokenPos pos = ast_node_token(x->expr).pos; if (x_is_untyped) { ExprInfo *info = map_expr_info_get(&c->info.untyped, hash_pointer(x->expr)); if (info != NULL) { info->is_lhs = true; } x->mode = Addressing_Value; + // x->value = x_val; return; } } @@ -1740,6 +1598,14 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { gb_string_free(err_str); } + if (!is_type_integer(x->type)) { + gbString err_str = expr_to_string(y->expr); + error_node(node, "Shift operand `%s` must be an integer", err_str); + gb_string_free(err_str); + x->mode = Addressing_Invalid; + return; + } + x->mode = Addressing_Value; } @@ -2129,10 +1995,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { } if (op.kind == Token_Add || op.kind == Token_Sub) { - if (is_type_pointer(x->type) && is_type_integer(base_enum_type(y->type))) { + if (is_type_pointer(x->type) && is_type_integer(y->type)) { *x = check_ptr_addition(c, op.kind, x, y, node); return; - } else if (is_type_integer(base_enum_type(x->type)) && is_type_pointer(y->type)) { + } else if (is_type_integer(x->type) && is_type_pointer(y->type)) { if (op.kind == Token_Sub) { gbString lhs = expr_to_string(x->expr); gbString rhs = expr_to_string(y->expr); @@ -2159,7 +2025,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { } if (token_is_comparison(op)) { - check_comparison(c, x, y, op); + check_comparison(c, x, y, op.kind); return; } @@ -2259,48 +2125,58 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) { if (found == NULL) { return; } + ExprInfo old = *found; switch (e->kind) { case_ast_node(ue, UnaryExpr, e); - if (found->value.kind != ExactValue_Invalid) { + if (old.value.kind != ExactValue_Invalid) { + // NOTE(bill): if `e` is constant, the operands will be constant too. + // They don't need to be updated as they will be updated later and + // checked at the end of general checking stage. break; } update_expr_type(c, ue->expr, type, final); case_end; case_ast_node(be, BinaryExpr, e); - if (found->value.kind != ExactValue_Invalid) { + if (old.value.kind != ExactValue_Invalid) { + // See above note in UnaryExpr case break; } - if (!token_is_comparison(be->op)) { - if (token_is_shift(be->op)) { - update_expr_type(c, be->left, type, final); - } else { - update_expr_type(c, be->left, type, final); - update_expr_type(c, be->right, type, final); - } + if (token_is_comparison(be->op)) { + } + else if (token_is_shift(be->op)) { + update_expr_type(c, be->left, type, final); + } else { + update_expr_type(c, be->left, type, final); + update_expr_type(c, be->right, type, final); } case_end; + + case_ast_node(pe, ParenExpr, e); + update_expr_type(c, pe->expr, type, final); + case_end; } if (!final && is_type_untyped(type)) { - found->type = base_type(type); - map_expr_info_set(&c->info.untyped, key, *found); - } else { - ExprInfo old = *found; - map_expr_info_remove(&c->info.untyped, key); + old.type = base_type(type); + map_expr_info_set(&c->info.untyped, key, old); + return; + } - if (old.is_lhs && !is_type_integer(type)) { - gbString expr_str = expr_to_string(e); - gbString type_str = type_to_string(type); - error_node(e, "Shifted operand %s must be an integer, got %s", expr_str, type_str); - gb_string_free(type_str); - gb_string_free(expr_str); - return; - } + // We need to remove it and then give it a new one + map_expr_info_remove(&c->info.untyped, key); - add_type_and_value(&c->info, e, found->mode, type, found->value); + if (old.is_lhs && !is_type_integer(type)) { + gbString expr_str = expr_to_string(e); + gbString type_str = type_to_string(type); + error_node(e, "Shifted operand %s must be an integer, got %s", expr_str, type_str); + gb_string_free(type_str); + gb_string_free(expr_str); + return; } + + add_type_and_value(&c->info, e, old.mode, type, old.value); } void update_expr_value(Checker *c, AstNode *e, ExactValue value) { @@ -2426,7 +2302,7 @@ bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *val return false; } - if (!is_type_integer(base_enum_type(operand.type))) { + if (!is_type_integer(operand.type)) { gbString expr_str = expr_to_string(operand.expr); error_node(operand.expr, "Index `%s` must be an integer", expr_str); gb_string_free(expr_str); @@ -2665,7 +2541,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (op.mode == Addressing_Invalid) { return false; } - if (!is_type_integer(base_enum_type(op.type))) { + if (!is_type_integer(op.type)) { gbString type_str = type_to_string(op.type); error_node(call, "Length for `new_slice` must be an integer, got `%s`", type_str); gb_string_free(type_str); @@ -4605,7 +4481,6 @@ gbString write_expr_to_string(gbString str, AstNode *node); gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) { for_array(i, params) { - ast_node(p, Field, params.e[i]); if (i > 0) { str = gb_string_appendc(str, sep); } @@ -4615,6 +4490,18 @@ gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) { return str; } +gbString write_record_fields_to_string(gbString str, AstNodeArray params) { + for_array(i, params) { + if (i > 0) { + str = gb_string_appendc(str, " "); + } + str = write_expr_to_string(str, params.e[i]); + str = gb_string_appendc(str, ";"); + + } + return str; +} + gbString string_append_token(gbString str, Token token) { if (token.string.len > 0) { return gb_string_append_length(str, token.string.text, token.string.len); @@ -4758,12 +4645,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = write_expr_to_string(str, vt->elem); case_end; - case_ast_node(p, Field, node); - if (p->is_using) { + case_ast_node(f, Field, node); + if (f->flags&FieldFlag_using) { str = gb_string_appendc(str, "using "); } - for_array(i, p->names) { - AstNode *name = p->names.e[i]; + for_array(i, f->names) { + AstNode *name = f->names.e[i]; if (i > 0) { str = gb_string_appendc(str, ", "); } @@ -4771,7 +4658,10 @@ gbString write_expr_to_string(gbString str, AstNode *node) { } str = gb_string_appendc(str, ": "); - str = write_expr_to_string(str, p->type); + if (f->flags&FieldFlag_ellipsis) { + str = gb_string_appendc(str, "..."); + } + str = write_expr_to_string(str, f->type); case_end; case_ast_node(ce, CallExpr, node); @@ -4798,37 +4688,22 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "struct "); if (st->is_packed) str = gb_string_appendc(str, "#packed "); if (st->is_ordered) str = gb_string_appendc(str, "#ordered "); - for_array(i, st->fields) { - if (i > 0) { - str = gb_string_appendc(str, "; "); - } - str = write_expr_to_string(str, st->fields.e[i]); - } - // str = write_params_to_string(str, st->decl_list, ", "); + str = gb_string_appendc(str, "{"); + str = write_record_fields_to_string(str, st->fields); str = gb_string_appendc(str, "}"); case_end; case_ast_node(st, RawUnionType, node); - str = gb_string_appendc(str, "raw_union {"); - for_array(i, st->fields) { - if (i > 0) { - str = gb_string_appendc(str, "; "); - } - str = write_expr_to_string(str, st->fields.e[i]); - } - // str = write_params_to_string(str, st->decl_list, ", "); + str = gb_string_appendc(str, "raw_union "); + str = gb_string_appendc(str, "{"); + str = write_record_fields_to_string(str, st->fields); str = gb_string_appendc(str, "}"); case_end; case_ast_node(st, UnionType, node); - str = gb_string_appendc(str, "union {"); - for_array(i, st->fields) { - if (i > 0) { - str = gb_string_appendc(str, "; "); - } - str = write_expr_to_string(str, st->fields.e[i]); - } - // str = write_params_to_string(str, st->decl_list, ", "); + str = gb_string_appendc(str, "union "); + str = gb_string_appendc(str, "{"); + str = write_record_fields_to_string(str, st->fields); str = gb_string_appendc(str, "}"); case_end; @@ -4839,6 +4714,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, " "); } str = gb_string_appendc(str, "{"); + str = write_params_to_string(str, et->fields, ", "); str = gb_string_appendc(str, "}"); case_end; |