implement ?return
expression
This commit is contained in:
parent
6149f73189
commit
1f7ec741fa
33
doc/codegen.md
Normal file
33
doc/codegen.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Code Generation
|
||||||
|
|
||||||
|
## Data Representation
|
||||||
|
|
||||||
|
Every type has a "handle". If a type is a simple primitive type such as i32 or
|
||||||
|
f64, the handle is "by value", meaning that we pass around the value itself when
|
||||||
|
we refer to a value of that type.
|
||||||
|
|
||||||
|
If a type is a container, error union, maybe type, slice, or array, then its
|
||||||
|
handle is a pointer, and everywhere we refer to a value of this type we refer to
|
||||||
|
a pointer.
|
||||||
|
|
||||||
|
Parameters and return values are always passed as handles.
|
||||||
|
|
||||||
|
Error union types are represented as:
|
||||||
|
|
||||||
|
struct {
|
||||||
|
error: u32,
|
||||||
|
payload: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
Maybe types are represented as:
|
||||||
|
|
||||||
|
struct {
|
||||||
|
payload: T,
|
||||||
|
is_non_null: u1,
|
||||||
|
}
|
||||||
|
|
||||||
|
## Data Optimizations
|
||||||
|
|
||||||
|
Maybe pointer types are special: the 0x0 pointer value is used to represent a
|
||||||
|
null pointer. Thus, instead of the struct above, maybe pointer types are
|
||||||
|
represented as a `usize` in codegen and the handle is by value.
|
@ -6271,7 +6271,34 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ReturnKindMaybe:
|
case ReturnKindMaybe:
|
||||||
zig_panic("TODO");
|
{
|
||||||
|
TypeTableEntry *expected_maybe_type;
|
||||||
|
if (expected_type) {
|
||||||
|
expected_maybe_type = get_maybe_type(g, expected_type);
|
||||||
|
} else {
|
||||||
|
expected_maybe_type = nullptr;
|
||||||
|
}
|
||||||
|
TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type,
|
||||||
|
node->data.return_expr.expr);
|
||||||
|
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||||
|
return resolved_type;
|
||||||
|
} else if (resolved_type->id == TypeTableEntryIdMaybe) {
|
||||||
|
TypeTableEntry *return_type = context->fn_entry->type_entry->data.fn.fn_type_id.return_type;
|
||||||
|
if (return_type->id != TypeTableEntryIdMaybe) {
|
||||||
|
ErrorMsg *msg = add_node_error(g, node,
|
||||||
|
buf_sprintf("?return statement in function with return type '%s'",
|
||||||
|
buf_ptr(&return_type->name)));
|
||||||
|
AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type;
|
||||||
|
add_error_note(g, msg, return_type_node, buf_sprintf("function return type here"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved_type->data.maybe.child_type;
|
||||||
|
} else {
|
||||||
|
add_node_error(g, node->data.return_expr.expr,
|
||||||
|
buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name)));
|
||||||
|
return g->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
@ -2497,7 +2497,45 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case ReturnKindMaybe:
|
case ReturnKindMaybe:
|
||||||
zig_panic("TODO");
|
{
|
||||||
|
assert(value_type->id == TypeTableEntryIdMaybe);
|
||||||
|
TypeTableEntry *child_type = value_type->data.maybe.child_type;
|
||||||
|
|
||||||
|
LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn");
|
||||||
|
LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue");
|
||||||
|
|
||||||
|
set_debug_source_node(g, node);
|
||||||
|
LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
|
||||||
|
LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, "");
|
||||||
|
|
||||||
|
LLVMValueRef zero = LLVMConstNull(LLVMInt1Type());
|
||||||
|
LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, "");
|
||||||
|
LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
|
||||||
|
|
||||||
|
LLVMPositionBuilderAtEnd(g->builder, return_block);
|
||||||
|
TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
|
||||||
|
assert(return_type->id == TypeTableEntryIdMaybe);
|
||||||
|
if (handle_is_ptr(return_type)) {
|
||||||
|
assert(g->cur_ret_ptr);
|
||||||
|
|
||||||
|
set_debug_source_node(g, node);
|
||||||
|
LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, "");
|
||||||
|
LLVMBuildStore(g->builder, zero, maybe_bit_ptr);
|
||||||
|
LLVMBuildRetVoid(g->builder);
|
||||||
|
} else {
|
||||||
|
LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref);
|
||||||
|
gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMPositionBuilderAtEnd(g->builder, continue_block);
|
||||||
|
if (type_has_bits(child_type)) {
|
||||||
|
set_debug_source_node(g, node);
|
||||||
|
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
|
||||||
|
return get_handle_value(g, node, val_ptr, child_type);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ pub struct SmallList(inline T: type, inline STATIC_SIZE: usize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#attribute("test")
|
#attribute("test")
|
||||||
fn function_with_return_type_type() {
|
fn functionWithReturnTypeType() {
|
||||||
var list: List(i32) = undefined;
|
var list: List(i32) = undefined;
|
||||||
var list2: List(i32) = undefined;
|
var list2: List(i32) = undefined;
|
||||||
list.length = 10;
|
list.length = 10;
|
||||||
|
@ -6,6 +6,7 @@ const other = @import("other.zig");
|
|||||||
const test_return_type_type = @import("cases/return_type_type.zig");
|
const test_return_type_type = @import("cases/return_type_type.zig");
|
||||||
const test_zeroes = @import("cases/zeroes.zig");
|
const test_zeroes = @import("cases/zeroes.zig");
|
||||||
const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig");
|
const test_sizeof_and_typeof = @import("cases/sizeof_and_typeof.zig");
|
||||||
|
const test_maybe_return = @import("cases/maybe_return.zig");
|
||||||
|
|
||||||
// normal comment
|
// normal comment
|
||||||
/// this is a documentation comment
|
/// this is a documentation comment
|
||||||
|
Loading…
x
Reference in New Issue
Block a user