astgen: fix fnDecl anytype params, type coercion, and export linkage
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
221
astgen.c
221
astgen.c
@@ -8541,9 +8541,20 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t fn_token = tree->nodes.main_tokens[proto_node];
|
||||
uint32_t fn_name_token = fn_token + 1;
|
||||
|
||||
// Check for 'pub' modifier (Ast.zig:2003-2025).
|
||||
bool is_pub = (fn_token > 0
|
||||
&& tree->tokens.tags[fn_token - 1] == TOKEN_KEYWORD_PUB);
|
||||
// Check for 'pub', 'export' modifiers (Ast.zig:2003-2025,
|
||||
// AstGen.zig:4102-4106).
|
||||
bool is_pub = false;
|
||||
bool is_export = false;
|
||||
for (uint32_t i = fn_token; i > 0;) {
|
||||
i--;
|
||||
uint32_t ttag = tree->tokens.tags[i];
|
||||
if (ttag == TOKEN_KEYWORD_PUB)
|
||||
is_pub = true;
|
||||
else if (ttag == TOKEN_KEYWORD_EXPORT)
|
||||
is_export = true;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// makeDeclaration on fn_proto node (AstGen.zig:4090).
|
||||
uint32_t decl_inst = makeDeclaration(ag, proto_node);
|
||||
@@ -8646,44 +8657,98 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
uint32_t param_insts[32];
|
||||
uint32_t param_insts_len = 0;
|
||||
|
||||
for (uint32_t param_i = 0; param_i < params_len; param_i++) {
|
||||
uint32_t param_type_node = param_nodes[param_i];
|
||||
// Parameter iteration using token-based iterator, mirroring upstream
|
||||
// FnProto.Iterator (Ast.zig:2680-2768, AstGen.zig:4260-4363).
|
||||
// The params array only contains type-expression params; anytype params
|
||||
// exist as tokens between/after the type-expression nodes.
|
||||
uint32_t lparen = fn_name_token + 1; // '(' token
|
||||
uint32_t iter_tok_i = lparen + 1; // first token after '('
|
||||
bool iter_tok_flag = true; // start in token-scanning mode
|
||||
uint32_t iter_param_i = 0;
|
||||
ResultLoc coerced_type_ri = { .tag = RL_COERCED_TY,
|
||||
.data = ZIR_REF_TYPE_TYPE,
|
||||
.src_node = 0,
|
||||
.ctx = RI_CTX_NONE };
|
||||
|
||||
// Find param name token by scanning backwards from firstToken of
|
||||
// type expression (mirrors FnProto.Iterator.next, Ast.zig:2687).
|
||||
// Layout: [comptime] [name] [:] type_expr
|
||||
// So: type_first_tok - 1 is ':', type_first_tok - 2 is name.
|
||||
uint32_t type_first_tok = firstToken(tree, param_type_node);
|
||||
uint32_t name_token = 0; // 0 = no name found
|
||||
while (true) {
|
||||
uint32_t name_token = 0;
|
||||
uint32_t comptime_noalias_token = 0;
|
||||
bool is_comptime_param = false;
|
||||
if (type_first_tok >= 2
|
||||
&& tree->tokens.tags[type_first_tok - 1] == TOKEN_COLON) {
|
||||
// Named parameter: name is at type_first_tok - 2.
|
||||
uint32_t maybe_name = type_first_tok - 2;
|
||||
uint32_t name_start = tree->tokens.starts[maybe_name];
|
||||
char ch = tree->source[name_start];
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
||||
|| ch == '_' || ch == '@') {
|
||||
// Could be name or comptime/noalias keyword.
|
||||
if (name_start + 8 <= tree->source_len
|
||||
&& memcmp(tree->source + name_start, "comptime", 8) == 0) {
|
||||
is_comptime_param = true;
|
||||
} else if (name_start + 7 <= tree->source_len
|
||||
&& memcmp(tree->source + name_start, "noalias", 7) == 0) {
|
||||
// noalias keyword, not a name.
|
||||
} else {
|
||||
name_token = maybe_name;
|
||||
// Check for preceding comptime keyword.
|
||||
if (maybe_name > 0) {
|
||||
uint32_t prev = maybe_name - 1;
|
||||
uint32_t prev_start = tree->tokens.starts[prev];
|
||||
if (prev_start + 8 <= tree->source_len
|
||||
&& memcmp(tree->source + prev_start, "comptime", 8)
|
||||
== 0)
|
||||
is_comptime_param = true;
|
||||
}
|
||||
bool is_anytype = false;
|
||||
uint32_t param_type_node = 0;
|
||||
|
||||
if (!iter_tok_flag) {
|
||||
// Return next param from params array.
|
||||
if (iter_param_i >= params_len)
|
||||
break;
|
||||
param_type_node = param_nodes[iter_param_i];
|
||||
// Scan backwards from type expression to find
|
||||
// name/comptime/noalias (Ast.zig:2698-2705).
|
||||
uint32_t tok_i = firstToken(tree, param_type_node);
|
||||
while (tok_i > 0) {
|
||||
tok_i--;
|
||||
uint32_t ttag = tree->tokens.tags[tok_i];
|
||||
if (ttag == TOKEN_COLON)
|
||||
continue;
|
||||
if (ttag == TOKEN_IDENTIFIER) {
|
||||
name_token = tok_i;
|
||||
continue;
|
||||
}
|
||||
if (ttag == TOKEN_KEYWORD_COMPTIME
|
||||
|| ttag == TOKEN_KEYWORD_NOALIAS) {
|
||||
comptime_noalias_token = tok_i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
iter_param_i++;
|
||||
iter_tok_i = lastToken(tree, param_type_node) + 1;
|
||||
// Skip comma after param for anytype scanning.
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_COMMA)
|
||||
iter_tok_i++;
|
||||
iter_tok_flag = true;
|
||||
} else {
|
||||
// Token-scanning mode: look for anytype/ellipsis params
|
||||
// (Ast.zig:2721-2767).
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_COMMA)
|
||||
iter_tok_i++;
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_R_PAREN)
|
||||
break;
|
||||
// Skip doc comments.
|
||||
while (tree->tokens.tags[iter_tok_i] == TOKEN_DOC_COMMENT)
|
||||
iter_tok_i++;
|
||||
// Check for ellipsis3 (varargs) - skip for now.
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_ELLIPSIS3)
|
||||
break;
|
||||
// Check for comptime/noalias prefix.
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_COMPTIME
|
||||
|| tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_NOALIAS) {
|
||||
comptime_noalias_token = iter_tok_i;
|
||||
iter_tok_i++;
|
||||
}
|
||||
// Check for name: identifier followed by colon.
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_IDENTIFIER
|
||||
&& tree->tokens.tags[iter_tok_i + 1] == TOKEN_COLON) {
|
||||
name_token = iter_tok_i;
|
||||
iter_tok_i += 2;
|
||||
}
|
||||
// Check for anytype keyword.
|
||||
if (tree->tokens.tags[iter_tok_i] == TOKEN_KEYWORD_ANYTYPE) {
|
||||
is_anytype = true;
|
||||
iter_tok_i++;
|
||||
} else {
|
||||
// Not an anytype param; switch to param-array mode.
|
||||
iter_tok_flag = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine is_comptime from comptime_noalias token
|
||||
// (AstGen.zig:4265-4273).
|
||||
if (comptime_noalias_token != 0
|
||||
&& tree->tokens.tags[comptime_noalias_token]
|
||||
== TOKEN_KEYWORD_COMPTIME) {
|
||||
is_comptime_param = true;
|
||||
}
|
||||
|
||||
// Determine param name string (AstGen.zig:4283-4321).
|
||||
@@ -8707,38 +8772,49 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate param type expression in a sub-block
|
||||
// (AstGen.zig:4333-4337).
|
||||
GenZir param_gz = makeSubBlock(&decl_gz, params_scope);
|
||||
uint32_t param_type_ref
|
||||
= expr(¶m_gz, params_scope, param_type_node);
|
||||
// Emit param instruction (AstGen.zig:4323-4345).
|
||||
uint32_t param_inst_ref;
|
||||
if (is_anytype) {
|
||||
// anytype parameter: emit param_anytype/param_anytype_comptime
|
||||
// (AstGen.zig:4323-4329).
|
||||
uint32_t anytype_name_token
|
||||
= name_token != 0 ? name_token : (iter_tok_i - 1);
|
||||
ZirInstTag anytype_tag = is_comptime_param
|
||||
? ZIR_INST_PARAM_ANYTYPE_COMPTIME
|
||||
: ZIR_INST_PARAM_ANYTYPE;
|
||||
uint32_t anytype_inst = addStrTok(
|
||||
&decl_gz, anytype_tag, param_name_str, anytype_name_token);
|
||||
param_inst_ref = anytype_inst + ZIR_REF_START_INDEX;
|
||||
if (param_insts_len < 32)
|
||||
param_insts[param_insts_len++] = anytype_inst;
|
||||
} else {
|
||||
// Type-expression parameter (AstGen.zig:4330-4344).
|
||||
GenZir param_gz = makeSubBlock(&decl_gz, params_scope);
|
||||
uint32_t param_type_ref = fullBodyExpr(
|
||||
¶m_gz, params_scope, coerced_type_ri, param_type_node);
|
||||
|
||||
if (ag->has_compile_errors)
|
||||
return;
|
||||
if (ag->has_compile_errors)
|
||||
return;
|
||||
|
||||
// The break_inline target is the param instruction we're about to
|
||||
// create (AstGen.zig:4336-4337).
|
||||
uint32_t param_inst_expected = ag->inst_len + 1;
|
||||
// +1 because: the break_inline is emitted first (uses inst_len),
|
||||
// then addParam emits the param instruction at inst_len.
|
||||
// Actually, addParam emits the param after break_inline. The
|
||||
// break_inline's block_inst field should point to the param inst.
|
||||
// We know it will be at ag->inst_len after the break_inline.
|
||||
makeBreakInline(¶m_gz, param_inst_expected, param_type_ref,
|
||||
(int32_t)param_type_node - (int32_t)param_gz.decl_node_index);
|
||||
// The break_inline target is the param instruction we're about
|
||||
// to create (AstGen.zig:4336-4337).
|
||||
uint32_t param_inst_expected = ag->inst_len + 1;
|
||||
makeBreakInline(¶m_gz, param_inst_expected, param_type_ref,
|
||||
(int32_t)param_type_node - (int32_t)param_gz.decl_node_index);
|
||||
|
||||
// Create param instruction (AstGen.zig:4341-4343).
|
||||
ZirInstTag param_tag
|
||||
= is_comptime_param ? ZIR_INST_PARAM_COMPTIME : ZIR_INST_PARAM;
|
||||
uint32_t name_tok_for_src = name_token != 0
|
||||
? name_token
|
||||
: tree->nodes.main_tokens[param_type_node];
|
||||
uint32_t param_inst = addParam(
|
||||
&decl_gz, ¶m_gz, param_tag, name_tok_for_src, param_name_str);
|
||||
(void)param_inst_expected;
|
||||
// Record param instruction index (AstGen.zig:4360).
|
||||
if (param_insts_len < 32)
|
||||
param_insts[param_insts_len++] = param_inst;
|
||||
// Create param instruction (AstGen.zig:4341-4343).
|
||||
ZirInstTag param_tag
|
||||
= is_comptime_param ? ZIR_INST_PARAM_COMPTIME : ZIR_INST_PARAM;
|
||||
uint32_t name_tok_for_src = name_token != 0
|
||||
? name_token
|
||||
: tree->nodes.main_tokens[param_type_node];
|
||||
uint32_t param_inst = addParam(&decl_gz, ¶m_gz, param_tag,
|
||||
name_tok_for_src, param_name_str);
|
||||
(void)param_inst_expected;
|
||||
param_inst_ref = param_inst + ZIR_REF_START_INDEX;
|
||||
if (param_insts_len < 32)
|
||||
param_insts[param_insts_len++] = param_inst;
|
||||
}
|
||||
|
||||
// Create ScopeLocalVal for this param (AstGen.zig:4349-4359).
|
||||
if (param_name_str != 0 && param_scope_count < 32) {
|
||||
@@ -8746,7 +8822,7 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
lv->base.tag = SCOPE_LOCAL_VAL;
|
||||
lv->parent = params_scope;
|
||||
lv->gen_zir = &decl_gz;
|
||||
lv->inst = param_inst + ZIR_REF_START_INDEX; // toRef()
|
||||
lv->inst = param_inst_ref;
|
||||
lv->token_src = name_token;
|
||||
lv->name = param_name_str;
|
||||
params_scope = &lv->base;
|
||||
@@ -8757,7 +8833,8 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
GenZir ret_gz = makeSubBlock(&decl_gz, params_scope);
|
||||
uint32_t ret_ref = ZIR_REF_NONE;
|
||||
if (return_type_node != 0) {
|
||||
ret_ref = expr(&ret_gz, params_scope, return_type_node);
|
||||
ret_ref = fullBodyExpr(
|
||||
&ret_gz, params_scope, coerced_type_ri, return_type_node);
|
||||
if (ag->has_compile_errors)
|
||||
return;
|
||||
// If ret_gz produced instructions, add break_inline
|
||||
@@ -8891,8 +8968,12 @@ static void fnDecl(AstGenCtx* ag, GenZir* gz, uint32_t* wip_decl_insts,
|
||||
&decl_gz, decl_inst, func_ref, (int32_t)node - (int32_t)proto_node);
|
||||
|
||||
// setDeclaration (AstGen.zig:4208-4225).
|
||||
DeclFlagsId decl_id
|
||||
= is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE;
|
||||
// Linkage: export > normal (AstGen.zig:4217).
|
||||
DeclFlagsId decl_id;
|
||||
if (is_export)
|
||||
decl_id = is_pub ? DECL_ID_PUB_EXPORT_CONST : DECL_ID_EXPORT_CONST;
|
||||
else
|
||||
decl_id = is_pub ? DECL_ID_PUB_CONST_SIMPLE : DECL_ID_CONST_SIMPLE;
|
||||
uint32_t name_str = identAsString(ag, fn_name_token);
|
||||
setDeclaration(ag, decl_inst,
|
||||
(SetDeclArgs) { .src_line = decl_line,
|
||||
|
||||
Reference in New Issue
Block a user