mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 20:00:09 +00:00
#optional_ok tag for procedures
This commit is contained in:
@@ -47,10 +47,16 @@ array_slice :: proc(a: $A/Array($T)) -> []T {
|
|||||||
|
|
||||||
|
|
||||||
array_get :: proc(a: $A/Array($T), index: int) -> T {
|
array_get :: proc(a: $A/Array($T), index: int) -> T {
|
||||||
|
assert(uint(index) < a.len);
|
||||||
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index))^;
|
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index))^;
|
||||||
}
|
}
|
||||||
|
array_get_ptr :: proc(a: $A/Array($T), index: int) -> ^T {
|
||||||
|
assert(uint(index) < a.len);
|
||||||
|
return (^T)(uintptr(a.data) + size_of(T)*uintptr(index));
|
||||||
|
}
|
||||||
|
|
||||||
array_set :: proc(a: ^$A/Array($T), index: int, item: T) {
|
array_set :: proc(a: ^$A/Array($T), index: int, item: T) {
|
||||||
|
assert(uint(index) < a.len);
|
||||||
(^T)(uintptr(a.data) + size_of(T)*uintptr(index))^ = item;
|
(^T)(uintptr(a.data) + size_of(T)*uintptr(index))^ = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +128,7 @@ array_clear :: proc(q: ^$Q/Queue($T)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
array_push :: proc(a: ^$A/Array($T), items: ..T) {
|
array_push_back_elems :: proc(a: ^$A/Array($T), items: ..T) {
|
||||||
if array_space(a^) < len(items) {
|
if array_space(a^) < len(items) {
|
||||||
array_grow(a, a.size + len(items));
|
array_grow(a, a.size + len(items));
|
||||||
}
|
}
|
||||||
@@ -133,6 +139,8 @@ array_push :: proc(a: ^$A/Array($T), items: ..T) {
|
|||||||
a.len = offset + n;
|
a.len = offset + n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
array_push :: proc{array_push_back, array_push_back_elems};
|
||||||
|
array_append :: proc{array_push_back, array_push_back_elems};
|
||||||
|
|
||||||
array_set_capacity :: proc(a: ^$A/Array($T), new_capacity: int) {
|
array_set_capacity :: proc(a: ^$A/Array($T), new_capacity: int) {
|
||||||
if new_capacity == a.cap {
|
if new_capacity == a.cap {
|
||||||
|
|||||||
+11
-4
@@ -107,8 +107,12 @@ ptr_sub :: inline proc "contextless" (a, b: $P/^$T) -> int {
|
|||||||
|
|
||||||
slice_ptr :: inline proc "contextless" (ptr: ^$T, len: int) -> []T {
|
slice_ptr :: inline proc "contextless" (ptr: ^$T, len: int) -> []T {
|
||||||
assert(len >= 0);
|
assert(len >= 0);
|
||||||
slice := Raw_Slice{data = ptr, len = len};
|
return transmute([]T)Raw_Slice{data = ptr, len = len};
|
||||||
return transmute([]T)slice;
|
}
|
||||||
|
|
||||||
|
slice_ptr_to_bytes :: proc "contextless" (ptr: rawptr, len: int) -> []byte {
|
||||||
|
assert(len >= 0);
|
||||||
|
return transmute([]byte)Raw_Slice{data = ptr, len = len};
|
||||||
}
|
}
|
||||||
|
|
||||||
slice_to_bytes :: inline proc "contextless" (slice: $E/[]$T) -> []byte {
|
slice_to_bytes :: inline proc "contextless" (slice: $E/[]$T) -> []byte {
|
||||||
@@ -127,16 +131,19 @@ slice_data_cast :: inline proc "contextless" ($T: typeid/[]$A, slice: $S/[]$B) -
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slice_to_components :: proc "contextless" (slice: $E/[]$T) -> (data: ^T, len: int) {
|
||||||
|
s := transmute(Raw_Slice)slice;
|
||||||
|
return s.data, s.len;
|
||||||
|
}
|
||||||
|
|
||||||
buffer_from_slice :: inline proc(backing: $T/[]$E) -> [dynamic]E {
|
buffer_from_slice :: inline proc(backing: $T/[]$E) -> [dynamic]E {
|
||||||
s := transmute(Raw_Slice)backing;
|
s := transmute(Raw_Slice)backing;
|
||||||
d := Raw_Dynamic_Array{
|
return transmute([dynamic]E)Raw_Dynamic_Array{
|
||||||
data = s.data,
|
data = s.data,
|
||||||
len = 0,
|
len = 0,
|
||||||
cap = s.len,
|
cap = s.len,
|
||||||
allocator = nil_allocator(),
|
allocator = nil_allocator(),
|
||||||
};
|
};
|
||||||
return transmute([dynamic]E)d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_to_bytes :: inline proc "contextless" (ptr: ^$T, len := 1) -> []byte {
|
ptr_to_bytes :: inline proc "contextless" (ptr: ^$T, len := 1) -> []byte {
|
||||||
|
|||||||
+51
-1
@@ -5750,12 +5750,41 @@ bool check_assignment_arguments(CheckerContext *ctx, Array<Operand> const &lhs,
|
|||||||
|
|
||||||
optional_ok = true;
|
optional_ok = true;
|
||||||
tuple_index += 2;
|
tuple_index += 2;
|
||||||
|
} else if (o.mode == Addressing_OptionalOk) {
|
||||||
|
Type *tuple = o.type;
|
||||||
|
GB_ASSERT(is_type_tuple(tuple));
|
||||||
|
GB_ASSERT(tuple->Tuple.variables.count == 2);
|
||||||
|
Ast *expr = unparen_expr(o.expr);
|
||||||
|
if (expr->kind == Ast_CallExpr) {
|
||||||
|
expr->CallExpr.optional_ok_one = true;
|
||||||
|
}
|
||||||
|
Operand val = o;
|
||||||
|
val.type = tuple->Tuple.variables[0]->type;
|
||||||
|
val.mode = Addressing_Value;
|
||||||
|
array_add(operands, val);
|
||||||
|
tuple_index += 1;
|
||||||
} else {
|
} else {
|
||||||
array_add(operands, o);
|
array_add(operands, o);
|
||||||
tuple_index += 1;
|
tuple_index += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TypeTuple *tuple = &o.type->Tuple;
|
TypeTuple *tuple = &o.type->Tuple;
|
||||||
|
if (o.mode == Addressing_OptionalOk) {
|
||||||
|
GB_ASSERT(tuple->variables.count == 2);
|
||||||
|
if (lhs.count == 1) {
|
||||||
|
Ast *expr = unparen_expr(o.expr);
|
||||||
|
if (expr->kind == Ast_CallExpr) {
|
||||||
|
expr->CallExpr.optional_ok_one = true;
|
||||||
|
}
|
||||||
|
Operand val = o;
|
||||||
|
val.type = tuple->variables[0]->type;
|
||||||
|
val.mode = Addressing_Value;
|
||||||
|
array_add(operands, val);
|
||||||
|
tuple_index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for_array(j, tuple->variables) {
|
for_array(j, tuple->variables) {
|
||||||
o.type = tuple->variables[j]->type;
|
o.type = tuple->variables[j]->type;
|
||||||
array_add(operands, o);
|
array_add(operands, o);
|
||||||
@@ -5839,6 +5868,22 @@ bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TypeTuple *tuple = &o.type->Tuple;
|
TypeTuple *tuple = &o.type->Tuple;
|
||||||
|
if (o.mode == Addressing_OptionalOk) {
|
||||||
|
GB_ASSERT(tuple->variables.count == 2);
|
||||||
|
if (lhs_count == 1) {
|
||||||
|
Ast *expr = unparen_expr(o.expr);
|
||||||
|
if (expr->kind == Ast_CallExpr) {
|
||||||
|
expr->CallExpr.optional_ok_one = true;
|
||||||
|
}
|
||||||
|
Operand val = o;
|
||||||
|
val.type = tuple->variables[0]->type;
|
||||||
|
val.mode = Addressing_Value;
|
||||||
|
array_add(operands, val);
|
||||||
|
tuple_index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for_array(j, tuple->variables) {
|
for_array(j, tuple->variables) {
|
||||||
o.type = tuple->variables[j]->type;
|
o.type = tuple->variables[j]->type;
|
||||||
array_add(operands, o);
|
array_add(operands, o);
|
||||||
@@ -7332,7 +7377,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *t
|
|||||||
if (pl->inlining == ProcInlining_no_inline) {
|
if (pl->inlining == ProcInlining_no_inline) {
|
||||||
error(call, "'inline' cannot be applied to a procedure that has be marked as 'no_inline'");
|
error(call, "'inline' cannot be applied to a procedure that has be marked as 'no_inline'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -7342,6 +7387,11 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
operand->expr = call;
|
operand->expr = call;
|
||||||
|
|
||||||
|
if (pt->kind == Type_Proc && pt->Proc.optional_ok) {
|
||||||
|
operand->mode = Addressing_OptionalOk;
|
||||||
|
}
|
||||||
|
|
||||||
return Expr_Expr;
|
return Expr_Expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2530,6 +2530,22 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
|||||||
}
|
}
|
||||||
GB_ASSERT(cc > 0);
|
GB_ASSERT(cc > 0);
|
||||||
|
|
||||||
|
bool optional_ok = (pt->tags & ProcTag_optional_ok) != 0;
|
||||||
|
if (optional_ok) {
|
||||||
|
if (result_count != 2) {
|
||||||
|
error(proc_type_node, "A procedure type with the #optional_ok tag requires 2 return values, got %td", result_count);
|
||||||
|
} else {
|
||||||
|
Entity *second = results->Tuple.variables[1];
|
||||||
|
if (is_type_polymorphic(second->type)) {
|
||||||
|
// ignore
|
||||||
|
} else if (is_type_boolean(second->type)) {
|
||||||
|
// GOOD
|
||||||
|
} else {
|
||||||
|
error(second->token, "Second return value of an #optional_ok procedure must be a boolean, got %s", type_to_string(second->type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type->Proc.node = proc_type_node;
|
type->Proc.node = proc_type_node;
|
||||||
type->Proc.scope = c->scope;
|
type->Proc.scope = c->scope;
|
||||||
type->Proc.params = params;
|
type->Proc.params = params;
|
||||||
@@ -2542,6 +2558,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
|||||||
type->Proc.is_polymorphic = pt->generic;
|
type->Proc.is_polymorphic = pt->generic;
|
||||||
type->Proc.specialization_count = specialization_count;
|
type->Proc.specialization_count = specialization_count;
|
||||||
type->Proc.diverging = pt->diverging;
|
type->Proc.diverging = pt->diverging;
|
||||||
|
type->Proc.optional_ok = optional_ok;
|
||||||
type->Proc.tags = pt->tags;
|
type->Proc.tags = pt->tags;
|
||||||
|
|
||||||
if (param_count > 0) {
|
if (param_count > 0) {
|
||||||
|
|||||||
+1
-1
@@ -468,8 +468,8 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
|||||||
|
|
||||||
|
|
||||||
struct StringIntern {
|
struct StringIntern {
|
||||||
isize len;
|
|
||||||
StringIntern *next;
|
StringIntern *next;
|
||||||
|
isize len;
|
||||||
char str[1];
|
char str[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+311
-297
@@ -7081,6 +7081,311 @@ irValue *ir_build_expr(irProcedure *proc, Ast *expr) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
irValue *ir_build_call_expr(irProcedure *proc, Ast *expr) {
|
||||||
|
ast_node(ce, CallExpr, expr);
|
||||||
|
TypeAndValue tv = type_and_value_of_expr(expr);
|
||||||
|
TypeAndValue proc_tv = type_and_value_of_expr(ce->proc);
|
||||||
|
AddressingMode proc_mode = proc_tv.mode;
|
||||||
|
if (proc_mode == Addressing_Type) {
|
||||||
|
GB_ASSERT(ce->args.count == 1);
|
||||||
|
irValue *x = ir_build_expr(proc, ce->args[0]);
|
||||||
|
irValue *y = ir_emit_conv(proc, x, tv.type);
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast *p = unparen_expr(ce->proc);
|
||||||
|
if (proc_mode == Addressing_Builtin) {
|
||||||
|
Entity *e = entity_of_node(p);
|
||||||
|
BuiltinProcId id = BuiltinProc_Invalid;
|
||||||
|
if (e != nullptr) {
|
||||||
|
id = cast(BuiltinProcId)e->Builtin.id;
|
||||||
|
} else {
|
||||||
|
id = BuiltinProc_DIRECTIVE;
|
||||||
|
}
|
||||||
|
return ir_build_builtin_proc(proc, expr, tv, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Regular call
|
||||||
|
irValue *value = nullptr;
|
||||||
|
Ast *proc_expr = unparen_expr(ce->proc);
|
||||||
|
if (proc_expr->tav.mode == Addressing_Constant) {
|
||||||
|
ExactValue v = proc_expr->tav.value;
|
||||||
|
switch (v.kind) {
|
||||||
|
case ExactValue_Integer:
|
||||||
|
{
|
||||||
|
u64 u = big_int_to_u64(&v.value_integer);
|
||||||
|
irValue *x = ir_const_uintptr(u);
|
||||||
|
x = ir_emit_conv(proc, x, t_rawptr);
|
||||||
|
value = ir_emit_conv(proc, x, proc_expr->tav.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExactValue_Pointer:
|
||||||
|
{
|
||||||
|
u64 u = cast(u64)v.value_pointer;
|
||||||
|
irValue *x = ir_const_uintptr(u);
|
||||||
|
x = ir_emit_conv(proc, x, t_rawptr);
|
||||||
|
value = ir_emit_conv(proc, x, proc_expr->tav.type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == nullptr) {
|
||||||
|
value = ir_build_expr(proc, proc_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(value != nullptr);
|
||||||
|
Type *proc_type_ = base_type(ir_type(value));
|
||||||
|
GB_ASSERT(proc_type_->kind == Type_Proc);
|
||||||
|
TypeProc *pt = &proc_type_->Proc;
|
||||||
|
set_procedure_abi_types(heap_allocator(), proc_type_);
|
||||||
|
|
||||||
|
if (is_call_expr_field_value(ce)) {
|
||||||
|
auto args = array_make<irValue *>(ir_allocator(), pt->param_count);
|
||||||
|
|
||||||
|
for_array(arg_index, ce->args) {
|
||||||
|
Ast *arg = ce->args[arg_index];
|
||||||
|
ast_node(fv, FieldValue, arg);
|
||||||
|
GB_ASSERT(fv->field->kind == Ast_Ident);
|
||||||
|
String name = fv->field->Ident.token.string;
|
||||||
|
isize index = lookup_procedure_parameter(pt, name);
|
||||||
|
GB_ASSERT(index >= 0);
|
||||||
|
TypeAndValue tav = type_and_value_of_expr(fv->value);
|
||||||
|
if (tav.mode == Addressing_Type) {
|
||||||
|
args[index] = ir_value_nil(tav.type);
|
||||||
|
} else {
|
||||||
|
args[index] = ir_build_expr(proc, fv->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeTuple *params = &pt->params->Tuple;
|
||||||
|
for (isize i = 0; i < args.count; i++) {
|
||||||
|
Entity *e = params->variables[i];
|
||||||
|
if (e->kind == Entity_TypeName) {
|
||||||
|
args[i] = ir_value_nil(e->type);
|
||||||
|
} else if (e->kind == Entity_Constant) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
if (args[i] == nullptr) {
|
||||||
|
switch (e->Variable.param_value.kind) {
|
||||||
|
case ParameterValue_Constant:
|
||||||
|
args[i] = ir_value_constant(e->type, e->Variable.param_value.value);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Nil:
|
||||||
|
args[i] = ir_value_nil(e->type);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Location:
|
||||||
|
args[i] = ir_emit_source_code_location(proc, proc->entity->token.string, ast_token(expr).pos);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Value:
|
||||||
|
args[i] = ir_build_expr(proc, e->Variable.param_value.ast_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ir_emit_call(proc, value, args, ce->inlining, proc->return_ptr_hint_ast == expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
isize arg_index = 0;
|
||||||
|
|
||||||
|
isize arg_count = 0;
|
||||||
|
for_array(i, ce->args) {
|
||||||
|
Ast *arg = ce->args[i];
|
||||||
|
TypeAndValue tav = type_and_value_of_expr(arg);
|
||||||
|
GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(arg), expr_to_string(expr));
|
||||||
|
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
|
||||||
|
Type *at = tav.type;
|
||||||
|
if (at->kind == Type_Tuple) {
|
||||||
|
arg_count += at->Tuple.variables.count;
|
||||||
|
} else {
|
||||||
|
arg_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isize param_count = 0;
|
||||||
|
if (pt->params) {
|
||||||
|
GB_ASSERT(pt->params->kind == Type_Tuple);
|
||||||
|
param_count = pt->params->Tuple.variables.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto args = array_make<irValue *>(ir_allocator(), cast(isize)gb_max(param_count, arg_count));
|
||||||
|
isize variadic_index = pt->variadic_index;
|
||||||
|
bool variadic = pt->variadic && variadic_index >= 0;
|
||||||
|
bool vari_expand = ce->ellipsis.pos.line != 0;
|
||||||
|
bool is_c_vararg = pt->c_vararg;
|
||||||
|
|
||||||
|
String proc_name = {};
|
||||||
|
if (proc->entity != nullptr) {
|
||||||
|
proc_name = proc->entity->token.string;
|
||||||
|
}
|
||||||
|
TokenPos pos = ast_token(ce->proc).pos;
|
||||||
|
|
||||||
|
TypeTuple *param_tuple = nullptr;
|
||||||
|
if (pt->params) {
|
||||||
|
GB_ASSERT(pt->params->kind == Type_Tuple);
|
||||||
|
param_tuple = &pt->params->Tuple;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_array(i, ce->args) {
|
||||||
|
Ast *arg = ce->args[i];
|
||||||
|
TypeAndValue arg_tv = type_and_value_of_expr(arg);
|
||||||
|
if (arg_tv.mode == Addressing_Type) {
|
||||||
|
args[arg_index++] = ir_value_nil(arg_tv.type);
|
||||||
|
} else {
|
||||||
|
irValue *a = ir_build_expr(proc, arg);
|
||||||
|
Type *at = ir_type(a);
|
||||||
|
if (at->kind == Type_Tuple) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args[arg_index++] = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (param_count > 0) {
|
||||||
|
GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
|
||||||
|
GB_ASSERT(param_count < 1000000);
|
||||||
|
|
||||||
|
if (arg_count < param_count) {
|
||||||
|
isize end = cast(isize)param_count;
|
||||||
|
if (variadic) {
|
||||||
|
end = variadic_index;
|
||||||
|
}
|
||||||
|
while (arg_index < end) {
|
||||||
|
Entity *e = param_tuple->variables[arg_index];
|
||||||
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
|
switch (e->Variable.param_value.kind) {
|
||||||
|
case ParameterValue_Constant:
|
||||||
|
args[arg_index++] = ir_value_constant(e->type, e->Variable.param_value.value);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Nil:
|
||||||
|
args[arg_index++] = ir_value_nil(e->type);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Location:
|
||||||
|
args[arg_index++] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Value:
|
||||||
|
args[arg_index++] = ir_build_expr(proc, e->Variable.param_value.ast_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_c_vararg) {
|
||||||
|
GB_ASSERT(variadic);
|
||||||
|
GB_ASSERT(!vari_expand);
|
||||||
|
isize i = 0;
|
||||||
|
for (; i < variadic_index; i++) {
|
||||||
|
Entity *e = param_tuple->variables[i];
|
||||||
|
if (e->kind == Entity_Variable) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type *variadic_type = param_tuple->variables[i]->type;
|
||||||
|
GB_ASSERT(is_type_slice(variadic_type));
|
||||||
|
variadic_type = base_type(variadic_type)->Slice.elem;
|
||||||
|
if (!is_type_any(variadic_type)) {
|
||||||
|
for (; i < arg_count; i++) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], variadic_type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; i < arg_count; i++) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], default_type(ir_type(args[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (variadic) {
|
||||||
|
isize i = 0;
|
||||||
|
for (; i < variadic_index; i++) {
|
||||||
|
Entity *e = param_tuple->variables[i];
|
||||||
|
if (e->kind == Entity_Variable) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!vari_expand) {
|
||||||
|
Type *variadic_type = param_tuple->variables[i]->type;
|
||||||
|
GB_ASSERT(is_type_slice(variadic_type));
|
||||||
|
variadic_type = base_type(variadic_type)->Slice.elem;
|
||||||
|
for (; i < arg_count; i++) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], variadic_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (isize i = 0; i < param_count; i++) {
|
||||||
|
Entity *e = param_tuple->variables[i];
|
||||||
|
if (e->kind == Entity_Variable) {
|
||||||
|
GB_ASSERT(args[i] != nullptr);
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], e->type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variadic && !vari_expand && !is_c_vararg) {
|
||||||
|
ir_emit_comment(proc, str_lit("variadic call argument generation"));
|
||||||
|
gbAllocator allocator = ir_allocator();
|
||||||
|
Type *slice_type = param_tuple->variables[variadic_index]->type;
|
||||||
|
Type *elem_type = base_type(slice_type)->Slice.elem;
|
||||||
|
irValue *slice = ir_add_local_generated(proc, slice_type, true);
|
||||||
|
isize slice_len = arg_count+1 - (variadic_index+1);
|
||||||
|
|
||||||
|
if (slice_len > 0) {
|
||||||
|
irValue *base_array = ir_add_local_generated(proc, alloc_type_array(elem_type, slice_len), true);
|
||||||
|
|
||||||
|
for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
|
||||||
|
irValue *addr = ir_emit_array_epi(proc, base_array, cast(i32)j);
|
||||||
|
ir_emit_store(proc, addr, args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
|
||||||
|
irValue *len = ir_const_int(slice_len);
|
||||||
|
ir_fill_slice(proc, slice, base_elem, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_count = param_count;
|
||||||
|
args[variadic_index] = ir_emit_load(proc, slice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variadic && variadic_index+1 < param_count) {
|
||||||
|
for (isize i = variadic_index+1; i < param_count; i++) {
|
||||||
|
Entity *e = param_tuple->variables[i];
|
||||||
|
switch (e->Variable.param_value.kind) {
|
||||||
|
case ParameterValue_Constant:
|
||||||
|
args[i] = ir_value_constant(e->type, e->Variable.param_value.value);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Nil:
|
||||||
|
args[i] = ir_value_nil(e->type);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Location:
|
||||||
|
args[i] = ir_emit_source_code_location(proc, proc_name, pos);
|
||||||
|
break;
|
||||||
|
case ParameterValue_Value:
|
||||||
|
args[i] = ir_build_expr(proc, e->Variable.param_value.ast_value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isize final_count = param_count;
|
||||||
|
if (is_c_vararg) {
|
||||||
|
final_count = arg_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto call_args = array_slice(args, 0, final_count);
|
||||||
|
return ir_emit_call(proc, value, call_args, ce->inlining, proc->return_ptr_hint_ast == expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
||||||
Ast *original_expr = expr;
|
Ast *original_expr = expr;
|
||||||
expr = unparen_expr(expr);
|
expr = unparen_expr(expr);
|
||||||
@@ -7551,304 +7856,13 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
|
|||||||
|
|
||||||
|
|
||||||
case_ast_node(ce, CallExpr, expr);
|
case_ast_node(ce, CallExpr, expr);
|
||||||
TypeAndValue proc_tv = type_and_value_of_expr(ce->proc);
|
irValue *res = ir_build_call_expr(proc, expr);
|
||||||
AddressingMode proc_mode = proc_tv.mode;
|
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
|
||||||
if (proc_mode == Addressing_Type) {
|
GB_ASSERT(is_type_tuple(ir_type(res)));
|
||||||
GB_ASSERT(ce->args.count == 1);
|
GB_ASSERT(ir_type(res)->Tuple.variables.count == 2);
|
||||||
irValue *x = ir_build_expr(proc, ce->args[0]);
|
return ir_emit_struct_ev(proc, res, 0);
|
||||||
irValue *y = ir_emit_conv(proc, x, tv.type);
|
|
||||||
return y;
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
Ast *p = unparen_expr(ce->proc);
|
|
||||||
if (proc_mode == Addressing_Builtin) {
|
|
||||||
Entity *e = entity_of_node(p);
|
|
||||||
BuiltinProcId id = BuiltinProc_Invalid;
|
|
||||||
if (e != nullptr) {
|
|
||||||
id = cast(BuiltinProcId)e->Builtin.id;
|
|
||||||
} else {
|
|
||||||
id = BuiltinProc_DIRECTIVE;
|
|
||||||
}
|
|
||||||
return ir_build_builtin_proc(proc, expr, tv, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): Regular call
|
|
||||||
irValue *value = nullptr;
|
|
||||||
Ast *proc_expr = unparen_expr(ce->proc);
|
|
||||||
if (proc_expr->tav.mode == Addressing_Constant) {
|
|
||||||
ExactValue v = proc_expr->tav.value;
|
|
||||||
switch (v.kind) {
|
|
||||||
case ExactValue_Integer:
|
|
||||||
{
|
|
||||||
u64 u = big_int_to_u64(&v.value_integer);
|
|
||||||
irValue *x = ir_const_uintptr(u);
|
|
||||||
x = ir_emit_conv(proc, x, t_rawptr);
|
|
||||||
value = ir_emit_conv(proc, x, proc_expr->tav.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ExactValue_Pointer:
|
|
||||||
{
|
|
||||||
u64 u = cast(u64)v.value_pointer;
|
|
||||||
irValue *x = ir_const_uintptr(u);
|
|
||||||
x = ir_emit_conv(proc, x, t_rawptr);
|
|
||||||
value = ir_emit_conv(proc, x, proc_expr->tav.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == nullptr) {
|
|
||||||
value = ir_build_expr(proc, proc_expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
GB_ASSERT(value != nullptr);
|
|
||||||
Type *proc_type_ = base_type(ir_type(value));
|
|
||||||
GB_ASSERT(proc_type_->kind == Type_Proc);
|
|
||||||
TypeProc *pt = &proc_type_->Proc;
|
|
||||||
set_procedure_abi_types(heap_allocator(), proc_type_);
|
|
||||||
|
|
||||||
if (is_call_expr_field_value(ce)) {
|
|
||||||
auto args = array_make<irValue *>(ir_allocator(), pt->param_count);
|
|
||||||
|
|
||||||
for_array(arg_index, ce->args) {
|
|
||||||
Ast *arg = ce->args[arg_index];
|
|
||||||
ast_node(fv, FieldValue, arg);
|
|
||||||
GB_ASSERT(fv->field->kind == Ast_Ident);
|
|
||||||
String name = fv->field->Ident.token.string;
|
|
||||||
isize index = lookup_procedure_parameter(pt, name);
|
|
||||||
GB_ASSERT(index >= 0);
|
|
||||||
TypeAndValue tav = type_and_value_of_expr(fv->value);
|
|
||||||
if (tav.mode == Addressing_Type) {
|
|
||||||
args[index] = ir_value_nil(tav.type);
|
|
||||||
} else {
|
|
||||||
args[index] = ir_build_expr(proc, fv->value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeTuple *params = &pt->params->Tuple;
|
|
||||||
for (isize i = 0; i < args.count; i++) {
|
|
||||||
Entity *e = params->variables[i];
|
|
||||||
if (e->kind == Entity_TypeName) {
|
|
||||||
args[i] = ir_value_nil(e->type);
|
|
||||||
} else if (e->kind == Entity_Constant) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
|
||||||
if (args[i] == nullptr) {
|
|
||||||
switch (e->Variable.param_value.kind) {
|
|
||||||
case ParameterValue_Constant:
|
|
||||||
args[i] = ir_value_constant(e->type, e->Variable.param_value.value);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Nil:
|
|
||||||
args[i] = ir_value_nil(e->type);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Location:
|
|
||||||
args[i] = ir_emit_source_code_location(proc, proc->entity->token.string, ast_token(expr).pos);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Value:
|
|
||||||
args[i] = ir_build_expr(proc, e->Variable.param_value.ast_value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ir_emit_call(proc, value, args, ce->inlining, proc->return_ptr_hint_ast == expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
isize arg_index = 0;
|
|
||||||
|
|
||||||
isize arg_count = 0;
|
|
||||||
for_array(i, ce->args) {
|
|
||||||
Ast *arg = ce->args[i];
|
|
||||||
TypeAndValue tav = type_and_value_of_expr(arg);
|
|
||||||
GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(arg), expr_to_string(expr));
|
|
||||||
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
|
|
||||||
Type *at = tav.type;
|
|
||||||
if (at->kind == Type_Tuple) {
|
|
||||||
arg_count += at->Tuple.variables.count;
|
|
||||||
} else {
|
|
||||||
arg_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isize param_count = 0;
|
|
||||||
if (pt->params) {
|
|
||||||
GB_ASSERT(pt->params->kind == Type_Tuple);
|
|
||||||
param_count = pt->params->Tuple.variables.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto args = array_make<irValue *>(ir_allocator(), cast(isize)gb_max(param_count, arg_count));
|
|
||||||
isize variadic_index = pt->variadic_index;
|
|
||||||
bool variadic = pt->variadic && variadic_index >= 0;
|
|
||||||
bool vari_expand = ce->ellipsis.pos.line != 0;
|
|
||||||
bool is_c_vararg = pt->c_vararg;
|
|
||||||
|
|
||||||
String proc_name = {};
|
|
||||||
if (proc->entity != nullptr) {
|
|
||||||
proc_name = proc->entity->token.string;
|
|
||||||
}
|
|
||||||
TokenPos pos = ast_token(ce->proc).pos;
|
|
||||||
|
|
||||||
TypeTuple *param_tuple = nullptr;
|
|
||||||
if (pt->params) {
|
|
||||||
GB_ASSERT(pt->params->kind == Type_Tuple);
|
|
||||||
param_tuple = &pt->params->Tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, ce->args) {
|
|
||||||
Ast *arg = ce->args[i];
|
|
||||||
TypeAndValue arg_tv = type_and_value_of_expr(arg);
|
|
||||||
if (arg_tv.mode == Addressing_Type) {
|
|
||||||
args[arg_index++] = ir_value_nil(arg_tv.type);
|
|
||||||
} else {
|
|
||||||
irValue *a = ir_build_expr(proc, arg);
|
|
||||||
Type *at = ir_type(a);
|
|
||||||
if (at->kind == Type_Tuple) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args[arg_index++] = a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (param_count > 0) {
|
|
||||||
GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
|
|
||||||
GB_ASSERT(param_count < 1000000);
|
|
||||||
|
|
||||||
if (arg_count < param_count) {
|
|
||||||
isize end = cast(isize)param_count;
|
|
||||||
if (variadic) {
|
|
||||||
end = variadic_index;
|
|
||||||
}
|
|
||||||
while (arg_index < end) {
|
|
||||||
Entity *e = param_tuple->variables[arg_index];
|
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
|
||||||
|
|
||||||
switch (e->Variable.param_value.kind) {
|
|
||||||
case ParameterValue_Constant:
|
|
||||||
args[arg_index++] = ir_value_constant(e->type, e->Variable.param_value.value);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Nil:
|
|
||||||
args[arg_index++] = ir_value_nil(e->type);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Location:
|
|
||||||
args[arg_index++] = ir_emit_source_code_location(proc, proc_name, pos);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Value:
|
|
||||||
args[arg_index++] = ir_build_expr(proc, e->Variable.param_value.ast_value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_c_vararg) {
|
|
||||||
GB_ASSERT(variadic);
|
|
||||||
GB_ASSERT(!vari_expand);
|
|
||||||
isize i = 0;
|
|
||||||
for (; i < variadic_index; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type *variadic_type = param_tuple->variables[i]->type;
|
|
||||||
GB_ASSERT(is_type_slice(variadic_type));
|
|
||||||
variadic_type = base_type(variadic_type)->Slice.elem;
|
|
||||||
if (!is_type_any(variadic_type)) {
|
|
||||||
for (; i < arg_count; i++) {
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], variadic_type);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (; i < arg_count; i++) {
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], default_type(ir_type(args[i])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (variadic) {
|
|
||||||
isize i = 0;
|
|
||||||
for (; i < variadic_index; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!vari_expand) {
|
|
||||||
Type *variadic_type = param_tuple->variables[i]->type;
|
|
||||||
GB_ASSERT(is_type_slice(variadic_type));
|
|
||||||
variadic_type = base_type(variadic_type)->Slice.elem;
|
|
||||||
for (; i < arg_count; i++) {
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], variadic_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (isize i = 0; i < param_count; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
GB_ASSERT(args[i] != nullptr);
|
|
||||||
args[i] = ir_emit_conv(proc, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variadic && !vari_expand && !is_c_vararg) {
|
|
||||||
ir_emit_comment(proc, str_lit("variadic call argument generation"));
|
|
||||||
gbAllocator allocator = ir_allocator();
|
|
||||||
Type *slice_type = param_tuple->variables[variadic_index]->type;
|
|
||||||
Type *elem_type = base_type(slice_type)->Slice.elem;
|
|
||||||
irValue *slice = ir_add_local_generated(proc, slice_type, true);
|
|
||||||
isize slice_len = arg_count+1 - (variadic_index+1);
|
|
||||||
|
|
||||||
if (slice_len > 0) {
|
|
||||||
irValue *base_array = ir_add_local_generated(proc, alloc_type_array(elem_type, slice_len), true);
|
|
||||||
|
|
||||||
for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
|
|
||||||
irValue *addr = ir_emit_array_epi(proc, base_array, cast(i32)j);
|
|
||||||
ir_emit_store(proc, addr, args[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
|
|
||||||
irValue *len = ir_const_int(slice_len);
|
|
||||||
ir_fill_slice(proc, slice, base_elem, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_count = param_count;
|
|
||||||
args[variadic_index] = ir_emit_load(proc, slice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variadic && variadic_index+1 < param_count) {
|
|
||||||
for (isize i = variadic_index+1; i < param_count; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
switch (e->Variable.param_value.kind) {
|
|
||||||
case ParameterValue_Constant:
|
|
||||||
args[i] = ir_value_constant(e->type, e->Variable.param_value.value);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Nil:
|
|
||||||
args[i] = ir_value_nil(e->type);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Location:
|
|
||||||
args[i] = ir_emit_source_code_location(proc, proc_name, pos);
|
|
||||||
break;
|
|
||||||
case ParameterValue_Value:
|
|
||||||
args[i] = ir_build_expr(proc, e->Variable.param_value.ast_value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isize final_count = param_count;
|
|
||||||
if (is_c_vararg) {
|
|
||||||
final_count = arg_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto call_args = array_slice(args, 0, final_count);
|
|
||||||
return ir_emit_call(proc, value, call_args, ce->inlining, proc->return_ptr_hint_ast == expr);
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(se, SliceExpr, expr);
|
case_ast_node(se, SliceExpr, expr);
|
||||||
|
|||||||
@@ -8903,7 +8903,13 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(ce, CallExpr, expr);
|
case_ast_node(ce, CallExpr, expr);
|
||||||
return lb_build_call_expr(p, expr);
|
lbValue res = lb_build_call_expr(p, expr);
|
||||||
|
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
|
||||||
|
GB_ASSERT(is_type_tuple(res.type));
|
||||||
|
GB_ASSERT(res.type->Tuple.variables.count == 2);
|
||||||
|
return lb_emit_struct_ev(p, res, 0);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(se, SliceExpr, expr);
|
case_ast_node(se, SliceExpr, expr);
|
||||||
|
|||||||
@@ -1618,6 +1618,7 @@ void parse_proc_tags(AstFile *f, u64 *tags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (false) {}
|
if (false) {}
|
||||||
|
ELSE_IF_ADD_TAG(optional_ok)
|
||||||
ELSE_IF_ADD_TAG(require_results)
|
ELSE_IF_ADD_TAG(require_results)
|
||||||
ELSE_IF_ADD_TAG(bounds_check)
|
ELSE_IF_ADD_TAG(bounds_check)
|
||||||
ELSE_IF_ADD_TAG(no_bounds_check)
|
ELSE_IF_ADD_TAG(no_bounds_check)
|
||||||
|
|||||||
@@ -165,7 +165,9 @@ enum ProcInlining {
|
|||||||
enum ProcTag {
|
enum ProcTag {
|
||||||
ProcTag_bounds_check = 1<<0,
|
ProcTag_bounds_check = 1<<0,
|
||||||
ProcTag_no_bounds_check = 1<<1,
|
ProcTag_no_bounds_check = 1<<1,
|
||||||
|
|
||||||
ProcTag_require_results = 1<<4,
|
ProcTag_require_results = 1<<4,
|
||||||
|
ProcTag_optional_ok = 1<<5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ProcCallingConvention {
|
enum ProcCallingConvention {
|
||||||
@@ -282,6 +284,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
|||||||
Token close; \
|
Token close; \
|
||||||
Token ellipsis; \
|
Token ellipsis; \
|
||||||
ProcInlining inlining; \
|
ProcInlining inlining; \
|
||||||
|
bool optional_ok_one; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||||
AST_KIND(TernaryExpr, "ternary expression", struct { Ast *cond, *x, *y; }) \
|
AST_KIND(TernaryExpr, "ternary expression", struct { Ast *cond, *x, *y; }) \
|
||||||
|
|||||||
+6
-3
@@ -232,6 +232,7 @@ struct TypeUnion {
|
|||||||
Array<Type *> abi_compat_params; \
|
Array<Type *> abi_compat_params; \
|
||||||
Type * abi_compat_result_type; \
|
Type * abi_compat_result_type; \
|
||||||
i32 variadic_index; \
|
i32 variadic_index; \
|
||||||
|
/* TODO(bill): Make this a flag set rather than bools */ \
|
||||||
bool variadic; \
|
bool variadic; \
|
||||||
bool abi_types_set; \
|
bool abi_types_set; \
|
||||||
bool require_results; \
|
bool require_results; \
|
||||||
@@ -242,6 +243,7 @@ struct TypeUnion {
|
|||||||
bool has_named_results; \
|
bool has_named_results; \
|
||||||
bool diverging; /* no return */ \
|
bool diverging; /* no return */ \
|
||||||
bool return_by_pointer; \
|
bool return_by_pointer; \
|
||||||
|
bool optional_ok; \
|
||||||
u64 tags; \
|
u64 tags; \
|
||||||
isize specialization_count; \
|
isize specialization_count; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
@@ -1979,9 +1981,10 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
if (y->kind == Type_Proc) {
|
if (y->kind == Type_Proc) {
|
||||||
return x->Proc.calling_convention == y->Proc.calling_convention &&
|
return x->Proc.calling_convention == y->Proc.calling_convention &&
|
||||||
x->Proc.c_vararg == y->Proc.c_vararg &&
|
x->Proc.c_vararg == y->Proc.c_vararg &&
|
||||||
x->Proc.variadic == y->Proc.variadic &&
|
x->Proc.variadic == y->Proc.variadic &&
|
||||||
x->Proc.diverging == y->Proc.diverging &&
|
x->Proc.diverging == y->Proc.diverging &&
|
||||||
|
x->Proc.optional_ok == y->Proc.optional_ok &&
|
||||||
are_types_identical(x->Proc.params, y->Proc.params) &&
|
are_types_identical(x->Proc.params, y->Proc.params) &&
|
||||||
are_types_identical(x->Proc.results, y->Proc.results);
|
are_types_identical(x->Proc.results, y->Proc.results);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user