parent
1826a96160
commit
17cb85dfb8
|
@ -33,7 +33,7 @@ FnDef = option("inline" | "extern") FnProto Block
|
||||||
|
|
||||||
ParamDeclList = "(" list(ParamDecl, ",") ")"
|
ParamDeclList = "(" list(ParamDecl, ",") ")"
|
||||||
|
|
||||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..."
|
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
|
||||||
|
|
||||||
Block = "{" list(option(Statement), ";") "}"
|
Block = "{" list(option(Statement), ";") "}"
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,11 @@ struct ConstBoundFnValue {
|
||||||
IrInstruction *first_arg;
|
IrInstruction *first_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConstArgTuple {
|
||||||
|
size_t start_index;
|
||||||
|
size_t end_index;
|
||||||
|
};
|
||||||
|
|
||||||
enum ConstValSpecial {
|
enum ConstValSpecial {
|
||||||
ConstValSpecialRuntime,
|
ConstValSpecialRuntime,
|
||||||
ConstValSpecialStatic,
|
ConstValSpecialStatic,
|
||||||
|
@ -163,6 +168,7 @@ struct ConstExprValue {
|
||||||
ConstPtrValue x_ptr;
|
ConstPtrValue x_ptr;
|
||||||
ImportTableEntry *x_import;
|
ImportTableEntry *x_import;
|
||||||
Scope *x_block;
|
Scope *x_block;
|
||||||
|
ConstArgTuple x_arg_tuple;
|
||||||
|
|
||||||
// populated if special == ConstValSpecialRuntime
|
// populated if special == ConstValSpecialRuntime
|
||||||
RuntimeHintErrorUnion rh_error_union;
|
RuntimeHintErrorUnion rh_error_union;
|
||||||
|
@ -325,6 +331,7 @@ struct AstNodeParamDecl {
|
||||||
AstNode *type;
|
AstNode *type;
|
||||||
bool is_noalias;
|
bool is_noalias;
|
||||||
bool is_inline;
|
bool is_inline;
|
||||||
|
bool is_var_args;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeBlock {
|
struct AstNodeBlock {
|
||||||
|
@ -936,6 +943,7 @@ enum TypeTableEntryId {
|
||||||
TypeTableEntryIdNamespace,
|
TypeTableEntryIdNamespace,
|
||||||
TypeTableEntryIdBlock,
|
TypeTableEntryIdBlock,
|
||||||
TypeTableEntryIdBoundFn,
|
TypeTableEntryIdBoundFn,
|
||||||
|
TypeTableEntryIdArgTuple,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeTableEntry {
|
struct TypeTableEntry {
|
||||||
|
@ -1034,6 +1042,8 @@ struct FnTableEntry {
|
||||||
|
|
||||||
ZigList<IrInstruction *> alloca_list;
|
ZigList<IrInstruction *> alloca_list;
|
||||||
ZigList<VariableTableEntry *> variable_list;
|
ZigList<VariableTableEntry *> variable_list;
|
||||||
|
|
||||||
|
VariableTableEntry *var_args_var;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t fn_table_entry_hash(FnTableEntry*);
|
uint32_t fn_table_entry_hash(FnTableEntry*);
|
||||||
|
@ -1155,6 +1165,7 @@ struct CodeGen {
|
||||||
TypeTableEntry *entry_environ_enum;
|
TypeTableEntry *entry_environ_enum;
|
||||||
TypeTableEntry *entry_oformat_enum;
|
TypeTableEntry *entry_oformat_enum;
|
||||||
TypeTableEntry *entry_atomic_order_enum;
|
TypeTableEntry *entry_atomic_order_enum;
|
||||||
|
TypeTableEntry *entry_arg_tuple;
|
||||||
} builtin_types;
|
} builtin_types;
|
||||||
|
|
||||||
ZigTarget zig_target;
|
ZigTarget zig_target;
|
||||||
|
|
|
@ -208,6 +208,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
@ -245,6 +246,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
@ -921,6 +923,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||||
assert(param_node->type == NodeTypeParamDecl);
|
assert(param_node->type == NodeTypeParamDecl);
|
||||||
|
|
||||||
bool param_is_inline = param_node->data.param_decl.is_inline;
|
bool param_is_inline = param_node->data.param_decl.is_inline;
|
||||||
|
bool param_is_var_args = param_node->data.param_decl.is_var_args;
|
||||||
|
|
||||||
if (param_is_inline) {
|
if (param_is_inline) {
|
||||||
if (fn_type_id.is_extern) {
|
if (fn_type_id.is_extern) {
|
||||||
|
@ -929,6 +932,13 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
}
|
}
|
||||||
return get_generic_fn_type(g, &fn_type_id);
|
return get_generic_fn_type(g, &fn_type_id);
|
||||||
|
} else if (param_is_var_args) {
|
||||||
|
if (fn_type_id.is_extern) {
|
||||||
|
fn_type_id.param_count = fn_type_id.next_param_index;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return get_generic_fn_type(g, &fn_type_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
|
TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
|
||||||
|
@ -939,6 +949,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||||
case TypeTableEntryIdUnreachable:
|
case TypeTableEntryIdUnreachable:
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
case TypeTableEntryIdNullLit:
|
case TypeTableEntryIdNullLit:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
add_node_error(g, param_node->data.param_decl.type,
|
add_node_error(g, param_node->data.param_decl.type,
|
||||||
buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
|
buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
|
||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
|
@ -989,6 +1000,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||||
|
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
case TypeTableEntryIdNullLit:
|
case TypeTableEntryIdNullLit:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
add_node_error(g, fn_proto->return_type,
|
add_node_error(g, fn_proto->return_type,
|
||||||
buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
|
buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
|
||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
|
@ -1558,13 +1570,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
|
||||||
|
|
||||||
AstNode *fn_def_node = fn_proto->fn_def_node;
|
AstNode *fn_def_node = fn_proto->fn_def_node;
|
||||||
|
|
||||||
if (fn_def_node && fn_proto->is_var_args) {
|
|
||||||
add_node_error(g, proto_node,
|
|
||||||
buf_sprintf("variadic arguments only allowed in extern function declarations"));
|
|
||||||
tld_fn->base.resolution = TldResolutionInvalid;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node);
|
FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node);
|
||||||
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');
|
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_');
|
||||||
|
|
||||||
|
@ -1799,6 +1804,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
case TypeTableEntryIdNullLit:
|
case TypeTableEntryIdNullLit:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",
|
add_node_error(g, source_node, buf_sprintf("variable of type '%s' not allowed",
|
||||||
buf_ptr(&underlying_type->name)));
|
buf_ptr(&underlying_type->name)));
|
||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
|
@ -2210,6 +2216,7 @@ static bool is_container(TypeTableEntry *type_entry) {
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
@ -2260,6 +2267,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
|
||||||
case TypeTableEntryIdInvalid:
|
case TypeTableEntryIdInvalid:
|
||||||
case TypeTableEntryIdVar:
|
case TypeTableEntryIdVar:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2290,7 +2298,13 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
|
||||||
for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
|
for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
|
||||||
FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
|
FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
|
||||||
AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
|
AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
|
||||||
Buf *param_name = param_decl_node ? param_decl_node->data.param_decl.name : buf_sprintf("arg%zu", i);
|
Buf *param_name;
|
||||||
|
bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
|
||||||
|
if (param_decl_node && !is_var_args) {
|
||||||
|
param_name = param_decl_node->data.param_decl.name;
|
||||||
|
} else {
|
||||||
|
param_name = buf_sprintf("arg%zu", i);
|
||||||
|
}
|
||||||
|
|
||||||
TypeTableEntry *param_type = param_info->type;
|
TypeTableEntry *param_type = param_info->type;
|
||||||
bool is_noalias = param_info->is_noalias;
|
bool is_noalias = param_info->is_noalias;
|
||||||
|
@ -2308,6 +2322,7 @@ void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, Vari
|
||||||
param_name, true, create_const_runtime(param_type));
|
param_name, true, create_const_runtime(param_type));
|
||||||
var->src_arg_index = i;
|
var->src_arg_index = i;
|
||||||
fn_table_entry->child_scope = var->child_scope;
|
fn_table_entry->child_scope = var->child_scope;
|
||||||
|
var->shadowable = var->shadowable || is_var_args;
|
||||||
|
|
||||||
if (type_has_bits(param_type)) {
|
if (type_has_bits(param_type)) {
|
||||||
fn_table_entry->variable_list.append(var);
|
fn_table_entry->variable_list.append(var);
|
||||||
|
@ -2627,6 +2642,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdVar:
|
case TypeTableEntryIdVar:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
case TypeTableEntryIdUnreachable:
|
case TypeTableEntryIdUnreachable:
|
||||||
case TypeTableEntryIdVoid:
|
case TypeTableEntryIdVoid:
|
||||||
|
@ -2742,6 +2758,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||||
case TypeTableEntryIdFloat:
|
case TypeTableEntryIdFloat:
|
||||||
case TypeTableEntryIdNumLitFloat:
|
case TypeTableEntryIdNumLitFloat:
|
||||||
return const_val->data.x_bignum.data.x_float * UINT32_MAX;
|
return const_val->data.x_bignum.data.x_float * UINT32_MAX;
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
|
return const_val->data.x_arg_tuple.start_index * 281907309 +
|
||||||
|
const_val->data.x_arg_tuple.end_index * 2290442768;
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index);
|
return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index);
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
|
@ -2805,7 +2824,7 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) {
|
||||||
bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
|
bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
|
||||||
assert(a->fn_entry);
|
assert(a->fn_entry);
|
||||||
if (a->fn_entry != b->fn_entry) return false;
|
if (a->fn_entry != b->fn_entry) return false;
|
||||||
assert(a->param_count == b->param_count);
|
if (a->param_count != b->param_count) return false;
|
||||||
for (size_t i = 0; i < a->param_count; i += 1) {
|
for (size_t i = 0; i < a->param_count; i += 1) {
|
||||||
ConstExprValue *a_val = &a->params[i];
|
ConstExprValue *a_val = &a->params[i];
|
||||||
ConstExprValue *b_val = &b->params[i];
|
ConstExprValue *b_val = &b->params[i];
|
||||||
|
@ -2904,6 +2923,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdVar:
|
case TypeTableEntryIdVar:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
return type_of_first_thing_in_memory(type_entry->data.array.child_type);
|
return type_of_first_thing_in_memory(type_entry->data.array.child_type);
|
||||||
|
@ -2946,6 +2966,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
|
||||||
case TypeTableEntryIdNamespace:
|
case TypeTableEntryIdNamespace:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
return true;
|
return true;
|
||||||
case TypeTableEntryIdArray:
|
case TypeTableEntryIdArray:
|
||||||
case TypeTableEntryIdStruct:
|
case TypeTableEntryIdStruct:
|
||||||
|
@ -3155,6 +3176,20 @@ ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t in
|
||||||
return const_val;
|
return const_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end) {
|
||||||
|
const_val->special = ConstValSpecialStatic;
|
||||||
|
const_val->type = g->builtin_types.entry_arg_tuple;
|
||||||
|
const_val->data.x_arg_tuple.start_index = arg_index_start;
|
||||||
|
const_val->data.x_arg_tuple.end_index = arg_index_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end) {
|
||||||
|
ConstExprValue *const_val = allocate<ConstExprValue>(1);
|
||||||
|
init_const_arg_tuple(g, const_val, arg_index_start, arg_index_end);
|
||||||
|
return const_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) {
|
void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) {
|
||||||
if (type_entry->id == TypeTableEntryIdStruct) {
|
if (type_entry->id == TypeTableEntryIdStruct) {
|
||||||
if (!type_entry->data.structure.complete)
|
if (!type_entry->data.structure.complete)
|
||||||
|
@ -3245,6 +3280,9 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||||
return a->data.x_import == b->data.x_import;
|
return a->data.x_import == b->data.x_import;
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
return a->data.x_block == b->data.x_block;
|
return a->data.x_block == b->data.x_block;
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
|
return a->data.x_arg_tuple.start_index == b->data.x_arg_tuple.start_index &&
|
||||||
|
a->data.x_arg_tuple.end_index == b->data.x_arg_tuple.end_index;
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdInvalid:
|
case TypeTableEntryIdInvalid:
|
||||||
case TypeTableEntryIdUnreachable:
|
case TypeTableEntryIdUnreachable:
|
||||||
|
@ -3506,7 +3544,11 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) {
|
||||||
buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
|
buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
|
{
|
||||||
|
buf_appendf(buf, "(args value)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,4 +133,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
|
||||||
size_t start, size_t len, bool is_const);
|
size_t start, size_t len, bool is_const);
|
||||||
ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const);
|
ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t start, size_t len, bool is_const);
|
||||||
|
|
||||||
|
void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end);
|
||||||
|
ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -393,7 +393,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||||
print_symbol(ar, node->data.fn_proto.name);
|
print_symbol(ar, node->data.fn_proto.name);
|
||||||
fprintf(ar->f, "(");
|
fprintf(ar->f, "(");
|
||||||
int arg_count = node->data.fn_proto.params.length;
|
int arg_count = node->data.fn_proto.params.length;
|
||||||
bool is_var_args = node->data.fn_proto.is_var_args;
|
|
||||||
for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {
|
for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {
|
||||||
AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
|
AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
|
||||||
assert(param_decl->type == NodeTypeParamDecl);
|
assert(param_decl->type == NodeTypeParamDecl);
|
||||||
|
@ -404,15 +403,16 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||||
print_symbol(ar, param_decl->data.param_decl.name);
|
print_symbol(ar, param_decl->data.param_decl.name);
|
||||||
fprintf(ar->f, ": ");
|
fprintf(ar->f, ": ");
|
||||||
}
|
}
|
||||||
render_node_grouped(ar, param_decl->data.param_decl.type);
|
if (param_decl->data.param_decl.is_var_args) {
|
||||||
|
fprintf(ar->f, "...");
|
||||||
|
} else {
|
||||||
|
render_node_grouped(ar, param_decl->data.param_decl.type);
|
||||||
|
}
|
||||||
|
|
||||||
if (arg_i + 1 < arg_count || is_var_args) {
|
if (arg_i + 1 < arg_count) {
|
||||||
fprintf(ar->f, ", ");
|
fprintf(ar->f, ", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_var_args) {
|
|
||||||
fprintf(ar->f, "...");
|
|
||||||
}
|
|
||||||
fprintf(ar->f, ")");
|
fprintf(ar->f, ")");
|
||||||
|
|
||||||
AstNode *return_type_node = node->data.fn_proto.return_type;
|
AstNode *return_type_node = node->data.fn_proto.return_type;
|
||||||
|
|
|
@ -2636,6 +2636,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdVar:
|
case TypeTableEntryIdVar:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3179,6 +3180,12 @@ static void define_builtin_types(CodeGen *g) {
|
||||||
buf_init_from_str(&entry->name, "(var)");
|
buf_init_from_str(&entry->name, "(var)");
|
||||||
g->builtin_types.entry_var = entry;
|
g->builtin_types.entry_var = entry;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArgTuple);
|
||||||
|
buf_init_from_str(&entry->name, "(args)");
|
||||||
|
entry->zero_bits = true;
|
||||||
|
g->builtin_types.entry_arg_tuple = entry;
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
|
for (size_t int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
|
||||||
size_t size_in_bits = int_sizes_in_bits[int_size_i];
|
size_t size_in_bits = int_sizes_in_bits[int_size_i];
|
||||||
|
@ -3947,6 +3954,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
case TypeTableEntryIdNullLit:
|
case TypeTableEntryIdNullLit:
|
||||||
case TypeTableEntryIdVar:
|
case TypeTableEntryIdVar:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
151
src/ir.cpp
151
src/ir.cpp
|
@ -4347,8 +4347,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||||
|
|
||||||
IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
|
IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
|
||||||
|
|
||||||
IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val);
|
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val);
|
||||||
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type);
|
|
||||||
IrInstruction *elem_var_type;
|
IrInstruction *elem_var_type;
|
||||||
if (node->data.for_expr.elem_is_ptr) {
|
if (node->data.for_expr.elem_is_ptr) {
|
||||||
elem_var_type = pointer_type;
|
elem_var_type = pointer_type;
|
||||||
|
@ -6887,6 +6886,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
|
||||||
case TypeTableEntryIdNamespace:
|
case TypeTableEntryIdNamespace:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
if (!is_equality_cmp) {
|
if (!is_equality_cmp) {
|
||||||
ir_add_error_node(ira, source_node,
|
ir_add_error_node(ira, source_node,
|
||||||
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
|
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
|
||||||
|
@ -7449,6 +7449,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
// OK
|
// OK
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -7520,21 +7521,35 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||||
{
|
{
|
||||||
AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i);
|
AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i);
|
||||||
assert(param_decl_node->type == NodeTypeParamDecl);
|
assert(param_decl_node->type == NodeTypeParamDecl);
|
||||||
AstNode *param_type_node = param_decl_node->data.param_decl.type;
|
bool is_var_args = param_decl_node->data.param_decl.is_var_args;
|
||||||
TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);
|
bool arg_part_of_generic_id = false;
|
||||||
if (param_type->id == TypeTableEntryIdInvalid)
|
IrInstruction *casted_arg;
|
||||||
return false;
|
if (is_var_args) {
|
||||||
|
arg_part_of_generic_id = true;
|
||||||
|
casted_arg = arg;
|
||||||
|
} else {
|
||||||
|
AstNode *param_type_node = param_decl_node->data.param_decl.type;
|
||||||
|
TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);
|
||||||
|
if (param_type->id == TypeTableEntryIdInvalid)
|
||||||
|
return false;
|
||||||
|
|
||||||
IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type);
|
bool is_var_type = (param_type->id == TypeTableEntryIdVar);
|
||||||
if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
|
if (is_var_type) {
|
||||||
return false;
|
arg_part_of_generic_id = true;
|
||||||
|
casted_arg = arg;
|
||||||
|
} else {
|
||||||
|
casted_arg = ir_implicit_cast(ira, arg, param_type);
|
||||||
|
if (casted_arg->value.type->id == TypeTableEntryIdInvalid)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool inline_arg = param_decl_node->data.param_decl.is_inline;
|
bool comptime_arg = param_decl_node->data.param_decl.is_inline;
|
||||||
bool is_var_type = (param_type->id == TypeTableEntryIdVar);
|
|
||||||
|
|
||||||
ConstExprValue *arg_val;
|
ConstExprValue *arg_val;
|
||||||
|
|
||||||
if (inline_arg) {
|
if (comptime_arg) {
|
||||||
|
arg_part_of_generic_id = true;
|
||||||
arg_val = ir_resolve_const(ira, casted_arg, UndefBad);
|
arg_val = ir_resolve_const(ira, casted_arg, UndefBad);
|
||||||
if (!arg_val)
|
if (!arg_val)
|
||||||
return false;
|
return false;
|
||||||
|
@ -7544,26 +7559,41 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||||
} else {
|
} else {
|
||||||
arg_val = create_const_runtime(casted_arg->value.type);
|
arg_val = create_const_runtime(casted_arg->value.type);
|
||||||
}
|
}
|
||||||
|
if (arg_part_of_generic_id) {
|
||||||
Buf *param_name = param_decl_node->data.param_decl.name;
|
|
||||||
VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
|
|
||||||
*child_scope, param_name, true, arg_val);
|
|
||||||
var->value.depends_on_compile_var = true;
|
|
||||||
*child_scope = var->child_scope;
|
|
||||||
|
|
||||||
if (inline_arg || is_var_type) {
|
|
||||||
generic_id->params[generic_id->param_count] = *arg_val;
|
generic_id->params[generic_id->param_count] = *arg_val;
|
||||||
generic_id->param_count += 1;
|
generic_id->param_count += 1;
|
||||||
}
|
}
|
||||||
if (!inline_arg) {
|
|
||||||
if (type_requires_comptime(var->value.type)) {
|
Buf *param_name = param_decl_node->data.param_decl.name;
|
||||||
ir_add_error(ira, arg,
|
if (is_var_args) {
|
||||||
buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&var->value.type->name)));
|
if (!impl_fn->var_args_var) {
|
||||||
|
ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
|
||||||
|
fn_type_id->param_count, fn_type_id->param_count + 1);
|
||||||
|
VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
|
||||||
|
*child_scope, param_name, true, var_args_val);
|
||||||
|
var->value.depends_on_compile_var = true;
|
||||||
|
*child_scope = var->child_scope;
|
||||||
|
impl_fn->var_args_var = var;
|
||||||
|
}
|
||||||
|
impl_fn->var_args_var->value.data.x_arg_tuple.end_index = fn_type_id->param_count + 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
VariableTableEntry *var = add_variable(ira->codegen, param_decl_node,
|
||||||
|
*child_scope, param_name, true, arg_val);
|
||||||
|
var->value.depends_on_compile_var = true;
|
||||||
|
*child_scope = var->child_scope;
|
||||||
|
var->shadowable = !comptime_arg;
|
||||||
|
|
||||||
|
*next_proto_i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!comptime_arg) {
|
||||||
|
if (type_requires_comptime(casted_arg->value.type)) {
|
||||||
|
ir_add_error(ira, casted_arg,
|
||||||
|
buf_sprintf("parameter of type '%s' requires comptime", buf_ptr(&casted_arg->value.type->name)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var->shadowable = true;
|
|
||||||
|
|
||||||
casted_args[fn_type_id->param_count] = casted_arg;
|
casted_args[fn_type_id->param_count] = casted_arg;
|
||||||
FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count];
|
FnTypeParamInfo *param_info = &fn_type_id->param_info[fn_type_id->param_count];
|
||||||
param_info->type = casted_arg->value.type;
|
param_info->type = casted_arg->value.type;
|
||||||
|
@ -7571,7 +7601,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||||
impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node;
|
impl_fn->param_source_nodes[fn_type_id->param_count] = param_decl_node;
|
||||||
fn_type_id->param_count += 1;
|
fn_type_id->param_count += 1;
|
||||||
}
|
}
|
||||||
*next_proto_i += 1;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7682,6 +7712,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||||
FnTypeId inst_fn_type_id = {0};
|
FnTypeId inst_fn_type_id = {0};
|
||||||
init_fn_type_id(&inst_fn_type_id, fn_proto_node);
|
init_fn_type_id(&inst_fn_type_id, fn_proto_node);
|
||||||
inst_fn_type_id.param_count = 0;
|
inst_fn_type_id.param_count = 0;
|
||||||
|
inst_fn_type_id.is_var_args = false;
|
||||||
|
|
||||||
// TODO maybe GenericFnTypeId can be replaced with using the child_scope directly
|
// TODO maybe GenericFnTypeId can be replaced with using the child_scope directly
|
||||||
// as the key in generic_table
|
// as the key in generic_table
|
||||||
|
@ -7918,6 +7949,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdUnreachable:
|
case TypeTableEntryIdUnreachable:
|
||||||
case TypeTableEntryIdVar:
|
case TypeTableEntryIdVar:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
ir_add_error_node(ira, un_op_instruction->base.source_node,
|
ir_add_error_node(ira, un_op_instruction->base.source_node,
|
||||||
buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));
|
buf_sprintf("unable to wrap type '%s' in error type", buf_ptr(&meta_type->name)));
|
||||||
// TODO if meta_type is type decl, add note pointing to type decl declaration
|
// TODO if meta_type is type decl, add note pointing to type decl declaration
|
||||||
|
@ -7990,6 +8022,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
{
|
{
|
||||||
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
|
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
|
||||||
value->value.depends_on_compile_var);
|
value->value.depends_on_compile_var);
|
||||||
|
@ -8327,6 +8360,30 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
|
||||||
return_type = array_type;
|
return_type = array_type;
|
||||||
} else if (is_slice(array_type)) {
|
} else if (is_slice(array_type)) {
|
||||||
return_type = array_type->data.structure.fields[0].type_entry;
|
return_type = array_type->data.structure.fields[0].type_entry;
|
||||||
|
} else if (array_type->id == TypeTableEntryIdArgTuple) {
|
||||||
|
ConstExprValue *ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);
|
||||||
|
if (!ptr_val)
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
ConstExprValue *args_val = const_ptr_pointee(ptr_val);
|
||||||
|
size_t start = args_val->data.x_arg_tuple.start_index;
|
||||||
|
size_t end = args_val->data.x_arg_tuple.end_index;
|
||||||
|
ConstExprValue *elem_index_val = ir_resolve_const(ira, elem_index, UndefBad);
|
||||||
|
if (!elem_index_val)
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
size_t index = bignum_to_twos_complement(&elem_index_val->data.x_bignum);
|
||||||
|
size_t len = end - start;
|
||||||
|
if (index >= len) {
|
||||||
|
ir_add_error(ira, &elem_ptr_instruction->base,
|
||||||
|
buf_sprintf("index %zu outside argument list of size %zu", index, len));
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
size_t abs_index = start + index;
|
||||||
|
FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
|
||||||
|
assert(fn_entry);
|
||||||
|
VariableTableEntry *var = fn_entry->variable_list.at(abs_index);
|
||||||
|
bool depends_on_compile_var = array_ptr->value.depends_on_compile_var ||
|
||||||
|
elem_index->value.depends_on_compile_var;
|
||||||
|
return ir_analyze_var_ptr(ira, &elem_ptr_instruction->base, var, true, depends_on_compile_var);
|
||||||
} else {
|
} else {
|
||||||
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
|
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
|
||||||
buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));
|
buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name)));
|
||||||
|
@ -8572,6 +8629,29 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||||
ConstExprValue *len_val = allocate<ConstExprValue>(1);
|
ConstExprValue *len_val = allocate<ConstExprValue>(1);
|
||||||
init_const_usize(ira->codegen, len_val, container_type->data.array.len);
|
init_const_usize(ira->codegen, len_val, container_type->data.array.len);
|
||||||
|
|
||||||
|
TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
|
||||||
|
bool ptr_is_const = true;
|
||||||
|
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
|
||||||
|
usize, false, ConstPtrSpecialNone, ptr_is_const);
|
||||||
|
} else {
|
||||||
|
ir_add_error_node(ira, source_node,
|
||||||
|
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
|
||||||
|
buf_ptr(&container_type->name)));
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
} else if (container_type->id == TypeTableEntryIdArgTuple) {
|
||||||
|
ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
|
||||||
|
if (!container_ptr_val)
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
|
assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
|
||||||
|
ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
|
||||||
|
|
||||||
|
if (buf_eql_str(field_name, "len")) {
|
||||||
|
ConstExprValue *len_val = allocate<ConstExprValue>(1);
|
||||||
|
size_t len = child_val->data.x_arg_tuple.end_index - child_val->data.x_arg_tuple.start_index;
|
||||||
|
init_const_usize(ira->codegen, len_val, len);
|
||||||
|
|
||||||
TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
|
TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
|
||||||
bool ptr_is_const = true;
|
bool ptr_is_const = true;
|
||||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
|
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
|
||||||
|
@ -8830,6 +8910,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdTypeDecl:
|
case TypeTableEntryIdTypeDecl:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
{
|
{
|
||||||
ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);
|
ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);
|
||||||
// TODO depends_on_compile_var should be set based on whether the type of the expression
|
// TODO depends_on_compile_var should be set based on whether the type of the expression
|
||||||
|
@ -8847,8 +8928,8 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
|
||||||
static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
|
static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
|
||||||
IrInstructionToPtrType *to_ptr_type_instruction)
|
IrInstructionToPtrType *to_ptr_type_instruction)
|
||||||
{
|
{
|
||||||
IrInstruction *type_value = to_ptr_type_instruction->value->other;
|
IrInstruction *value = to_ptr_type_instruction->value->other;
|
||||||
TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
|
TypeTableEntry *type_entry = value->value.type;
|
||||||
if (type_entry->id == TypeTableEntryIdInvalid)
|
if (type_entry->id == TypeTableEntryIdInvalid)
|
||||||
return type_entry;
|
return type_entry;
|
||||||
|
|
||||||
|
@ -8857,6 +8938,11 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
|
||||||
ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false);
|
ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false);
|
||||||
} else if (is_slice(type_entry)) {
|
} else if (is_slice(type_entry)) {
|
||||||
ptr_type = type_entry->data.structure.fields[0].type_entry;
|
ptr_type = type_entry->data.structure.fields[0].type_entry;
|
||||||
|
} else if (type_entry->id == TypeTableEntryIdArgTuple) {
|
||||||
|
ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad);
|
||||||
|
if (!arg_tuple_val)
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
zig_panic("TODO for loop on var args");
|
||||||
} else {
|
} else {
|
||||||
ir_add_error_node(ira, to_ptr_type_instruction->base.source_node,
|
ir_add_error_node(ira, to_ptr_type_instruction->base.source_node,
|
||||||
buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name)));
|
buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name)));
|
||||||
|
@ -8864,7 +8950,7 @@ static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base,
|
ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base,
|
||||||
type_value->value.depends_on_compile_var);
|
value->value.depends_on_compile_var);
|
||||||
out_val->data.x_type = ptr_type;
|
out_val->data.x_type = ptr_type;
|
||||||
return ira->codegen->builtin_types.entry_type;
|
return ira->codegen->builtin_types.entry_type;
|
||||||
}
|
}
|
||||||
|
@ -9027,6 +9113,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
case TypeTableEntryIdNullLit:
|
case TypeTableEntryIdNullLit:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
ir_add_error_node(ira, slice_type_instruction->base.source_node,
|
ir_add_error_node(ira, slice_type_instruction->base.source_node,
|
||||||
buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name)));
|
buf_sprintf("slice of type '%s' not allowed", buf_ptr(&resolved_child_type->name)));
|
||||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||||
|
@ -9118,6 +9205,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||||
case TypeTableEntryIdUndefLit:
|
case TypeTableEntryIdUndefLit:
|
||||||
case TypeTableEntryIdNullLit:
|
case TypeTableEntryIdNullLit:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
ir_add_error_node(ira, array_type_instruction->base.source_node,
|
ir_add_error_node(ira, array_type_instruction->base.source_node,
|
||||||
buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));
|
buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));
|
||||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||||
|
@ -9214,6 +9302,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
|
||||||
case TypeTableEntryIdMetaType:
|
case TypeTableEntryIdMetaType:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdNamespace:
|
case TypeTableEntryIdNamespace:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
ir_add_error_node(ira, size_of_instruction->base.source_node,
|
ir_add_error_node(ira, size_of_instruction->base.source_node,
|
||||||
buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
|
buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
|
||||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||||
|
@ -9559,6 +9648,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
ir_add_error(ira, &switch_target_instruction->base,
|
ir_add_error(ira, &switch_target_instruction->base,
|
||||||
buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
|
buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
|
||||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||||
|
@ -10075,6 +10165,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
|
||||||
case TypeTableEntryIdNamespace:
|
case TypeTableEntryIdNamespace:
|
||||||
case TypeTableEntryIdBlock:
|
case TypeTableEntryIdBlock:
|
||||||
case TypeTableEntryIdBoundFn:
|
case TypeTableEntryIdBoundFn:
|
||||||
|
case TypeTableEntryIdArgTuple:
|
||||||
{
|
{
|
||||||
const char *err_format = is_max ?
|
const char *err_format = is_max ?
|
||||||
"no max value available for type '%s'" :
|
"no max value available for type '%s'" :
|
||||||
|
|
|
@ -250,16 +250,11 @@ static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") TypeExpr | "..."
|
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
|
static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
|
|
||||||
if (token->id == TokenIdEllipsis) {
|
|
||||||
*token_index += 1;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token);
|
AstNode *node = ast_create_node(pc, NodeTypeParamDecl, token);
|
||||||
|
|
||||||
if (token->id == TokenIdKeywordNoAlias) {
|
if (token->id == TokenIdKeywordNoAlias) {
|
||||||
|
@ -282,7 +277,13 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true);
|
Token *ellipsis_tok = &pc->tokens->at(*token_index);
|
||||||
|
if (ellipsis_tok->id == TokenIdEllipsis) {
|
||||||
|
*token_index += 1;
|
||||||
|
node->data.param_decl.is_var_args = true;
|
||||||
|
} else {
|
||||||
|
node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true);
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -304,12 +305,10 @@ static void ast_parse_param_decl_list(ParseContext *pc, size_t *token_index,
|
||||||
for (;;) {
|
for (;;) {
|
||||||
AstNode *param_decl_node = ast_parse_param_decl(pc, token_index);
|
AstNode *param_decl_node = ast_parse_param_decl(pc, token_index);
|
||||||
bool expect_end = false;
|
bool expect_end = false;
|
||||||
if (param_decl_node) {
|
assert(param_decl_node);
|
||||||
params->append(param_decl_node);
|
params->append(param_decl_node);
|
||||||
} else {
|
expect_end = param_decl_node->data.param_decl.is_var_args;
|
||||||
*is_var_args = true;
|
*is_var_args = expect_end;
|
||||||
expect_end = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
const assert = @import("std").debug.assert;
|
||||||
|
|
||||||
|
fn add(args: ...) -> i32 {
|
||||||
|
var sum = i32(0);
|
||||||
|
{comptime var i: usize = 0; inline while (i < args.len; i += 1) {
|
||||||
|
sum += args[i];
|
||||||
|
}}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testAddArbitraryArgs() {
|
||||||
|
@setFnTest(this);
|
||||||
|
|
||||||
|
assert(add(i32(1), i32(2), i32(3), i32(4)) == 10);
|
||||||
|
assert(add(i32(1234)) == 1234);
|
||||||
|
}
|
|
@ -832,10 +832,6 @@ fn f() {
|
||||||
)SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'",
|
)SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'",
|
||||||
".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'");
|
".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'");
|
||||||
|
|
||||||
add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
|
|
||||||
fn f(...) {}
|
|
||||||
)SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern function declarations");
|
|
||||||
|
|
||||||
add_compile_fail_case("write to const global variable", R"SOURCE(
|
add_compile_fail_case("write to const global variable", R"SOURCE(
|
||||||
const x : i32 = 99;
|
const x : i32 = 99;
|
||||||
fn f() {
|
fn f() {
|
||||||
|
@ -1633,6 +1629,33 @@ pub fn maybeInt() -> ?i32 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
)SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression");
|
)SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression");
|
||||||
|
|
||||||
|
add_compile_fail_case("attempt to access var args out of bounds", R"SOURCE(
|
||||||
|
fn add(args: ...) -> i32 {
|
||||||
|
args[0] + args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() -> i32 {
|
||||||
|
add(i32(1234))
|
||||||
|
}
|
||||||
|
)SOURCE", 2,
|
||||||
|
".tmp_source.zig:3:19: error: index 1 outside argument list of size 1",
|
||||||
|
".tmp_source.zig:7:8: note: called from here");
|
||||||
|
|
||||||
|
add_compile_fail_case("pass integer literal to var args", R"SOURCE(
|
||||||
|
fn add(args: ...) -> i32 {
|
||||||
|
var sum = i32(0);
|
||||||
|
{comptime var i: usize = 0; inline while (i < args.len; i += 1) {
|
||||||
|
sum += args[i];
|
||||||
|
}}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() -> i32 {
|
||||||
|
add(1, 2, 3, 4)
|
||||||
|
}
|
||||||
|
)SOURCE", 1, ".tmp_source.zig:11:9: error: parameter of type '(integer literal)' requires comptime");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -28,4 +28,5 @@ const test_switch = @import("cases/switch.zig");
|
||||||
const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");
|
const test_switch_prong_err_enum = @import("cases/switch_prong_err_enum.zig");
|
||||||
const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");
|
const test_switch_prong_implicit_cast = @import("cases/switch_prong_implicit_cast.zig");
|
||||||
const test_this = @import("cases/this.zig");
|
const test_this = @import("cases/this.zig");
|
||||||
|
const test_var_args = @import("cases/var_args.zig");
|
||||||
const test_while = @import("cases/while.zig");
|
const test_while = @import("cases/while.zig");
|
||||||
|
|
Loading…
Reference in New Issue