mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-03 03:32:37 +00:00
#const value procedure parameters; $N for polymorphic array lengths
This commit is contained in:
@@ -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},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -686,7 +686,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
specialization = nullptr;
|
||||
}
|
||||
}
|
||||
type = make_type_generic(c->allocator, 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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
26
src/ir.cpp
26
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<irValue *> 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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 ");
|
||||
|
||||
Reference in New Issue
Block a user