From f5612e38183dc20d18f207f8ab055574a4d93ad0 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 21 Sep 2025 15:14:37 -0400 Subject: Bugfixes for anonymous enums, code cleanup to remove type_to_string(), and changed it so anonymous enums show up in doctests with their full type instead of `enum$20` --- src/compile/assertions.c | 2 +- src/compile/assignments.c | 4 +- src/compile/binops.c | 42 +++++++-------- src/compile/comparisons.c | 4 +- src/compile/conditionals.c | 4 +- src/compile/declarations.c | 4 +- src/compile/enums.c | 5 +- src/compile/expressions.c | 6 +-- src/compile/fieldaccess.c | 4 +- src/compile/files.c | 4 +- src/compile/functions.c | 14 ++--- src/compile/headers.c | 4 +- src/compile/indexing.c | 4 +- src/compile/integers.c | 4 +- src/compile/loops.c | 2 +- src/compile/optionals.c | 6 +-- src/compile/pointers.c | 2 +- src/compile/promotions.c | 2 +- src/compile/reductions.c | 2 +- src/compile/statements.c | 4 +- src/compile/structs.c | 4 +- src/compile/tables.c | 2 +- src/compile/text.c | 6 +-- src/compile/types.c | 4 +- src/compile/whens.c | 6 +-- src/environment.c | 2 +- src/tomo.c | 2 +- src/typecheck.c | 130 ++++++++++++++++++++++++--------------------- src/types.c | 33 ++++++------ src/types.h | 1 - 30 files changed, 161 insertions(+), 152 deletions(-) diff --git a/src/compile/assertions.c b/src/compile/assertions.c index 0f1d27b6..3ea6bf1e 100644 --- a/src/compile/assertions.c +++ b/src/compile/assertions.c @@ -43,7 +43,7 @@ Text_t compile_assertion(env_t *env, ast_t *ast) { } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) { operand_t = rhs_t; } else { - code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + code_err(ast, "I can't do comparisons between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t)); } ast_t *lhs_var = FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_lhs"))), diff --git a/src/compile/assignments.c b/src/compile/assignments.c index 6848e298..921b5320 100644 --- a/src/compile/assignments.c +++ b/src/compile/assignments.c @@ -142,9 +142,9 @@ Text_t compile_lvalue(env_t *env, ast_t *ast) { } else if (ast->tag == FieldAccess) { ast_t *subject = Match(ast, FieldAccess)->fielded; type_t *t = get_type(env, subject); - code_err(subject, "This is an immutable ", type_to_str(t), " value, you can't assign to its fields"); + code_err(subject, "This is an immutable ", type_to_text(t), " value, you can't assign to its fields"); } else { - code_err(ast, "This is a value of type ", type_to_str(get_type(env, ast)), + code_err(ast, "This is a value of type ", type_to_text(get_type(env, ast)), " and can't be used as an assignment target"); } } diff --git a/src/compile/binops.c b/src/compile/binops.c index ed4aaeba..9710019b 100644 --- a/src/compile/binops.c +++ b/src/compile/binops.c @@ -88,8 +88,8 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { if (is_incomplete_type(rhs_t)) { type_t *complete = most_complete_type(rhs_t, Match(lhs_t, OptionalType)->type); if (complete == NULL) - code_err(binop.rhs, "I don't know how to convert a ", type_to_str(rhs_t), " to a ", - type_to_str(Match(lhs_t, OptionalType)->type)); + code_err(binop.rhs, "I don't know how to convert a ", type_to_text(rhs_t), " to a ", + type_to_text(Match(lhs_t, OptionalType)->type)); rhs_t = complete; } @@ -103,8 +103,8 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { } else if (rhs_t->tag == BoolType) { return Texts("((!", check_none(lhs_t, compile(env, binop.lhs)), ") || ", compile(env, binop.rhs), ")"); } else { - code_err(ast, "I don't know how to do an 'or' operation between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t)); + code_err(ast, "I don't know how to do an 'or' operation between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); } } @@ -114,7 +114,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { switch (ast->tag) { case Power: { if (overall_t->tag != NumType) - code_err(ast, "Exponentiation is only supported for Num types, not ", type_to_str(overall_t)); + code_err(ast, "Exponentiation is only supported for Num types, not ", type_to_text(overall_t)); if (overall_t->tag == NumType && Match(overall_t, NumType)->bits == TYPE_NBITS32) return Texts("powf(", lhs, ", ", rhs, ")"); else return Texts("pow(", lhs, ", ", rhs, ")"); @@ -124,7 +124,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " * ", rhs, ")"); } case Divide: { @@ -132,7 +132,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " / ", rhs, ")"); } case Mod: { @@ -140,7 +140,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " % ", rhs, ")"); } case Mod1: { @@ -148,7 +148,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("((((", lhs, ")-1) % (", rhs, ")) + 1)"); } case Plus: { @@ -156,7 +156,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " + ", rhs, ")"); } case Minus: { @@ -166,7 +166,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " - ", rhs, ")"); } case LeftShift: { @@ -174,7 +174,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " << ", rhs, ")"); } case RightShift: { @@ -182,7 +182,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", lhs, " >> ", rhs, ")"); } case UnsignedLeftShift: { @@ -190,7 +190,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")"); } case UnsignedRightShift: { @@ -198,7 +198,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { code_err(ast, "Math operations are only supported for values of the same " "numeric type, not ", - type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + type_to_text(lhs_t), " and ", type_to_text(rhs_t)); return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")"); } case And: { @@ -207,8 +207,8 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { else if (overall_t->tag == SetType) return Texts("Table$overlap(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); else - code_err(ast, "The 'and' operator isn't supported between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t), " values"); + code_err(ast, "The 'and' operator isn't supported between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t), " values"); } case Compare: { return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")"); @@ -221,7 +221,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { } else if (overall_t->tag == SetType) { return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); } else { - code_err(ast, "The 'or' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), + code_err(ast, "The 'or' operator isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " values"); } } @@ -232,8 +232,8 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { else if (overall_t->tag == SetType) return Texts("Table$xor(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")"); else - code_err(ast, "The 'xor' operator isn't supported between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t), " values"); + code_err(ast, "The 'xor' operator isn't supported between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t), " values"); } case Concat: { if (overall_t == PATH_TYPE) return Texts("Path$concat(", lhs, ", ", rhs, ")"); @@ -246,7 +246,7 @@ Text_t compile_binary_op(env_t *env, ast_t *ast) { compile_type(Match(overall_t, ListType)->item_type), "))"); } default: - code_err(ast, "Concatenation isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), + code_err(ast, "Concatenation isn't supported between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " values"); } } diff --git a/src/compile/comparisons.c b/src/compile/comparisons.c index d7531261..0f9a7ddd 100644 --- a/src/compile/comparisons.c +++ b/src/compile/comparisons.c @@ -38,7 +38,7 @@ Text_t compile_comparison(env_t *env, ast_t *ast) { } else if (can_compile_to_type(env, binop.lhs, rhs_t)) { operand_t = rhs_t; } else { - code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + code_err(ast, "I can't do comparisons between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t)); } Text_t lhs, rhs; @@ -78,7 +78,7 @@ Text_t compile_comparison(env_t *env, ast_t *ast) { } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) { operand_t = rhs_t; } else { - code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + code_err(ast, "I can't do comparisons between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t)); } Text_t lhs = compile_to_type(env, cmp.lhs, operand_t); diff --git a/src/compile/conditionals.c b/src/compile/conditionals.c index f9dfa751..7fcd6cc8 100644 --- a/src/compile/conditionals.c +++ b/src/compile/conditionals.c @@ -26,7 +26,7 @@ Text_t compile_condition(env_t *env, ast_t *ast) { code_err(ast, "This pointer will always be non-none, so it should not be " "used in a conditional."); } else { - code_err(ast, type_to_str(t), " values cannot be used for conditionals"); + code_err(ast, type_to_text(t), " values cannot be used for conditionals"); } return EMPTY_TEXT; } @@ -102,7 +102,7 @@ Text_t compile_if_expression(env_t *env, ast_t *ast) { "This `if var := ...:` declaration should be an " "optional " "type, not ", - type_to_str(condition_type)); + type_to_text(condition_type)); if (is_incomplete_type(condition_type)) code_err(condition, "This type is incomplete!"); diff --git a/src/compile/declarations.c b/src/compile/declarations.c index 3f2164af..f1c59f73 100644 --- a/src/compile/declarations.c +++ b/src/compile/declarations.c @@ -32,7 +32,7 @@ Text_t compile_declared_value(env_t *env, ast_t *declare_ast) { type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType) - code_err(declare_ast, "You can't declare a variable with a ", type_to_str(t), " value"); + code_err(declare_ast, "You can't declare a variable with a ", type_to_text(t), " value"); if (decl->value) { Text_t val_code = compile_maybe_incref(env, decl->value, t); @@ -44,7 +44,7 @@ Text_t compile_declared_value(env_t *env, ast_t *declare_ast) { } else { Text_t val_code = compile_empty(t); if (val_code.length == 0) - code_err(declare_ast, "This type (", type_to_str(t), + code_err(declare_ast, "This type (", type_to_text(t), ") cannot be uninitialized. You must provide a value."); return val_code; } diff --git a/src/compile/enums.c b/src/compile/enums.c index f8a3994e..ec7a1755 100644 --- a/src/compile/enums.c +++ b/src/compile/enums.c @@ -30,7 +30,7 @@ Text_t compile_enum_typeinfo(env_t *env, const char *name, tag_ast_t *tags) { Text_t info = namespace_name(env, env->namespace, Texts(name, "$$info")); Text_t typeinfo = Texts("public const TypeInfo_t ", info, " = {", (int64_t)type_size(t), "u, ", (int64_t)type_align(t), - "u, .metamethods=", metamethods, ", {.tag=EnumInfo, .EnumInfo={.name=\"", name, + "u, .metamethods=", metamethods, ", {.tag=EnumInfo, .EnumInfo={.name=\"", type_to_text(t), "\", " ".num_tags=", (int64_t)num_tags, ", .tags=(NamedType_t[]){"); @@ -78,6 +78,7 @@ Text_t compile_enum_header(env_t *env, const char *name, tag_ast_t *tags) { Text_t none_name = namespace_name(env, env->namespace, Texts(name, "$none")); Text_t enum_name = namespace_name(env, env->namespace, Texts(name, "$$enum")); Text_t enum_tags = Texts("{ ", none_name, "=0, "); + assert(Table$str_get(*env->types, name)); bool has_any_tags_with_fields = false; for (tag_ast_t *tag = tags; tag; tag = tag->next) { @@ -167,5 +168,5 @@ Text_t compile_enum_field_access(env_t *env, ast_t *ast) { } } } - code_err(ast, "The field '", f->field, "' is not a valid tag name of ", type_to_str(value_t)); + code_err(ast, "The field '", f->field, "' is not a valid tag name of ", type_to_text(value_t)); } diff --git a/src/compile/expressions.c b/src/compile/expressions.c index e888ce16..16b94d73 100644 --- a/src/compile/expressions.c +++ b/src/compile/expressions.c @@ -98,7 +98,7 @@ Text_t compile(env_t *env, ast_t *ast) { else if (t->tag == TextType) return Texts("(", compile(env, value), ".length == 0)"); else if (t->tag == OptionalType) return check_none(t, compile(env, value)); - code_err(ast, "I don't know how to negate values of type ", type_to_str(t)); + code_err(ast, "I don't know how to negate values of type ", type_to_text(t)); } case Negative: { ast_t *value = Match(ast, Negative)->value; @@ -112,7 +112,7 @@ Text_t compile(env_t *env, ast_t *ast) { if (t->tag == IntType || t->tag == NumType) return Texts("-(", compile(env, value), ")"); - code_err(ast, "I don't know how to get the negative value of type ", type_to_str(t)); + code_err(ast, "I don't know how to get the negative value of type ", type_to_text(t)); } case HeapAllocate: case StackReference: return compile_typed_allocation(env, ast, get_type(env, ast)); @@ -218,7 +218,7 @@ Text_t compile(env_t *env, ast_t *ast) { ast_t *value = Match(ast, Deserialize)->value; type_t *value_type = get_type(env, value); if (!type_eq(value_type, Type(ListType, Type(ByteType)))) - code_err(value, "This value should be a list of bytes, not a ", type_to_str(value_type)); + code_err(value, "This value should be a list of bytes, not a ", type_to_text(value_type)); type_t *t = parse_type_ast(env, Match(ast, Deserialize)->type); return Texts("({ ", compile_declaration(t, Text("deserialized")), ";\n" diff --git a/src/compile/fieldaccess.c b/src/compile/fieldaccess.c index f1780fc9..24e091f0 100644 --- a/src/compile/fieldaccess.c +++ b/src/compile/fieldaccess.c @@ -35,7 +35,7 @@ Text_t compile_field_access(env_t *env, ast_t *ast) { } else if (streq(f->field, "length")) { return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)"); } - code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values"); + code_err(ast, "There is no '", f->field, "' field on ", type_to_text(value_t), " values"); } case StructType: { return compile_struct_field_access(env, ast); @@ -83,6 +83,6 @@ Text_t compile_field_access(env_t *env, ast_t *ast) { env_t *module_env = Table$str_get(*env->imports, name); return compile(module_env, WrapAST(ast, Var, f->field)); } - default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values"); + default: code_err(ast, "Field accesses are not supported on ", type_to_text(fielded_t), " values"); } } diff --git a/src/compile/files.c b/src/compile/files.c index 7ff252c2..bd1e9cc3 100644 --- a/src/compile/files.c +++ b/src/compile/files.c @@ -111,7 +111,7 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast) { code_err(ast, "Conversions are only supported for text, struct, and enum " "types, not ", - type_to_str(type)); + type_to_text(type)); Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", get_line_number(ast->file, ast->start))); return compile_function(env, name_code, ast, &env->code->staticdefs); @@ -170,6 +170,8 @@ typedef struct { static void add_type_infos(type_ast_t *type_ast, void *userdata) { if (type_ast && type_ast->tag == EnumTypeAST) { compile_info_t *info = (compile_info_t *)userdata; + // Force the type to get defined: + (void)parse_type_ast(info->env, type_ast); *info->code = Texts( *info->code, compile_enum_typeinfo(info->env, String("enum$", (int64_t)(type_ast->start - type_ast->file->text)), diff --git a/src/compile/functions.c b/src/compile/functions.c index 1e0fa106..d113316b 100644 --- a/src/compile/functions.c +++ b/src/compile/functions.c @@ -55,7 +55,7 @@ Text_t compile_convert_declaration(env_t *env, ast_t *ast) { code_err(ast, "Conversions are only supported for text, struct, and enum " "types, not ", - type_to_str(ret_t)); + type_to_text(ret_t)); Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", get_line_number(ast->file, ast->start))); return Texts(ret_type_code, " ", name_code, arg_signature, ";\n"); } @@ -216,7 +216,7 @@ Text_t compile_function_call(env_t *env, ast_t *ast) { code_err(ast, "I could not find a constructor matching these arguments " "for ", - type_to_str(t)); + type_to_text(t)); } else if (fn_t->tag == ClosureType) { fn_t = Match(fn_t, ClosureType)->fn; arg_t *type_args = Match(fn_t, FunctionType)->args; @@ -241,7 +241,7 @@ Text_t compile_function_call(env_t *env, ast_t *ast) { "closure.userdata); })"); } } else { - code_err(call->fn, "This is not a function, it's a ", type_to_str(fn_t)); + code_err(call->fn, "This is not a function, it's a ", type_to_text(fn_t)); } } @@ -268,7 +268,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) { binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride * i; if (has_stack_memory(entry->b->type)) - code_err(ast, "This function is holding onto a reference to ", type_to_str(entry->b->type), + code_err(ast, "This function is holding onto a reference to ", type_to_text(entry->b->type), " stack memory in the variable `", entry->name, "`, but the function may outlive the stack memory"); if (entry->b->type->tag == ModuleType) continue; @@ -510,7 +510,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t if (clause->pattern->tag == Var) clause_tag_name = Match(clause->pattern, Var)->name; else if (clause->pattern->tag == FunctionCall && Match(clause->pattern, FunctionCall)->fn->tag == Var) clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name; - else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum"); + else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_text(subject_t), " enum"); type_t *tag_type = NULL; for (tag_t *tag = enum_t->tags; tag; tag = tag->next) { @@ -634,7 +634,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static code_err(ast, "Conversions are only supported for text, struct, and enum " "types, not ", - type_to_str(ret_t)); + type_to_text(ret_t)); body = convertdef->body; cache = convertdef->cache; is_inline = convertdef->is_inline; @@ -693,7 +693,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static code_err(ast, "This function looks like it can reach the end without " "returning a ", - type_to_str(ret_t), + type_to_text(ret_t), " value! \n " "If this is not the case, please add a call to " "`fail(\"Unreachable\")` at the end of the function to " diff --git a/src/compile/headers.c b/src/compile/headers.c index 77040445..f6313cd6 100644 --- a/src/compile/headers.c +++ b/src/compile/headers.c @@ -79,7 +79,7 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t if (t->tag == FunctionType) t = Type(ClosureType, t); assert(t->tag != ModuleType); if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType) - code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value"); + code_err(ast, "You can't declare a variable with a ", type_to_text(t), " value"); return Texts(decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT, "extern ", compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n"); @@ -151,6 +151,8 @@ static void add_type_headers(type_ast_t *type_ast, void *userdata) { if (type_ast->tag == EnumTypeAST) { compile_typedef_info_t *info = (compile_typedef_info_t *)userdata; + // Force the type to get defined: + (void)parse_type_ast(info->env, type_ast); DeclareMatch(enum_, type_ast, EnumTypeAST); bool has_any_tags_with_fields = false; for (tag_ast_t *tag = enum_->tags; tag; tag = tag->next) { diff --git a/src/compile/indexing.c b/src/compile/indexing.c index bb7bf6b9..771e9acd 100644 --- a/src/compile/indexing.c +++ b/src/compile/indexing.c @@ -33,7 +33,7 @@ Text_t compile_indexing(env_t *env, ast_t *ast, bool checked) { type_t *index_t = get_type(env, indexing->index); if (container_t->tag == ListType) { if (index_t->tag != IntType && index_t->tag != BigIntType && index_t->tag != ByteType) - code_err(indexing->index, "Lists can only be indexed by integers, not ", type_to_str(index_t)); + code_err(indexing->index, "Lists can only be indexed by integers, not ", type_to_text(index_t)); type_t *item_type = Match(container_t, ListType)->item_type; Text_t list = compile_to_pointer_depth(env, indexing->indexed, 0, false); Text_t index_code = @@ -82,6 +82,6 @@ Text_t compile_indexing(env_t *env, ast_t *ast, bool checked) { compile_to_type(env, indexing->index, Type(BigIntType)), ")"); } } else { - code_err(ast, "Indexing is not supported for type: ", type_to_str(container_t)); + code_err(ast, "Indexing is not supported for type: ", type_to_text(container_t)); } } diff --git a/src/compile/integers.c b/src/compile/integers.c index 9ebb8818..4747f8ba 100644 --- a/src/compile/integers.c +++ b/src/compile/integers.c @@ -18,7 +18,7 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { Text_t code = compile(env, ast); type_t *actual_type = get_type(env, ast); if (!promote(env, ast, &code, actual_type, target)) - code_err(ast, "I couldn't promote this ", type_to_str(actual_type), " to a ", type_to_str(target)); + code_err(ast, "I couldn't promote this ", type_to_text(actual_type), " to a ", type_to_text(target)); return code; } @@ -72,7 +72,7 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { } code_err(ast, "This integer cannot fit in a ", target_bits, "-bit value"); } else { - code_err(ast, "I don't know how to compile this to a ", type_to_str(target)); + code_err(ast, "I don't know how to compile this to a ", type_to_text(target)); } return EMPTY_TEXT; } diff --git a/src/compile/loops.c b/src/compile/loops.c index 332024f4..b68c908f 100644 --- a/src/compile/loops.c +++ b/src/compile/loops.c @@ -355,7 +355,7 @@ Text_t compile_for_loop(env_t *env, ast_t *ast) { return code; } - default: code_err(for_->iter, "Iteration is not implemented for type: ", type_to_str(iter_t)); + default: code_err(for_->iter, "Iteration is not implemented for type: ", type_to_text(iter_t)); } } diff --git a/src/compile/optionals.c b/src/compile/optionals.c index 8340ecaa..234a1cd2 100644 --- a/src/compile/optionals.c +++ b/src/compile/optionals.c @@ -32,7 +32,7 @@ Text_t promote_to_optional(type_t *t, Text_t code) { case TYPE_IBITS16: return Texts("((OptionalInt16_t){.value=", code, "})"); case TYPE_IBITS32: return Texts("((OptionalInt32_t){.value=", code, "})"); case TYPE_IBITS64: return Texts("((OptionalInt64_t){.value=", code, "})"); - default: errx(1, "Unsupported in type: %s", type_to_str(t)); + default: errx(1, "Unsupported in type: %s", type_to_text(t)); } return code; } else if (t->tag == ByteType) { @@ -83,7 +83,7 @@ Text_t compile_none(type_t *t) { env_t *enum_env = Match(t, EnumType)->env; return Texts("((", compile_type(t), "){", namespace_name(enum_env, enum_env->namespace, Text("none")), "})"); } - default: compiler_err(NULL, NULL, NULL, "none isn't implemented for this type: ", type_to_str(t)); + default: compiler_err(NULL, NULL, NULL, "none isn't implemented for this type: ", type_to_text(t)); } return EMPTY_TEXT; } @@ -109,7 +109,7 @@ Text_t check_none(type_t *t, Text_t value) { if (enum_has_fields(t)) return Texts("((", value, ").$tag == 0)"); else return Texts("((", value, ") == 0)"); } - print_err("Optional check not implemented for: ", type_to_str(t)); + print_err("Optional check not implemented for: ", type_to_text(t)); return EMPTY_TEXT; } diff --git a/src/compile/pointers.c b/src/compile/pointers.c index 644b3bc7..31687d78 100644 --- a/src/compile/pointers.c +++ b/src/compile/pointers.c @@ -27,7 +27,7 @@ Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bo while (depth != target_depth) { if (depth < target_depth) { if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")"); - else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast))); + else code_err(ast, "This should be a pointer, not ", type_to_text(get_type(env, ast))); t = Type(PointerType, .pointed = t, .is_stack = true); ++depth; } else { diff --git a/src/compile/promotions.c b/src/compile/promotions.c index 26f3af9f..3441632e 100644 --- a/src/compile/promotions.c +++ b/src/compile/promotions.c @@ -191,5 +191,5 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) { 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)); + code_err(ast, "I expected a ", type_to_text(t), " here, but this is a ", type_to_text(actual)); } diff --git a/src/compile/reductions.c b/src/compile/reductions.c index 438e072b..159158e3 100644 --- a/src/compile/reductions.c +++ b/src/compile/reductions.c @@ -17,7 +17,7 @@ Text_t compile_reduction(env_t *env, ast_t *ast) { type_t *iter_t = get_type(env, reduction->iter); type_t *item_t = get_iterated_type(iter_t); if (!item_t) - code_err(reduction->iter, "I couldn't figure out how to iterate over this type: ", type_to_str(iter_t)); + code_err(reduction->iter, "I couldn't figure out how to iterate over this type: ", type_to_text(iter_t)); static int64_t next_id = 1; ast_t *item = FakeAST(Var, String("$it", next_id++)); diff --git a/src/compile/statements.c b/src/compile/statements.c index 3fc44ac4..db8f5b1f 100644 --- a/src/compile/statements.c +++ b/src/compile/statements.c @@ -48,7 +48,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) { type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); if (t->tag == FunctionType) t = Type(ClosureType, t); if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType) - code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value"); + code_err(ast, "You can't declare a variable with a ", type_to_text(t), " value"); Text_t val_code = compile_declared_value(env, ast); return Texts(compile_declaration(t, Texts("_$", name)), " = ", val_code, ";"); @@ -214,7 +214,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) { // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ", // is_discardable(env, ast)); if (!is_discardable(env, ast)) - code_err(ast, "The ", type_to_str(get_type(env, ast)), " result of this statement cannot be discarded"); + code_err(ast, "The ", type_to_text(get_type(env, ast)), " result of this statement cannot be discarded"); return Texts("(void)", compile(env, ast), ";"); } } diff --git a/src/compile/structs.c b/src/compile/structs.c index 8560a790..aaebef22 100644 --- a/src/compile/structs.c +++ b/src/compile/structs.c @@ -111,7 +111,7 @@ Text_t compile_struct_field_access(env_t *env, ast_t *ast) { } } } - code_err(ast, "The field '", f->field, "' is not a valid field name of ", type_to_str(value_t)); + code_err(ast, "The field '", f->field, "' is not a valid field name of ", type_to_text(value_t)); } public @@ -129,5 +129,5 @@ Text_t compile_struct_literal(env_t *env, ast_t *ast, type_t *t, arg_ast_t *args && is_valid_call(env, struct_->fields, args, (call_opts_t){.promotion = true, .underscores = true})) { code_err(ast, "This constructor uses private fields that are not exposed."); } - code_err(ast, "I could not find a constructor matching these arguments for the struct ", type_to_str(t)); + code_err(ast, "I could not find a constructor matching these arguments for the struct ", type_to_text(t)); } diff --git a/src/compile/tables.c b/src/compile/tables.c index dde8669a..b6efdecd 100644 --- a/src/compile/tables.c +++ b/src/compile/tables.c @@ -26,7 +26,7 @@ Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) { type_t *value_t = Match(table_type, TableType)->value_type; if (value_t->tag == OptionalType) - code_err(ast, "Tables whose values are optional (", type_to_str(value_t), ") are not currently supported."); + code_err(ast, "Tables whose values are optional (", type_to_text(value_t), ") are not currently supported."); for (ast_list_t *entry = table->entries; entry; entry = entry->next) { if (entry->ast->tag == Comprehension) goto table_comprehension; diff --git a/src/compile/text.c b/src/compile/text.c index 0e0b41f8..afb412e9 100644 --- a/src/compile/text.c +++ b/src/compile/text.c @@ -38,7 +38,7 @@ Text_t expr_as_text(Text_t expr, type_t *t, Text_t color) { case OptionalType: return Texts("Optional$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); case StructType: case EnumType: return Texts("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")"); - default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_str(t)); + default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_text(t)); } return EMPTY_TEXT; } @@ -136,8 +136,8 @@ Text_t compile_text_ast(env_t *env, ast_t *ast) { if (chunk_t->tag == TextType) chunk_code = compile(env, chunk->ast); else chunk_code = compile_text(env, chunk->ast, colorize); } else { - code_err(chunk->ast, "I don't know how to convert ", type_to_str(chunk_t), " to ", - type_to_str(text_t)); + code_err(chunk->ast, "I don't know how to convert ", type_to_text(chunk_t), " to ", + type_to_text(text_t)); } } code = Texts(code, chunk_code); diff --git a/src/compile/types.c b/src/compile/types.c index f6f276a5..6b6f48f8 100644 --- a/src/compile/types.c +++ b/src/compile/types.c @@ -79,7 +79,7 @@ Text_t compile_type(type_t *t) { DeclareMatch(s, nonnull, StructType); return namespace_name(s->env, s->env->namespace->parent, Texts("$Optional", s->name, "$$type")); } - default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t)); + default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_text(t)); } } case TypeInfoType: return Text("TypeInfo_t"); @@ -147,7 +147,7 @@ Text_t compile_type_info(type_t *t) { case TypeInfoType: return Texts("Type$info(", quoted_text(type_to_text(Match(t, TypeInfoType)->type)), ")"); case MemoryType: return Text("&Memory$info"); case VoidType: return Text("&Void$info"); - default: compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_str(t)); + default: compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_text(t)); } return EMPTY_TEXT; } diff --git a/src/compile/whens.c b/src/compile/whens.c index d9bef9e1..4f6a2a40 100644 --- a/src/compile/whens.c +++ b/src/compile/whens.c @@ -61,7 +61,7 @@ Text_t compile_when_statement(env_t *env, ast_t *ast) { } if (clause->pattern->tag != FunctionCall || Match(clause->pattern, FunctionCall)->fn->tag != Var) - code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum type"); + code_err(clause->pattern, "This is not a valid pattern for a ", type_to_text(subject_t), " enum type"); const char *clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name; code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), @@ -93,9 +93,9 @@ Text_t compile_when_statement(env_t *env, ast_t *ast) { arg_t *field = tag_struct->fields; for (arg_ast_t *arg = args; arg || field; arg = arg->next) { if (!arg) - code_err(ast, "The field ", type_to_str(subject_t), ".", clause_tag_name, ".", field->name, + code_err(ast, "The field ", type_to_text(subject_t), ".", clause_tag_name, ".", field->name, " wasn't accounted for"); - if (!field) code_err(arg->value, "This is one more field than ", type_to_str(subject_t), " has"); + if (!field) code_err(arg->value, "This is one more field than ", type_to_text(subject_t), " has"); if (arg->name) code_err(arg->value, "Named arguments are not currently supported"); const char *var_name = Match(arg->value, Var)->name; diff --git a/src/environment.c b/src/environment.c index b551abf1..045cf6d7 100644 --- a/src/environment.c +++ b/src/environment.c @@ -659,7 +659,7 @@ env_t *for_scope(env_t *env, ast_t *ast) { } return scope; } - default: code_err(for_->iter, "Iteration is not implemented for type: ", type_to_str(iter_t)); + default: code_err(for_->iter, "Iteration is not implemented for type: ", type_to_text(iter_t)); } return NULL; } diff --git a/src/tomo.c b/src/tomo.c index 6b80e71b..2f1d5651 100644 --- a/src/tomo.c +++ b/src/tomo.c @@ -788,7 +788,7 @@ void transpile_code(env_t *base_env, Path_t path) { type_t *ret = Match(main_binding->type, FunctionType)->ret; if (ret->tag != VoidType && ret->tag != AbortType) compiler_err(ast->file, ast->start, ast->end, "The main() function in this file has a return type of ", - type_to_str(ret), ", but it should not have any return value!"); + type_to_text(ret), ", but it should not have any return value!"); Text$print(c_file, Texts("int parse_and_run$$", main_binding->code, "(int argc, char *argv[]) {\n", module_env->do_source_mapping ? Text("#line 1\n") : EMPTY_TEXT, "tomo_init();\n", diff --git a/src/typecheck.c b/src/typecheck.c index 806cf1bf..87ed474a 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -117,15 +117,18 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast) { DeclareMatch(opt, ast, OptionalTypeAST); type_t *t = parse_type_ast(env, opt->type); if (t->tag == VoidType || t->tag == AbortType || t->tag == ReturnType) - code_err(ast, "Optional ", type_to_str(t), " types are not supported."); + code_err(ast, "Optional ", type_to_text(t), " types are not supported."); else if (t->tag == OptionalType) code_err(ast, "Nested optional types are not currently supported"); return Type(OptionalType, .type = t); } case EnumTypeAST: { + const char *enum_name = Text$as_c_string(Match(ast, EnumTypeAST)->name); + type_t *cached = Table$str_get(*env->types, enum_name); + if (cached) return cached; + tag_ast_t *tag_asts = Match(ast, EnumTypeAST)->tags; tag_t *tags = NULL; int64_t tag_value = 1; - const char *enum_name = Text$as_c_string(Match(ast, EnumTypeAST)->name); env_t *ns_env = namespace_env(env, enum_name); type_t *enum_type = Type(EnumType, .name = enum_name, .env = ns_env, .tags = NULL); @@ -213,7 +216,7 @@ PUREFUNC type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rh case NUM_PRECISION_MORE: return lhs_t; case NUM_PRECISION_LESS: return rhs_t; default: - code_err(ast, "Math operations between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), + code_err(ast, "Math operations between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t), " are not supported"); } return NULL; @@ -283,7 +286,7 @@ void prebind_statement(env_t *env, ast_t *statement) { case StructDef: { DeclareMatch(def, statement, StructDef); if (get_binding(env, def->name)) - code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name), + code_err(statement, "A ", type_to_text(get_binding(env, def->name)->type), " called ", quoted(def->name), " has already been defined"); env_t *ns_env = namespace_env(env, def->name); @@ -300,7 +303,7 @@ void prebind_statement(env_t *env, ast_t *statement) { case EnumDef: { DeclareMatch(def, statement, EnumDef); if (get_binding(env, def->name)) - code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name), + code_err(statement, "A ", type_to_text(get_binding(env, def->name)->type), " called ", quoted(def->name), " has already been defined"); env_t *ns_env = namespace_env(env, def->name); @@ -316,7 +319,7 @@ void prebind_statement(env_t *env, ast_t *statement) { case LangDef: { DeclareMatch(def, statement, LangDef); if (get_binding(env, def->name)) - code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name), + code_err(statement, "A ", type_to_text(get_binding(env, def->name)->type), " called ", quoted(def->name), " has already been defined"); env_t *ns_env = namespace_env(env, def->name); @@ -348,8 +351,8 @@ void prebind_statement(env_t *env, ast_t *statement) { binding_t *clobbered = Table$str_get(*ns_env->locals, entry->name); if (clobbered && !type_eq(clobbered->type, entry->binding->type)) code_err(statement, "This `extend` block overwrites the binding for ", quoted(entry->name), - " in the original namespace (with type ", type_to_str(clobbered->type), - ") with a new binding with type ", type_to_str(entry->binding->type)); + " in the original namespace (with type ", type_to_text(clobbered->type), + ") with a new binding with type ", type_to_text(entry->binding->type)); Table$str_set(ns_env->locals, entry->name, entry->binding); } break; @@ -374,7 +377,7 @@ void bind_statement(env_t *env, ast_t *statement) { if (streq(name, "_")) // Explicit discard return; if (get_binding(env, name)) - code_err(decl->var, "A ", type_to_str(get_binding(env, name)->type), " called ", quoted(name), + code_err(decl->var, "A ", type_to_text(get_binding(env, name)->type), " called ", quoted(name), " has already been defined"); if (decl->value) bind_statement(env, decl->value); type_t *type = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value); @@ -400,7 +403,7 @@ void bind_statement(env_t *env, ast_t *statement) { const char *name = get_type_name(ret_t); if (!name) code_err(statement, "Conversions are only supported for text, struct, and enum types, not ", - type_to_str(ret_t)); + type_to_text(ret_t)); Text_t code = namespace_name(env, env->namespace, Texts(name, "$", get_line_number(statement->file, statement->start))); @@ -435,20 +438,20 @@ void bind_statement(env_t *env, ast_t *statement) { compiler_err(file, start, end, "This is a recursive struct that would be infinitely large. Maybe you meant to " "use an optional '@", - type_to_str(type), "?' pointer instead?"); + type_to_text(type), "?' pointer instead?"); else if (non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->external) compiler_err( file, start, end, "This is an opaque externally defined struct.\n" "I can't use it as a member without knowing what its fields are.\n" "Either specify its fields and remove the `opaque` qualifier, or use something like a @", - type_to_str(non_opt_field_t), " pointer."); + type_to_text(non_opt_field_t), " pointer."); else compiler_err(file, start, end, "I'm still in the process of defining the fields of ", - type_to_str(field_t), + type_to_text(field_t), ", so I don't know how to use it as a member." "\nTry using a @", - type_to_str(field_t), " pointer for this field."); + type_to_text(field_t), " pointer for this field."); } fields = new (arg_t, .name = field_ast->name, .alias = field_ast->alias, .type = field_t, .default_val = field_ast->value, .next = fields); @@ -491,20 +494,20 @@ void bind_statement(env_t *env, ast_t *statement) { compiler_err(file, start, end, "This is a recursive enum that would be infinitely large. Maybe you meant to use " "an optional '@", - type_to_str(type), "?' pointer instead?"); + type_to_text(type), "?' pointer instead?"); else if (non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->external) compiler_err( file, start, end, "This is an opaque externally defined struct.\n" "I can't use it as a member without knowing what its fields are.\n" "Either specify its fields and remove the `opaque` qualifier, or use something like a @", - type_to_str(non_opt_field_t), " pointer."); + type_to_text(non_opt_field_t), " pointer."); else compiler_err(file, start, end, "I'm still in the process of defining the fields of ", - type_to_str(field_t), + type_to_text(field_t), ", so I don't know how to use it as a member." "\nTry using a @", - type_to_str(field_t), " pointer for this field."); + type_to_text(field_t), " pointer for this field."); } fields = new (arg_t, .name = field_ast->name, .alias = field_ast->alias, .type = field_t, .default_val = field_ast->value, .next = fields); @@ -577,8 +580,8 @@ void bind_statement(env_t *env, ast_t *statement) { binding_t *clobbered = Table$str_get(*ns_env->locals, entry->name); if (clobbered && !type_eq(clobbered->type, entry->binding->type)) code_err(statement, "This `extend` block overwrites the binding for ", quoted(entry->name), - " in the original namespace (with type ", type_to_str(clobbered->type), - ") with a new binding with type ", type_to_str(entry->binding->type)); + " in the original namespace (with type ", type_to_text(clobbered->type), + ") with a new binding with type ", type_to_text(entry->binding->type)); Table$str_set(ns_env->locals, entry->name, entry->binding); } break; @@ -673,8 +676,8 @@ type_t *get_function_type(env_t *env, ast_t *ast) { type_t *declared = parse_type_ast(env, ret_ast); if (can_promote(ret_t, declared)) ret_t = declared; else - code_err(ast, "This function was declared to return a value of type ", type_to_str(declared), - ", but actually returns a value of type ", type_to_str(ret_t)); + code_err(ast, "This function was declared to return a value of type ", type_to_text(declared), + ", but actually returns a value of type ", type_to_text(ret_t)); } if (has_stack_memory(ret_t)) @@ -696,7 +699,7 @@ type_t *get_function_return_type(env_t *env, ast_t *ast) { type_t *get_method_type(env_t *env, ast_t *self, const char *name) { binding_t *b = get_namespace_binding(env, self, name); - if (!b || !b->type) code_err(self, "No such method: ", type_to_str(get_type(env, self)), ".", name, "(...)"); + if (!b || !b->type) code_err(self, "No such method: ", type_to_text(get_type(env, self)), ".", name, "(...)"); return b->type; } @@ -705,7 +708,7 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) { if (clause->pattern->tag != FunctionCall || Match(clause->pattern, FunctionCall)->fn->tag != Var) code_err(clause->pattern, "I only support variables and constructors for pattern matching ", - type_to_str(subject_t), " types in a 'when' block"); + type_to_text(subject_t), " types in a 'when' block"); DeclareMatch(fn, clause->pattern, FunctionCall); const char *tag_name = Match(fn->fn, Var)->name; @@ -719,7 +722,7 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) { } if (!tag_type) - code_err(clause->pattern, "There is no tag ", quoted(tag_name), " for the type ", type_to_str(subject_t)); + code_err(clause->pattern, "There is no tag ", quoted(tag_name), " for the type ", type_to_text(subject_t)); if (!fn->args) return env; @@ -734,9 +737,9 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) { arg_t *field = tag_struct->fields; for (arg_ast_t *var = fn->args; var || field; var = var ? var->next : var) { if (!var) - code_err(clause->pattern, "The field ", type_to_str(subject_t), ".", tag_name, ".", field->name, + code_err(clause->pattern, "The field ", type_to_text(subject_t), ".", tag_name, ".", field->name, " wasn't accounted for"); - if (!field) code_err(var->value, "This is one more field than ", type_to_str(subject_t), " has"); + if (!field) code_err(var->value, "This is one more field than ", type_to_text(subject_t), " has"); if (var->value->tag != Var) code_err(var->value, "I expected this to be a plain variable so I could bind it to a value"); if (!streq(Match(var->value, Var)->name, "_")) @@ -971,7 +974,8 @@ type_t *get_type(env_t *env, ast_t *ast) { return b->type; } type_t *field_t = get_field_type(fielded_t, access->field); - if (!field_t) code_err(ast, type_to_str(fielded_t), " objects don't have a field called '", access->field, "'"); + if (!field_t) + code_err(ast, type_to_text(fielded_t), " objects don't have a field called '", access->field, "'"); return field_t; } case Index: { @@ -988,7 +992,7 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *index_t = get_type(env, indexing->index); if (index_t->tag == IntType || index_t->tag == BigIntType || index_t->tag == ByteType) return Type(OptionalType, Match(value_t, ListType)->item_type); - code_err(indexing->index, "I only know how to index lists using integers, not ", type_to_str(index_t)); + code_err(indexing->index, "I only know how to index lists using integers, not ", type_to_text(index_t)); } else if (value_t->tag == TableType) { DeclareMatch(table_type, value_t, TableType); if (table_type->default_value) return table_type->value_type; @@ -996,7 +1000,7 @@ type_t *get_type(env_t *env, ast_t *ast) { } else if (value_t->tag == TextType) { return Type(OptionalType, value_t); } else { - code_err(ast, "I don't know how to index ", type_to_str(indexed_t), " values"); + code_err(ast, "I don't know how to index ", type_to_text(indexed_t), " values"); } } case FunctionCall: { @@ -1023,7 +1027,7 @@ type_t *get_type(env_t *env, ast_t *ast) { } if (fn_type_t->tag == ClosureType) fn_type_t = Match(fn_type_t, ClosureType)->fn; if (fn_type_t->tag != FunctionType) - code_err(call->fn, "This isn't a function, it's a ", type_to_str(fn_type_t)); + code_err(call->fn, "This isn't a function, it's a ", type_to_text(fn_type_t)); DeclareMatch(fn_type, fn_type_t, FunctionType); return fn_type->ret; } @@ -1099,7 +1103,7 @@ type_t *get_type(env_t *env, ast_t *ast) { else if (streq(call->name, "set")) return Type(VoidType); else if (streq(call->name, "sorted")) return self_value_t; else if (streq(call->name, "with_fallback")) return self_value_t; - code_err(ast, "There is no '", call->name, "' method for ", type_to_str(self_value_t), " tables"); + code_err(ast, "There is no '", call->name, "' method for ", type_to_text(self_value_t), " tables"); } default: { if (call->name[0] == '_') { @@ -1114,7 +1118,7 @@ type_t *get_type(env_t *env, ast_t *ast) { if (field_type && field_type->tag == FunctionType) return Match(field_type, FunctionType)->ret; type_t *fn_type_t = get_method_type(env, call->self, call->name); if (!fn_type_t) code_err(ast, "No such method!"); - if (fn_type_t->tag != FunctionType) code_err(ast, "This isn't a method, it's a ", type_to_str(fn_type_t)); + if (fn_type_t->tag != FunctionType) code_err(ast, "This isn't a method, it's a ", type_to_text(fn_type_t)); DeclareMatch(fn_type, fn_type_t, FunctionType); return fn_type->ret; } @@ -1203,7 +1207,7 @@ type_t *get_type(env_t *env, ast_t *ast) { if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret)) return t; } - code_err(ast, "I don't know how to get the negative value of type ", type_to_str(t)); + code_err(ast, "I don't know how to get the negative value of type ", type_to_text(t)); } case Not: { type_t *t = get_type(env, Match(ast, Not)->value); @@ -1217,7 +1221,7 @@ type_t *get_type(env_t *env, ast_t *ast) { if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret)) return t; } code_err(ast, "I only know how to get 'not' of boolean, numeric, and optional pointer types, not ", - type_to_str(t)); + type_to_text(t)); } case Or: { binary_operands_t binop = BINARY_OPERANDS(ast); @@ -1245,8 +1249,8 @@ type_t *get_type(env_t *env, ast_t *ast) { if (rhs_t->tag == OptionalType) { type_t *result = most_complete_type(lhs_t, rhs_t); if (result == NULL) - code_err(ast, "I could not determine the type of ", type_to_str(lhs_t), " `or` ", - type_to_str(rhs_t)); + code_err(ast, "I could not determine the type of ", type_to_text(lhs_t), " `or` ", + type_to_text(rhs_t)); return result; } else if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) { return Match(lhs_t, OptionalType)->type; @@ -1262,7 +1266,8 @@ type_t *get_type(env_t *env, ast_t *ast) { } else if (lhs_t->tag == SetType && rhs_t->tag == SetType && type_eq(lhs_t, rhs_t)) { return lhs_t; } - code_err(ast, "I couldn't figure out how to do `or` between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + code_err(ast, "I couldn't figure out how to do `or` between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); } case And: { binary_operands_t binop = BINARY_OPERANDS(ast); @@ -1294,8 +1299,8 @@ type_t *get_type(env_t *env, ast_t *ast) { } else if (lhs_t->tag == SetType && rhs_t->tag == SetType && type_eq(lhs_t, rhs_t)) { return lhs_t; } - code_err(ast, "I couldn't figure out how to do `and` between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t)); + code_err(ast, "I couldn't figure out how to do `and` between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); } case Xor: { binary_operands_t binop = BINARY_OPERANDS(ast); @@ -1327,8 +1332,8 @@ type_t *get_type(env_t *env, ast_t *ast) { } else if (lhs_t->tag == SetType && rhs_t->tag == SetType && type_eq(lhs_t, rhs_t)) { return lhs_t; } - code_err(ast, "I couldn't figure out how to do `xor` between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t)); + code_err(ast, "I couldn't figure out how to do `xor` between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); } case Compare: case Equals: @@ -1345,7 +1350,7 @@ type_t *get_type(env_t *env, ast_t *ast) { || can_compile_to_type(env, binop.rhs, lhs_t) || can_compile_to_type(env, binop.lhs, rhs_t)) return ast->tag == Compare ? Type(IntType, .bits = TYPE_IBITS32) : Type(BoolType); - code_err(ast, "I don't know how to compare ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + code_err(ast, "I don't know how to compare ", type_to_text(lhs_t), " and ", type_to_text(rhs_t)); } case Power: case Multiply: @@ -1370,7 +1375,7 @@ type_t *get_type(env_t *env, ast_t *ast) { if (ast->tag == LeftShift || ast->tag == UnsignedLeftShift || ast->tag == RightShift || ast->tag == UnsignedRightShift) { if (!is_int_type(rhs_t)) - code_err(binop.rhs, "I only know how to do bit shifting by integer amounts, not ", type_to_str(rhs_t)); + code_err(binop.rhs, "I only know how to do bit shifting by integer amounts, not ", type_to_text(rhs_t)); } if (is_numeric_type(lhs_t) && binop.rhs->tag == Int) { @@ -1426,16 +1431,16 @@ type_t *get_type(env_t *env, ast_t *ast) { (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL)); if (overall_t == NULL) - code_err(ast, "I don't know how to do math operations between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t)); + code_err(ast, "I don't know how to do math operations between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t); if (b) return overall_t; if (is_numeric_type(lhs_t) && is_numeric_type(rhs_t)) return overall_t; - code_err(ast, "I don't know how to do math operations between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t)); + code_err(ast, "I don't know how to do math operations between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); } case Concat: { binary_operands_t binop = BINARY_OPERANDS(ast); @@ -1446,15 +1451,16 @@ type_t *get_type(env_t *env, ast_t *ast) { (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL)); if (overall_t == NULL) - code_err(ast, "I don't know how to do operations between ", type_to_str(lhs_t), " and ", - type_to_str(rhs_t)); + code_err(ast, "I don't know how to do operations between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t); if (b) return overall_t; if (overall_t->tag == ListType || overall_t->tag == SetType || overall_t->tag == TextType) return overall_t; - code_err(ast, "I don't know how to do concatenation between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t)); + code_err(ast, "I don't know how to do concatenation between ", type_to_text(lhs_t), " and ", + type_to_text(rhs_t)); } case Reduction: { @@ -1468,7 +1474,7 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *iterated = get_iterated_type(iter_t); if (!iterated) - code_err(reduction->iter, "I don't know how to do a reduction over ", type_to_str(iter_t), " values"); + code_err(reduction->iter, "I don't know how to do a reduction over ", type_to_text(iter_t), " values"); if (reduction->key && !(reduction->op == Min || reduction->op == Max)) { env_t *item_scope = fresh_scope(env); const char *op_str = binop_info[reduction->op].operator; @@ -1487,8 +1493,8 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *lhs_t = get_type(env, lhs), *rhs_t = get_type(env, rhs); type_t *t = type_or_type(lhs_t, rhs_t); if (!t) - code_err(ast, "The two sides of this operation are not compatible: ", type_to_str(lhs_t), " vs ", - type_to_str(rhs_t)); + code_err(ast, "The two sides of this operation are not compatible: ", type_to_text(lhs_t), " vs ", + type_to_text(rhs_t)); return t; } @@ -1533,8 +1539,8 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *false_t = get_type(falsey_scope, if_->else_body); type_t *t_either = type_or_type(true_t, false_t); if (!t_either) - code_err(if_->else_body, "I was expecting this block to have a ", type_to_str(true_t), - " value (based on earlier clauses), but it actually has a ", type_to_str(false_t), " value."); + code_err(if_->else_body, "I was expecting this block to have a ", type_to_text(true_t), + " value (based on earlier clauses), but it actually has a ", type_to_text(false_t), " value."); return t_either; } @@ -1568,7 +1574,7 @@ type_t *get_type(env_t *env, ast_t *ast) { if (clause->pattern->tag == Var) tag_name = Match(clause->pattern, Var)->name; else if (clause->pattern->tag == FunctionCall && Match(clause->pattern, FunctionCall)->fn->tag == Var) tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name; - else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum"); + else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_text(subject_t), " enum"); Text_t valid_tags = EMPTY_TEXT; for (match_t *m = matches; m; m = m->next) { @@ -1581,7 +1587,7 @@ type_t *get_type(env_t *env, ast_t *ast) { valid_tags = Texts(valid_tags, m->tag->name); } - code_err(clause->pattern, "There is no tag '", tag_name, "' for the type ", type_to_str(subject_t), + code_err(clause->pattern, "There is no tag '", tag_name, "' for the type ", type_to_text(subject_t), " (valid tags: ", valid_tags, ")"); found_matching_tag:; } @@ -1591,8 +1597,8 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *clause_type = get_type(clause_scope, clause->body); type_t *merged = type_or_type(overall_t, clause_type); if (!merged) - code_err(clause->body, "The type of this branch is ", type_to_str(clause_type), - ", which conflicts with the earlier branch type of ", type_to_str(overall_t)); + code_err(clause->body, "The type of this branch is ", type_to_text(clause_type), + ", which conflicts with the earlier branch type of ", type_to_text(overall_t)); overall_t = merged; } @@ -1612,8 +1618,8 @@ type_t *get_type(env_t *env, ast_t *ast) { type_t *else_t = get_type(env, when->else_body); type_t *merged = type_or_type(overall_t, else_t); if (!merged) - code_err(when->else_body, "I was expecting this block to have a ", type_to_str(overall_t), - " value (based on earlier clauses), but it actually has a ", type_to_str(else_t), " value."); + code_err(when->else_body, "I was expecting this block to have a ", type_to_text(overall_t), + " value (based on earlier clauses), but it actually has a ", type_to_text(else_t), " value."); return merged; } else { Text_t unhandled = EMPTY_TEXT; diff --git a/src/types.c b/src/types.c index a670f212..7db46b27 100644 --- a/src/types.c +++ b/src/types.c @@ -68,21 +68,22 @@ Text_t type_to_text(type_t *t) { } case EnumType: { DeclareMatch(enum_, t, EnumType); - return Text$from_str(enum_->name); - // Text_t text = Text("enum("); - // for (tag_t *tag = enum_->tags; tag; tag = tag->next) { - // text = Texts(text, Text$from_str(tag->name)); - // if (tag->type && Match(tag->type, StructType)->fields) { - // text = Texts(text, "("); - // for (arg_t *field = Match(tag->type, StructType)->fields; field; field = field->next) { - // text = Texts(text, Text$from_str(field->name), ":", type_to_text(field->type)); - // if (field->next) text = Texts(text, ", "); - // } - // text = Texts(text, ")"); - // } - // if (tag->next) text = Texts(text, ", "); - // } - // return enum_->name ? Text$from_str(enum_->name) : Text("enum"); + if (enum_->name != NULL && strncmp(enum_->name, "enum$", strlen("enum$")) != 0) + return Text$from_str(enum_->name); + Text_t text = Text("enum("); + for (tag_t *tag = enum_->tags; tag; tag = tag->next) { + text = Texts(text, Text$from_str(tag->name)); + if (tag->type && Match(tag->type, StructType)->fields) { + text = Texts(text, "("); + for (arg_t *field = Match(tag->type, StructType)->fields; field; field = field->next) { + text = Texts(text, Text$from_str(field->name), ":", type_to_text(field->type)); + if (field->next) text = Texts(text, ", "); + } + text = Texts(text, ")"); + } + if (tag->next) text = Texts(text, ", "); + } + return Texts(text, ")"); } case OptionalType: { type_t *opt = Match(t, OptionalType)->type; @@ -102,8 +103,6 @@ Text_t type_to_text(type_t *t) { } } -const char *type_to_str(type_t *t) { return Text$as_c_string(type_to_text(t)); } - PUREFUNC const char *get_type_name(type_t *t) { switch (t->tag) { case TextType: return Match(t, TextType)->lang; diff --git a/src/types.h b/src/types.h index 5b5c4fb9..24c4e621 100644 --- a/src/types.h +++ b/src/types.h @@ -139,7 +139,6 @@ struct type_s { _make_function_type(ret, sizeof((arg_t[]){__VA_ARGS__}) / sizeof(arg_t), (arg_t[]){__VA_ARGS__}) Text_t type_to_text(type_t *t); -const char *type_to_str(type_t *t); const char *get_type_name(type_t *t); PUREFUNC bool type_eq(type_t *a, type_t *b); PUREFUNC bool type_is_a(type_t *t, type_t *req); -- cgit v1.2.3