Best viable overloading procedure algorithm; no_alias; call expr style casts

This commit is contained in:
Ginger Bill
2017-01-17 15:20:11 +00:00
parent 6dc6b6f8aa
commit 383f5b55ad
14 changed files with 366 additions and 222 deletions
+21 -4
View File
@@ -2,9 +2,23 @@
#import "fmt.odin"; #import "fmt.odin";
#import "math.odin"; #import "math.odin";
#import "mem.odin"; #import "mem.odin";
#import "opengl.odin";
main :: proc() { main :: proc() {
foo :: proc(x: ^int) {
fmt.println("^int");
}
foo :: proc(x: rawptr) {
fmt.println("rawptr");
}
a: ^int;
b: ^f32;
c: rawptr;
foo(a);
foo(b);
foo(c);
// foo(nil);
foo :: proc() { foo :: proc() {
fmt.printf("Zero args\n"); fmt.printf("Zero args\n");
} }
@@ -18,13 +32,16 @@ main :: proc() {
THINGI :: 14451; THINGI :: 14451;
THINGF :: 14451.1; THINGF :: 14451.1;
foo(); foo();
foo(THINGI as int); foo(THINGI as int);
foo(int(THINGI));
// foo(THINGI);
foo(THINGF); foo(THINGF);
fmt.println(THINGI); fmt.println(THINGI);
fmt.println(THINGF); fmt.println(THINGF);
x: proc(); f: proc();
x = foo; f = foo;
x(); f();
} }
+2 -2
View File
@@ -297,11 +297,11 @@ __string_eq :: proc(a, b: string) -> bool {
if a.data == b.data { if a.data == b.data {
return true; return true;
} }
return mem.compare(a.data, b.data, a.count) == 0; return mem.compare(a.data as rawptr, b.data as rawptr, a.count) == 0;
} }
__string_cmp :: proc(a, b: string) -> int { __string_cmp :: proc(a, b: string) -> int {
return mem.compare(a.data, b.data, min(a.count, b.count)); return mem.compare(a.data as rawptr, b.data as rawptr, min(a.count, b.count));
} }
__string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); } __string_ne :: proc(a, b: string) -> bool #inline { return !__string_eq(a, b); }
+7 -7
View File
@@ -236,7 +236,7 @@ bprint :: proc(buf: ^Buffer, args: ...any) -> int {
if i > 0 && !is_string && !prev_string { if i > 0 && !is_string && !prev_string {
buffer_write_rune(buf, ' '); buffer_write_rune(buf, ' ');
} }
fmt_value(^fi, arg, 'v'); fmt_value(^fi, args[i], 'v');
prev_string = is_string; prev_string = is_string;
} }
return buf.length; return buf.length;
@@ -250,7 +250,7 @@ bprintln :: proc(buf: ^Buffer, args: ...any) -> int {
if i > 0 { if i > 0 {
buffer_write_rune(buf, ' '); buffer_write_rune(buf, ' ');
} }
fmt_value(^fi, arg, 'v'); fmt_value(^fi, args[i], 'v');
} }
buffer_write_rune(buf, '\n'); buffer_write_rune(buf, '\n');
return buf.length; return buf.length;
@@ -967,16 +967,16 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
} }
if is_type_integer(e.base) { if is_type_integer(e.base) {
for val, idx : e.values { for it, idx : e.values {
if val.i == i { if it.i == i {
buffer_write_string(fi.buf, e.names[idx]); buffer_write_string(fi.buf, e.names[idx]);
ok = true; ok = true;
break; break;
} }
} }
} else { } else {
for val, idx : e.values { for it, idx : e.values {
if val.f == f { if it.f == f {
buffer_write_string(fi.buf, e.names[idx]); buffer_write_string(fi.buf, e.names[idx]);
ok = true; ok = true;
break; break;
@@ -1312,7 +1312,7 @@ bprintf :: proc(b: ^Buffer, fmt: string, args: ...any) -> int {
if arg.data == nil || arg.type_info == nil { if arg.data == nil || arg.type_info == nil {
buffer_write_string(b, "<nil>"); buffer_write_string(b, "<nil>");
} else { } else {
fmt_arg(^fi, arg, 'v'); fmt_arg(^fi, args[index], 'v');
} }
} }
buffer_write_string(b, ")"); buffer_write_string(b, ")");
+1 -1
View File
@@ -166,7 +166,7 @@ mul :: proc(a, b: Mat4) -> Mat4 {
return c; return c;
} }
mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 { mul :: proc(m: Mat4, v: Vec4) -> Vec4 {
return Vec4{ return Vec4{
m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w, m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z + m[3][0]*v.w,
m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w, m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w,
+3 -2
View File
@@ -276,8 +276,9 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
check_init_constant(c, e, &operand); check_init_constant(c, e, &operand);
if (operand.mode == Addressing_Invalid) { if (operand.mode == Addressing_Invalid ||
error(e->token, "Illegal cyclic declaration"); base_type(operand.type) == t_invalid) {
error(e->token, "Invalid declaration type");
} }
} }
+260 -180
View File
@@ -1,24 +1,24 @@
void check_expr (Checker *c, Operand *operand, AstNode *expression); void check_expr (Checker *c, Operand *operand, AstNode *expression);
void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); void check_multi_expr (Checker *c, Operand *operand, AstNode *expression);
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression);
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type); Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type);
Type * check_type (Checker *c, AstNode *expression); Type * check_type (Checker *c, AstNode *expression);
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def);
Entity * check_selector (Checker *c, Operand *operand, AstNode *node); Entity * check_selector (Checker *c, Operand *operand, AstNode *node);
void check_not_tuple (Checker *c, Operand *operand); void check_not_tuple (Checker *c, Operand *operand);
bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level);
void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level); gbString expr_to_string (AstNode *expression);
gbString expr_to_string (AstNode *expression); void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type);
void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type); void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type);
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr, Type *named_type); void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body);
void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); void update_expr_type (Checker *c, AstNode *e, Type *type, bool final);
void update_expr_type (Checker *c, AstNode *e, Type *type, bool final); bool check_is_terminating (AstNode *node);
bool check_is_terminating (AstNode *node); bool check_has_break (AstNode *stmt, bool implicit);
bool check_has_break (AstNode *stmt, bool implicit); void check_stmt (Checker *c, AstNode *node, u32 flags);
void check_stmt (Checker *c, AstNode *node, u32 flags); void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags); void check_init_constant (Checker *c, Entity *e, Operand *operand);
void check_init_constant (Checker *c, Entity *e, Operand *operand); bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value);
gb_inline Type *check_type(Checker *c, AstNode *expression) { gb_inline Type *check_type(Checker *c, AstNode *expression) {
@@ -91,56 +91,70 @@ bool check_is_assignable_to_using_subtype(Type *dst, Type *src) {
} }
// IMPORTANT TODO(bill): figure out the exact distance rules
bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score) { // -1 is not convertable
// IMPORTANT TODO(bill): Determine score for assignments with use with overloaded procedures // 0 is exact
// >0 is convertable
i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
if (operand->mode == Addressing_Invalid || if (operand->mode == Addressing_Invalid ||
type == t_invalid) { type == t_invalid) {
if (score) *score = 0; return 0;
return true;
} }
if (operand->mode == Addressing_Builtin) { if (operand->mode == Addressing_Builtin) {
if (score) *score = 0; return -1;
return false;
} }
Type *s = operand->type; Type *s = operand->type;
if (are_types_identical(s, type)) { if (are_types_identical(s, type)) {
if (score) *score = 10; return 0;
return true;
} }
Type *src = base_type(s); Type *src = base_type(s);
Type *dst = base_type(type); Type *dst = base_type(type);
if (is_type_untyped_nil(src)) {
if (type_has_nil(dst)) {
return 1;
}
return -1;
}
if (is_type_untyped(src)) { if (is_type_untyped(src)) {
if (dst->kind == Type_Basic) { if (dst->kind == Type_Basic) {
if (operand->mode == Addressing_Constant) { if (operand->mode == Addressing_Constant) {
return check_value_is_expressible(c, operand->value, dst, NULL); if (check_representable_as_constant(c, operand->value, dst, NULL)) {
return 1;
} else {
return -1;
}
} }
if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) { if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) {
return is_type_boolean(dst); if (is_type_boolean(dst)) {
if (is_type_typed(type)) {
return 2;
}
return 1;
}
return -1;
} }
} }
if (type_has_nil(dst)) {
return operand->mode == Addressing_Value && operand->type == t_untyped_nil;
}
} }
if (are_types_identical(dst, src) && (!is_type_named(dst) || !is_type_named(src))) { if (are_types_identical(dst, src) && (!is_type_named(dst) || !is_type_named(src))) {
return true; return 1;
} }
if (is_type_maybe(dst)) { if (is_type_maybe(dst)) {
Type *elem = base_type(dst)->Maybe.elem; Type *elem = base_type(dst)->Maybe.elem;
bool ok = are_types_identical(elem, s); if (are_types_identical(elem, s)) {
return ok; return 1;
}
return -1;
} }
if (is_type_untyped_nil(src)) { if (check_is_assignable_to_using_subtype(operand->type, type)) {
return type_has_nil(dst); return 4;
} }
// ^T <- rawptr // ^T <- rawptr
@@ -151,33 +165,23 @@ bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type,
} }
#endif #endif
#if 1 #if 1
// TODO(bill): Should I allow this implicit conversion at all?!
// rawptr <- ^T // rawptr <- ^T
if (is_type_rawptr(dst) && is_type_pointer(src)) { if (is_type_rawptr(dst) && is_type_pointer(src)) {
// TODO(bill): Handle this properly
if (dst != type) { if (dst != type) {
return false; return -1;
} }
return true; return 5;
} }
#endif #endif
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;
}
}
if (dst->kind == Type_Slice && src->kind == Type_Slice) {
if (are_types_identical(dst->Slice.elem, src->Slice.elem)) {
return true;
}
}
if (is_type_union(dst)) { if (is_type_union(dst)) {
for (isize i = 0; i < dst->Record.field_count; i++) { for (isize i = 0; i < dst->Record.field_count; i++) {
Entity *f = dst->Record.fields[i]; Entity *f = dst->Record.fields[i];
if (are_types_identical(f->type, s)) { if (are_types_identical(f->type, s)) {
return true; return 1;
} }
} }
} }
@@ -186,10 +190,25 @@ bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type,
if (is_type_any(dst)) { if (is_type_any(dst)) {
// NOTE(bill): Anything can cast to `Any` // NOTE(bill): Anything can cast to `Any`
add_type_info_type(c, s); add_type_info_type(c, s);
return true; return 10;
} }
return false;
return -1;
}
bool check_is_assignable_to_with_score(Checker *c, Operand *operand, Type *type, i64 *score_) {
i64 score = 0;
i64 distance = check_distance_between_types(c, operand, type);
bool ok = distance >= 0;
if (ok) {
// TODO(bill): A decent score function
score = max(1000000 - distance*distance, 0);
}
if (score_) *score_ = score;
return ok;
} }
@@ -206,53 +225,58 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
return; return;
} }
if (is_type_untyped(operand->type)) { if (is_type_untyped(operand->type)) {
Type *target_type = type; Type *target_type = type;
if (type == NULL || is_type_any(type)) {
if (type == NULL || is_type_any(type) || is_type_untyped_nil(type)) { if (type == NULL && is_type_untyped_nil(operand->type)) {
if (type == NULL && base_type(operand->type) == t_untyped_nil) {
error_node(operand->expr, "Use of untyped nil in %.*s", LIT(context_name)); error_node(operand->expr, "Use of untyped nil in %.*s", LIT(context_name));
operand->mode = Addressing_Invalid; operand->mode = Addressing_Invalid;
return; return;
} }
add_type_info_type(c, type);
target_type = default_type(operand->type); target_type = default_type(operand->type);
add_type_info_type(c, type);
add_type_info_type(c, target_type);
} }
convert_to_typed(c, operand, target_type, 0); convert_to_typed(c, operand, target_type, 0);
if (operand->mode == Addressing_Invalid) { if (operand->mode == Addressing_Invalid) {
return; return;
} }
} }
if (type != NULL) {
if (!check_is_assignable_to(c, operand, type)) {
gbString type_str = type_to_string(type);
gbString op_type_str = type_to_string(operand->type);
gbString expr_str = expr_to_string(operand->expr);
if (operand->mode == Addressing_Builtin) {
// TODO(bill): is this a good enough error message?
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
} else {
// TODO(bill): is this a good enough error message?
error_node(operand->expr,
"Cannot assign value `%s` of type `%s` to `%s` in %.*s",
expr_str,
op_type_str,
type_str,
LIT(context_name));
}
operand->mode = Addressing_Invalid;
gb_string_free(expr_str);
gb_string_free(op_type_str); if (type == NULL) {
gb_string_free(type_str); return;
return; }
if (!check_is_assignable_to(c, operand, type)) {
gbString type_str = type_to_string(type);
gbString op_type_str = type_to_string(operand->type);
gbString expr_str = expr_to_string(operand->expr);
if (operand->mode == Addressing_Builtin) {
// TODO(bill): is this a good enough error message?
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
LIT(context_name));
} else {
// TODO(bill): is this a good enough error message?
error_node(operand->expr,
"Cannot assign value `%s` of type `%s` to `%s` in %.*s",
expr_str,
op_type_str,
type_str,
LIT(context_name));
} }
operand->mode = Addressing_Invalid;
gb_string_free(expr_str);
gb_string_free(op_type_str);
gb_string_free(type_str);
return;
} }
} }
@@ -727,10 +751,19 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
} }
Type *type = check_type(c, type_expr); Type *type = check_type(c, type_expr);
if (p->flags&FieldFlag_no_alias) {
if (!is_type_pointer(type)) {
error_node(params.e[i], "`no_alias` can only be applied to fields of pointer type");
p->flags &= ~FieldFlag_no_alias; // Remove the flag
}
}
for_array(j, p->names) { for_array(j, p->names) {
AstNode *name = p->names.e[j]; AstNode *name = p->names.e[j];
if (ast_node_expect(name, AstNode_Ident)) { if (ast_node_expect(name, AstNode_Ident)) {
Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->flags&FieldFlag_using); Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->flags&FieldFlag_using);
if (p->flags&FieldFlag_no_alias) {
param->flags |= EntityFlag_NoAlias;
}
add_entity(c, scope, name, param); add_entity(c, scope, name, param);
variables[variable_index++] = param; variables[variable_index++] = param;
} }
@@ -1288,7 +1321,7 @@ bool check_binary_op(Checker *c, Operand *o, Token op) {
} }
bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) { bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) {
if (in_value.kind == ExactValue_Invalid) { if (in_value.kind == ExactValue_Invalid) {
// NOTE(bill): There's already been an error // NOTE(bill): There's already been an error
return true; return true;
@@ -1374,7 +1407,7 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
void check_is_expressible(Checker *c, Operand *o, Type *type) { void check_is_expressible(Checker *c, Operand *o, Type *type) {
GB_ASSERT(is_type_constant_type(type)); GB_ASSERT(is_type_constant_type(type));
GB_ASSERT(o->mode == Addressing_Constant); GB_ASSERT(o->mode == Addressing_Constant);
if (!check_value_is_expressible(c, o->value, type, &o->value)) { if (!check_representable_as_constant(c, o->value, type, &o->value)) {
gbString a = expr_to_string(o->expr); gbString a = expr_to_string(o->expr);
gbString b = type_to_string(type); gbString b = type_to_string(type);
if (is_type_numeric(o->type) && is_type_numeric(type)) { if (is_type_numeric(o->type) && is_type_numeric(type)) {
@@ -1685,61 +1718,70 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
} }
Type *x = operand->type; Type *x = operand->type;
Type *xb = base_type(base_enum_type(x)); Type *src = base_type(base_enum_type(x));
Type *yb = base_type(base_enum_type(y)); Type *dst = base_type(base_enum_type(y));
if (are_types_identical(xb, yb)) { if (are_types_identical(src, dst)) {
return true; 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;
}
}
if (dst->kind == Type_Slice && src->kind == Type_Slice) {
return are_types_identical(dst->Slice.elem, src->Slice.elem);
}
// Cast between booleans and integers // Cast between booleans and integers
if (is_type_boolean(xb) || is_type_integer(xb)) { if (is_type_boolean(src) || is_type_integer(src)) {
if (is_type_boolean(yb) || is_type_integer(yb)) { if (is_type_boolean(dst) || is_type_integer(dst)) {
return true; return true;
} }
} }
// Cast between numbers // Cast between numbers
if (is_type_integer(xb) || is_type_float(xb)) { if (is_type_integer(src) || is_type_float(src)) {
if (is_type_integer(yb) || is_type_float(yb)) { if (is_type_integer(dst) || is_type_float(dst)) {
return true; return true;
} }
} }
// Cast between pointers // Cast between pointers
if (is_type_pointer(xb) && is_type_pointer(yb)) { if (is_type_pointer(src) && is_type_pointer(dst)) {
return true; return true;
} }
// (u)int <-> pointer // (u)int <-> pointer
if (is_type_int_or_uint(xb) && is_type_rawptr(yb)) { if (is_type_int_or_uint(src) && is_type_rawptr(dst)) {
return true; return true;
} }
if (is_type_rawptr(xb) && is_type_int_or_uint(yb)) { if (is_type_rawptr(src) && is_type_int_or_uint(dst)) {
return true; return true;
} }
// []byte/[]u8 <-> string // []byte/[]u8 <-> string
if (is_type_u8_slice(xb) && is_type_string(yb)) { if (is_type_u8_slice(src) && is_type_string(dst)) {
return true; return true;
} }
if (is_type_string(xb) && is_type_u8_slice(yb)) { if (is_type_string(src) && is_type_u8_slice(dst)) {
if (is_type_typed(xb)) { if (is_type_typed(src)) {
return true; return true;
} }
} }
// proc <-> proc // proc <-> proc
if (is_type_proc(xb) && is_type_proc(yb)) { if (is_type_proc(src) && is_type_proc(dst)) {
return true; return true;
} }
// proc -> rawptr // proc -> rawptr
if (is_type_proc(xb) && is_type_rawptr(yb)) { if (is_type_proc(src) && is_type_rawptr(dst)) {
return true; return true;
} }
// rawptr -> proc // rawptr -> proc
if (is_type_rawptr(xb) && is_type_proc(yb)) { if (is_type_rawptr(src) && is_type_proc(dst)) {
return true; return true;
} }
@@ -1814,6 +1856,48 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
} }
void check_conversion(Checker *c, Operand *x, Type *type) {
bool is_const_expr = x->mode == Addressing_Constant;
bool can_convert = false;
Type *bt = base_type(type);
if (is_const_expr && is_type_constant_type(bt)) {
if (bt->kind == Type_Basic) {
if (check_representable_as_constant(c, x->value, bt, &x->value)) {
can_convert = true;
}
}
} else if (check_is_castable_to(c, x, type)) {
if (x->mode != Addressing_Constant) {
x->mode = Addressing_Value;
}
can_convert = true;
}
if (!can_convert) {
gbString expr_str = expr_to_string(x->expr);
gbString to_type = type_to_string(type);
gbString from_type = type_to_string(x->type);
error_node(x->expr, "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type);
gb_string_free(from_type);
gb_string_free(to_type);
gb_string_free(expr_str);
x->mode = Addressing_Invalid;
return;
}
if (is_type_untyped(x->type)) {
Type *final_type = type;
if (is_const_expr && !is_type_constant_type(type)) {
final_type = default_type(x->type);
}
update_expr_type(c, x->expr, final_type, true);
}
x->type = type;
}
void check_binary_expr(Checker *c, Operand *x, AstNode *node) { void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
GB_ASSERT(node->kind == AstNode_BinaryExpr); GB_ASSERT(node->kind == AstNode_BinaryExpr);
Operand y_ = {0}, *y = &y_; Operand y_ = {0}, *y = &y_;
@@ -1827,46 +1911,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
if (x->mode == Addressing_Invalid) { if (x->mode == Addressing_Invalid) {
return; return;
} }
check_conversion(c, x, type);
bool is_const_expr = x->mode == Addressing_Constant;
bool can_convert = false;
Type *bt = base_type(type);
if (is_const_expr && is_type_constant_type(bt)) {
if (bt->kind == Type_Basic) {
if (check_value_is_expressible(c, x->value, bt, &x->value)) {
can_convert = true;
}
}
} else if (check_is_castable_to(c, x, type)) {
if (x->mode != Addressing_Constant) {
x->mode = Addressing_Value;
}
can_convert = true;
}
if (!can_convert) {
gbString expr_str = expr_to_string(x->expr);
gbString to_type = type_to_string(type);
gbString from_type = type_to_string(x->type);
error_node(x->expr, "Cannot cast `%s` as `%s` from `%s`", expr_str, to_type, from_type);
gb_string_free(from_type);
gb_string_free(to_type);
gb_string_free(expr_str);
x->mode = Addressing_Invalid;
return;
}
if (is_type_untyped(x->type)) {
Type *final_type = type;
if (is_const_expr && !is_type_constant_type(type)) {
final_type = default_type(x->type);
}
update_expr_type(c, x->expr, final_type, true);
}
x->type = type;
return; return;
} break; } break;
case Token_transmute: { case Token_transmute: {
@@ -2291,6 +2336,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
return; return;
} }
if (is_type_untyped(target_type)) { if (is_type_untyped(target_type)) {
GB_ASSERT(operand->type->kind == Type_Basic); GB_ASSERT(operand->type->kind == Type_Basic);
GB_ASSERT(target_type->kind == Type_Basic); GB_ASSERT(target_type->kind == Type_Basic);
@@ -2302,7 +2348,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
update_expr_type(c, operand->expr, target_type, false); update_expr_type(c, operand->expr, target_type, false);
} }
} else if (x_kind != y_kind) { } else if (x_kind != y_kind) {
convert_untyped_error(c, operand, target_type); goto error;
} }
return; return;
} }
@@ -2320,23 +2366,20 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
switch (operand->type->Basic.kind) { switch (operand->type->Basic.kind) {
case Basic_UntypedBool: case Basic_UntypedBool:
if (!is_type_boolean(target_type)) { if (!is_type_boolean(target_type)) {
convert_untyped_error(c, operand, target_type); goto error;
return;
} }
break; break;
case Basic_UntypedInteger: case Basic_UntypedInteger:
case Basic_UntypedFloat: case Basic_UntypedFloat:
case Basic_UntypedRune: case Basic_UntypedRune:
if (!is_type_numeric(target_type)) { if (!is_type_numeric(target_type)) {
convert_untyped_error(c, operand, target_type); goto error;
return;
} }
break; break;
case Basic_UntypedNil: case Basic_UntypedNil:
if (!type_has_nil(target_type)) { if (!type_has_nil(target_type)) {
convert_untyped_error(c, operand, target_type); goto error;
return;
} }
break; break;
} }
@@ -2347,21 +2390,24 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
if (is_type_untyped_nil(operand->type)) { if (is_type_untyped_nil(operand->type)) {
// Okay // Okay
} else if (level == 0) { } else if (level == 0) {
convert_to_typed(c, operand, t->Maybe.elem, level+1); goto error;
return;
} }
default: default:
if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
convert_untyped_error(c, operand, target_type); goto error;
return;
} }
target_type = t_untyped_nil;
break; break;
} }
operand->type = target_type; operand->type = target_type;
update_expr_type(c, operand->expr, target_type, true);
return;
error:
operand->mode = Addressing_Invalid;
convert_untyped_error(c, operand, target_type);
} }
bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) { bool check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) {
@@ -3525,6 +3571,17 @@ CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type
return err; return err;
} }
typedef struct ValidProcAndScore {
isize index;
i64 score;
} ValidProcAndScore;
int valid_proc_and_score_cmp(void const *a, void const *b) {
i64 si = (cast(ValidProcAndScore const *)a)->score;
i64 sj = (cast(ValidProcAndScore const *)b)->score;
return sj < si ? -1 : sj > si;
}
Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
GB_ASSERT(call->kind == AstNode_CallExpr); GB_ASSERT(call->kind == AstNode_CallExpr);
@@ -3553,11 +3610,10 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
String name = operand->initial_overload_entity->token.string; String name = operand->initial_overload_entity->token.string;
HashKey key = hash_string(name); HashKey key = hash_string(name);
isize overload_count = operand->overload_count; isize overload_count = operand->overload_count;
Entity **procs = gb_alloc_array(heap_allocator(), Entity *, overload_count); Entity ** procs = gb_alloc_array(heap_allocator(), Entity *, overload_count);
isize * valid_procs = gb_alloc_array(heap_allocator(), isize, overload_count); ValidProcAndScore *valids = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count);
i64 * valid_scores = gb_alloc_array(heap_allocator(), i64, overload_count); isize valid_count = 0;
isize valid_count = 0;
map_entity_multi_get_all(&s->elements, key, procs); map_entity_multi_get_all(&s->elements, key, procs);
@@ -3576,44 +3632,49 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod
i64 score = 0; i64 score = 0;
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, false, &score); CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, false, &score);
if (err == CallArgumentError_None) { if (err == CallArgumentError_None) {
valid_procs[valid_count] = i; valids[valid_count].index = i;
valid_scores[valid_count] = score; valids[valid_count].score = score;
valid_count++; valid_count++;
} }
} }
} }
// IMPORTANT TODO(bill): Get the best proc by its score if (valid_count > 1) {
// i64 best_score = 0; gb_sort_array(valids, valid_count, valid_proc_and_score_cmp);
// isize best_index = 0; i64 best_score = valids[0].score;
// for (isize i = 0; i < valid_count; i++) { for (isize i = 0; i < valid_count; i++) {
// if (best_score < valid_scores[i]) { if (best_score > valids[i].score) {
// best_score = valid_scores[i]; valid_count = i;
// best_index = i; break;
// } }
// } best_score = valids[i].score;
}
}
if (valid_count == 0) { if (valid_count == 0) {
error_node(operand->expr, "No overloads for `%.*s` that match the specified arguments", LIT(name)); error_node(operand->expr, "No overloads for `%.*s` that match with the given arguments", LIT(name));
proc_type = t_invalid; proc_type = t_invalid;
} else if (valid_count > 1) { } else if (valid_count > 1) {
error_node(operand->expr, "Ambiguous procedure call `%.*s`, could be:", LIT(name)); error_node(operand->expr, "Ambiguous procedure call `%.*s`, could be:", LIT(name));
for (isize i = 0; i < valid_count; i++) { for (isize i = 0; i < valid_count; i++) {
TokenPos pos = procs[valid_procs[i]]->token.pos; Entity *proc = procs[valids[i].index];
gb_printf_err("\t`%.*s` at %.*s(%td:%td)\n", LIT(name), LIT(pos.file), pos.line, pos.column); TokenPos pos = proc->token.pos;
gbString pt = type_to_string(proc->type);
gb_printf_err("\t%.*s :: %s at %.*s(%td:%td)\n", LIT(name), pt, LIT(pos.file), pos.line, pos.column);
gb_string_free(pt);
} }
proc_type = t_invalid; proc_type = t_invalid;
} else { } else {
GB_ASSERT(operand->expr->kind == AstNode_Ident); GB_ASSERT(operand->expr->kind == AstNode_Ident);
Entity *e = procs[valid_procs[0]]; Entity *e = procs[valids[0].index];
add_entity_use(c, operand->expr, e); add_entity_use(c, operand->expr, e);
proc_type = e->type; proc_type = e->type;
i64 score = 0; i64 score = 0;
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, true, &score); CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.e, operands.count, true, &score);
} }
gb_free(heap_allocator(), valid_procs); gb_free(heap_allocator(), valids);
gb_free(heap_allocator(), procs); gb_free(heap_allocator(), procs);
} else { } else {
i64 score = 0; i64 score = 0;
@@ -3660,6 +3721,25 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
return Expr_Stmt; return Expr_Stmt;
} }
if (operand->mode == Addressing_Type) {
Type *t = operand->type;
gbString str = type_to_string(t);
operand->mode = Addressing_Invalid;
isize arg_count = ce->args.count;
switch (arg_count) {
case 0: error_node(call, "Missing argument in convertion to `%s`", str); break;
default: error_node(call, "Too many arguments in convertion to `%s`", str); break;
case 1:
check_expr(c, operand, ce->args.e[0]);
if (operand->mode != Addressing_Invalid) {
check_conversion(c, operand, t);
}
break;
}
gb_string_free(str);
return Expr_Expr;
}
if (operand->mode == Addressing_Builtin) { if (operand->mode == Addressing_Builtin) {
i32 id = operand->builtin_id; i32 id = operand->builtin_id;
+3 -1
View File
@@ -680,11 +680,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} }
break; break;
case Type_Array: case Type_Array:
// val = make_type_pointer(c->allocator, t->Array.elem);
val = t->Array.elem; val = t->Array.elem;
idx = t_int; idx = t_int;
break; break;
case Type_Slice: case Type_Slice:
val = t->Array.elem; // val = make_type_pointer(c->allocator, t->Slice.elem);
val = t->Slice.elem;
idx = t_int; idx = t_int;
break; break;
} }
+10 -6
View File
@@ -1,11 +1,5 @@
#include "exact_value.c" #include "exact_value.c"
#include "entity.c" #include "entity.c"
#include "types.c"
#define MAP_TYPE Entity *
#define MAP_PROC map_entity_
#define MAP_NAME MapEntity
#include "map.c"
typedef enum AddressingMode { typedef enum AddressingMode {
Addressing_Invalid, Addressing_Invalid,
@@ -20,6 +14,13 @@ typedef enum AddressingMode {
Addressing_Count, Addressing_Count,
} AddressingMode; } AddressingMode;
#include "types.c"
#define MAP_TYPE Entity *
#define MAP_PROC map_entity_
#define MAP_NAME MapEntity
#include "map.c"
typedef struct Operand { typedef struct Operand {
AddressingMode mode; AddressingMode mode;
Type * type; Type * type;
@@ -45,6 +46,9 @@ bool is_operand_value(Operand o) {
} }
return false; return false;
} }
bool is_operand_nil(Operand o) {
return o.mode == Addressing_Value && o.type == t_untyped_nil;
}
+1
View File
@@ -35,6 +35,7 @@ typedef enum EntityFlag {
EntityFlag_Field = 1<<3, EntityFlag_Field = 1<<3,
EntityFlag_Param = 1<<4, EntityFlag_Param = 1<<4,
EntityFlag_VectorElem = 1<<5, EntityFlag_VectorElem = 1<<5,
EntityFlag_NoAlias = 1<<6,
} EntityFlag; } EntityFlag;
typedef enum OverloadKind { typedef enum OverloadKind {
+9
View File
@@ -2819,6 +2819,13 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
case_ast_node(ce, CallExpr, expr); case_ast_node(ce, CallExpr, expr);
if (map_tav_get(&proc->module->info->types, hash_pointer(ce->proc))->mode == Addressing_Type) {
GB_ASSERT(ce->args.count == 1);
irValue *x = ir_build_expr(proc, ce->args.e[0]);
irValue *y = ir_emit_conv(proc, x, tv->type);
return y;
}
AstNode *p = unparen_expr(ce->proc); AstNode *p = unparen_expr(ce->proc);
if (p->kind == AstNode_Ident) { if (p->kind == AstNode_Ident) {
Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(p)); Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(p));
@@ -3960,10 +3967,12 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type,
if (val_type != NULL) { if (val_type != NULL) {
switch (expr_type->kind) { switch (expr_type->kind) {
case Type_Array: { case Type_Array: {
// val = ir_emit_array_ep(proc, expr, idx);
val = ir_emit_load(proc, ir_emit_array_ep(proc, expr, idx)); val = ir_emit_load(proc, ir_emit_array_ep(proc, expr, idx));
} break; } break;
case Type_Slice: { case Type_Slice: {
irValue *elem = ir_slice_elem(proc, expr); irValue *elem = ir_slice_elem(proc, expr);
// val = ir_emit_ptr_offset(proc, elem, idx);
val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx)); val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx));
} break; } break;
default: default:
+6
View File
@@ -1078,6 +1078,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
} }
ir_print_type(f, m, t); ir_print_type(f, m, t);
if (e->flags&EntityFlag_NoAlias) {
ir_fprintf(f, " noalias");
}
ir_fprintf(f, " "); ir_fprintf(f, " ");
irValue *arg = call->args[i]; irValue *arg = call->args[i];
ir_print_value(f, m, arg, t); ir_print_value(f, m, arg, t);
@@ -1277,6 +1280,9 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
ir_fprintf(f, ", "); ir_fprintf(f, ", ");
} }
ir_print_type(f, m, e->type); ir_print_type(f, m, e->type);
if (e->flags&EntityFlag_NoAlias) {
ir_fprintf(f, " noalias");
}
if (proc->body != NULL) { if (proc->body != NULL) {
if (!str_eq(e->token.string, str_lit("")) && if (!str_eq(e->token.string, str_lit("")) &&
!str_eq(e->token.string, str_lit("_"))) { !str_eq(e->token.string, str_lit("_"))) {
+40 -18
View File
@@ -94,7 +94,8 @@ typedef enum StmtStateFlag {
typedef enum FieldFlag { typedef enum FieldFlag {
FieldFlag_using = 1<<0, FieldFlag_using = 1<<0,
FieldFlag_ellipsis = 1<<1, FieldFlag_no_alias = 1<<1,
FieldFlag_ellipsis = 1<<2,
} FieldListTag; } FieldListTag;
AstNodeArray make_ast_node_array(AstFile *f) { AstNodeArray make_ast_node_array(AstFile *f) {
@@ -1786,6 +1787,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
} }
bool is_literal_type(AstNode *node) { bool is_literal_type(AstNode *node) {
node = unparen_expr(node);
switch (node->kind) { switch (node->kind) {
case AstNode_BadExpr: case AstNode_BadExpr:
case AstNode_Ident: case AstNode_Ident:
@@ -2232,30 +2234,51 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
while (f->curr_token.kind != follow && while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
bool is_using = false; i32 using_count = 0;
if (allow_token(f, Token_using)) { i32 no_alias_count = 0;
is_using = true; while (f->curr_token.kind == Token_using ||
f->curr_token.kind == Token_no_alias) {
if (allow_token(f, Token_using)) {
using_count++;
}
if (allow_token(f, Token_no_alias)) {
no_alias_count++;
}
} }
AstNodeArray names = parse_identifier_list(f); AstNodeArray names = parse_identifier_list(f);
if (names.count == 0) { if (names.count == 0) {
syntax_error(f->curr_token, "Empty parameter declaration"); syntax_error(f->curr_token, "Empty field declaration");
break; break;
} }
if (names.count > 1 && is_using) { if (names.count > 1 && using_count > 0) {
syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type"); syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
is_using = false; using_count = 0;
} }
if ((flags&FieldFlag_using) == 0 && is_using) { if ((flags&FieldFlag_using) == 0 && using_count > 0) {
syntax_error(f->curr_token, "`using` is not allowed within this parameter list"); syntax_error(f->curr_token, "`using` is not allowed within this field list");
is_using = false; using_count = 0;
} }
if ((flags&FieldFlag_no_alias) == 0 && no_alias_count > 0) {
syntax_error(f->curr_token, "`no_alias` is not allowed within this field list");
no_alias_count = 0;
}
if (using_count > 1) {
syntax_error(f->curr_token, "Multiple `using` in this field list");
using_count = 1;
}
if (no_alias_count > 1) {
syntax_error(f->curr_token, "Multiple `no_alias` in this field list");
no_alias_count = 1;
}
name_count += names.count; name_count += names.count;
expect_token_after(f, Token_Colon, "parameter list"); expect_token_after(f, Token_Colon, "field list");
AstNode *type = NULL; AstNode *type = NULL;
if ((flags&FieldFlag_ellipsis) != 0 && f->curr_token.kind == Token_Ellipsis) { if ((flags&FieldFlag_ellipsis) != 0 && f->curr_token.kind == Token_Ellipsis) {
@@ -2263,11 +2286,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
next_token(f); next_token(f);
type = parse_type_attempt(f); type = parse_type_attempt(f);
if (type == NULL) { if (type == NULL) {
syntax_error(f->curr_token, "variadic parameter is missing a type after `..`"); syntax_error(f->curr_token, "variadic field is missing a type after `..`");
type = make_bad_expr(f, ellipsis, f->curr_token); type = make_bad_expr(f, ellipsis, f->curr_token);
} else { } else {
if (names.count > 1) { if (names.count > 1) {
syntax_error(f->curr_token, "mutliple variadic parameters, only `..`"); syntax_error(f->curr_token, "mutliple variadic fields, only `..`");
} else { } else {
type = make_ellipsis(f, ellipsis, type); type = make_ellipsis(f, ellipsis, type);
} }
@@ -2278,13 +2301,12 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 flags,
if (type == NULL) { if (type == NULL) {
syntax_error(f->curr_token, "Expected a type for this parameter declaration"); syntax_error(f->curr_token, "Expected a type for this field declaration");
} }
u32 flags = 0; u32 flags = 0;
if (is_using) { if (using_count > 0) flags |= FieldFlag_using;
flags |= FieldFlag_using; if (no_alias_count > 0) flags |= FieldFlag_no_alias;
}
AstNode *param = make_field(f, names, type, flags); AstNode *param = make_field(f, names, type, flags);
array_add(&params, param); array_add(&params, param);
@@ -2491,7 +2513,7 @@ void parse_proc_signature(AstFile *f,
AstNodeArray *params, AstNodeArray *params,
AstNodeArray *results) { AstNodeArray *results) {
expect_token(f, Token_OpenParen); expect_token(f, Token_OpenParen);
*params = parse_field_list(f, NULL, FieldFlag_using|FieldFlag_ellipsis, Token_Comma, Token_CloseParen); *params = parse_field_list(f, NULL, FieldFlag_using|FieldFlag_no_alias|FieldFlag_ellipsis, Token_Comma, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list"); expect_token_after(f, Token_CloseParen, "parameter list");
*results = parse_results(f); *results = parse_results(f);
} }
+1
View File
@@ -105,6 +105,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_enum, "enum"), \ TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \ TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \ TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_push_context, "push_context"), \
+2 -1
View File
@@ -686,7 +686,8 @@ bool type_has_nil(Type *t) {
case Basic_any: case Basic_any:
return true; return true;
} }
} return false;
} break;
case Type_Slice: case Type_Slice:
case Type_Proc: case Type_Proc:
case Type_Pointer: case Type_Pointer: