From: Brendan Hansen Date: Sat, 11 Mar 2023 03:25:36 +0000 (-0600) Subject: added: implicit conversion to optional where appropriate X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=afe53134c834bcb09472ebc0b998108465717397;p=onyx.git added: implicit conversion to optional where appropriate --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 778dd0a2..19722988 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1783,19 +1783,20 @@ TypeMatch implicit_cast_to_bool(AstTyped **pnode); AstNode* strip_aliases(AstNode* node); -AstNumLit* make_bool_literal(bh_allocator, b32 b); -AstNumLit* make_int_literal(bh_allocator a, i64 value); -AstNumLit* make_float_literal(bh_allocator a, f64 value); -AstRangeLiteral* make_range_literal(bh_allocator a, AstTyped* low, AstTyped* high); -AstBinaryOp* make_binary_op(bh_allocator a, BinaryOp operation, AstTyped* left, AstTyped* right); -AstArgument* make_argument(bh_allocator a, AstTyped* value); -AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field); -AstAddressOf* make_address_of(bh_allocator a, AstTyped* node); -AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node); -AstLocal* make_local_with_type(bh_allocator a, OnyxToken* token, Type* type); -AstNode* make_symbol(bh_allocator a, OnyxToken* sym); -AstUnaryOp* make_cast(bh_allocator a, AstTyped* expr, Type* to); -AstZeroValue* make_zero_value(bh_allocator a, OnyxToken *token, Type* type); +AstNumLit* make_bool_literal(bh_allocator, b32 b); +AstNumLit* make_int_literal(bh_allocator a, i64 value); +AstNumLit* make_float_literal(bh_allocator a, f64 value); +AstRangeLiteral* make_range_literal(bh_allocator a, AstTyped* low, AstTyped* high); +AstBinaryOp* make_binary_op(bh_allocator a, BinaryOp operation, AstTyped* left, AstTyped* right); +AstArgument* make_argument(bh_allocator a, AstTyped* value); +AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field); +AstAddressOf* make_address_of(bh_allocator a, AstTyped* node); +AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node); +AstLocal* make_local_with_type(bh_allocator a, OnyxToken* token, Type* type); +AstNode* make_symbol(bh_allocator a, OnyxToken* sym); +AstUnaryOp* make_cast(bh_allocator a, AstTyped* expr, Type* to); +AstZeroValue* make_zero_value(bh_allocator a, OnyxToken *token, Type* type); +AstStructLiteral* make_optional_literal_some(bh_allocator a, AstTyped *expr, Type* opt_type); void arguments_initialize(Arguments* args); b32 fill_in_arguments(Arguments* args, AstNode* provider, char** err_msg, b32 insert_zero_values); diff --git a/compiler/src/astnodes.c b/compiler/src/astnodes.c index 8cc2e2cc..38f01ce5 100644 --- a/compiler/src/astnodes.c +++ b/compiler/src/astnodes.c @@ -751,6 +751,20 @@ TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) { return legal ? TYPE_MATCH_SUCCESS : TYPE_MATCH_FAILED; } + // If the destination type is an optional, and the node's type is a value of + // the same underlying type, then we can construct an optional with a value + // implicitly. This makes working with optionals barable. + else if (type_struct_constructed_from_poly_struct(type, builtin_optional_type)) { + TypeMatch match = unify_node_and_type_(pnode, type->Struct.poly_sln[0].type, permanent); + if (match != TYPE_MATCH_SUCCESS) return match; + + AstStructLiteral *opt_lit = make_optional_literal_some(context.ast_alloc, node, type); + + *(AstStructLiteral **) pnode = opt_lit; + return TYPE_MATCH_SUCCESS; + } + + // If the node is a numeric literal, try to convert it to the destination type. else if (node->kind == Ast_Kind_NumLit) { if (convert_numlit_to_type((AstNumLit *) node, type)) return TYPE_MATCH_SUCCESS; @@ -1430,6 +1444,7 @@ AstNumLit* make_bool_literal(bh_allocator a, b32 b) { AstNumLit* bl = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit); bl->flags |= Ast_Flag_Comptime; bl->type_node = (AstType *) &basic_type_bool; + bl->type = &basic_types[Basic_Kind_Bool]; bl->value.i = b ? 1 : 0; return bl; @@ -1539,6 +1554,21 @@ AstZeroValue* make_zero_value(bh_allocator a, OnyxToken* token, Type* type) { return zero_value; } +AstStructLiteral* make_optional_literal_some(bh_allocator a, AstTyped *expr, Type *opt_type) { + AstStructLiteral *opt_lit = onyx_ast_node_new(a, sizeof(AstStructLiteral), Ast_Kind_Struct_Literal); + opt_lit->token = expr->token; + + arguments_initialize(&opt_lit->args); + arguments_ensure_length(&opt_lit->args, 2); + opt_lit->args.values[0] = make_bool_literal(a, 1); + opt_lit->args.values[1] = expr; + + opt_lit->type = opt_type; + return opt_lit; +} + + + void arguments_initialize(Arguments* args) { if (args->values == NULL) bh_arr_new(global_heap_allocator, args->values, 2); if (args->named_values == NULL) bh_arr_new(global_heap_allocator, args->named_values, 2); diff --git a/tests/first_class_optional b/tests/first_class_optional new file mode 100644 index 00000000..ec6955c6 --- /dev/null +++ b/tests/first_class_optional @@ -0,0 +1,6 @@ +0 +30 +None +Some(40) +Some(0) +Some(60) diff --git a/tests/first_class_optional.onyx b/tests/first_class_optional.onyx new file mode 100644 index 00000000..1fc21d4d --- /dev/null +++ b/tests/first_class_optional.onyx @@ -0,0 +1,20 @@ +use core + +foo :: (x: ?i32) -> i32 { + return x? + 10; +} + +bar :: (x: ?i32) -> ?i32 { + return x? * 2; +} + +main :: () { + println(foo(.{})); + println(foo(20)); + + println(bar(.{})); + println(bar(20)); + + println(bar(foo(.{}))); + println(bar(foo(20))); +} \ No newline at end of file