aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2017-11-05 18:26:24 +0000
committergingerBill <bill@gingerbill.org>2017-11-05 18:26:24 +0000
commit66ee2cb6ed8ea511b2f8987678695f66d748cf1e (patch)
tree8f42579e9612198c908380ceefc40cc841f32eeb
parent1d4881cbbe0da6c5f9cd4a99dd1bf65c5e00c51d (diff)
#const value procedure parameters; $N for polymorphic array lengths
-rw-r--r--core/math.odin76
-rw-r--r--src/check_expr.cpp95
-rw-r--r--src/check_type.cpp125
-rw-r--r--src/checker.cpp18
-rw-r--r--src/entity.cpp11
-rw-r--r--src/ir.cpp26
-rw-r--r--src/parser.cpp28
-rw-r--r--src/tokenizer.cpp11
-rw-r--r--src/types.cpp38
9 files changed, 298 insertions, 130 deletions
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, 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;
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<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);
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 ");