ability to infer parameter types
parent
de7e88c38f
commit
d324b1befa
|
@ -45,7 +45,7 @@ Label = Symbol ":"
|
|||
|
||||
Expression = BlockExpression | NonBlockExpression
|
||||
|
||||
TypeExpr = PrefixOpExpression
|
||||
TypeExpr = PrefixOpExpression | "var"
|
||||
|
||||
NonBlockExpression = ReturnExpression | AssignmentExpression
|
||||
|
||||
|
|
|
@ -194,6 +194,7 @@ enum NodeType {
|
|||
NodeTypeArrayType,
|
||||
NodeTypeErrorType,
|
||||
NodeTypeTypeLiteral,
|
||||
NodeTypeVarLiteral,
|
||||
};
|
||||
|
||||
struct AstNodeRoot {
|
||||
|
@ -218,6 +219,7 @@ struct AstNodeFnProto {
|
|||
Expr resolved_expr;
|
||||
// computed from params field
|
||||
int inline_arg_count;
|
||||
int inline_or_var_type_arg_count;
|
||||
// if this is a generic function implementation, this points to the generic node
|
||||
AstNode *generic_proto_node;
|
||||
};
|
||||
|
@ -754,6 +756,11 @@ struct AstNodeTypeLiteral {
|
|||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeVarLiteral {
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNode {
|
||||
enum NodeType type;
|
||||
int line;
|
||||
|
@ -812,6 +819,7 @@ struct AstNode {
|
|||
AstNodeArrayType array_type;
|
||||
AstNodeErrorType error_type;
|
||||
AstNodeTypeLiteral type_literal;
|
||||
AstNodeVarLiteral var_literal;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
@ -836,6 +844,7 @@ struct FnTypeParamInfo {
|
|||
struct GenericParamValue {
|
||||
TypeTableEntry *type;
|
||||
AstNode *node;
|
||||
int impl_index;
|
||||
};
|
||||
|
||||
struct GenericFnTypeId {
|
||||
|
@ -976,6 +985,7 @@ struct TypeTableEntryTypeDecl {
|
|||
|
||||
enum TypeTableEntryId {
|
||||
TypeTableEntryIdInvalid,
|
||||
TypeTableEntryIdVar,
|
||||
TypeTableEntryIdMetaType,
|
||||
TypeTableEntryIdVoid,
|
||||
TypeTableEntryIdBool,
|
||||
|
@ -1229,6 +1239,7 @@ struct CodeGen {
|
|||
TypeTableEntry *entry_num_lit_float;
|
||||
TypeTableEntry *entry_undef;
|
||||
TypeTableEntry *entry_null;
|
||||
TypeTableEntry *entry_var;
|
||||
TypeTableEntry *entry_pure_error;
|
||||
TypeTableEntry *entry_os_enum;
|
||||
TypeTableEntry *entry_arch_enum;
|
||||
|
@ -1337,6 +1348,7 @@ struct VariableTableEntry {
|
|||
LLVMValueRef param_value_ref;
|
||||
bool force_depends_on_compile_var;
|
||||
ImportTableEntry *import;
|
||||
bool shadowable;
|
||||
};
|
||||
|
||||
struct ErrorTableEntry {
|
||||
|
|
222
src/analyze.cpp
222
src/analyze.cpp
|
@ -109,6 +109,7 @@ static AstNode *first_executing_node(AstNode *node) {
|
|||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeContainerInitExpr:
|
||||
case NodeTypeVarLiteral:
|
||||
return node;
|
||||
}
|
||||
zig_unreachable();
|
||||
|
@ -219,6 +220,7 @@ static int bits_needed_for_unsigned(uint64_t x) {
|
|||
static bool type_is_complete(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdStruct:
|
||||
return type_entry->data.structure.complete;
|
||||
|
@ -919,39 +921,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
|||
fn_type_id.is_var_args = fn_proto->is_var_args;
|
||||
fn_type_id.return_type = analyze_type_expr(g, import, context, fn_proto->return_type);
|
||||
|
||||
switch (fn_type_id.return_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
fn_proto->skip = true;
|
||||
break;
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
fn_proto->skip = true;
|
||||
add_node_error(g, fn_proto->return_type,
|
||||
buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
|
||||
break;
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fn_type_id.param_count; i += 1) {
|
||||
AstNode *child = fn_proto->params.at(i);
|
||||
assert(child->type == NodeTypeParamDecl);
|
||||
|
@ -996,6 +965,10 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
|||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
break;
|
||||
case TypeTableEntryIdVar:
|
||||
// var types are treated as generic functions; if we get to this code we should
|
||||
// already be an instantiated function.
|
||||
zig_unreachable();
|
||||
}
|
||||
if (type_entry->id == TypeTableEntryIdInvalid) {
|
||||
fn_proto->skip = true;
|
||||
|
@ -1005,6 +978,42 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
|||
param_info->is_noalias = child->data.param_decl.is_noalias;
|
||||
}
|
||||
|
||||
switch (fn_type_id.return_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
fn_proto->skip = true;
|
||||
break;
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
fn_proto->skip = true;
|
||||
add_node_error(g, fn_proto->return_type,
|
||||
buf_sprintf("return type '%s' not allowed", buf_ptr(&fn_type_id.return_type->name)));
|
||||
break;
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
break;
|
||||
case TypeTableEntryIdVar:
|
||||
zig_panic("TODO var return type");
|
||||
}
|
||||
|
||||
|
||||
if (fn_proto->skip) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
@ -1618,6 +1627,11 @@ static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNo
|
|||
node->data.struct_decl.generic_fn_type = get_generic_fn_type(g, node);
|
||||
}
|
||||
|
||||
static bool get_is_generic_fn(AstNode *proto_node) {
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
return proto_node->data.fn_proto.inline_or_var_type_arg_count > 0;
|
||||
}
|
||||
|
||||
static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node,
|
||||
BlockContext *containing_context)
|
||||
{
|
||||
|
@ -1628,7 +1642,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
|
|||
}
|
||||
|
||||
bool is_generic_instance = proto_node->data.fn_proto.generic_proto_node;
|
||||
bool is_generic_fn = proto_node->data.fn_proto.inline_arg_count > 0;
|
||||
bool is_generic_fn = get_is_generic_fn(proto_node);
|
||||
assert(!is_generic_instance || !is_generic_fn);
|
||||
|
||||
AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;
|
||||
|
@ -1875,6 +1889,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
|
|||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeVarLiteral:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
|
@ -1936,6 +1951,9 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
|
|||
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
return type_has_codegen_value(type_entry->data.type_decl.canonical_type);
|
||||
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -3374,6 +3392,9 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
|
|||
add_node_error(g, node,
|
||||
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val;
|
||||
|
@ -3751,20 +3772,22 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
|||
}
|
||||
|
||||
// Set name to nullptr to make the variable anonymous (not visible to programmer).
|
||||
static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
|
||||
BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node)
|
||||
static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
|
||||
BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node,
|
||||
bool shadowable)
|
||||
{
|
||||
VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
|
||||
variable_entry->type = type_entry;
|
||||
variable_entry->block_context = context;
|
||||
variable_entry->import = import;
|
||||
variable_entry->shadowable = shadowable;
|
||||
|
||||
if (name) {
|
||||
buf_init_from_buf(&variable_entry->name, name);
|
||||
|
||||
if (type_entry->id != TypeTableEntryIdInvalid) {
|
||||
VariableTableEntry *existing_var = find_variable(g, context, name);
|
||||
if (existing_var) {
|
||||
if (existing_var && !existing_var->shadowable) {
|
||||
ErrorMsg *msg = add_node_error(g, source_node,
|
||||
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
|
||||
add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
|
||||
|
@ -3805,6 +3828,12 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor
|
|||
return variable_entry;
|
||||
}
|
||||
|
||||
static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import,
|
||||
BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node)
|
||||
{
|
||||
return add_local_var_shadowable(g, source_node, import, context, name, type_entry, is_const, val_node, false);
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
|
@ -5227,6 +5256,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
|||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdVar:
|
||||
add_node_error(g, expr_node,
|
||||
buf_sprintf("type '%s' not eligible for @typeOf", buf_ptr(&type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
|
@ -5542,23 +5572,22 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
|
|||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
int inline_arg_count = decl_node->data.fn_proto.inline_arg_count;
|
||||
assert(inline_arg_count > 0);
|
||||
int inline_or_var_type_arg_count = decl_node->data.fn_proto.inline_or_var_type_arg_count;
|
||||
assert(inline_or_var_type_arg_count > 0);
|
||||
|
||||
BlockContext *child_context = decl_node->owner->block_context;
|
||||
int next_generic_param_index = 0;
|
||||
|
||||
GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
|
||||
generic_fn_type_id->decl_node = decl_node;
|
||||
generic_fn_type_id->generic_param_count = inline_arg_count;
|
||||
generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_arg_count);
|
||||
generic_fn_type_id->generic_param_count = inline_or_var_type_arg_count;
|
||||
generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_or_var_type_arg_count);
|
||||
|
||||
int next_impl_i = 0;
|
||||
for (int call_i = 0; call_i < call_param_count; call_i += 1) {
|
||||
int proto_i = call_i + struct_node_1_or_0;
|
||||
AstNode *generic_param_decl_node = decl_node->data.fn_proto.params.at(proto_i);
|
||||
assert(generic_param_decl_node->type == NodeTypeParamDecl);
|
||||
bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
|
||||
if (!is_inline) continue;
|
||||
|
||||
AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
|
||||
TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, child_context,
|
||||
|
@ -5567,9 +5596,17 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
|
|||
return expected_param_type;
|
||||
}
|
||||
|
||||
bool is_var_type = (expected_param_type->id == TypeTableEntryIdVar);
|
||||
bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
|
||||
if (!is_inline && !is_var_type) {
|
||||
next_impl_i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i);
|
||||
TypeTableEntry *param_type = analyze_expression(g, import, parent_context,
|
||||
expected_param_type, *param_node);
|
||||
is_var_type ? nullptr : expected_param_type, *param_node);
|
||||
if (param_type->id == TypeTableEntryIdInvalid) {
|
||||
return param_type;
|
||||
}
|
||||
|
@ -5578,27 +5615,32 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
|
|||
child_context = new_block_context(generic_param_decl_node, child_context);
|
||||
|
||||
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
|
||||
if (const_val->ok) {
|
||||
VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
|
||||
generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
|
||||
// This generic function instance could be called with anything, so when this variable is read it
|
||||
// needs to know that it depends on compile time variable data.
|
||||
var->force_depends_on_compile_var = true;
|
||||
} else {
|
||||
if (is_inline && !const_val->ok) {
|
||||
add_node_error(g, *param_node,
|
||||
buf_sprintf("unable to evaluate constant expression for inline parameter"));
|
||||
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
VariableTableEntry *var = add_local_var_shadowable(g, generic_param_decl_node, decl_node->owner, child_context,
|
||||
generic_param_decl_node->data.param_decl.name, param_type, true, *param_node, true);
|
||||
// This generic function instance could be called with anything, so when this variable is read it
|
||||
// needs to know that it depends on compile time variable data.
|
||||
var->force_depends_on_compile_var = true;
|
||||
|
||||
GenericParamValue *generic_param_value =
|
||||
&generic_fn_type_id->generic_params[next_generic_param_index];
|
||||
generic_param_value->type = param_type;
|
||||
generic_param_value->node = *param_node;
|
||||
generic_param_value->node = is_inline ? *param_node : nullptr;
|
||||
generic_param_value->impl_index = next_impl_i;
|
||||
next_generic_param_index += 1;
|
||||
|
||||
if (!is_inline) {
|
||||
next_impl_i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(next_generic_param_index == inline_arg_count);
|
||||
assert(next_generic_param_index == inline_or_var_type_arg_count);
|
||||
|
||||
auto entry = g->generic_table.maybe_get(generic_fn_type_id);
|
||||
FnTableEntry *impl_fn;
|
||||
|
@ -5612,8 +5654,23 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
|
|||
&g->next_node_index, AstCloneSpecialOmitInlineParams);
|
||||
AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
|
||||
impl_decl_node->data.fn_proto.inline_arg_count = 0;
|
||||
impl_decl_node->data.fn_proto.inline_or_var_type_arg_count = 0;
|
||||
impl_decl_node->data.fn_proto.generic_proto_node = decl_node;
|
||||
|
||||
// replace var arg types with actual types
|
||||
for (int generic_arg_i = 0; generic_arg_i < inline_or_var_type_arg_count; generic_arg_i += 1) {
|
||||
GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[generic_arg_i];
|
||||
if (!generic_param_value->node) {
|
||||
int impl_i = generic_param_value->impl_index;
|
||||
AstNode *impl_param_decl_node = impl_decl_node->data.fn_proto.params.at(impl_i);
|
||||
assert(impl_param_decl_node->type == NodeTypeParamDecl);
|
||||
|
||||
impl_param_decl_node->data.param_decl.type = create_ast_type_node(g, import,
|
||||
generic_param_value->type, impl_param_decl_node);
|
||||
normalize_parent_ptrs(impl_param_decl_node);
|
||||
}
|
||||
}
|
||||
|
||||
preview_fn_proto_instance(g, import, impl_decl_node, child_context);
|
||||
g->generic_table.put(generic_fn_type_id, impl_decl_node);
|
||||
impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
|
||||
|
@ -5660,6 +5717,9 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
|
|||
if (expected_param_type->id == TypeTableEntryIdInvalid) {
|
||||
return expected_param_type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AstNode **param_node = &node->data.fn_call_expr.params.at(i);
|
||||
|
||||
TypeTableEntry *param_type = analyze_expression(g, import, parent_context, expected_param_type,
|
||||
|
@ -6605,6 +6665,9 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
|
|||
case NodeTypeSwitchExpr:
|
||||
return_type = analyze_switch_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeVarLiteral:
|
||||
return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_var, false);
|
||||
break;
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
case NodeTypeDirective:
|
||||
|
@ -6750,18 +6813,25 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex
|
|||
}
|
||||
}
|
||||
|
||||
static int fn_proto_inline_arg_count(AstNode *proto_node) {
|
||||
static void count_inline_and_var_args(AstNode *proto_node) {
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
int result = 0;
|
||||
|
||||
int *inline_arg_count = &proto_node->data.fn_proto.inline_arg_count;
|
||||
int *inline_or_var_type_arg_count = &proto_node->data.fn_proto.inline_or_var_type_arg_count;
|
||||
|
||||
*inline_arg_count = 0;
|
||||
*inline_or_var_type_arg_count = 0;
|
||||
|
||||
for (int i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
|
||||
AstNode *param_node = proto_node->data.fn_proto.params.at(i);
|
||||
assert(param_node->type == NodeTypeParamDecl);
|
||||
result += param_node->data.param_decl.is_inline ? 1 : 0;
|
||||
bool is_inline = param_node->data.param_decl.is_inline;
|
||||
*inline_arg_count += is_inline ? 1 : 0;
|
||||
*inline_or_var_type_arg_count += (is_inline ||
|
||||
param_node->data.param_decl.type->type == NodeTypeVarLiteral) ? 1 : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeRoot:
|
||||
|
@ -6804,7 +6874,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
|
|||
add_node_error(g, node, buf_sprintf("missing function name"));
|
||||
break;
|
||||
}
|
||||
node->data.fn_proto.inline_arg_count = fn_proto_inline_arg_count(node);
|
||||
count_inline_and_var_args(node);
|
||||
|
||||
add_top_level_decl(g, import, context, node, fn_name);
|
||||
break;
|
||||
|
@ -6861,6 +6931,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
|
|||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeVarLiteral:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
@ -7118,6 +7189,8 @@ Expr *get_resolved_expr(AstNode *node) {
|
|||
return &node->data.switch_expr.resolved_expr;
|
||||
case NodeTypeFnProto:
|
||||
return &node->data.fn_proto.resolved_expr;
|
||||
case NodeTypeVarLiteral:
|
||||
return &node->data.var_literal.resolved_expr;
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
case NodeTypeRoot:
|
||||
|
@ -7192,6 +7265,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
|
|||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeVarLiteral:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
|
@ -7250,6 +7324,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
|||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVoid:
|
||||
|
@ -7392,6 +7467,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
|
|||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
|
@ -7402,9 +7478,12 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) {
|
|||
result += hash_ptr(id->decl_node);
|
||||
for (int i = 0; i < id->generic_param_count; i += 1) {
|
||||
GenericParamValue *generic_param = &id->generic_params[i];
|
||||
ConstExprValue *const_val = &get_resolved_expr(generic_param->node)->const_val;
|
||||
assert(const_val->ok);
|
||||
result += hash_const_val(generic_param->type, const_val);
|
||||
if (generic_param->node) {
|
||||
ConstExprValue *const_val = &get_resolved_expr(generic_param->node)->const_val;
|
||||
assert(const_val->ok);
|
||||
result += hash_const_val(generic_param->type, const_val);
|
||||
}
|
||||
result += hash_ptr(generic_param->type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -7415,13 +7494,17 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
|
|||
for (int i = 0; i < a->generic_param_count; i += 1) {
|
||||
GenericParamValue *a_val = &a->generic_params[i];
|
||||
GenericParamValue *b_val = &b->generic_params[i];
|
||||
assert(a_val->type == b_val->type);
|
||||
ConstExprValue *a_const_val = &get_resolved_expr(a_val->node)->const_val;
|
||||
ConstExprValue *b_const_val = &get_resolved_expr(b_val->node)->const_val;
|
||||
assert(a_const_val->ok);
|
||||
assert(b_const_val->ok);
|
||||
if (!const_values_equal(a_const_val, b_const_val, a_val->type)) {
|
||||
return false;
|
||||
if (a_val->type != b_val->type) return false;
|
||||
if (a_val->node && b_val->node) {
|
||||
ConstExprValue *a_const_val = &get_resolved_expr(a_val->node)->const_val;
|
||||
ConstExprValue *b_const_val = &get_resolved_expr(b_val->node)->const_val;
|
||||
assert(a_const_val->ok);
|
||||
assert(b_const_val->ok);
|
||||
if (!const_values_equal(a_const_val, b_const_val, a_val->type)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
assert(!a_val->node && !b_val->node);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -7457,6 +7540,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
|
|||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdArray:
|
||||
return type_of_first_thing_in_memory(type_entry->data.array.child_type);
|
||||
|
|
|
@ -213,6 +213,8 @@ static const char *node_type_str(NodeType node_type) {
|
|||
return "ErrorType";
|
||||
case NodeTypeTypeLiteral:
|
||||
return "TypeLiteral";
|
||||
case NodeTypeVarLiteral:
|
||||
return "VarLiteral";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -672,6 +674,9 @@ static void render_node(AstRender *ar, AstNode *node) {
|
|||
case NodeTypeTypeLiteral:
|
||||
fprintf(ar->f, "type");
|
||||
break;
|
||||
case NodeTypeVarLiteral:
|
||||
fprintf(ar->f, "var");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3597,6 +3597,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
|||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeArrayType:
|
||||
case NodeTypeVarLiteral:
|
||||
// caught by constant expression eval codegen
|
||||
zig_unreachable();
|
||||
case NodeTypeRoot:
|
||||
|
@ -3815,6 +3816,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
|
|||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
|
||||
}
|
||||
|
@ -4362,6 +4364,12 @@ static void define_builtin_types(CodeGen *g) {
|
|||
entry->deep_const = true;
|
||||
g->builtin_types.entry_null = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVar);
|
||||
buf_init_from_str(&entry->name, "(var)");
|
||||
entry->deep_const = true;
|
||||
g->builtin_types.entry_var = entry;
|
||||
}
|
||||
|
||||
for (int int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
|
||||
int size_in_bits = int_sizes_in_bits[int_size_i];
|
||||
|
@ -5129,6 +5137,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
|
|||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,9 +55,11 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
|
|||
zig_panic("TODO");
|
||||
case TypeTableEntryIdNamespace:
|
||||
zig_panic("TODO");
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
|
@ -1301,6 +1303,7 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
|||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeVarLiteral:
|
||||
zig_panic("TODO");
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeFnProto:
|
||||
|
|
|
@ -266,6 +266,20 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
/*
|
||||
TypeExpr = PrefixOpExpression | "var"
|
||||
*/
|
||||
static AstNode *ast_parse_type_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
if (token->id == TokenIdKeywordVar) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeVarLiteral, token);
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else {
|
||||
return ast_parse_prefix_op_expr(pc, token_index, mandatory);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
|
||||
*/
|
||||
|
@ -299,7 +313,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
|
|||
}
|
||||
}
|
||||
|
||||
node->data.param_decl.type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true);
|
||||
|
||||
normalize_parent_ptrs(node);
|
||||
return node;
|
||||
|
@ -414,7 +428,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo
|
|||
node->data.array_type.is_const = true;
|
||||
}
|
||||
|
||||
node->data.array_type.child_type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
node->data.array_type.child_type = ast_parse_type_expr(pc, token_index, true);
|
||||
|
||||
normalize_parent_ptrs(node);
|
||||
return node;
|
||||
|
@ -460,7 +474,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
|
|||
if (token->id == TokenIdSymbol) {
|
||||
asm_output->variable_name = token_buf(token);
|
||||
} else if (token->id == TokenIdArrow) {
|
||||
asm_output->return_type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
asm_output->return_type = ast_parse_type_expr(pc, token_index, true);
|
||||
} else {
|
||||
ast_invalid_token_error(pc, token);
|
||||
}
|
||||
|
@ -1354,7 +1368,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
|
|||
node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
|
||||
} else if (eq_or_colon->id == TokenIdColon) {
|
||||
*token_index += 1;
|
||||
node->data.if_var_expr.var_decl.type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
node->data.if_var_expr.var_decl.type = ast_parse_type_expr(pc, token_index, true);
|
||||
|
||||
ast_eat_token(pc, token_index, TokenIdMaybeAssign);
|
||||
node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
|
||||
|
@ -1504,7 +1518,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
|
|||
normalize_parent_ptrs(node);
|
||||
return node;
|
||||
} else if (eq_or_colon->id == TokenIdColon) {
|
||||
node->data.variable_declaration.type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
node->data.variable_declaration.type = ast_parse_type_expr(pc, token_index, true);
|
||||
Token *eq_token = &pc->tokens->at(*token_index);
|
||||
if (eq_token->id == TokenIdEq) {
|
||||
*token_index += 1;
|
||||
|
@ -2038,7 +2052,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
|
|||
Token *next_token = &pc->tokens->at(*token_index);
|
||||
if (next_token->id == TokenIdArrow) {
|
||||
*token_index += 1;
|
||||
node->data.fn_proto.return_type = ast_parse_prefix_op_expr(pc, token_index, false);
|
||||
node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, false);
|
||||
} else {
|
||||
node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token);
|
||||
}
|
||||
|
@ -2315,7 +2329,7 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, int *token_index,
|
|||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeTypeDecl, first_token);
|
||||
node->data.type_decl.symbol = token_buf(name_tok);
|
||||
node->data.type_decl.child_type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
node->data.type_decl.child_type = ast_parse_type_expr(pc, token_index, true);
|
||||
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
|
||||
|
@ -2628,6 +2642,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
|||
case NodeTypeTypeLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeVarLiteral:
|
||||
// none
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2907,6 +2924,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
|
|||
case NodeTypeTypeLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeVarLiteral:
|
||||
// none
|
||||
break;
|
||||
}
|
||||
|
||||
return new_node;
|
||||
|
|
|
@ -73,11 +73,7 @@ fn findCompileUnitOffset(st: &ElfStackTrace, target_address: usize) -> %u64 {
|
|||
|
||||
while (true) {
|
||||
const tag_id = %return st.self_exe_stream.readByte();
|
||||
if (tag_id == DW.TAG_compile_unit) {
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
// TODO iterate until we find the relevant compile unit
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
const assert = @import("std").debug.assert;
|
||||
|
||||
#attribute("test")
|
||||
fn varParams() {
|
||||
assert(max_i32(12, 34) == 34);
|
||||
assert(max_f64(1.2, 3.4) == 3.4);
|
||||
|
||||
assert(max_i32_noeval(12, 34) == 34);
|
||||
assert(max_f64_noeval(1.2, 3.4) == 3.4);
|
||||
}
|
||||
|
||||
fn max(a: var, b: var) -> @typeOf(a) {
|
||||
if (a > b) a else b
|
||||
}
|
||||
|
||||
fn max_i32(a: i32, b: i32) -> i32 {
|
||||
max(a, b)
|
||||
}
|
||||
|
||||
fn max_f64(a: f64, b: f64) -> f64 {
|
||||
max(a, b)
|
||||
}
|
||||
|
||||
#static_eval_enable(false)
|
||||
fn max_i32_noeval(a: i32, b: i32) -> i32 {
|
||||
max(a, b)
|
||||
}
|
||||
|
||||
#static_eval_enable(false)
|
||||
fn max_f64_noeval(a: f64, b: f64) -> f64 {
|
||||
max(a, b)
|
||||
}
|
|
@ -3,11 +3,13 @@ const assert = std.debug.assert;
|
|||
const str = std.str;
|
||||
const cstr = std.cstr;
|
||||
const other = @import("other.zig");
|
||||
// TODO '_' identifier for unused variable bindings
|
||||
const test_return_type_type = @import("cases/return_type_type.zig");
|
||||
const test_zeroes = @import("cases/zeroes.zig");
|
||||
const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig");
|
||||
const test_maybe_return = @import("cases/maybe_return.zig");
|
||||
const test_max_value_type = @import("cases/max_value_type.zig");
|
||||
const test_var_params = @import("cases/var_params.zig");
|
||||
|
||||
// normal comment
|
||||
/// this is a documentation comment
|
||||
|
|
Loading…
Reference in New Issue