From 5bc70e2d64392441d182fc9c6e65d4ba5b92e4c2 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 24 Aug 2025 17:20:52 -0400 Subject: Rename promotion -> promotions --- src/compile.c | 2 +- src/compile/assignments.c | 2 +- src/compile/functions.c | 2 +- src/compile/integers.c | 2 +- src/compile/lists.c | 2 +- src/compile/pointers.c | 2 +- src/compile/promotion.c | 198 ---------------------------------------------- src/compile/promotion.h | 7 -- src/compile/promotions.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++ src/compile/promotions.h | 7 ++ src/compile/sets.c | 2 +- src/compile/statements.c | 2 +- src/compile/tables.c | 2 +- 13 files changed, 214 insertions(+), 214 deletions(-) delete mode 100644 src/compile/promotion.c delete mode 100644 src/compile/promotion.h create mode 100644 src/compile/promotions.c create mode 100644 src/compile/promotions.h diff --git a/src/compile.c b/src/compile.c index 2a33afb3..5a347e6d 100644 --- a/src/compile.c +++ b/src/compile.c @@ -13,7 +13,7 @@ #include "compile/lists.h" #include "compile/optionals.h" #include "compile/pointers.h" -#include "compile/promotion.h" +#include "compile/promotions.h" #include "compile/sets.h" #include "compile/statements.h" #include "compile/structs.h" diff --git a/src/compile/assignments.c b/src/compile/assignments.c index 83dbd287..0f4c8835 100644 --- a/src/compile/assignments.c +++ b/src/compile/assignments.c @@ -8,7 +8,7 @@ #include "../typecheck.h" #include "integers.h" #include "pointers.h" -#include "promotion.h" +#include "promotions.h" #include "types.h" public diff --git a/src/compile/functions.c b/src/compile/functions.c index cc6aba87..418705aa 100644 --- a/src/compile/functions.c +++ b/src/compile/functions.c @@ -14,7 +14,7 @@ #include "assignments.h" #include "blocks.h" #include "integers.h" -#include "promotion.h" +#include "promotions.h" #include "statements.h" #include "structs.h" #include "text.h" diff --git a/src/compile/integers.c b/src/compile/integers.c index 97c9c61a..fc615c3b 100644 --- a/src/compile/integers.c +++ b/src/compile/integers.c @@ -8,7 +8,7 @@ #include "../stdlib/text.h" #include "../typecheck.h" #include "../types.h" -#include "promotion.h" +#include "promotions.h" Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { if (ast->tag != Int) { diff --git a/src/compile/lists.c b/src/compile/lists.c index 9e9fa2fa..a7667634 100644 --- a/src/compile/lists.c +++ b/src/compile/lists.c @@ -15,7 +15,7 @@ #include "functions.h" #include "optionals.h" #include "pointers.h" -#include "promotion.h" +#include "promotions.h" #include "statements.h" #include "types.h" diff --git a/src/compile/pointers.c b/src/compile/pointers.c index 7efb5179..b9486899 100644 --- a/src/compile/pointers.c +++ b/src/compile/pointers.c @@ -11,7 +11,7 @@ #include "../stdlib/text.h" #include "../typecheck.h" #include "assignments.h" -#include "promotion.h" +#include "promotions.h" public Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) { diff --git a/src/compile/promotion.c b/src/compile/promotion.c deleted file mode 100644 index 30c8f69b..00000000 --- a/src/compile/promotion.c +++ /dev/null @@ -1,198 +0,0 @@ -#include "promotion.h" -#include "../ast.h" -#include "../compile.h" -#include "../environment.h" -#include "../stdlib/datatypes.h" -#include "../stdlib/text.h" -#include "../typecheck.h" -#include "../types.h" -#include "assignments.h" -#include "functions.h" -#include "integers.h" -#include "lists.h" -#include "optionals.h" -#include "pointers.h" -#include "sets.h" -#include "tables.h" -#include "types.h" - -static Text_t quoted_str(const char *str) { return Text$quoted(Text$from_str(str), false, Text("\"")); } - -public -bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed) { - if (type_eq(actual, needed)) return true; - - if (!can_promote(actual, needed)) return false; - - if (needed->tag == ClosureType && actual->tag == FunctionType) { - *code = Texts("((Closure_t){", *code, ", NULL})"); - return true; - } - - // Empty promotion: - type_t *more_complete = most_complete_type(actual, needed); - if (more_complete) return true; - - // Optional promotion: - if (needed->tag == OptionalType && type_eq(actual, Match(needed, OptionalType)->type)) { - *code = promote_to_optional(actual, *code); - return true; - } - - // Optional -> Bool promotion - if (actual->tag == OptionalType && needed->tag == BoolType) { - *code = Texts("(!", check_none(actual, *code), ")"); - return true; - } - - // Lang to Text_t: - if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text")) return true; - - // Automatic optional checking for nums: - if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) { - int64_t line = get_line_number(ast->file, ast->start); - *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ", "if unlikely (", - check_none(actual, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(", - quoted_str(ast->file->filename), ", ", String((int64_t)(ast->start - ast->file->text)), ", ", - String((int64_t)(ast->end - ast->file->text)), ", ", - "\"This was expected to be a value, but it's none\");\n", - optional_into_nonnone(actual, Text("opt")), "; })"); - return true; - } - - // Numeric promotions/demotions - if ((is_numeric_type(actual) || actual->tag == BoolType) && (is_numeric_type(needed) || needed->tag == BoolType)) { - arg_ast_t *args = new (arg_ast_t, .value = LiteralCode(*code, .type = actual)); - binding_t *constructor = get_constructor( - env, needed, args, env->current_type != NULL && type_eq(env->current_type, value_type(needed))); - if (constructor) { - DeclareMatch(fn, constructor->type, FunctionType); - if (fn->args->next == NULL) { - *code = Texts(constructor->code, "(", compile_arguments(env, ast, fn->args, args), ")"); - return true; - } - } - } - - if (needed->tag == EnumType) { - const char *tag = enum_single_value_tag(needed, actual); - binding_t *b = get_binding(Match(needed, EnumType)->env, tag); - assert(b && b->type->tag == FunctionType); - // Single-value enum constructor: - if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type)) return false; - *code = Texts(b->code, "(", *code, ")"); - return true; - } - - // Text_t to C String - if (actual->tag == TextType && type_eq(actual, TEXT_TYPE) && needed->tag == CStringType) { - *code = Texts("Text$as_c_string(", *code, ")"); - return true; - } - - // Automatic dereferencing: - if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed)) { - *code = Texts("*(", *code, ")"); - return promote(env, ast, code, Match(actual, PointerType)->pointed, needed); - } - - // Stack ref promotion: - if (actual->tag == PointerType && needed->tag == PointerType) return true; - - // Cross-promotion between tables with default values and without - if (needed->tag == TableType && actual->tag == TableType) return true; - - if (needed->tag == ClosureType && actual->tag == ClosureType) return true; - - if (needed->tag == FunctionType && actual->tag == FunctionType) { - *code = Texts("(", compile_type(needed), ")", *code); - return true; - } - - // Set -> List promotion: - if (needed->tag == ListType && actual->tag == SetType - && type_eq(Match(needed, ListType)->item_type, Match(actual, SetType)->item_type)) { - *code = Texts("(", *code, ").entries"); - return true; - } - - return false; -} - -public -Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) { - assert(!is_incomplete_type(t)); - if (ast->tag == Int && is_numeric_type(non_optional(t))) { - return compile_int_to_type(env, ast, t); - } else if (ast->tag == Num && t->tag == NumType) { - double n = Match(ast, Num)->n; - switch (Match(t, NumType)->bits) { - case TYPE_NBITS64: return Text$from_str(String(hex_double(n))); - case TYPE_NBITS32: return Text$from_str(String(hex_double(n), "f")); - default: code_err(ast, "This is not a valid number bit width"); - } - } else if (ast->tag == None) { - if (t->tag != OptionalType) code_err(ast, "This is not supposed to be an optional type"); - else if (Match(t, OptionalType)->type == NULL) - code_err(ast, "I don't know what kind of `none` this is supposed to " - "be!\nPlease " - "tell me by declaring a variable like `foo : Type = none`"); - return compile_none(t); - } else if (t->tag == PointerType && (ast->tag == HeapAllocate || ast->tag == StackReference)) { - return compile_typed_allocation(env, ast, t); - } else if (t->tag == ListType && ast->tag == List) { - return compile_typed_list(env, ast, t); - } else if (t->tag == TableType && ast->tag == Table) { - return compile_typed_table(env, ast, t); - } else if (t->tag == SetType && ast->tag == Set) { - return compile_typed_set(env, ast, t); - } - - type_t *actual = get_type(env, ast); - - // Edge case: there are some situations where a method call needs to have - // the `self` value get compiled to a specific type that can't be fully - // inferred from the expression itself. We can infer what the specific type - // should be from what we know the specific type of the return value is, - // but it requires a bit of special logic. - // For example: - // x : [Int?] = [none].sorted() - // Here, we know that `[none]` is `[Int?]`, but we need to thread that - // information through the compiler using an `ExplicitlyTyped` node. - if (ast->tag == MethodCall) { - DeclareMatch(methodcall, ast, MethodCall); - type_t *self_type = get_type(env, methodcall->self); - // Currently, this is only implemented for cases where you have the - // return type and the self type equal to each other, because that's the - // main case I care about with list and set methods (e.g. - // `List.sorted()`) - if (is_incomplete_type(self_type) && type_eq(self_type, actual)) { - type_t *completed_self = most_complete_type(self_type, t); - if (completed_self) { - ast_t *explicit_self = - WrapAST(methodcall->self, ExplicitlyTyped, .ast = methodcall->self, .type = completed_self); - ast_t *new_methodcall = - WrapAST(ast, MethodCall, .self = explicit_self, .name = methodcall->name, .args = methodcall->args); - return compile_to_type(env, new_methodcall, t); - } - } - } - - // Promote values to views-of-values if needed: - if (t->tag == PointerType && Match(t, PointerType)->is_stack && actual->tag != PointerType) - return Texts("stack(", compile_to_type(env, ast, Match(t, PointerType)->pointed), ")"); - - if (!is_incomplete_type(actual)) { - Text_t code = compile(env, ast); - if (promote(env, ast, &code, actual, t)) return code; - } - - arg_ast_t *constructor_args = new (arg_ast_t, .value = ast); - binding_t *constructor = get_constructor(env, t, constructor_args, true); - if (constructor) { - arg_t *arg_spec = Match(constructor->type, FunctionType)->args; - return Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, constructor_args), ")"); - } - - code_err(ast, "I expected a ", type_to_str(t), " here, but this is a ", type_to_str(actual)); -} diff --git a/src/compile/promotion.h b/src/compile/promotion.h deleted file mode 100644 index 2cfe0cbf..00000000 --- a/src/compile/promotion.h +++ /dev/null @@ -1,7 +0,0 @@ - -#include "../ast.h" -#include "../environment.h" -#include "../types.h" - -bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed); -Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t); diff --git a/src/compile/promotions.c b/src/compile/promotions.c new file mode 100644 index 00000000..febbbd1f --- /dev/null +++ b/src/compile/promotions.c @@ -0,0 +1,198 @@ +#include "promotions.h" +#include "../ast.h" +#include "../compile.h" +#include "../environment.h" +#include "../stdlib/datatypes.h" +#include "../stdlib/text.h" +#include "../typecheck.h" +#include "../types.h" +#include "assignments.h" +#include "functions.h" +#include "integers.h" +#include "lists.h" +#include "optionals.h" +#include "pointers.h" +#include "sets.h" +#include "tables.h" +#include "types.h" + +static Text_t quoted_str(const char *str) { return Text$quoted(Text$from_str(str), false, Text("\"")); } + +public +bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed) { + if (type_eq(actual, needed)) return true; + + if (!can_promote(actual, needed)) return false; + + if (needed->tag == ClosureType && actual->tag == FunctionType) { + *code = Texts("((Closure_t){", *code, ", NULL})"); + return true; + } + + // Empty promotion: + type_t *more_complete = most_complete_type(actual, needed); + if (more_complete) return true; + + // Optional promotion: + if (needed->tag == OptionalType && type_eq(actual, Match(needed, OptionalType)->type)) { + *code = promote_to_optional(actual, *code); + return true; + } + + // Optional -> Bool promotion + if (actual->tag == OptionalType && needed->tag == BoolType) { + *code = Texts("(!", check_none(actual, *code), ")"); + return true; + } + + // Lang to Text_t: + if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text")) return true; + + // Automatic optional checking for nums: + if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) { + int64_t line = get_line_number(ast->file, ast->start); + *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ", "if unlikely (", + check_none(actual, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(", + quoted_str(ast->file->filename), ", ", String((int64_t)(ast->start - ast->file->text)), ", ", + String((int64_t)(ast->end - ast->file->text)), ", ", + "\"This was expected to be a value, but it's none\");\n", + optional_into_nonnone(actual, Text("opt")), "; })"); + return true; + } + + // Numeric promotions/demotions + if ((is_numeric_type(actual) || actual->tag == BoolType) && (is_numeric_type(needed) || needed->tag == BoolType)) { + arg_ast_t *args = new (arg_ast_t, .value = LiteralCode(*code, .type = actual)); + binding_t *constructor = get_constructor( + env, needed, args, env->current_type != NULL && type_eq(env->current_type, value_type(needed))); + if (constructor) { + DeclareMatch(fn, constructor->type, FunctionType); + if (fn->args->next == NULL) { + *code = Texts(constructor->code, "(", compile_arguments(env, ast, fn->args, args), ")"); + return true; + } + } + } + + if (needed->tag == EnumType) { + const char *tag = enum_single_value_tag(needed, actual); + binding_t *b = get_binding(Match(needed, EnumType)->env, tag); + assert(b && b->type->tag == FunctionType); + // Single-value enum constructor: + if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type)) return false; + *code = Texts(b->code, "(", *code, ")"); + return true; + } + + // Text_t to C String + if (actual->tag == TextType && type_eq(actual, TEXT_TYPE) && needed->tag == CStringType) { + *code = Texts("Text$as_c_string(", *code, ")"); + return true; + } + + // Automatic dereferencing: + if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed)) { + *code = Texts("*(", *code, ")"); + return promote(env, ast, code, Match(actual, PointerType)->pointed, needed); + } + + // Stack ref promotion: + if (actual->tag == PointerType && needed->tag == PointerType) return true; + + // Cross-promotion between tables with default values and without + if (needed->tag == TableType && actual->tag == TableType) return true; + + if (needed->tag == ClosureType && actual->tag == ClosureType) return true; + + if (needed->tag == FunctionType && actual->tag == FunctionType) { + *code = Texts("(", compile_type(needed), ")", *code); + return true; + } + + // Set -> List promotion: + if (needed->tag == ListType && actual->tag == SetType + && type_eq(Match(needed, ListType)->item_type, Match(actual, SetType)->item_type)) { + *code = Texts("(", *code, ").entries"); + return true; + } + + return false; +} + +public +Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) { + assert(!is_incomplete_type(t)); + if (ast->tag == Int && is_numeric_type(non_optional(t))) { + return compile_int_to_type(env, ast, t); + } else if (ast->tag == Num && t->tag == NumType) { + double n = Match(ast, Num)->n; + switch (Match(t, NumType)->bits) { + case TYPE_NBITS64: return Text$from_str(String(hex_double(n))); + case TYPE_NBITS32: return Text$from_str(String(hex_double(n), "f")); + default: code_err(ast, "This is not a valid number bit width"); + } + } else if (ast->tag == None) { + if (t->tag != OptionalType) code_err(ast, "This is not supposed to be an optional type"); + else if (Match(t, OptionalType)->type == NULL) + code_err(ast, "I don't know what kind of `none` this is supposed to " + "be!\nPlease " + "tell me by declaring a variable like `foo : Type = none`"); + return compile_none(t); + } else if (t->tag == PointerType && (ast->tag == HeapAllocate || ast->tag == StackReference)) { + return compile_typed_allocation(env, ast, t); + } else if (t->tag == ListType && ast->tag == List) { + return compile_typed_list(env, ast, t); + } else if (t->tag == TableType && ast->tag == Table) { + return compile_typed_table(env, ast, t); + } else if (t->tag == SetType && ast->tag == Set) { + return compile_typed_set(env, ast, t); + } + + type_t *actual = get_type(env, ast); + + // Edge case: there are some situations where a method call needs to have + // the `self` value get compiled to a specific type that can't be fully + // inferred from the expression itself. We can infer what the specific type + // should be from what we know the specific type of the return value is, + // but it requires a bit of special logic. + // For example: + // x : [Int?] = [none].sorted() + // Here, we know that `[none]` is `[Int?]`, but we need to thread that + // information through the compiler using an `ExplicitlyTyped` node. + if (ast->tag == MethodCall) { + DeclareMatch(methodcall, ast, MethodCall); + type_t *self_type = get_type(env, methodcall->self); + // Currently, this is only implemented for cases where you have the + // return type and the self type equal to each other, because that's the + // main case I care about with list and set methods (e.g. + // `List.sorted()`) + if (is_incomplete_type(self_type) && type_eq(self_type, actual)) { + type_t *completed_self = most_complete_type(self_type, t); + if (completed_self) { + ast_t *explicit_self = + WrapAST(methodcall->self, ExplicitlyTyped, .ast = methodcall->self, .type = completed_self); + ast_t *new_methodcall = + WrapAST(ast, MethodCall, .self = explicit_self, .name = methodcall->name, .args = methodcall->args); + return compile_to_type(env, new_methodcall, t); + } + } + } + + // Promote values to views-of-values if needed: + if (t->tag == PointerType && Match(t, PointerType)->is_stack && actual->tag != PointerType) + return Texts("stack(", compile_to_type(env, ast, Match(t, PointerType)->pointed), ")"); + + if (!is_incomplete_type(actual)) { + Text_t code = compile(env, ast); + if (promote(env, ast, &code, actual, t)) return code; + } + + arg_ast_t *constructor_args = new (arg_ast_t, .value = ast); + binding_t *constructor = get_constructor(env, t, constructor_args, true); + if (constructor) { + arg_t *arg_spec = Match(constructor->type, FunctionType)->args; + return Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, constructor_args), ")"); + } + + code_err(ast, "I expected a ", type_to_str(t), " here, but this is a ", type_to_str(actual)); +} diff --git a/src/compile/promotions.h b/src/compile/promotions.h new file mode 100644 index 00000000..2cfe0cbf --- /dev/null +++ b/src/compile/promotions.h @@ -0,0 +1,7 @@ + +#include "../ast.h" +#include "../environment.h" +#include "../types.h" + +bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed); +Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t); diff --git a/src/compile/sets.c b/src/compile/sets.c index 2abd4a08..bfa21db7 100644 --- a/src/compile/sets.c +++ b/src/compile/sets.c @@ -9,7 +9,7 @@ #include "functions.h" #include "optionals.h" #include "pointers.h" -#include "promotion.h" +#include "promotions.h" #include "statements.h" #include "types.h" diff --git a/src/compile/statements.c b/src/compile/statements.c index 8dcac48c..30972a9b 100644 --- a/src/compile/statements.c +++ b/src/compile/statements.c @@ -18,7 +18,7 @@ #include "functions.h" #include "optionals.h" #include "pointers.h" -#include "promotion.h" +#include "promotions.h" #include "statements.h" #include "text.h" #include "types.h" diff --git a/src/compile/tables.c b/src/compile/tables.c index c9feca5e..c99ac1b1 100644 --- a/src/compile/tables.c +++ b/src/compile/tables.c @@ -9,7 +9,7 @@ #include "functions.h" #include "optionals.h" #include "pointers.h" -#include "promotion.h" +#include "promotions.h" #include "statements.h" #include "types.h" -- cgit v1.2.3