fix: for循环变量作用域 + 列表推导crash (两个已知bug)
Bug 1 - For循环变量作用域: - AST_BLOCK 在 sema 中未创建子作用域 → 连续 for 循环用同名变量报"重复定义" - 修复: sema AST_BLOCK 创建 block_scope (scope_new) - 修复: codegen AST_BLOCK 保存/恢复 var_table 实现块级变量隔离 Bug 2 - 列表推导 >2元素 crash: - sema 对 TYPE_ARRAY 标注跳过 init 分析 → 列表推导表达式未被semantize - 导致 codegen 处 element_type=0, array_size=0 → LLVM alloca 崩溃 - 修复: 仅自引用 (= 变量名) 跳过分析,列表推导等正常分析 - 修复: cg_list_comp 使用 to_llvm_type(elem) 而非 type_info_to_llvm(full_array) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -476,8 +476,9 @@ static AstDispatch cg_dispatch;
|
||||
|
||||
static LLVMValueRef cg_list_comp_impl(CgCtx* ctx, AstNode* node) {
|
||||
TypeInfo* ti = &node->type;
|
||||
LLVMTypeRef elem_ty = type_info_to_llvm(ctx, ti);
|
||||
LLVMTypeRef arr_ty = LLVMArrayType(elem_ty, (unsigned)ti->array_size);
|
||||
LLVMTypeRef elem_ty = to_llvm_type(ctx, ti->element_type);
|
||||
LLVMTypeRef arr_ty = LLVMArrayType(elem_ty,
|
||||
ti->array_size > 0 ? (unsigned)ti->array_size : 1);
|
||||
LLVMValueRef result = LLVMBuildAlloca(ctx->builder, arr_ty, "list");
|
||||
// 初始化为零
|
||||
LLVMBuildStore(ctx->builder, LLVMConstNull(arr_ty), result);
|
||||
|
||||
@@ -205,10 +205,12 @@ void codegen_stmt(CgCtx* ctx, AstNode* node) {
|
||||
case AST_BLOCK: {
|
||||
if (++codegen_depth > MAX_CODEGEN_DEPTH) { codegen_depth--; return; }
|
||||
size_t block_mark = ctx->cleanup_count;
|
||||
VarEntry* saved_table = ctx->var_table;
|
||||
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
||||
codegen_stmt(ctx, node->as.block.stmts[i]);
|
||||
}
|
||||
cleanup_emit(ctx, block_mark); // 作用域退出: 释放块内 str 堆分配
|
||||
ctx->var_table = saved_table;
|
||||
cleanup_emit(ctx, block_mark);
|
||||
codegen_depth--;
|
||||
break;
|
||||
}
|
||||
|
||||
+9
-3
@@ -223,9 +223,10 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_BLOCK:
|
||||
case AST_BLOCK: {
|
||||
Scope* block_scope = scope_new(a, scope);
|
||||
for (size_t i = 0; i < node->as.block.stmt_count; i++) {
|
||||
analyze_node(node->as.block.stmts[i], scope, errors, a);
|
||||
analyze_node(node->as.block.stmts[i], block_scope, errors, a);
|
||||
}
|
||||
// 表达式作为值: 块类型 = 最后一条产生值的语句类型
|
||||
if (node->as.block.stmt_count > 0) {
|
||||
@@ -245,6 +246,7 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AST_LET_STMT: {
|
||||
TypeKind var_type;
|
||||
@@ -253,9 +255,13 @@ void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) {
|
||||
|
||||
if (node->as.let_stmt.has_type_annot) {
|
||||
if (node->as.let_stmt.annot_type == TYPE_ARRAY) {
|
||||
// 数组类型标注: 跳过 init 分析 (init 是自引用的占位符)
|
||||
is_array_type = true;
|
||||
var_type = TYPE_ARRAY;
|
||||
// 分析 init — 除非是自引用 (如 let a: i64[3] = a;)
|
||||
bool self_ref = (node->as.let_stmt.init->kind == AST_IDENT_EXPR
|
||||
&& strcmp(node->as.let_stmt.init->as.ident.name,
|
||||
node->as.let_stmt.name) == 0);
|
||||
if (!self_ref) analyze_expr(node->as.let_stmt.init, scope, errors, a);
|
||||
} else {
|
||||
analyze_expr(node->as.let_stmt.init, scope, errors, a);
|
||||
TypeKind inferred = node->as.let_stmt.init->type.kind;
|
||||
|
||||
Reference in New Issue
Block a user