소스 검색

Fix conversion of untyped integers to pointers

Ginger Bill 8 년 전
부모
커밋
367d307dc4
7개의 변경된 파일130개의 추가작업 그리고 25개의 파일을 삭제
  1. 4 2
      code/demo.odin
  2. 0 1
      core/atomic.odin
  3. 2 2
      core/sys/windows.odin
  4. 47 3
      src/check_expr.c
  5. 27 12
      src/ir.c
  6. 5 5
      src/parser.c
  7. 45 0
      src/types.c

+ 4 - 2
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);

+ 0 - 1
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);

+ 2 - 2
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;

+ 47 - 3
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);

+ 27 - 12
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 (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 (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);
+				}
+				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;

+ 5 - 5
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;
 

+ 45 - 0
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);