mirror of
https://github.com/ziglang/zig.git
synced 2025-12-16 11:13:08 +00:00
IR: error for returning from defer expression
also fix peer type resolution for pure error mixed with error union
This commit is contained in:
parent
dc26dec8e0
commit
a9acc8cb45
@ -344,7 +344,7 @@ struct AstNodeDefer {
|
|||||||
|
|
||||||
// temporary data used in IR generation
|
// temporary data used in IR generation
|
||||||
Scope *child_scope;
|
Scope *child_scope;
|
||||||
Scope *parent_scope;
|
Scope *expr_scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeVariableDeclaration {
|
struct AstNodeVariableDeclaration {
|
||||||
@ -1280,6 +1280,7 @@ enum ScopeId {
|
|||||||
ScopeIdDecls,
|
ScopeIdDecls,
|
||||||
ScopeIdBlock,
|
ScopeIdBlock,
|
||||||
ScopeIdDefer,
|
ScopeIdDefer,
|
||||||
|
ScopeIdDeferExpr,
|
||||||
ScopeIdVarDecl,
|
ScopeIdVarDecl,
|
||||||
ScopeIdCImport,
|
ScopeIdCImport,
|
||||||
ScopeIdLoop,
|
ScopeIdLoop,
|
||||||
@ -1321,11 +1322,21 @@ struct ScopeBlock {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// This scope is created from every defer expression.
|
// This scope is created from every defer expression.
|
||||||
|
// It's the code following the defer statement.
|
||||||
// NodeTypeDefer
|
// NodeTypeDefer
|
||||||
struct ScopeDefer {
|
struct ScopeDefer {
|
||||||
Scope base;
|
Scope base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This scope is created from every defer expression.
|
||||||
|
// It's the parent of the defer expression itself.
|
||||||
|
// NodeTypeDefer
|
||||||
|
struct ScopeDeferExpr {
|
||||||
|
Scope base;
|
||||||
|
|
||||||
|
bool reported_err;
|
||||||
|
};
|
||||||
|
|
||||||
// This scope is created for every variable declaration inside an IrExecutable
|
// This scope is created for every variable declaration inside an IrExecutable
|
||||||
// NodeTypeVariableDeclaration, NodeTypeParamDecl
|
// NodeTypeVariableDeclaration, NodeTypeParamDecl
|
||||||
struct ScopeVarDecl {
|
struct ScopeVarDecl {
|
||||||
|
|||||||
@ -163,6 +163,13 @@ ScopeDefer *create_defer_scope(AstNode *node, Scope *parent) {
|
|||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopeDeferExpr *create_defer_expr_scope(AstNode *node, Scope *parent) {
|
||||||
|
assert(node->type == NodeTypeDefer);
|
||||||
|
ScopeDeferExpr *scope = allocate<ScopeDeferExpr>(1);
|
||||||
|
init_scope(&scope->base, ScopeIdDeferExpr, node, parent);
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
|
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
|
||||||
ScopeVarDecl *scope = allocate<ScopeVarDecl>(1);
|
ScopeVarDecl *scope = allocate<ScopeVarDecl>(1);
|
||||||
init_scope(&scope->base, ScopeIdVarDecl, node, parent);
|
init_scope(&scope->base, ScopeIdVarDecl, node, parent);
|
||||||
@ -2183,6 +2190,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
case ScopeIdDecls:
|
case ScopeIdDecls:
|
||||||
case ScopeIdDefer:
|
case ScopeIdDefer:
|
||||||
|
case ScopeIdDeferExpr:
|
||||||
case ScopeIdVarDecl:
|
case ScopeIdVarDecl:
|
||||||
case ScopeIdCImport:
|
case ScopeIdCImport:
|
||||||
case ScopeIdLoop:
|
case ScopeIdLoop:
|
||||||
|
|||||||
@ -84,6 +84,7 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *
|
|||||||
|
|
||||||
ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
|
ScopeBlock *create_block_scope(AstNode *node, Scope *parent);
|
||||||
ScopeDefer *create_defer_scope(AstNode *node, Scope *parent);
|
ScopeDefer *create_defer_scope(AstNode *node, Scope *parent);
|
||||||
|
ScopeDeferExpr *create_defer_expr_scope(AstNode *node, Scope *parent);
|
||||||
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
|
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
|
||||||
ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent);
|
ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent);
|
||||||
Scope *create_loop_scope(AstNode *node, Scope *parent);
|
Scope *create_loop_scope(AstNode *node, Scope *parent);
|
||||||
|
|||||||
@ -325,6 +325,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
|
|||||||
scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
|
scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
|
||||||
return scope->di_scope;
|
return scope->di_scope;
|
||||||
}
|
}
|
||||||
|
case ScopeIdDeferExpr:
|
||||||
|
return get_di_scope(g, scope->parent);
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/ir.cpp
38
src/ir.cpp
@ -1980,7 +1980,7 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
|
|||||||
(gen_maybe_defers && defer_kind == ReturnKindMaybe))
|
(gen_maybe_defers && defer_kind == ReturnKindMaybe))
|
||||||
{
|
{
|
||||||
AstNode *defer_expr_node = defer_node->data.defer.expr;
|
AstNode *defer_expr_node = defer_node->data.defer.expr;
|
||||||
ir_gen_node(irb, defer_expr_node, defer_node->data.defer.parent_scope);
|
ir_gen_node(irb, defer_expr_node, defer_node->data.defer.expr_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1994,6 +1994,18 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
|
|||||||
irb->current_basic_block = basic_block;
|
irb->current_basic_block = basic_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
|
||||||
|
while (scope) {
|
||||||
|
if (scope->id == ScopeIdDeferExpr)
|
||||||
|
return (ScopeDeferExpr *)scope;
|
||||||
|
if (scope->id == ScopeIdFnDef)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
scope = scope->parent;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
|
static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
|
||||||
assert(node->type == NodeTypeReturnExpr);
|
assert(node->type == NodeTypeReturnExpr);
|
||||||
|
|
||||||
@ -2003,6 +2015,15 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
|
|||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope);
|
||||||
|
if (scope_defer_expr) {
|
||||||
|
if (!scope_defer_expr->reported_err) {
|
||||||
|
add_node_error(irb->codegen, node, buf_sprintf("cannot return from defer expression"));
|
||||||
|
scope_defer_expr->reported_err = true;
|
||||||
|
}
|
||||||
|
return irb->codegen->invalid_instruction;
|
||||||
|
}
|
||||||
|
|
||||||
Scope *outer_scope = fn_entry->child_scope;
|
Scope *outer_scope = fn_entry->child_scope;
|
||||||
|
|
||||||
AstNode *expr_node = node->data.return_expr.expr;
|
AstNode *expr_node = node->data.return_expr.expr;
|
||||||
@ -2593,6 +2614,8 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
|
|||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO put a variable of same name with invalid type in global scope
|
||||||
|
// so that future references to this same name will find a variable with an invalid type
|
||||||
add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
|
add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
|
||||||
return irb->codegen->invalid_instruction;
|
return irb->codegen->invalid_instruction;
|
||||||
}
|
}
|
||||||
@ -4012,9 +4035,11 @@ static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *n
|
|||||||
static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
|
static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
|
||||||
assert(node->type == NodeTypeDefer);
|
assert(node->type == NodeTypeDefer);
|
||||||
|
|
||||||
ScopeDefer *defer_scope = create_defer_scope(node, parent_scope);
|
ScopeDefer *defer_child_scope = create_defer_scope(node, parent_scope);
|
||||||
node->data.defer.child_scope = &defer_scope->base;
|
node->data.defer.child_scope = &defer_child_scope->base;
|
||||||
node->data.defer.parent_scope = parent_scope;
|
|
||||||
|
ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(node, parent_scope);
|
||||||
|
node->data.defer.expr_scope = &defer_expr_scope->base;
|
||||||
|
|
||||||
return ir_build_const_void(irb, parent_scope, node);
|
return ir_build_const_void(irb, parent_scope, node);
|
||||||
}
|
}
|
||||||
@ -4665,6 +4690,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||||||
ir_add_error_node(ira, source_node,
|
ir_add_error_node(ira, source_node,
|
||||||
buf_sprintf("unable to make error union out of null literal"));
|
buf_sprintf("unable to make error union out of null literal"));
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
} else if (prev_inst->value.type->id == TypeTableEntryIdErrorUnion) {
|
||||||
|
return prev_inst->value.type;
|
||||||
} else {
|
} else {
|
||||||
return get_error_type(ira->codegen, prev_inst->value.type);
|
return get_error_type(ira->codegen, prev_inst->value.type);
|
||||||
}
|
}
|
||||||
@ -4675,6 +4702,8 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
|
|||||||
ir_add_error_node(ira, source_node,
|
ir_add_error_node(ira, source_node,
|
||||||
buf_sprintf("unable to make maybe out of number literal"));
|
buf_sprintf("unable to make maybe out of number literal"));
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
} else if (prev_inst->value.type->id == TypeTableEntryIdMaybe) {
|
||||||
|
return prev_inst->value.type;
|
||||||
} else {
|
} else {
|
||||||
return get_maybe_type(ira->codegen, prev_inst->value.type);
|
return get_maybe_type(ira->codegen, prev_inst->value.type);
|
||||||
}
|
}
|
||||||
@ -9955,6 +9984,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
|
|||||||
static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
|
static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
|
||||||
IrInstructionUnwrapErrPayload *instruction)
|
IrInstructionUnwrapErrPayload *instruction)
|
||||||
{
|
{
|
||||||
|
assert(instruction->value->other);
|
||||||
IrInstruction *value = instruction->value->other;
|
IrInstruction *value = instruction->value->other;
|
||||||
if (value->value.type->id == TypeTableEntryIdInvalid)
|
if (value->value.type->id == TypeTableEntryIdInvalid)
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user