From 367d307dc48fb4ee6815141d2f22b69a0996eb66 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 17 Jan 2017 20:27:14 +0000 Subject: [PATCH] Fix conversion of untyped integers to pointers --- code/demo.odin | 6 ++++-- core/atomic.odin | 1 - core/sys/windows.odin | 4 ++-- src/check_expr.c | 50 ++++++++++++++++++++++++++++++++++++++++--- src/ir.c | 37 ++++++++++++++++++++++---------- src/parser.c | 10 ++++----- src/types.c | 45 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 129 insertions(+), 24 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 1602450a1..83d9f09e0 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -5,6 +5,7 @@ #import "mem.odin"; #import "opengl.odin"; #import "os.odin"; +#import win32 "sys/windows.odin"; #import "sync.odin"; #import "utf8.odin"; @@ -16,6 +17,9 @@ main :: proc() { fmt.println("rawptr"); } + THINGI :: 14451; + THINGF :: 14451.1; + a: i32; b: f32; c: rawptr; @@ -35,8 +39,6 @@ main :: proc() { i := f as int; fmt.printf("f64 arg, f=%d\n", i); } - THINGI :: 14451; - THINGF :: 14451.1; foo(); foo(THINGI as int); diff --git a/core/atomic.odin b/core/atomic.odin index 2ed69c438..cc381300e 100644 --- a/core/atomic.odin +++ b/core/atomic.odin @@ -29,7 +29,6 @@ fetch_add :: proc(a: ^i32, operand: i32) -> i32 { } fetch_and :: proc(a: ^i32, operand: i32) -> i32 { return win32.InterlockedAnd(a, operand); - } fetch_or :: proc(a: ^i32, operand: i32) -> i32 { return win32.InterlockedOr(a, operand); diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 959f96a54..df9f5aea7 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -19,7 +19,7 @@ BOOL :: i32; WNDPROC :: type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; -INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE; +INVALID_HANDLE_VALUE :: ~int(0) as HANDLE; FALSE: BOOL : 0; TRUE: BOOL : 1; @@ -46,7 +46,7 @@ WM_KEYUP :: 0x0101; PM_REMOVE :: 1; -COLOR_BACKGROUND :: 1 as HBRUSH; +COLOR_BACKGROUND :: HBRUSH(int(1)); BLACK_BRUSH :: 4; SM_CXSCREEN :: 0; diff --git a/src/check_expr.c b/src/check_expr.c index bd8183069..0096c7566 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1398,7 +1398,8 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type return true; } if (in_value.kind == ExactValue_Integer) { - return true; + return false; + // return true; } if (out_value) *out_value = in_value; } @@ -1727,6 +1728,7 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) { return true; } + if (dst->kind == Type_Array && src->kind == Type_Array) { if (are_types_identical(dst->Array.elem, src->Array.elem)) { return dst->Array.count == src->Array.count; @@ -1868,6 +1870,8 @@ void check_conversion(Checker *c, Operand *x, Type *type) { if (bt->kind == Type_Basic) { if (check_representable_as_constant(c, x->value, bt, &x->value)) { can_convert = true; + } else if (is_type_pointer(type) && check_is_castable_to(c, x, type)) { + can_convert = true; } } } else if (check_is_castable_to(c, x, type)) { @@ -2478,8 +2482,10 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h goto error; } - if (ast_node_expect(selector, AstNode_Ident)) { - + // if (selector->kind != AstNode_Ident && selector->kind != AstNode_BasicLit) { + if (selector->kind != AstNode_Ident) { + error_node(selector, "Illegal selector kind: `%.*s`", LIT(ast_node_strings[selector->kind])); + goto error; } if (op_expr->kind == AstNode_Ident) { @@ -2577,6 +2583,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h } } } + if (check_op_expr) { check_expr_base(c, operand, op_expr, NULL); if (operand->mode == Addressing_Invalid) { @@ -2589,6 +2596,43 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type); entity = sel.entity; } + if (entity == NULL && selector->kind == AstNode_BasicLit) { + if (is_type_struct(operand->type) || is_type_tuple(operand->type)) { + Type *type = base_type(operand->type); + Operand o = {0}; + check_expr(c, &o, selector); + if (o.mode != Addressing_Constant || + !is_type_integer(o.type)) { + error_node(op_expr, "Indexed based selectors must be a constant integer %s"); + goto error; + } + i64 index = o.value.value_integer; + if (index < 0) { + error_node(o.expr, "Index %lld cannot be a negative value", index); + goto error; + } + + i64 max_count = 0; + switch (type->kind) { + case Type_Record: max_count = type->Record.field_count; break; + case Type_Tuple: max_count = type->Tuple.variable_count; break; + } + + if (index >= max_count) { + error_node(o.expr, "Index %lld is out of bounds range 0..<%lld", index, max_count); + goto error; + } + + sel = lookup_field_from_index(heap_allocator(), type, index); + entity = sel.entity; + + GB_ASSERT(entity != NULL); + + } else { + error_node(op_expr, "Indexed based selectors may only be used on structs or tuples"); + goto error; + } + } if (entity == NULL) { gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string(operand->type); diff --git a/src/ir.c b/src/ir.c index 1888c71e6..4ad0db922 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1718,7 +1718,10 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec } else if (type->kind == Type_Record) { type = type->Record.fields[index]->type; e = ir_emit_struct_ep(proc, e, index); - } else if (type->kind == Type_Basic) { + } else if (type->kind == Type_Tuple) { + type = type->Tuple.variables[index]->type; + e = ir_emit_struct_ep(proc, e, index); + }else if (type->kind == Type_Basic) { switch (type->Basic.kind) { case Basic_any: { if (index == 0) { @@ -3351,19 +3354,31 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { case_ast_node(se, SelectorExpr, expr); ir_emit_comment(proc, str_lit("SelectorExpr")); AstNode *sel = unparen_expr(se->selector); - GB_ASSERT(sel->kind == AstNode_Ident); - String selector = sel->Ident.string; - Type *type = base_type(type_of_expr(proc->module->info, se->expr)); + if (sel->kind == AstNode_Ident) { + String selector = sel->Ident.string; + Type *type = base_type(type_of_expr(proc->module->info, se->expr)); - if (type == t_invalid) { - // NOTE(bill): Imports - Entity *imp = entity_of_ident(proc->module->info, se->expr); - if (imp != NULL) { - GB_ASSERT(imp->kind == Entity_ImportName); + if (type == t_invalid) { + // NOTE(bill): Imports + Entity *imp = entity_of_ident(proc->module->info, se->expr); + if (imp != NULL) { + GB_ASSERT(imp->kind == Entity_ImportName); + } + return ir_build_addr(proc, unparen_expr(se->selector)); + } else { + Selection sel = lookup_field(proc->module->allocator, type, selector, false); + GB_ASSERT(sel.entity != NULL); + + irValue *a = ir_build_addr(proc, se->expr).addr; + a = ir_emit_deep_field_gep(proc, type, a, sel); + return ir_make_addr(a, expr); } - return ir_build_addr(proc, unparen_expr(se->selector)); } else { - Selection sel = lookup_field(proc->module->allocator, type, selector, false); + Type *type = base_type(type_of_expr(proc->module->info, se->expr)); + ExactValue val = type_and_value_of_expression(proc->module->info, sel)->value; + i64 index = val.value_integer; + + Selection sel = lookup_field_from_index(proc->module->allocator, type, index); GB_ASSERT(sel.entity != NULL); irValue *a = ir_build_addr(proc, se->expr).addr; diff --git a/src/parser.c b/src/parser.c index 3e5486a64..f42e3c94c 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1854,15 +1854,15 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) { case Token_Ident: operand = make_selector_expr(f, token, operand, parse_identifier(f)); break; - case Token_Integer: - operand = make_selector_expr(f, token, operand, parse_expr(f, lhs)); - break; - default: { + // case Token_Integer: + // operand = make_selector_expr(f, token, operand, parse_expr(f, lhs)); + // break; + default: syntax_error(f->curr_token, "Expected a selector"); next_token(f); operand = make_bad_expr(f, ast_node_token(operand), f->curr_token); // operand = make_selector_expr(f, f->curr_token, operand, NULL); - } break; + break; } } break; diff --git a/src/types.c b/src/types.c index 9981b197d..c71f162c4 100644 --- a/src/types.c +++ b/src/types.c @@ -980,6 +980,51 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, bool is_ty return lookup_field_with_selection(a, type_, field_name, is_type, empty_selection); } +Selection lookup_field_from_index(gbAllocator a, Type *type, i64 index) { + GB_ASSERT(is_type_struct(type) || is_type_tuple(type)); + type = base_type(type); + + i64 max_count = 0; + switch (type->kind) { + case Type_Record: max_count = type->Record.field_count; break; + case Type_Tuple: max_count = type->Tuple.variable_count; break; + } + + if (index >= max_count) { + return empty_selection; + } + + switch (type->kind) { + case Type_Record: + for (isize i = 0; i < max_count; i++) { + Entity *f = type->Record.fields[i]; + if (f->kind == Entity_Variable) { + if (f->Variable.field_src_index == index) { + Array_isize sel_array = {0}; + array_init_count(&sel_array, a, 1); + sel_array.e[0] = i; + return make_selection(f, sel_array, false); + } + } + } + break; + case Type_Tuple: + for (isize i = 0; i < max_count; i++) { + Entity *f = type->Tuple.variables[i]; + if (i == index) { + Array_isize sel_array = {0}; + array_init_count(&sel_array, a, 1); + sel_array.e[0] = i; + return make_selection(f, sel_array, false); + } + } + break; + } + + GB_PANIC("Illegal index"); + return empty_selection; +} + Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) { GB_ASSERT(type_ != NULL);