diff --git a/core/math.odin b/core/math.odin index 41cd64718..acd9d539d 100644 --- a/core/math.odin +++ b/core/math.odin @@ -16,9 +16,9 @@ EPSILON :: 1.19209290e-7; τ :: TAU; π :: PI; -Vec2 :: [vector 2]f32; -Vec3 :: [vector 3]f32; -Vec4 :: [vector 4]f32; +Vec2 :: [2]f32; +Vec3 :: [3]f32; +Vec4 :: [4]f32; // Column major Mat2 :: [2][2]f32; @@ -122,38 +122,38 @@ to_degrees :: proc(radians: f32) -> f32 do return radians * 360 / TAU; -dot :: proc(a, b: $T/[vector 2]$E) -> E { c := a*b; return c.x + c.y; } -dot :: proc(a, b: $T/[vector 3]$E) -> E { c := a*b; return c.x + c.y + c.z; } -dot :: proc(a, b: $T/[vector 4]$E) -> E { c := a*b; return c.x + c.y + c.z + c.w; } +dot :: proc(a, b: $T/[2]$E) -> E { c := a*b; return c[0] + c[1]; } +dot :: proc(a, b: $T/[3]$E) -> E { c := a*b; return c[0] + c[1] + c[2]; } +dot :: proc(a, b: $T/[4]$E) -> E { c := a*b; return c[0] + c[1] + c[2] + c[3]; } -cross :: proc(x, y: $T/[vector 3]$E) -> T { +cross :: proc(x, y: $T/[3]$E) -> T { a := swizzle(x, 1, 2, 0) * swizzle(y, 2, 0, 1); b := swizzle(x, 2, 0, 1) * swizzle(y, 1, 2, 0); return T(a - b); } -mag :: proc(v: $T/[vector 2]$E) -> E do return sqrt(dot(v, v)); -mag :: proc(v: $T/[vector 3]$E) -> E do return sqrt(dot(v, v)); -mag :: proc(v: $T/[vector 4]$E) -> E do return sqrt(dot(v, v)); +mag :: proc(v: $T/[2]$E) -> E do return sqrt(dot(v, v)); +mag :: proc(v: $T/[3]$E) -> E do return sqrt(dot(v, v)); +mag :: proc(v: $T/[4]$E) -> E do return sqrt(dot(v, v)); -norm :: proc(v: $T/[vector 2]$E) -> T do return v / mag(v); -norm :: proc(v: $T/[vector 3]$E) -> T do return v / mag(v); -norm :: proc(v: $T/[vector 4]$E) -> T do return v / mag(v); +norm :: proc(v: $T/[2]$E) -> T do return v / mag(v); +norm :: proc(v: $T/[3]$E) -> T do return v / mag(v); +norm :: proc(v: $T/[4]$E) -> T do return v / mag(v); -norm0 :: proc(v: $T/[vector 2]$E) -> T { +norm0 :: proc(v: $T/[2]$E) -> T { m := mag(v); if m == 0 do return 0; return v/m; } -norm0 :: proc(v: $T/[vector 3]$E) -> T { +norm0 :: proc(v: $T/[3]$E) -> T { m := mag(v); if m == 0 do return 0; return v/m; } -norm0 :: proc(v: $T/[vector 4]$E) -> T { +norm0 :: proc(v: $T/[4]$E) -> T { m := mag(v); if m == 0 do return 0; return v/m; @@ -194,10 +194,10 @@ mul :: proc(a, b: Mat4) -> Mat4 { mul :: proc(m: Mat4, v: Vec4) -> 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][1]*v.x + m[1][1]*v.y + m[2][1]*v.z + m[3][1]*v.w, - m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z + m[3][2]*v.w, - m[0][3]*v.x + m[1][3]*v.y + m[2][3]*v.z + m[3][3]*v.w, + m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3], + m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3], + m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3], + m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3], }; } @@ -273,9 +273,9 @@ inverse :: proc(m: Mat4) -> Mat4 { mat4_translate :: proc(v: Vec3) -> Mat4 { m := mat4_identity(); - m[3][0] = v.x; - m[3][1] = v.y; - m[3][2] = v.z; + m[3][0] = v[0]; + m[3][1] = v[1]; + m[3][2] = v[2]; m[3][3] = 1; return m; } @@ -289,28 +289,28 @@ mat4_rotate :: proc(v: Vec3, angle_radians: f32) -> Mat4 { rot := mat4_identity(); - rot[0][0] = c + t.x*a.x; - rot[0][1] = 0 + t.x*a.y + s*a.z; - rot[0][2] = 0 + t.x*a.z - s*a.y; + rot[0][0] = c + t[0]*a[0]; + rot[0][1] = 0 + t[0]*a[1] + s*a[2]; + rot[0][2] = 0 + t[0]*a[2] - s*a[1]; rot[0][3] = 0; - rot[1][0] = 0 + t.y*a.x - s*a.z; - rot[1][1] = c + t.y*a.y; - rot[1][2] = 0 + t.y*a.z + s*a.x; + rot[1][0] = 0 + t[1]*a[0] - s*a[2]; + rot[1][1] = c + t[1]*a[1]; + rot[1][2] = 0 + t[1]*a[2] + s*a[0]; rot[1][3] = 0; - rot[2][0] = 0 + t.z*a.x + s*a.y; - rot[2][1] = 0 + t.z*a.y - s*a.x; - rot[2][2] = c + t.z*a.z; + rot[2][0] = 0 + t[2]*a[0] + s*a[1]; + rot[2][1] = 0 + t[2]*a[1] - s*a[0]; + rot[2][2] = c + t[2]*a[2]; rot[2][3] = 0; return rot; } scale :: proc(m: Mat4, v: Vec3) -> Mat4 { - m[0][0] *= v.x; - m[1][1] *= v.y; - m[2][2] *= v.z; + m[0][0] *= v[0]; + m[1][1] *= v[1]; + m[2][2] *= v[2]; return m; } @@ -328,9 +328,9 @@ look_at :: proc(eye, centre, up: Vec3) -> Mat4 { u := cross(s, f); return Mat4{ - {+s.x, +u.x, -f.x, 0}, - {+s.y, +u.y, -f.y, 0}, - {+s.z, +u.z, -f.z, 0}, + {+s[0], +u[0], -f[0], 0}, + {+s[1], +u[1], -f[1], 0}, + {+s[2], +u[2], -f[2], 0}, {-dot(s, eye), -dot(u, eye), dot(f, eye), 1}, }; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4ad649c05..46e3f7b84 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -755,8 +755,6 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n } } - - bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool compound, bool modify_type) { Operand o = {Addressing_Value}; o.type = source; @@ -792,9 +790,73 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c } return false; case Type_Array: - if (source->kind == Type_Array && - poly->Array.count == source->Array.count) { - return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type); + if (source->kind == Type_Array) { + if (poly->Array.generic_type && modify_type) { + Type *gt = poly->Array.generic_type; + GB_ASSERT(gt->kind == Type_Generic); + Entity *e = scope_lookup_entity(gt->Generic.scope, gt->Generic.name); + GB_ASSERT(e != nullptr); + if (e->kind == Entity_TypeName) { + poly->Array.generic_type = nullptr; + poly->Array.count = source->Array.count; + + e->kind = Entity_Constant; + e->Constant.value = exact_value_i64(source->Array.count); + e->type = t_untyped_integer; + } else if (e->kind == Entity_Constant) { + poly->Array.generic_type = nullptr; + if (e->Constant.value.kind != ExactValue_Integer) { + return false; + } + i64 count = i128_to_i64(e->Constant.value.value_integer); + if (count != source->Array.count) { + return false; + } + poly->Array.count = source->Array.count; + } else { + return false; + } + + return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type); + } + if (poly->Array.count == source->Array.count) { + return is_polymorphic_type_assignable(c, poly->Array.elem, source->Array.elem, true, modify_type); + } + } + return false; + case Type_Vector: + if (source->kind == Type_Vector) { + if (poly->Vector.generic_type && modify_type) { + Type *gt = poly->Vector.generic_type; + GB_ASSERT(gt->kind == Type_Generic); + Entity *e = scope_lookup_entity(gt->Generic.scope, gt->Generic.name); + GB_ASSERT(e != nullptr); + if (e->kind == Entity_TypeName) { + poly->Vector.generic_type = nullptr; + poly->Vector.count = source->Vector.count; + + e->kind = Entity_Constant; + e->Constant.value = exact_value_i64(source->Vector.count); + e->type = t_untyped_integer; + } else if (e->kind == Entity_Constant) { + poly->Vector.generic_type = nullptr; + if (e->Constant.value.kind != ExactValue_Integer) { + return false; + } + i64 count = i128_to_i64(e->Constant.value.value_integer); + if (count != source->Vector.count) { + return false; + } + poly->Vector.count = source->Vector.count; + } else { + return false; + } + + return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true, modify_type); + } + if (poly->Vector.count == source->Vector.count) { + return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true, modify_type); + } } return false; case Type_DynamicArray: @@ -802,12 +864,6 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c return is_polymorphic_type_assignable(c, poly->DynamicArray.elem, source->DynamicArray.elem, true, modify_type); } return false; - case Type_Vector: - if (source->kind == Type_Vector && - poly->Vector.count == source->Vector.count) { - return is_polymorphic_type_assignable(c, poly->Vector.elem, source->Vector.elem, true, modify_type); - } - return false; case Type_Slice: if (source->kind == Type_Slice) { return is_polymorphic_type_assignable(c, poly->Slice.elem, source->Slice.elem, true, modify_type); @@ -4109,12 +4165,13 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { break; } - GB_ASSERT(e->kind == Entity_Variable); - if (e->Variable.default_value.kind != ExactValue_Invalid || - e->Variable.default_is_nil || - e->Variable.default_is_location) { - param_count_excluding_defaults--; - continue; + if (e->kind == Entity_Variable) { + if (e->Variable.default_value.kind != ExactValue_Invalid || + e->Variable.default_is_nil || + e->Variable.default_is_location) { + param_count_excluding_defaults--; + continue; + } } break; } @@ -4374,6 +4431,8 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { if (e->kind == Entity_TypeName) { error(call, "Type parameter `%.*s` is missing in procedure call", LIT(e->token.string)); + } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) { + // Ignore } else { gbString str = type_to_string(e->type); error(call, "Parameter `%.*s` of type `%s` is missing in procedure call", @@ -5339,7 +5398,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t if (cl->type != nullptr) { type = nullptr; - // [..]Type + // [...]Type if (cl->type->kind == AstNode_ArrayType && cl->type->ArrayType.count != nullptr) { AstNode *count = cl->type->ArrayType.count; if (count->kind == AstNode_UnaryExpr && diff --git a/src/check_type.cpp b/src/check_type.cpp index 2d881fbe0..befe56711 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -686,7 +686,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Arrayallocator, 0, str_lit(""), specialization); + type = make_type_generic(c->allocator, c->context.scope, 0, str_lit(""), specialization); } else { type = check_type(c, type_expr); if (is_type_polymorphic(type)) { @@ -1270,6 +1270,9 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari bool detemine_type_from_operand = false; Type *specialization = nullptr; + bool is_using = (p->flags&FieldFlag_using) != 0; + bool is_constant_value = (p->flags&FieldFlag_const) != 0; + if (type_expr == nullptr) { if (default_value->kind == AstNode_BasicDirective && @@ -1338,7 +1341,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari detemine_type_from_operand = true; type = t_invalid; } else { - type = make_type_generic(c->allocator, 0, str_lit(""), specialization); + type = make_type_generic(c->allocator, c->context.scope, 0, str_lit(""), specialization); } } else { bool prev = c->context.allow_polymorphic_types; @@ -1357,6 +1360,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (default_value != nullptr) { if (type_expr->kind == AstNode_TypeType) { error(default_value, "A type parameter may not have a default value"); + } else if (is_constant_value) { + error(default_value, "A constant parameter may not have a default value"); } else { Operand o = {}; if (default_value->kind == AstNode_BasicDirective && @@ -1431,6 +1436,16 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } } + if (is_constant_value) { + if (is_type_param) { + error(p->type, "`$` is not needed for a `type` parameter"); + } + if (p->flags&FieldFlag_no_alias) { + error(p->type, "`#no_alias` can only be applied to variable fields of pointer type"); + p->flags &= ~FieldFlag_no_alias; // Remove the flag + } + + } for_array(j, p->names) { AstNode *name = p->names[j]; @@ -1475,16 +1490,16 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari param = make_entity_type_name(c->allocator, scope, name->Ident.token, type); param->TypeName.is_type_alias = true; } else { - if (operands != nullptr && is_type_polymorphic_type && - operands->count > variables.count) { - Operand op = (*operands)[variables.count]; - type = determine_type_from_polymorphic(c, type, op); - if (type == t_invalid) { - success = false; - } else if (!c->context.no_polymorphic_errors) { - // NOTE(bill): The type should be determined now and thus, no need to determine the type any more - is_type_polymorphic_type = false; - // is_type_polymorphic_type = is_type_polymorphic(base_type(type)); + if (operands != nullptr && variables.count < operands->count) { + if (is_type_polymorphic_type) { + Operand op = (*operands)[variables.count]; + type = determine_type_from_polymorphic(c, type, op); + if (type == t_invalid) { + success = false; + } else if (!c->context.no_polymorphic_errors) { + // NOTE(bill): The type should be determined now and thus, no need to determine the type any more + is_type_polymorphic_type = false; + } } } @@ -1495,11 +1510,33 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } } - param = make_entity_param(c->allocator, scope, name->Ident.token, type, - (p->flags&FieldFlag_using) != 0, false); - param->Variable.default_value = value; - param->Variable.default_is_nil = default_is_nil; - param->Variable.default_is_location = default_is_location; + if (is_constant_value) { + if (!is_type_constant_type(type)) { + gbString str = type_to_string(type); + error(params[i], "Invalid constant type, %s", str); + gb_string_free(str); + } + + bool poly_const = true; + if (operands != nullptr) { + poly_const = false; + if (variables.count < operands->count) { + Operand op = (*operands)[variables.count]; + if (op.mode != Addressing_Constant) { + error(op.expr, "Expected a constant parameter value"); + } else { + value = op.value; + } + } + } + + param = make_entity_const_param(c->allocator, scope, name->Ident.token, type, value, poly_const); + } else { + param = make_entity_param(c->allocator, scope, name->Ident.token, type, is_using, false); + param->Variable.default_value = value; + param->Variable.default_is_nil = default_is_nil; + param->Variable.default_is_location = default_is_location; + } } if (p->flags&FieldFlag_no_alias) { @@ -1952,27 +1989,36 @@ bool check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node, Array } -i64 check_array_count(Checker *c, AstNode *e) { +i64 check_array_count(Checker *c, Operand *o, AstNode *e) { if (e == nullptr) { return 0; } - Operand o = {}; if (e->kind == AstNode_UnaryExpr && e->UnaryExpr.op.kind == Token_Ellipsis) { return -1; } - check_expr(c, &o, e); - if (o.mode != Addressing_Constant) { - if (o.mode != Addressing_Invalid) { + check_expr_or_type(c, o, e); + if (o->mode == Addressing_Type && o->type->kind == Type_Generic) { + if (c->context.allow_polymorphic_types) { + if (o->type->Generic.specialized) { + o->type->Generic.specialized = nullptr; + error(o->expr, "Polymorphic array length cannot have a specialization"); + } + return 0; + } + } + if (o->mode != Addressing_Constant) { + if (o->mode != Addressing_Invalid) { + o->mode = Addressing_Invalid; error(e, "Array count must be a constant"); } return 0; } - Type *type = base_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 = i128_to_i64(o.value.value_integer); + if (o->value.kind == ExactValue_Integer) { + i64 count = i128_to_i64(o->value.value_integer); if (count >= 0) { return count; } @@ -2162,7 +2208,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) specific = nullptr; } } - Type *t = make_type_generic(c->allocator, 0, token.string, specific); + Type *t = make_type_generic(c->allocator, c->context.scope, 0, token.string, specific); if (c->context.allow_polymorphic_types) { Scope *ps = c->context.polymorphic_scope; Scope *s = c->context.scope; @@ -2176,7 +2222,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) add_entity(c, ps, ident, e); add_entity(c, s, ident, e); } else { - error(ident, "Invalid use of a polymorphic type `$%.*s`", LIT(token.string)); + error(ident, "Invalid use of a polymorphic parameter `$%.*s`", LIT(token.string)); *type = t_invalid; return false; } @@ -2233,13 +2279,18 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) case_ast_node(at, ArrayType, e); if (at->count != nullptr) { - Type *elem = check_type(c, at->elem, nullptr); - i64 count = check_array_count(c, at->count); + Operand o = {}; + i64 count = check_array_count(c, &o, at->count); + Type *generic_type = nullptr; + if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { + generic_type = o.type; + } if (count < 0) { error(at->count, "... can only be used in conjuction with compound literals"); count = 0; } - *type = make_type_array(c->allocator, elem, count); + Type *elem = check_type(c, at->elem, nullptr); + *type = make_type_array(c->allocator, elem, count, generic_type); } else { Type *elem = check_type(c, at->elem); *type = make_type_slice(c->allocator, elem); @@ -2256,15 +2307,25 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) case_ast_node(vt, VectorType, e); + + Operand o = {}; + i64 count = check_array_count(c, &o, vt->count); + Type *generic_type = nullptr; + if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { + generic_type = o.type; + } + if (count < 0) { + count = 0; + } + Type *elem = check_type(c, vt->elem); Type *be = base_type(elem); - i64 count = check_array_count(c, vt->count); if (is_type_vector(be) || (!is_type_boolean(be) && !is_type_numeric(be) && be->kind != Type_Generic)) { gbString err_str = type_to_string(elem); error(vt->elem, "Vector element type must be numerical or a boolean, got `%s`", err_str); gb_string_free(err_str); } - *type = make_type_vector(c->allocator, elem, count); + *type = make_type_vector(c->allocator, elem, count, generic_type); return true; case_end; diff --git a/src/checker.cpp b/src/checker.cpp index a10b503b4..cfa1d30cc 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -514,15 +514,15 @@ void scope_lookup_parent_entity (Scope *s, String name, Scope **scope_, Entit Entity *scope_insert_entity (Scope *s, Entity *entity); -ExprInfo *check_get_expr_info(CheckerInfo *i, AstNode *expr); -void check_set_expr_info(CheckerInfo *i, AstNode *expr, ExprInfo info); -void check_remove_expr_info(CheckerInfo *i, AstNode *expr); -void add_untyped(CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value); -void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value); -void add_entity_use(Checker *c, AstNode *identifier, Entity *entity); -void add_implicit_entity(Checker *c, AstNode *node, Entity *e); -void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d); -void add_implicit_entity(Checker *c, AstNode *node, Entity *e); +ExprInfo *check_get_expr_info (CheckerInfo *i, AstNode *expr); +void check_set_expr_info (CheckerInfo *i, AstNode *expr, ExprInfo info); +void check_remove_expr_info (CheckerInfo *i, AstNode *expr); +void add_untyped (CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value); +void add_type_and_value (CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value); +void add_entity_use (Checker *c, AstNode *identifier, Entity *entity); +void add_implicit_entity (Checker *c, AstNode *node, Entity *e); +void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d); +void add_implicit_entity (Checker *c, AstNode *node, Entity *e); void check_add_import_decl(Checker *c, AstNodeImportDecl *id); void check_add_export_decl(Checker *c, AstNodeExportDecl *ed); diff --git a/src/entity.cpp b/src/entity.cpp index 8fb6f8b69..0cb05d428 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -43,6 +43,7 @@ enum EntityFlag { EntityFlag_Value = 1<<9, EntityFlag_Sret = 1<<10, EntityFlag_BitFieldValue = 1<<11, + EntityFlag_PolyConst = 1<<12, EntityFlag_CVarArg = 1<<20, }; @@ -207,6 +208,16 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, return entity; } + +Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) { + Entity *entity = make_entity_constant(a, scope, token, type, value); + entity->flags |= EntityFlag_Used; + if (poly_const) entity->flags |= EntityFlag_PolyConst; + entity->flags |= EntityFlag_Param; + return entity; +} + + Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index) { Entity *entity = make_entity_variable(a, scope, token, type, false); entity->Variable.field_src_index = field_src_index; diff --git a/src/ir.cpp b/src/ir.cpp index 17b02ffbc..0ea5ade77 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5012,6 +5012,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { Entity *e = pt->variables[i]; if (e->kind == Entity_TypeName) { args[i] = ir_value_nil(proc->module->allocator, e->type); + } else if (e->kind == Entity_Constant) { + continue; } else { GB_ASSERT(e->kind == Entity_Variable); if (args[i] == nullptr) { @@ -5029,8 +5031,6 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { return ir_emit_call(proc, value, args, param_count); } - isize arg_index = 0; - isize arg_count = 0; for_array(i, ce->args) { AstNode *a = ce->args[i]; @@ -5042,8 +5042,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } - - irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count)); + Array args = {}; + array_init(&args, proc->module->allocator, gb_max(type->param_count, arg_count)); bool variadic = type->variadic; bool vari_expand = ce->ellipsis.pos.line != 0; bool is_c_vararg = type->c_vararg; @@ -5052,7 +5052,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { AstNode *arg = ce->args[i]; TypeAndValue arg_tv = type_and_value_of_expr(proc->module->info, arg); if (arg_tv.mode == Addressing_Type) { - args[arg_index++] = ir_value_nil(proc->module->allocator, arg_tv.type); + array_add(&args, ir_value_nil(proc->module->allocator, arg_tv.type)); } else { irValue *a = ir_build_expr(proc, arg); Type *at = ir_type(a); @@ -5060,10 +5060,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { for_array(i, at->Tuple.variables) { Entity *e = at->Tuple.variables[i]; irValue *v = ir_emit_struct_ev(proc, a, cast(i32)i); - args[arg_index++] = v; + array_add(&args, v); } } else { - args[arg_index++] = a; + array_add(&args, a); } } } @@ -5081,15 +5081,15 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { if (variadic) { end--; } - while (arg_index < end) { - Entity *e = pt->variables[arg_index]; + while (args.count < end) { + Entity *e = pt->variables[args.count]; GB_ASSERT(e->kind == Entity_Variable); if (e->Variable.default_value.kind != ExactValue_Invalid) { - args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value); + array_add(&args, ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value)); } else if (e->Variable.default_is_location) { - args[arg_index++] = ir_emit_source_code_location(proc, procedure, pos); + array_add(&args, ir_emit_source_code_location(proc, procedure, pos)); } else { - args[arg_index++] = ir_value_nil(proc->module->allocator, e->type); + array_add(&args, ir_value_nil(proc->module->allocator, e->type)); } } } @@ -5172,7 +5172,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { args[arg_count-1] = ir_emit_load(proc, slice); } - return ir_emit_call(proc, value, args, final_count); + return ir_emit_call(proc, value, args.data, final_count); case_end; case_ast_node(se, SliceExpr, expr); diff --git a/src/parser.cpp b/src/parser.cpp index dc148f1b5..4ba465e64 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -126,8 +126,9 @@ enum FieldFlag { FieldFlag_using = 1<<1, FieldFlag_no_alias = 1<<2, FieldFlag_c_vararg = 1<<3, + FieldFlag_const = 1<<4, - FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg, + FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const, FieldFlag_Struct = FieldFlag_using, }; @@ -3314,6 +3315,10 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token) { is_generic = true; break; } + if (f->flags&FieldFlag_const) { + is_generic = true; + break; + } } @@ -3357,6 +3362,7 @@ enum FieldPrefixKind { FieldPrefix_Using, FieldPrefix_NoAlias, FieldPrefix_CVarArg, + FieldPrefix_Const, }; FieldPrefixKind is_token_field_prefix(AstFile *f) { @@ -3367,15 +3373,17 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) { case Token_using: return FieldPrefix_Using; + case Token_Hash: { advance_token(f); switch (f->curr_token.kind) { case Token_Ident: if (f->curr_token.string == "no_alias") { return FieldPrefix_NoAlias; - } - if (f->curr_token.string == "c_vararg") { + } else if (f->curr_token.string == "c_vararg") { return FieldPrefix_CVarArg; + } else if (f->curr_token.string == "const") { + return FieldPrefix_Const; } break; } @@ -3389,6 +3397,7 @@ u32 parse_field_prefixes(AstFile *f) { i32 using_count = 0; i32 no_alias_count = 0; i32 c_vararg_count = 0; + i32 const_count = 0; for (;;) { FieldPrefixKind kind = is_token_field_prefix(f); @@ -3396,20 +3405,23 @@ u32 parse_field_prefixes(AstFile *f) { break; } switch (kind) { - case FieldPrefix_Using: using_count += 1; advance_token(f); break; - case FieldPrefix_NoAlias: no_alias_count += 1; advance_token(f); break; - case FieldPrefix_CVarArg: c_vararg_count += 1; advance_token(f); break; + case FieldPrefix_Using: using_count += 1; advance_token(f); break; + case FieldPrefix_NoAlias: no_alias_count += 1; advance_token(f); break; + case FieldPrefix_CVarArg: c_vararg_count += 1; advance_token(f); break; + case FieldPrefix_Const: const_count += 1; advance_token(f); break; } } if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list"); if (no_alias_count > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list"); if (c_vararg_count > 1) syntax_error(f->curr_token, "Multiple `#c_vararg` in this field list"); + if (const_count > 1) syntax_error(f->curr_token, "Multiple `$` in this field list"); u32 field_flags = 0; if (using_count > 0) field_flags |= FieldFlag_using; if (no_alias_count > 0) field_flags |= FieldFlag_no_alias; if (c_vararg_count > 0) field_flags |= FieldFlag_c_vararg; + if (const_count > 0) field_flags |= FieldFlag_const; return field_flags; } @@ -3431,6 +3443,10 @@ u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 se syntax_error(f->curr_token, "`#c_vararg` is not allowed within this field list"); set_flags &= ~FieldFlag_c_vararg; } + if ((allowed_flags&FieldFlag_const) == 0 && (set_flags&FieldFlag_const)) { + syntax_error(f->curr_token, "`$` is not allowed within this field list"); + set_flags &= ~FieldFlag_const; + } return set_flags; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index dc0c2a56d..f5b5b241f 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -155,14 +155,13 @@ TokenPos token_pos(String file, isize line, isize column) { } i32 token_pos_cmp(TokenPos const &a, TokenPos const &b) { - if (a.line == b.line) { - if (a.column == b.column) { - isize min_len = gb_min(a.file.len, b.file.len); - return gb_memcompare(a.file.text, b.file.text, min_len); - } + if (a.line != b.line) { + return (a.line < b.line) ? -1 : +1; + } + if (a.column != b.column) { return (a.column < b.column) ? -1 : +1; } - return (a.line < b.line) ? -1 : +1; + return string_compare(a.file, b.file); } bool operator==(TokenPos const &a, TokenPos const &b) { return token_pos_cmp(a, b) == 0; } diff --git a/src/types.cpp b/src/types.cpp index 364023d7e..8137c8069 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -98,11 +98,20 @@ struct TypeStruct { i64 id; \ String name; \ Type * specialized; \ + Scope *scope; \ }) \ TYPE_KIND(Pointer, struct { Type *elem; }) \ - TYPE_KIND(Array, struct { Type *elem; i64 count; }) \ + TYPE_KIND(Array, struct { \ + Type *elem; \ + i64 count; \ + Type *generic_type; \ + }) \ TYPE_KIND(DynamicArray, struct { Type *elem; }) \ - TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \ + TYPE_KIND(Vector, struct { \ + Type *elem; \ + i64 count; \ + Type *generic_type; \ + }) \ TYPE_KIND(Slice, struct { Type *elem; }) \ TYPE_KIND(Struct, TypeStruct) \ TYPE_KIND(Enum, struct { \ @@ -466,11 +475,12 @@ Type *make_type_basic(gbAllocator a, BasicType basic) { return t; } -Type *make_type_generic(gbAllocator a, i64 id, String name, Type *specialized) { +Type *make_type_generic(gbAllocator a, Scope *scope, i64 id, String name, Type *specialized) { Type *t = alloc_type(a, Type_Generic); t->Generic.id = id; t->Generic.name = name; t->Generic.specialized = specialized; + t->Generic.scope = scope; return t; } @@ -480,10 +490,11 @@ Type *make_type_pointer(gbAllocator a, Type *elem) { return t; } -Type *make_type_array(gbAllocator a, Type *elem, i64 count) { +Type *make_type_array(gbAllocator a, Type *elem, i64 count, Type *generic_type = nullptr) { Type *t = alloc_type(a, Type_Array); t->Array.elem = elem; t->Array.count = count; + t->Array.generic_type = generic_type; return t; } @@ -493,10 +504,11 @@ Type *make_type_dynamic_array(gbAllocator a, Type *elem) { return t; } -Type *make_type_vector(gbAllocator a, Type *elem, i64 count) { +Type *make_type_vector(gbAllocator a, Type *elem, i64 count, Type *generic_type = nullptr) { Type *t = alloc_type(a, Type_Vector); t->Vector.elem = elem; t->Vector.count = count; + t->Vector.generic_type = generic_type; return t; } @@ -951,11 +963,14 @@ bool is_type_polymorphic(Type *t) { case Type_Pointer: return is_type_polymorphic(t->Pointer.elem); case Type_Array: + if (t->Array.generic_type != nullptr) { + return true; + } return is_type_polymorphic(t->Array.elem); - case Type_DynamicArray: - return is_type_polymorphic(t->DynamicArray.elem); case Type_Vector: return is_type_polymorphic(t->Vector.elem); + case Type_DynamicArray: + return is_type_polymorphic(t->DynamicArray.elem); case Type_Slice: return is_type_polymorphic(t->Slice.elem); @@ -2415,12 +2430,19 @@ gbString write_type_to_string(gbString str, Type *type) { case Type_Tuple: if (type->Tuple.variables.count > 0) { + isize comma_index = 0; for_array(i, type->Tuple.variables) { Entity *var = type->Tuple.variables[i]; if (var != nullptr) { - if (i > 0) { + if (var->kind == Entity_Constant) { + // Ignore + continue; + } + + if (comma_index++ > 0) { str = gb_string_appendc(str, ", "); } + if (var->kind == Entity_Variable) { if (var->flags&EntityFlag_CVarArg) { str = gb_string_appendc(str, "#c_vararg ");