aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp52
-rw-r--r--src/check_type.cpp17
-rw-r--r--src/common.cpp2
-rw-r--r--src/ir.cpp608
-rw-r--r--src/llvm_backend.cpp8
-rw-r--r--src/parser.cpp1
-rw-r--r--src/parser.hpp3
-rw-r--r--src/types.cpp9
8 files changed, 397 insertions, 303 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 9879d3b8b..357c6b53a 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -5750,12 +5750,41 @@ bool check_assignment_arguments(CheckerContext *ctx, Array<Operand> const &lhs,
optional_ok = true;
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 {
array_add(operands, o);
tuple_index += 1;
}
} else {
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) {
o.type = tuple->variables[j]->type;
array_add(operands, o);
@@ -5839,6 +5868,22 @@ bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count,
}
} else {
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) {
o.type = tuple->variables[j]->type;
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) {
error(call, "'inline' cannot be applied to a procedure that has be marked as 'no_inline'");
}
- }
+ }
}
break;
}
@@ -7342,6 +7387,11 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *t
}
operand->expr = call;
+
+ if (pt->kind == Type_Proc && pt->Proc.optional_ok) {
+ operand->mode = Addressing_OptionalOk;
+ }
+
return Expr_Expr;
}
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 6df824ec1..73f732b45 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -2530,6 +2530,22 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
}
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.scope = c->scope;
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.specialization_count = specialization_count;
type->Proc.diverging = pt->diverging;
+ type->Proc.optional_ok = optional_ok;
type->Proc.tags = pt->tags;
if (param_count > 0) {
diff --git a/src/common.cpp b/src/common.cpp
index ba9f297a3..af6ceee63 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -468,8 +468,8 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
struct StringIntern {
- isize len;
StringIntern *next;
+ isize len;
char str[1];
};
diff --git a/src/ir.cpp b/src/ir.cpp
index 6490995e8..78642a917 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -7081,6 +7081,311 @@ irValue *ir_build_expr(irProcedure *proc, Ast *expr) {
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) {
Ast *original_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);
- 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;
- }
- }
+ irValue *res = ir_build_call_expr(proc, expr);
+ if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
+ GB_ASSERT(is_type_tuple(ir_type(res)));
+ GB_ASSERT(ir_type(res)->Tuple.variables.count == 2);
+ return ir_emit_struct_ev(proc, res, 0);
}
-
-
- 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);
+ return res;
case_end;
case_ast_node(se, SliceExpr, expr);
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index b03f195b9..cc6eccff6 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -8903,7 +8903,13 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
case_end;
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_ast_node(se, SliceExpr, expr);
diff --git a/src/parser.cpp b/src/parser.cpp
index e0cd60d79..eb5bdf7b6 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1618,6 +1618,7 @@ void parse_proc_tags(AstFile *f, u64 *tags) {
}
if (false) {}
+ ELSE_IF_ADD_TAG(optional_ok)
ELSE_IF_ADD_TAG(require_results)
ELSE_IF_ADD_TAG(bounds_check)
ELSE_IF_ADD_TAG(no_bounds_check)
diff --git a/src/parser.hpp b/src/parser.hpp
index 1b236b921..9ef1a8720 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -165,7 +165,9 @@ enum ProcInlining {
enum ProcTag {
ProcTag_bounds_check = 1<<0,
ProcTag_no_bounds_check = 1<<1,
+
ProcTag_require_results = 1<<4,
+ ProcTag_optional_ok = 1<<5,
};
enum ProcCallingConvention {
@@ -282,6 +284,7 @@ AST_KIND(_ExprBegin, "", bool) \
Token close; \
Token ellipsis; \
ProcInlining inlining; \
+ bool optional_ok_one; \
}) \
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
AST_KIND(TernaryExpr, "ternary expression", struct { Ast *cond, *x, *y; }) \
diff --git a/src/types.cpp b/src/types.cpp
index 530a02df7..1590d0a43 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -232,6 +232,7 @@ struct TypeUnion {
Array<Type *> abi_compat_params; \
Type * abi_compat_result_type; \
i32 variadic_index; \
+ /* TODO(bill): Make this a flag set rather than bools */ \
bool variadic; \
bool abi_types_set; \
bool require_results; \
@@ -242,6 +243,7 @@ struct TypeUnion {
bool has_named_results; \
bool diverging; /* no return */ \
bool return_by_pointer; \
+ bool optional_ok; \
u64 tags; \
isize specialization_count; \
ProcCallingConvention calling_convention; \
@@ -1979,9 +1981,10 @@ bool are_types_identical(Type *x, Type *y) {
case Type_Proc:
if (y->kind == Type_Proc) {
return x->Proc.calling_convention == y->Proc.calling_convention &&
- x->Proc.c_vararg == y->Proc.c_vararg &&
- x->Proc.variadic == y->Proc.variadic &&
- x->Proc.diverging == y->Proc.diverging &&
+ x->Proc.c_vararg == y->Proc.c_vararg &&
+ x->Proc.variadic == y->Proc.variadic &&
+ 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.results, y->Proc.results);
}