| ... | @@ -3280,7 +3280,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -3280,7 +3280,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3280 | } | 3280 | } |
| 3281 | | 3281 | |
| 3282 | static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, | 3282 | static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, |
| 3283 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) | 3283 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime, |
| | 3284 | bool skip_name_check) |
| 3284 | { | 3285 | { |
| 3285 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); | 3286 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 3286 | variable_entry->parent_scope = parent_scope; | 3287 | variable_entry->parent_scope = parent_scope; |
| ... | @@ -3293,29 +3294,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco | ... | @@ -3293,29 +3294,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco |
| 3293 | if (name) { | 3294 | if (name) { |
| 3294 | buf_init_from_buf(&variable_entry->name, name); | 3295 | buf_init_from_buf(&variable_entry->name, name); |
| 3295 | | 3296 | |
| 3296 | VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name); | 3297 | if (!skip_name_check) { |
| 3297 | if (existing_var && !existing_var->shadowable) { | 3298 | VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name); |
| 3298 | ErrorMsg *msg = add_node_error(codegen, node, | 3299 | if (existing_var && !existing_var->shadowable) { |
| 3299 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | 3300 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3300 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); | 3301 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| 3301 | variable_entry->value->type = codegen->builtin_types.entry_invalid; | 3302 | add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); |
| 3302 | } else { | | |
| 3303 | TypeTableEntry *type = get_primitive_type(codegen, name); | | |
| 3304 | if (type != nullptr) { | | |
| 3305 | add_node_error(codegen, node, | | |
| 3306 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); | | |
| 3307 | variable_entry->value->type = codegen->builtin_types.entry_invalid; | 3303 | variable_entry->value->type = codegen->builtin_types.entry_invalid; |
| 3308 | } else { | 3304 | } else { |
| 3309 | Tld *tld = find_decl(codegen, parent_scope, name); | 3305 | TypeTableEntry *type = get_primitive_type(codegen, name); |
| 3310 | if (tld != nullptr) { | 3306 | if (type != nullptr) { |
| 3311 | ErrorMsg *msg = add_node_error(codegen, node, | 3307 | add_node_error(codegen, node, |
| 3312 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | 3308 | buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); |
| 3313 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); | | |
| 3314 | variable_entry->value->type = codegen->builtin_types.entry_invalid; | 3309 | variable_entry->value->type = codegen->builtin_types.entry_invalid; |
| | 3310 | } else { |
| | 3311 | Tld *tld = find_decl(codegen, parent_scope, name); |
| | 3312 | if (tld != nullptr) { |
| | 3313 | ErrorMsg *msg = add_node_error(codegen, node, |
| | 3314 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); |
| | 3315 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); |
| | 3316 | variable_entry->value->type = codegen->builtin_types.entry_invalid; |
| | 3317 | } |
| 3315 | } | 3318 | } |
| 3316 | } | 3319 | } |
| 3317 | } | 3320 | } |
| 3318 | | | |
| 3319 | } else { | 3321 | } else { |
| 3320 | assert(is_shadowable); | 3322 | assert(is_shadowable); |
| 3321 | // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" | 3323 | // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" |
| ... | @@ -3338,14 +3340,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s | ... | @@ -3338,14 +3340,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s |
| 3338 | bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) | 3340 | bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) |
| 3339 | { | 3341 | { |
| 3340 | bool is_underscored = name ? buf_eql_str(name, "_") : false; | 3342 | bool is_underscored = name ? buf_eql_str(name, "_") : false; |
| 3341 | VariableTableEntry *var = create_local_var( irb->codegen | 3343 | VariableTableEntry *var = create_local_var(irb->codegen, node, scope, |
| 3342 | , node | 3344 | (is_underscored ? nullptr : name), src_is_const, gen_is_const, |
| 3343 | , scope | 3345 | (is_underscored ? true : is_shadowable), is_comptime, false); |
| 3344 | , (is_underscored ? nullptr : name) | | |
| 3345 | , src_is_const | | |
| 3346 | , gen_is_const | | |
| 3347 | , (is_underscored ? true : is_shadowable) | | |
| 3348 | , is_comptime ); | | |
| 3349 | if (is_comptime != nullptr || gen_is_const) { | 3346 | if (is_comptime != nullptr || gen_is_const) { |
| 3350 | var->mem_slot_index = exec_next_mem_slot(irb->exec); | 3347 | var->mem_slot_index = exec_next_mem_slot(irb->exec); |
| 3351 | var->owner_exec = irb->exec; | 3348 | var->owner_exec = irb->exec; |
| ... | @@ -12495,6 +12492,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc | ... | @@ -12495,6 +12492,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 12495 | } | 12492 | } |
| 12496 | } | 12493 | } |
| 12497 | | 12494 | |
| | 12495 | if (var->value->type != nullptr && var->value->type != result_type && !is_comptime_var) { |
| | 12496 | // This is at least the second time we've seen this variable declaration during analysis. |
| | 12497 | // This means that this is actually a different variable due to, e.g. an inline while loop. |
| | 12498 | // We make a new variable so that it can hold a different type, and so the debug info can |
| | 12499 | // be distinct. |
| | 12500 | VariableTableEntry *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope, |
| | 12501 | &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true); |
| | 12502 | var->next_var = new_var; |
| | 12503 | var = new_var; |
| | 12504 | } |
| | 12505 | |
| 12498 | var->value->type = result_type; | 12506 | var->value->type = result_type; |
| 12499 | assert(var->value->type); | 12507 | assert(var->value->type); |
| 12500 | | 12508 | |
| ... | @@ -12977,6 +12985,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -12977,6 +12985,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 12977 | VariableTableEntry *var) | 12985 | VariableTableEntry *var) |
| 12978 | { | 12986 | { |
| 12979 | Error err; | 12987 | Error err; |
| | 12988 | while (var->next_var != nullptr) { |
| | 12989 | var = var->next_var; |
| | 12990 | } |
| | 12991 | |
| 12980 | if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) { | 12992 | if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) { |
| 12981 | assert(ira->codegen->errors.length != 0); | 12993 | assert(ira->codegen->errors.length != 0); |
| 12982 | return ira->codegen->invalid_instruction; | 12994 | return ira->codegen->invalid_instruction; |