code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(1.9K lines)
1 // Logic for getting a type from an AST node
2 #include <ctype.h>
3 #include <gc.h>
4 #include <glob.h>
5 #include <stdarg.h>
6 #include <string.h>
7 #include <sys/stat.h>
9 #include "ast.h"
10 #include "config.h"
11 #include "environment.h"
12 #include "naming.h"
13 #include "packages.h"
14 #include "parse/files.h"
15 #include "parse/types.h"
16 #include "stdlib/optionals.h"
17 #include "stdlib/paths.h"
18 #include "stdlib/tables.h"
19 #include "stdlib/text.h"
20 #include "stdlib/util.h"
21 #include "typecheck.h"
22 #include "types.h"
24 type_t *parse_type_ast(env_t *env, type_ast_t *ast) {
25 #ifdef __GNUC__
26 #pragma GCC diagnostic push
27 #pragma GCC diagnostic ignored "-Wswitch-default"
28 #endif
29 switch (ast->tag) {
30 case VarTypeAST: {
31 const char *name = Match(ast, VarTypeAST)->name;
32 type_t *t = Table$str_get(*env->types, name);
33 if (t) return t;
34 while (strchr(name, '.')) {
35 char *module_name = GC_strndup(name, strcspn(name, "."));
36 binding_t *b = get_binding(env, module_name);
37 if (!b || b->type->tag != ModuleType)
38 code_err(ast, "I don't know a module with the name '", module_name, "'");
40 env_t *imported = Table$str_get(*env->imports, Match(b->type, ModuleType)->name);
41 assert(imported);
42 env = imported;
43 name = strchr(name, '.') + 1;
44 t = Table$str_get(*env->types, name);
45 if (t) return t;
47 code_err(ast, "I don't know a type with the name '", name, "'");
49 case PointerTypeAST: {
50 DeclareMatch(ptr, ast, PointerTypeAST);
51 type_t *pointed_t = parse_type_ast(env, ptr->pointed);
52 if (pointed_t->tag == VoidType)
53 code_err(ast, "Void pointers are not supported. You probably meant 'Memory' instead of 'Void'");
54 return Type(PointerType, .pointed = pointed_t, .is_stack = ptr->is_stack);
56 case ListTypeAST: {
57 type_ast_t *item_type = Match(ast, ListTypeAST)->item;
58 type_t *item_t = parse_type_ast(env, item_type);
59 if (!item_t) code_err(item_type, "I can't figure out what this type is.");
60 if (has_stack_memory(item_t))
61 code_err(item_type, "Lists can't have stack references because the list may outlive the stack frame.");
62 if (type_size(item_t) > LIST_MAX_STRIDE)
63 code_err(ast, "This list holds items that take up ", (uint64_t)type_size(item_t),
64 " bytes, but the maximum supported size is ", (int64_t)LIST_MAX_STRIDE,
65 " bytes. Consider using a list of pointers instead.");
66 return Type(ListType, .item_type = item_t);
68 case TableTypeAST: {
69 DeclareMatch(table_type, ast, TableTypeAST);
70 type_ast_t *key_type_ast = table_type->key;
71 type_t *key_type = parse_type_ast(env, key_type_ast);
72 if (!key_type) code_err(key_type_ast, "I can't figure out what type this is.");
73 if (has_stack_memory(key_type))
74 code_err(key_type_ast, "Tables can't have stack references because the list may outlive the stack frame.");
76 type_t *val_type = table_type->value ? parse_type_ast(env, table_type->value) : PRESENT_TYPE;
77 if (!val_type) code_err(ast, "I can't figure out what the value type for this entry is.");
79 if (table_type->value && has_stack_memory(val_type))
80 code_err(table_type->value,
81 "Tables can't have stack references because the list may outlive the stack frame.");
82 else if (table_type->value && val_type->tag == OptionalType)
83 code_err(ast, "Tables with optional-typed values are not currently supported");
85 return Type(TableType, .key_type = key_type, .value_type = val_type, .env = env,
86 .default_value = table_type->default_value);
88 case FunctionTypeAST: {
89 DeclareMatch(fn, ast, FunctionTypeAST);
90 type_t *ret_t = fn->ret ? parse_type_ast(env, fn->ret) : Type(VoidType);
91 if (fn->ret && has_stack_memory(ret_t))
92 code_err(fn->ret, "Functions are not allowed to return stack references, because the reference may no "
93 "longer exist on the stack.");
94 arg_t *type_args = NULL;
95 for (arg_ast_t *arg = fn->args; arg; arg = arg->next) {
96 type_args = new (arg_t, .name = arg->name, .alias = arg->alias, .comment = arg->comment, .next = type_args);
97 if (arg->type) type_args->type = parse_type_ast(env, arg->type);
98 else if (arg->value) type_args->type = get_type(env, arg->value);
100 if (arg->value) type_args->default_val = arg->value;
102 REVERSE_LIST(type_args);
103 return Type(ClosureType, Type(FunctionType, .args = type_args, .ret = ret_t));
105 case OptionalTypeAST: {
106 DeclareMatch(opt, ast, OptionalTypeAST);
107 type_t *t = parse_type_ast(env, opt->type);
108 if (t->tag == VoidType || t->tag == AbortType || t->tag == ReturnType)
109 code_err(ast, "Optional ", type_to_text(t), " types are not supported.");
110 else if (t->tag == OptionalType) code_err(ast, "Nested optional types are not currently supported");
111 return Type(OptionalType, .type = t);
113 case EnumTypeAST: {
114 const char *enum_name = Text$as_c_string(Match(ast, EnumTypeAST)->name);
115 type_t *cached = Table$str_get(*env->types, enum_name);
116 if (cached) return cached;
118 tag_ast_t *tag_asts = Match(ast, EnumTypeAST)->tags;
119 tag_t *tags = NULL;
120 int64_t tag_value = 1;
121 env_t *ns_env = namespace_env(env, enum_name);
123 type_t *enum_type = Type(EnumType, .name = enum_name, .env = ns_env, .tags = NULL);
125 Table$str_set(env->types, enum_name, enum_type);
127 for (tag_ast_t *tag_ast = tag_asts; tag_ast; tag_ast = tag_ast->next) {
128 arg_t *fields = NULL;
129 for (arg_ast_t *field_ast = tag_ast->fields; field_ast; field_ast = field_ast->next) {
130 type_t *field_type =
131 field_ast->type ? parse_type_ast(env, field_ast->type) : get_type(env, field_ast->value);
132 fields = new (arg_t, .name = field_ast->name, .type = field_type, .default_val = field_ast->value,
133 .alias = field_ast->alias, .comment = field_ast->comment, .next = fields);
135 REVERSE_LIST(fields);
136 const char *struct_name = String(enum_name, "$", tag_ast->name);
137 env_t *struct_env = namespace_env(env, struct_name);
138 type_t *tag_type = Type(StructType, .name = tag_ast->name, .fields = fields, .env = struct_env);
139 tags = new (tag_t, .name = tag_ast->name, .tag_value = tag_value, .type = tag_type, .next = tags);
141 if (Match(tag_type, StructType)->fields) { // Constructor:
142 type_t *constructor_t =
143 Type(FunctionType, .args = Match(tag_type, StructType)->fields, .ret = enum_type);
144 Text_t tagged_name = namespace_name(env, env->namespace, Texts(enum_name, "$tagged$", tag_ast->name));
145 set_binding(ns_env, tag_ast->name, constructor_t, tagged_name);
146 binding_t binding = {.type = constructor_t, .code = tagged_name};
147 List$insert(&ns_env->namespace->constructors, &binding, I(1), sizeof(binding));
148 } else { // Empty singleton value:
149 Text_t code =
150 Texts("((", namespace_name(env, env->namespace, Texts(enum_name, "$$type")), "){",
151 namespace_name(env, env->namespace, Texts(enum_name, "$tag$", tag_ast->name)), "})");
152 set_binding(ns_env, tag_ast->name, enum_type, code);
154 Table$str_set(env->types, String(enum_name, "$", tag_ast->name), tag_type);
156 tag_value += 1;
158 REVERSE_LIST(tags);
159 enum_type->__data.EnumType.tags = tags;
160 return enum_type;
162 case UnknownTypeAST: code_err(ast, "I don't know how to get this type");
164 #ifdef __GNUC__
165 #pragma GCC diagnostic pop
166 #endif
167 errx(1, "Unreachable");
168 return NULL;
171 // static PUREFUNC bool risks_zero_or_inf(ast_t *ast)
172 // {
173 // switch (ast->tag) {
174 // case Int: {
175 // const char *str = Match(ast, Int)->str;
176 // OptionalInt_t int_val = Int$from_str(str);
177 // return (int_val.small == 0x1); // zero
178 // }
179 // case Num: {
180 // return Match(ast, Num)->n == 0.0;
181 // }
182 // case BINOP_CASES: {
183 // binary_operands_t binop = BINARY_OPERANDS(ast);
184 // if (ast->tag == Multiply || ast->tag == Divide || ast->tag == Min || ast->tag == Max)
185 // return risks_zero_or_inf(binop.lhs) || risks_zero_or_inf(binop.rhs);
186 // else
187 // return true;
188 // }
189 // default: return true;
190 // }
191 // }
193 PUREFUNC type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t) {
194 (void)env;
195 switch (compare_precision(lhs_t, rhs_t)) {
196 case NUM_PRECISION_EQUAL:
197 case NUM_PRECISION_MORE: return lhs_t;
198 case NUM_PRECISION_LESS: return rhs_t;
199 default:
200 code_err(ast, "Math operations between ", type_to_text(lhs_t), " and ", type_to_text(rhs_t),
201 " are not supported");
203 return NULL;
206 static env_t *load_module(env_t *env, ast_t *use_ast) {
207 DeclareMatch(use, use_ast, Use);
208 switch (use->what) {
209 case USE_LOCAL: {
210 Path_t source_path = Path$from_str(use_ast->file->filename);
211 Path_t source_dir = Path$parent(source_path);
212 Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
214 if (!Path$exists(used_path)) code_err(use_ast, "No such file exists: ", quoted(use->path));
216 env_t *module_env = Table$str_get(*env->imports, String(used_path));
217 if (module_env) return module_env;
219 ast_t *ast = parse_file(String(used_path), NULL);
220 if (!ast) print_err("Could not compile file ", used_path);
221 return load_module_env(env, ast);
223 case USE_PACKAGE: {
224 OptionalPath_t installed = find_installed_package(use_ast);
225 assert(installed);
226 Text_t name = get_package_name(installed);
227 env_t *module_env = fresh_scope(env);
228 Table$str_set(env->imports, Text$as_c_string(name), module_env);
229 List_t children = Path$glob(Path$child(installed, Text("/[!._0-9]*.tm")));
230 for (int64_t i = 0; i < (int64_t)children.length; i++) {
231 Path_t child = *(Path_t *)(children.data + i * children.stride);
232 ast_t *ast = parse_file(child, NULL);
233 if (!ast) print_err("Could not compile file ", child);
234 env_t *module_file_env = fresh_scope(module_env);
235 module_file_env->namespace = NULL;
236 env_t *subenv = load_module_env(module_file_env, ast);
237 for (int64_t j = 0; j < (int64_t)subenv->locals->entries.length; j++) {
238 struct {
239 const char *name;
240 binding_t *binding;
241 } *entry = subenv->locals->entries.data + j * subenv->locals->entries.stride;
242 Table$str_set(module_env->locals, entry->name, entry->binding);
245 return module_env;
247 default: return NULL;
251 void prebind_statement(env_t *env, ast_t *statement) {
252 switch (statement->tag) {
253 case DebugLog: {
254 for (ast_list_t *value = Match(statement, DebugLog)->values; value; value = value->next)
255 prebind_statement(env, value->ast);
256 break;
258 case Assert: {
259 prebind_statement(env, Match(statement, Assert)->expr);
260 break;
262 case StructDef: {
263 DeclareMatch(def, statement, StructDef);
264 if (get_binding(env, def->name))
265 code_err(statement, "A ", type_to_text(get_binding(env, def->name)->type), " called ", quoted(def->name),
266 " has already been defined");
268 env_t *ns_env = namespace_env(env, def->name);
269 type_t *type = Type(StructType, .name = def->name, .opaque = true, .external = def->external,
270 .env = ns_env); // placeholder
271 Table$str_set(env->types, def->name, type);
272 set_binding(env, def->name, Type(TypeInfoType, .name = def->name, .type = type, .env = ns_env),
273 namespace_name(env, env->namespace, Texts(def->name, "$$info")));
274 for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
275 stmt = stmt->next)
276 prebind_statement(ns_env, stmt->ast);
277 break;
279 case EnumDef: {
280 DeclareMatch(def, statement, EnumDef);
281 if (get_binding(env, def->name))
282 code_err(statement, "A ", type_to_text(get_binding(env, def->name)->type), " called ", quoted(def->name),
283 " has already been defined");
285 env_t *ns_env = namespace_env(env, def->name);
286 type_t *type = Type(EnumType, .name = def->name, .opaque = true, .env = ns_env); // placeholder
287 Table$str_set(env->types, def->name, type);
288 set_binding(env, def->name, Type(TypeInfoType, .name = def->name, .type = type, .env = ns_env),
289 namespace_name(env, env->namespace, Texts(def->name, "$$info")));
290 for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
291 stmt = stmt->next)
292 prebind_statement(ns_env, stmt->ast);
293 break;
295 case LangDef: {
296 DeclareMatch(def, statement, LangDef);
297 if (get_binding(env, def->name))
298 code_err(statement, "A ", type_to_text(get_binding(env, def->name)->type), " called ", quoted(def->name),
299 " has already been defined");
301 env_t *ns_env = namespace_env(env, def->name);
302 type_t *type = Type(TextType, .lang = def->name, .env = ns_env);
303 Table$str_set(env->types, def->name, type);
304 set_binding(env, def->name, Type(TypeInfoType, .name = def->name, .type = type, .env = ns_env),
305 namespace_name(env, env->namespace, Texts(def->name, "$$info")));
306 for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
307 stmt = stmt->next)
308 prebind_statement(ns_env, stmt->ast);
309 break;
311 default: break;
315 void bind_statement(env_t *env, ast_t *statement) {
316 switch (statement->tag) {
317 case DebugLog: {
318 for (ast_list_t *value = Match(statement, DebugLog)->values; value; value = value->next)
319 bind_statement(env, value->ast);
320 break;
322 case Assert: {
323 bind_statement(env, Match(statement, Assert)->expr);
324 break;
326 case Declare: {
327 DeclareMatch(decl, statement, Declare);
328 const char *name = Match(decl->var, Var)->name;
329 if (streq(name, "_")) // Explicit discard
330 return;
331 if (get_binding(env, name))
332 code_err(decl->var, "A ", type_to_text(get_binding(env, name)->type), " called ", quoted(name),
333 " has already been defined");
334 if (decl->value) bind_statement(env, decl->value);
335 type_t *type = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
336 if (!type) code_err(statement, "I couldn't figure out the type of this value");
337 if (type->tag == FunctionType) type = Type(ClosureType, type);
338 Text_t code;
339 if (name[0] != '_' && (env->namespace || decl->top_level))
340 code = namespace_name(env, env->namespace, Text$from_str(name));
341 else code = Texts("_$", name);
342 set_binding(env, name, type, code);
343 break;
345 case FunctionDef: {
346 DeclareMatch(def, statement, FunctionDef);
347 const char *name = Match(def->name, Var)->name;
348 type_t *type = get_function_type(env, statement);
349 set_binding(env, name, type, namespace_name(env, env->namespace, Text$from_str(name)));
350 break;
352 case ConvertDef: {
353 type_t *type = get_function_type(env, statement);
354 type_t *ret_t = Match(type, FunctionType)->ret;
355 const char *name = get_type_name(ret_t);
356 if (!name)
357 code_err(statement, "Conversions are only supported for text, struct, and enum types, not ",
358 type_to_text(ret_t));
360 Text_t code =
361 namespace_name(env, env->namespace, Texts(name, "$", get_line_number(statement->file, statement->start)));
362 binding_t binding = {.type = type, .code = code};
363 env_t *type_ns = get_namespace_by_type(env, ret_t);
364 List$insert(&type_ns->namespace->constructors, &binding, I(0), sizeof(binding));
365 break;
367 case StructDef: {
368 DeclareMatch(def, statement, StructDef);
369 env_t *ns_env = namespace_env(env, def->name);
370 type_t *type = Table$str_get(*env->types, def->name);
371 if (!type) code_err(statement, "Couldn't find type!");
372 assert(type);
373 ns_env->current_type = type;
374 if (!def->opaque) {
375 arg_t *fields = NULL;
376 for (arg_ast_t *field_ast = def->fields; field_ast; field_ast = field_ast->next) {
377 type_t *field_t = get_arg_ast_type(env, field_ast);
378 type_t *non_opt_field_t = field_t->tag == OptionalType ? Match(field_t, OptionalType)->type : field_t;
379 if ((non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->opaque)
380 || (non_opt_field_t->tag == EnumType && Match(non_opt_field_t, EnumType)->opaque)) {
382 file_t *file = NULL;
383 const char *start = NULL, *end = NULL;
384 if (field_ast->type) {
385 file = field_ast->type->file, start = field_ast->type->start, end = field_ast->type->end;
386 } else if (field_ast->value) {
387 file = field_ast->value->file, start = field_ast->value->start, end = field_ast->value->end;
389 if (non_opt_field_t == type)
390 compiler_err(file, start, end,
391 "This is a recursive struct that would be infinitely large. Maybe you meant to "
392 "use an optional '@",
393 type_to_text(type), "?' pointer instead?");
394 else if (non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->external)
395 compiler_err(
396 file, start, end,
397 "This is an opaque externally defined struct.\n"
398 "I can't use it as a member without knowing what its fields are.\n"
399 "Either specify its fields and remove the `opaque` qualifier, or use something like a @",
400 type_to_text(non_opt_field_t), " pointer.");
401 else
402 compiler_err(file, start, end, "I'm still in the process of defining the fields of ",
403 type_to_text(field_t),
404 ", so I don't know how to use it as a member."
405 "\nTry using a @",
406 type_to_text(field_t), " pointer for this field.");
408 fields = new (arg_t, .name = field_ast->name, .alias = field_ast->alias, .type = field_t,
409 .comment = field_ast->comment, .default_val = field_ast->value, .next = fields);
411 REVERSE_LIST(fields);
412 type->__data.StructType.fields = fields; // populate placeholder
413 type->__data.StructType.opaque = false;
416 for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
417 stmt = stmt->next)
418 bind_statement(ns_env, stmt->ast);
419 break;
421 case EnumDef: {
422 DeclareMatch(def, statement, EnumDef);
423 env_t *ns_env = namespace_env(env, def->name);
424 type_t *type = Table$str_get(*env->types, def->name);
425 assert(type);
426 ns_env->current_type = type;
427 tag_t *tags = NULL;
428 int64_t next_tag = 1;
429 for (tag_ast_t *tag_ast = def->tags; tag_ast; tag_ast = tag_ast->next) {
430 arg_t *fields = NULL;
431 for (arg_ast_t *field_ast = tag_ast->fields; field_ast; field_ast = field_ast->next) {
432 type_t *field_t = get_arg_ast_type(env, field_ast);
433 type_t *non_opt_field_t = field_t->tag == OptionalType ? Match(field_t, OptionalType)->type : field_t;
434 if ((non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->opaque)
435 || (non_opt_field_t->tag == EnumType && Match(non_opt_field_t, EnumType)->opaque)) {
436 file_t *file = NULL;
437 const char *start = NULL, *end = NULL;
438 if (field_ast->type) {
439 file = field_ast->type->file, start = field_ast->type->start, end = field_ast->type->end;
440 } else if (field_ast->value) {
441 file = field_ast->value->file, start = field_ast->value->start, end = field_ast->value->end;
443 if (non_opt_field_t == type)
444 compiler_err(file, start, end,
445 "This is a recursive enum that would be infinitely large. Maybe you meant to use "
446 "an optional '@",
447 type_to_text(type), "?' pointer instead?");
448 else if (non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->external)
449 compiler_err(
450 file, start, end,
451 "This is an opaque externally defined struct.\n"
452 "I can't use it as a member without knowing what its fields are.\n"
453 "Either specify its fields and remove the `opaque` qualifier, or use something like a @",
454 type_to_text(non_opt_field_t), " pointer.");
455 else
456 compiler_err(file, start, end, "I'm still in the process of defining the fields of ",
457 type_to_text(field_t),
458 ", so I don't know how to use it as a member."
459 "\nTry using a @",
460 type_to_text(field_t), " pointer for this field.");
462 fields = new (arg_t, .name = field_ast->name, .alias = field_ast->alias, .type = field_t,
463 .comment = field_ast->comment, .default_val = field_ast->value, .next = fields);
465 REVERSE_LIST(fields);
466 env_t *member_ns = namespace_env(env, String(def->name, "$", tag_ast->name));
467 type_t *tag_type =
468 Type(StructType, .name = String(def->name, "$", tag_ast->name), .fields = fields, .env = member_ns);
469 tags = new (tag_t, .name = tag_ast->name, .tag_value = (next_tag++), .type = tag_type, .next = tags);
471 REVERSE_LIST(tags);
472 type->__data.EnumType.tags = tags;
473 type->__data.EnumType.opaque = false;
475 for (tag_t *tag = tags; tag; tag = tag->next) {
476 if (Match(tag->type, StructType)->fields) { // Constructor:
477 type_t *constructor_t = Type(FunctionType, .args = Match(tag->type, StructType)->fields, .ret = type);
478 Text_t tagged_name = namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name));
479 set_binding(ns_env, tag->name, constructor_t, tagged_name);
480 binding_t binding = {.type = constructor_t, .code = tagged_name};
481 List$insert(&ns_env->namespace->constructors, &binding, I(1), sizeof(binding));
482 } else { // Empty singleton value:
483 Text_t code = Texts("((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), "){",
484 namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)), "})");
485 set_binding(ns_env, tag->name, type, code);
487 Table$str_set(env->types, String(def->name, "$", tag->name), tag->type);
490 for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
491 stmt = stmt->next) {
492 bind_statement(ns_env, stmt->ast);
494 break;
496 case LangDef: {
497 DeclareMatch(def, statement, LangDef);
498 env_t *ns_env = namespace_env(env, def->name);
499 type_t *type = Type(TextType, .lang = def->name, .env = ns_env);
500 ns_env->current_type = type;
501 Table$str_set(env->types, def->name, type);
503 set_binding(ns_env, "from_text", NewFunctionType(type, {.name = "text", .type = TEXT_TYPE}),
504 Texts("(", namespace_name(env, env->namespace, Texts(def->name, "$$type")), ")"));
506 for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
507 stmt = stmt->next)
508 bind_statement(ns_env, stmt->ast);
509 break;
511 case Use: {
512 env_t *module_env = load_module(env, statement);
513 if (!module_env) break;
514 for (Table_t *bindings = module_env->locals; bindings != module_env->globals; bindings = bindings->fallback) {
515 List_t entries = bindings->entries;
516 for (int64_t i = 0; i < (int64_t)entries.length; i++) {
517 struct {
518 const char *name;
519 binding_t *binding;
520 } *entry = entries.data + entries.stride * i;
521 if (entry->name[0] == '_' || streq(entry->name, "main")) continue;
522 binding_t *b = Table$str_get(*env->locals, entry->name);
523 if (!b) Table$str_set(env->locals, entry->name, entry->binding);
524 else if (b != entry->binding)
525 code_err(statement, "This module imports a symbol called '", entry->name,
526 "', which would clobber another variable");
529 for (int64_t i = 0; i < (int64_t)module_env->types->entries.length; i++) {
530 struct {
531 const char *name;
532 type_t *type;
533 } *entry = module_env->types->entries.data + module_env->types->entries.stride * i;
534 if (entry->name[0] == '_') continue;
535 if (Table$str_get(*env->types, entry->name)) continue;
537 Table$str_set(env->types, entry->name, entry->type);
540 ast_t *var = Match(statement, Use)->var;
541 if (var) {
542 type_t *type = get_type(env, statement);
543 assert(type);
544 set_binding(env, Match(var, Var)->name, type, EMPTY_TEXT);
546 break;
548 default: break;
552 type_t *get_function_type(env_t *env, ast_t *ast) {
553 arg_ast_t *arg_asts;
554 type_ast_t *ret_ast;
555 switch (ast->tag) {
556 case FunctionDef:
557 arg_asts = Match(ast, FunctionDef)->args;
558 ret_ast = Match(ast, FunctionDef)->ret_type;
559 break;
560 case ConvertDef:
561 arg_asts = Match(ast, ConvertDef)->args;
562 ret_ast = Match(ast, ConvertDef)->ret_type;
563 break;
564 case Lambda:
565 arg_asts = Match(ast, Lambda)->args;
566 ret_ast = Match(ast, Lambda)->ret_type;
567 break;
568 default: code_err(ast, "This was expected to be a function definition of some sort");
570 arg_t *args = NULL;
571 env_t *scope = fresh_scope(env);
572 for (arg_ast_t *arg = arg_asts; arg; arg = arg->next) {
573 type_t *t = arg->type ? parse_type_ast(env, arg->type) : get_type(env, arg->value);
574 args = new (arg_t, .name = arg->name, .alias = arg->alias, .comment = arg->comment, .type = t,
575 .default_val = arg->value, .next = args);
576 set_binding(scope, arg->name, t, EMPTY_TEXT);
578 REVERSE_LIST(args);
580 if (ast->tag == Lambda) {
581 ast_t *body = Match(ast, Lambda)->body;
583 scope->fn = NULL;
584 type_t *ret_t = get_type(scope, body);
585 if (ret_t->tag == ReturnType) ret_t = Match(ret_t, ReturnType)->ret;
586 if (ret_t->tag == AbortType) ret_t = Type(VoidType);
588 if (ret_t->tag == OptionalType && !Match(ret_t, OptionalType)->type)
589 code_err(body, "This function doesn't return a specific optional type");
591 if (ret_ast) {
592 type_t *declared = parse_type_ast(env, ret_ast);
593 if (can_promote(ret_t, declared)) ret_t = declared;
594 else
595 code_err(ast, "This function was declared to return a value of type ", type_to_text(declared),
596 ", but actually returns a value of type ", type_to_text(ret_t));
599 if (has_stack_memory(ret_t))
600 code_err(ast, "Functions can't return stack references because the reference may outlive its stack frame.");
601 return Type(ClosureType, Type(FunctionType, .args = args, .ret = ret_t));
602 } else {
603 type_t *ret_t = ret_ast ? parse_type_ast(scope, ret_ast) : Type(VoidType);
604 if (has_stack_memory(ret_t))
605 code_err(ast, "Functions can't return stack references because the reference may outlive its stack frame.");
606 return Type(FunctionType, .args = args, .ret = ret_t);
610 type_t *get_function_return_type(env_t *env, ast_t *ast) {
611 type_t *fn_t = get_function_type(env, ast);
612 if (fn_t->tag == ClosureType) fn_t = Match(fn_t, ClosureType)->fn;
613 return Match(fn_t, FunctionType)->ret;
616 type_t *get_method_type(env_t *env, ast_t *self, const char *name) {
617 binding_t *b = get_namespace_binding(env, self, name);
618 if (!b || !b->type) {
619 OptionalText_t suggestion = suggest_best_name(name, get_method_names(env, get_type(env, self)));
620 code_err(self, "No such method: ", type_to_text(get_type(env, self)), ".", name, "(...)", suggestion);
622 return b->type;
625 env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) {
626 if (clause->pattern->tag == Var || subject_t->tag != EnumType) return env;
628 if (clause->pattern->tag != FunctionCall || Match(clause->pattern, FunctionCall)->fn->tag != Var)
629 code_err(clause->pattern, "I only support variables and constructors for pattern matching ",
630 type_to_text(subject_t), " types in a 'when' block");
632 DeclareMatch(fn, clause->pattern, FunctionCall);
633 const char *tag_name = Match(fn->fn, Var)->name;
634 type_t *tag_type = NULL;
635 tag_t *const tags = Match(subject_t, EnumType)->tags;
636 for (tag_t *tag = tags; tag; tag = tag->next) {
637 if (streq(tag->name, tag_name)) {
638 tag_type = tag->type;
639 break;
643 if (!tag_type)
644 code_err(clause->pattern, "There is no tag ", quoted(tag_name), " for the type ", type_to_text(subject_t));
646 if (!fn->args) return env;
648 env_t *scope = fresh_scope(env);
649 DeclareMatch(tag_struct, tag_type, StructType);
650 if (fn->args && !fn->args->next && tag_struct->fields && tag_struct->fields->next) {
651 if (fn->args->value->tag != Var) code_err(fn->args->value, "I expected a variable here");
652 set_binding(scope, Match(fn->args->value, Var)->name, tag_type, EMPTY_TEXT);
653 return scope;
656 arg_t *field = tag_struct->fields;
657 for (arg_ast_t *var = fn->args; var || field; var = var ? var->next : var) {
658 if (!var)
659 code_err(clause->pattern, "The field ", type_to_text(subject_t), ".", tag_name, ".", field->name,
660 " wasn't accounted for");
661 if (!field) code_err(var->value, "This is one more field than ", type_to_text(subject_t), " has");
662 if (var->value->tag != Var)
663 code_err(var->value, "I expected this to be a plain variable so I could bind it to a value");
664 if (!streq(Match(var->value, Var)->name, "_"))
665 set_binding(scope, Match(var->value, Var)->name, field->type, EMPTY_TEXT);
666 field = field->next;
668 return scope;
671 type_t *get_clause_type(env_t *env, type_t *subject_t, when_clause_t *clause) {
672 env_t *scope = when_clause_scope(env, subject_t, clause);
673 return get_type(scope, clause->body);
676 type_t *get_type(env_t *env, ast_t *ast) {
677 if (!ast) return NULL;
678 #ifdef __GNUC__
679 #pragma GCC diagnostic push
680 #pragma GCC diagnostic ignored "-Wswitch-default"
681 #endif
682 switch (ast->tag) {
683 case None: {
684 return Type(OptionalType, .type = NULL);
686 case Bool: {
687 return Type(BoolType);
689 case Int: {
690 return Type(BigIntType);
692 case Num: {
693 return Type(NumType, .bits = TYPE_NBITS64);
695 case HeapAllocate: {
696 type_t *pointed = get_type(env, Match(ast, HeapAllocate)->value);
697 if (has_stack_memory(pointed))
698 code_err(ast, "Stack references cannot be moved to the heap because they may outlive the stack frame they "
699 "were created in.");
700 return Type(PointerType, .pointed = pointed);
702 case StackReference: {
703 // Supported:
704 // &variable
705 // &struct_variable.field.(...)
706 // &struct_ptr.field.(...)
707 // &[10, 20, 30]; &{key:value}; &{10, 20, 30}
708 // &Foo(...)
709 // &(expression)
710 // Not supported:
711 // &ptr[]
712 // &list[index]
713 // &table[key]
714 // &(expression).field
715 // &optional_struct_ptr.field
716 ast_t *value = Match(ast, StackReference)->value;
717 switch (value->tag) {
718 case FieldAccess: {
719 ast_t *base = value;
720 while (base->tag == FieldAccess)
721 base = Match(base, FieldAccess)->fielded;
723 type_t *ref_type = get_type(env, value);
724 type_t *base_type = get_type(env, base);
725 if (base_type->tag == OptionalType) {
726 code_err(base, "This value might be none, so it can't be safely dereferenced");
727 } else if (base_type->tag == PointerType) {
728 DeclareMatch(ptr, base_type, PointerType);
729 return Type(PointerType, .pointed = ref_type, .is_stack = ptr->is_stack);
730 } else if (base->tag == Var) {
731 return Type(PointerType, .pointed = ref_type, .is_stack = true);
733 code_err(ast, "'&' stack references can only be used on the fields of pointers and local variables");
735 case Index: code_err(ast, "'&' stack references are not supported for list or table indexing");
736 default: return Type(PointerType, .pointed = get_type(env, value), .is_stack = true);
739 case NonOptional: {
740 ast_t *value = Match(ast, NonOptional)->value;
741 type_t *t = value_type(get_type(env, value));
742 if (t->tag == EnumType) {
743 tag_t *first_tag = Match(t, EnumType)->tags;
744 if (!first_tag) code_err(ast, "'!' cannot be used on an empty enum");
745 return first_tag->type;
747 if (t->tag != OptionalType)
748 code_err(value, "This value is not optional. Only optional values can use the '!' operator.");
749 return Match(t, OptionalType)->type;
751 case TextLiteral: return TEXT_TYPE;
752 case Path: return PATH_TYPE;
753 case TextJoin: {
754 const char *lang = Match(ast, TextJoin)->lang;
755 if (lang) {
756 binding_t *b = get_binding(env, lang);
757 if (!b || b->type->tag != TypeInfoType || Match(b->type, TypeInfoType)->type->tag != TextType)
758 code_err(ast, "There is no text language called '", lang, "'");
759 return Match(b->type, TypeInfoType)->type;
760 } else {
761 return TEXT_TYPE;
764 case Var: {
765 DeclareMatch(var, ast, Var);
766 binding_t *b = get_binding(env, var->name);
767 if (b) return b->type;
768 List_t candidates = EMPTY_LIST;
769 for (Table_t *scope = env->locals; scope; scope = scope->fallback) {
770 for (int64_t i = 0; i < (int64_t)scope->entries.length; i++) {
771 struct {
772 const char *key;
773 binding_t *value;
774 } *entry = (scope->entries.data + i * scope->entries.stride);
775 Text_t name = Text$from_str(entry->key);
776 List$insert(&candidates, &name, I(0), sizeof(Text_t));
779 OptionalText_t suggestion = suggest_best_name(var->name, candidates);
780 code_err(ast, "I don't know what ", quoted(var->name), " refers to", suggestion);
782 case List: {
783 DeclareMatch(list, ast, List);
784 type_t *item_type = NULL;
785 for (ast_list_t *item = list->items; item; item = item->next) {
786 ast_t *item_ast = item->ast;
787 env_t *scope = env;
788 while (item_ast->tag == Comprehension) {
789 DeclareMatch(comp, item_ast, Comprehension);
790 scope = for_scope(scope, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
791 item_ast = comp->expr;
793 type_t *t2 = get_type(scope, item_ast);
794 type_t *merged = item_type ? type_or_type(item_type, t2) : t2;
795 if (!merged) return Type(ListType, .item_type = NULL);
796 item_type = merged;
799 if (item_type && has_stack_memory(item_type))
800 code_err(ast, "Lists cannot hold stack references, because the list may outlive the stack frame the "
801 "reference was created in.");
803 return Type(ListType, .item_type = item_type);
805 case Table: {
806 DeclareMatch(table, ast, Table);
807 type_t *key_type = NULL, *value_type = NULL;
808 bool ambiguous_key_type = false, ambiguous_value_type = false;
809 for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
810 ast_t *entry_ast = entry->ast;
811 env_t *scope = env;
812 while (entry_ast->tag == Comprehension) {
813 DeclareMatch(comp, entry_ast, Comprehension);
814 scope = for_scope(scope, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
815 entry_ast = comp->expr;
818 DeclareMatch(e, entry_ast, TableEntry);
819 type_t *key_t = get_type(scope, e->key);
820 type_t *value_t = e->value ? get_type(scope, e->value) : PRESENT_TYPE;
822 type_t *key_merged = key_type ? type_or_type(key_type, key_t) : key_t;
823 if (!key_merged) ambiguous_key_type = true;
824 key_type = key_merged;
826 type_t *val_merged = value_type ? type_or_type(value_type, value_t) : value_t;
827 if (!val_merged) ambiguous_value_type = true;
828 value_type = val_merged;
831 if (ambiguous_key_type) key_type = NULL;
833 if (ambiguous_value_type) value_type = NULL;
835 if ((key_type && has_stack_memory(key_type)) || (value_type && has_stack_memory(value_type)))
836 code_err(ast,
837 "Tables cannot hold stack references because the table may outlive the reference's stack frame.");
839 return Type(TableType, .key_type = key_type, .value_type = value_type, .default_value = table->default_value,
840 .env = env);
842 case TableEntry: {
843 code_err(ast, "Table entries should not be typechecked directly");
845 case Comprehension: {
846 DeclareMatch(comp, ast, Comprehension);
847 env_t *scope = for_scope(env, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
848 if (comp->expr->tag == Comprehension) {
849 return get_type(scope, comp->expr);
850 } else if (comp->expr->tag == TableEntry) {
851 DeclareMatch(e, comp->expr, TableEntry);
852 return Type(TableType, .key_type = get_type(scope, e->key),
853 .value_type = e->value ? get_type(scope, e->value) : PRESENT_TYPE, .env = env);
854 } else {
855 return Type(ListType, .item_type = get_type(scope, comp->expr));
858 case FieldAccess: {
859 DeclareMatch(access, ast, FieldAccess);
860 type_t *fielded_t = get_type(env, access->fielded);
861 if (fielded_t->tag == ModuleType) {
862 const char *name = Match(fielded_t, ModuleType)->name;
863 env_t *module_env = Table$str_get(*env->imports, name);
864 if (!module_env) code_err(access->fielded, "I couldn't find the environment for the module ", name);
865 return get_type(module_env, WrapAST(ast, Var, access->field));
866 } else if (fielded_t->tag == TypeInfoType) {
867 DeclareMatch(info, fielded_t, TypeInfoType);
868 assert(info->env);
869 binding_t *b = get_binding(info->env, access->field);
870 if (!b) code_err(ast, "I couldn't find the field '", access->field, "' on this type");
871 return b->type;
873 type_t *field_t = get_field_type(fielded_t, access->field);
874 if (!field_t) {
875 OptionalText_t suggestion = suggest_best_name(access->field, get_field_names(env, fielded_t));
876 code_err(ast, type_to_text(fielded_t), " objects don't have a field called '", access->field, "'",
877 suggestion);
879 return field_t;
881 case Index: {
882 DeclareMatch(indexing, ast, Index);
883 type_t *indexed_t = get_type(env, indexing->indexed);
884 if (indexed_t->tag == OptionalType && !indexing->index)
885 code_err(ast, "You're attempting to dereference a value whose type indicates it could be none");
887 if (indexed_t->tag == PointerType && !indexing->index) return Match(indexed_t, PointerType)->pointed;
889 type_t *value_t = value_type(indexed_t);
890 if (value_t->tag == ListType) {
891 if (!indexing->index) return indexed_t;
892 type_t *index_t = get_type(env, indexing->index);
893 if (index_t->tag == IntType || index_t->tag == BigIntType || index_t->tag == ByteType) {
894 type_t *item_type = Match(value_t, ListType)->item_type;
895 return item_type->tag == OptionalType ? item_type : Type(OptionalType, item_type);
897 code_err(indexing->index, "I only know how to index lists using integers, not ", type_to_text(index_t));
898 } else if (value_t->tag == TableType) {
899 DeclareMatch(table_type, value_t, TableType);
900 if (table_type->default_value) return table_type->value_type;
901 return Type(OptionalType, table_type->value_type);
902 } else if (value_t->tag == TextType) {
903 return Type(OptionalType, value_t);
904 } else {
905 code_err(ast, "I don't know how to index ", type_to_text(indexed_t), " values");
908 case FunctionCall: {
909 DeclareMatch(call, ast, FunctionCall);
910 type_t *fn_type_t = get_type(env, call->fn);
911 if (!fn_type_t) code_err(call->fn, "I couldn't find this function");
913 if (fn_type_t->tag == TypeInfoType) {
914 type_t *t = Match(fn_type_t, TypeInfoType)->type;
916 binding_t *constructor =
917 get_constructor(env, t, call->args, env->current_type != NULL && type_eq(env->current_type, t));
918 if (constructor) return t;
919 else if (t->tag == StructType || t->tag == IntType || t->tag == BigIntType || t->tag == NumType
920 || t->tag == ByteType || t->tag == TextType || t->tag == CStringType)
921 return t; // Constructor
922 arg_t *arg_types = NULL;
923 for (arg_ast_t *arg = call->args; arg; arg = arg->next)
924 arg_types = new (arg_t, .type = get_type(env, arg->value), .name = arg->name, .alias = arg->alias,
925 .comment = arg->comment, .next = arg_types);
926 REVERSE_LIST(arg_types);
927 code_err(call->fn, "I couldn't find a type constructor for ",
928 type_to_text(Type(FunctionType, .args = arg_types, .ret = t)));
930 if (fn_type_t->tag == ClosureType) fn_type_t = Match(fn_type_t, ClosureType)->fn;
931 if (fn_type_t->tag != FunctionType)
932 code_err(call->fn, "This isn't a function, it's a ", type_to_text(fn_type_t));
933 DeclareMatch(fn_type, fn_type_t, FunctionType);
934 return fn_type->ret;
936 case MethodCall: {
937 DeclareMatch(call, ast, MethodCall);
938 type_t *self_value_t = get_type(env, call->self);
939 if (!self_value_t) code_err(call->self, "Couldn't get the type of this value");
940 self_value_t = value_type(self_value_t);
942 if (self_value_t->tag == TypeInfoType || self_value_t->tag == ModuleType) {
943 return get_type(env,
944 WrapAST(ast, FunctionCall,
945 .fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
946 .args = call->args));
949 switch (self_value_t->tag) {
950 case ListType: {
951 type_t *item_type = Match(self_value_t, ListType)->item_type;
952 if (streq(call->name, "binary_search")) return INT_TYPE;
953 else if (streq(call->name, "by")) return self_value_t;
954 else if (streq(call->name, "clear")) return Type(VoidType);
955 else if (streq(call->name, "counts")) return Type(TableType, .key_type = item_type, .value_type = INT_TYPE);
956 else if (streq(call->name, "find")) return Type(OptionalType, .type = INT_TYPE);
957 else if (streq(call->name, "where")) return Type(OptionalType, .type = INT_TYPE);
958 else if (streq(call->name, "from")) return self_value_t;
959 else if (streq(call->name, "has")) return Type(BoolType);
960 else if (streq(call->name, "heap_pop")) return Type(OptionalType, .type = item_type);
961 else if (streq(call->name, "heap_push")) return Type(VoidType);
962 else if (streq(call->name, "heapify")) return Type(VoidType);
963 else if (streq(call->name, "insert")) return Type(VoidType);
964 else if (streq(call->name, "insert_all")) return Type(VoidType);
965 else if (streq(call->name, "pop")) return Type(OptionalType, .type = item_type);
966 else if (streq(call->name, "random")) return Type(OptionalType, .type = item_type);
967 else if (streq(call->name, "remove_at")) return Type(VoidType);
968 else if (streq(call->name, "remove_item")) return Type(VoidType);
969 else if (streq(call->name, "reversed")) return self_value_t;
970 else if (streq(call->name, "sample")) return self_value_t;
971 else if (streq(call->name, "shuffle")) return Type(VoidType);
972 else if (streq(call->name, "shuffled")) return self_value_t;
973 else if (streq(call->name, "slice")) return self_value_t;
974 else if (streq(call->name, "sort")) return Type(VoidType);
975 else if (streq(call->name, "sorted")) return self_value_t;
976 else if (streq(call->name, "to")) return self_value_t;
977 else if (streq(call->name, "unique"))
978 return Type(TableType, .key_type = item_type, .value_type = PRESENT_TYPE);
980 OptionalText_t suggestion = suggest_best_name(call->name, get_method_names(env, self_value_t));
981 code_err(ast, "There is no '", call->name, "' method for lists", suggestion);
983 case TableType: {
984 DeclareMatch(table, self_value_t, TableType);
985 if (streq(call->name, "clear")) return Type(VoidType);
986 else if (streq(call->name, "get")) return Type(OptionalType, .type = table->value_type);
987 else if (streq(call->name, "get_or_set")) return table->value_type;
988 else if (streq(call->name, "has")) return Type(BoolType);
989 else if (streq(call->name, "remove")) return Type(VoidType);
990 else if (streq(call->name, "set")) return Type(VoidType);
991 else if (streq(call->name, "sorted")) return self_value_t;
992 else if (streq(call->name, "with_fallback")) return self_value_t;
993 else if (streq(call->name, "without")) return self_value_t;
994 else if (streq(call->name, "intersection")) return self_value_t;
995 else if (streq(call->name, "difference")) return self_value_t;
996 else if (streq(call->name, "with")) return self_value_t;
998 OptionalText_t suggestion = suggest_best_name(call->name, get_method_names(env, self_value_t));
999 code_err(ast, "There is no '", call->name, "' method for ", type_to_text(self_value_t), " tables",
1000 suggestion);
1002 default: {
1003 if (call->name[0] == '_') {
1004 if (env->current_type == NULL || !type_eq(env->current_type, self_value_t))
1005 code_err(ast, "You can't call private methods starting with underscore (like '", call->name,
1006 "') outside of the place where the type (", type_to_text(self_value_t), ") is defined.");
1008 type_t *field_type = get_field_type(self_value_t, call->name);
1009 if (field_type && field_type->tag == ClosureType) field_type = Match(field_type, ClosureType)->fn;
1010 if (field_type && field_type->tag == FunctionType) return Match(field_type, FunctionType)->ret;
1011 type_t *fn_type_t = get_method_type(env, call->self, call->name);
1012 if (!fn_type_t) {
1013 OptionalText_t suggestion = suggest_best_name(call->name, get_method_names(env, self_value_t));
1014 code_err(ast, "No such method!", suggestion);
1016 if (fn_type_t->tag != FunctionType) code_err(ast, "This isn't a method, it's a ", type_to_text(fn_type_t));
1017 DeclareMatch(fn_type, fn_type_t, FunctionType);
1018 return fn_type->ret;
1022 case Block: {
1023 DeclareMatch(block, ast, Block);
1024 ast_list_t *last = block->statements;
1025 if (!last) return Type(VoidType);
1026 while (last->next)
1027 last = last->next;
1029 // Early out if the type is knowable without any context from the block:
1030 switch (last->ast->tag) {
1031 case UPDATE_CASES:
1032 case Assign:
1033 case Declare:
1034 case FunctionDef:
1035 case ConvertDef:
1036 case StructDef:
1037 case EnumDef:
1038 case LangDef: return Type(VoidType);
1039 default: break;
1042 env_t *block_env = fresh_scope(env);
1043 for (ast_list_t *stmt = block->statements; stmt; stmt = stmt->next) {
1044 prebind_statement(block_env, stmt->ast);
1046 for (ast_list_t *stmt = block->statements; stmt; stmt = stmt->next) {
1047 bind_statement(block_env, stmt->ast);
1048 if (stmt->next) { // Check for unreachable code:
1049 if (stmt->ast->tag == Return)
1050 code_err(
1051 stmt->ast,
1052 "This statement will always return, so the rest of the code in this block is unreachable!");
1053 type_t *statement_type = get_type(block_env, stmt->ast);
1054 if (statement_type && statement_type->tag == AbortType && stmt->next)
1055 code_err(stmt->ast,
1056 "This statement will always abort, so the rest of the code in this block is unreachable!");
1059 return get_type(block_env, last->ast);
1061 case Declare:
1062 case Assign:
1063 case UPDATE_CASES:
1064 case DebugLog:
1065 case Assert: {
1066 return Type(VoidType);
1068 case Use: {
1069 switch (Match(ast, Use)->what) {
1070 case USE_LOCAL: {
1071 Path_t source_path = Path$from_str(ast->file->filename);
1072 Path_t source_dir = Path$parent(source_path);
1073 Path_t used_path = Path$resolved(Path$from_str(Match(ast, Use)->path), source_dir);
1074 return Type(ModuleType, Path$as_c_string(used_path));
1076 default: return Type(ModuleType, Match(ast, Use)->path);
1079 case Return: {
1080 ast_t *val = Match(ast, Return)->value;
1081 if (env->fn && (env->fn->tag != Lambda || Match(env->fn, Lambda)->ret_type != NULL)) {
1082 type_t *ret_type = get_function_return_type(env, env->fn);
1083 env = with_enum_scope(env, ret_type);
1085 return Type(ReturnType, .ret = (val ? get_type(env, val) : Type(VoidType)));
1087 case Stop:
1088 case Skip: {
1089 return Type(AbortType);
1091 case Pass:
1092 case Defer: return Type(VoidType);
1093 case Negative: {
1094 ast_t *value = Match(ast, Negative)->value;
1095 type_t *t = get_type(env, value);
1096 if (t->tag == IntType || t->tag == NumType) return t;
1098 binding_t *b = get_namespace_binding(env, value, "negative");
1099 if (b && b->type->tag == FunctionType) {
1100 DeclareMatch(fn, b->type, FunctionType);
1101 if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret)) return t;
1104 code_err(ast, "I don't know how to get the negative value of type ", type_to_text(t));
1106 case Not: {
1107 type_t *t = get_type(env, Match(ast, Not)->value);
1108 if (t->tag == IntType || t->tag == NumType || t->tag == BoolType) return t;
1109 if (t->tag == OptionalType) return Type(BoolType);
1111 ast_t *value = Match(ast, Not)->value;
1112 binding_t *b = get_namespace_binding(env, value, "negated");
1113 if (b && b->type->tag == FunctionType) {
1114 DeclareMatch(fn, b->type, FunctionType);
1115 if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret)) return t;
1117 code_err(ast, "I only know how to get 'not' of boolean, numeric, and optional pointer types, not ",
1118 type_to_text(t));
1120 case Or: {
1121 binary_operands_t binop = BINARY_OPERANDS(ast);
1122 type_t *lhs_t = get_type(env, binop.lhs);
1123 type_t *rhs_t = get_type(env, binop.rhs);
1125 if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t;
1126 else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t;
1128 // `opt? or (x == y)` / `(x == y) or opt?` is a boolean conditional:
1129 if ((lhs_t->tag == OptionalType && rhs_t->tag == BoolType)
1130 || (lhs_t->tag == BoolType && rhs_t->tag == OptionalType)) {
1131 return Type(BoolType);
1134 if (type_eq(lhs_t, rhs_t)) {
1135 binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, lhs_t);
1136 if (b) return lhs_t;
1139 if (lhs_t->tag == OptionalType) {
1140 if (rhs_t->tag == OptionalType) {
1141 type_t *result = most_complete_type(lhs_t, rhs_t);
1142 if (result == NULL)
1143 code_err(ast, "I could not determine the type of ", type_to_text(lhs_t), " `or` ",
1144 type_to_text(rhs_t));
1145 return result;
1146 } else if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) {
1147 return Match(lhs_t, OptionalType)->type;
1149 type_t *non_opt = Match(lhs_t, OptionalType)->type;
1150 non_opt = most_complete_type(non_opt, rhs_t);
1151 if (non_opt != NULL) return non_opt;
1152 } else if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType)
1153 && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType) && lhs_t->tag != NumType
1154 && rhs_t->tag != NumType) {
1155 if (can_compile_to_type(env, binop.rhs, lhs_t)) return lhs_t;
1156 else if (can_compile_to_type(env, binop.lhs, rhs_t)) return rhs_t;
1157 } else if (lhs_t->tag == TableType && rhs_t->tag == TableType && type_eq(lhs_t, rhs_t)) {
1158 return lhs_t;
1160 code_err(ast, "I couldn't figure out how to do `or` between ", type_to_text(lhs_t), " and ",
1161 type_to_text(rhs_t));
1163 case And: {
1164 binary_operands_t binop = BINARY_OPERANDS(ast);
1165 type_t *lhs_t = get_type(env, binop.lhs);
1166 type_t *rhs_t = get_type(env, binop.rhs);
1168 if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t;
1169 else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t;
1171 // `and` between optionals/bools is a boolean expression like `if opt? and opt?:` or `if x > 0 and opt?:`
1172 if ((lhs_t->tag == OptionalType || lhs_t->tag == BoolType)
1173 && (rhs_t->tag == OptionalType || rhs_t->tag == BoolType)) {
1174 return Type(BoolType);
1177 if (type_eq(lhs_t, rhs_t)) {
1178 binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, lhs_t);
1179 if (b) return lhs_t;
1182 // Bitwise AND:
1183 if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType) && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
1184 && lhs_t->tag != NumType && rhs_t->tag != NumType) {
1185 if (can_compile_to_type(env, binop.rhs, lhs_t)) return lhs_t;
1186 else if (can_compile_to_type(env, binop.lhs, rhs_t)) return rhs_t;
1187 } else if (lhs_t->tag == TableType && rhs_t->tag == TableType && type_eq(lhs_t, rhs_t)) {
1188 return lhs_t;
1190 code_err(ast, "I couldn't figure out how to do `and` between ", type_to_text(lhs_t), " and ",
1191 type_to_text(rhs_t));
1193 case Xor: {
1194 binary_operands_t binop = BINARY_OPERANDS(ast);
1195 type_t *lhs_t = get_type(env, binop.lhs);
1196 type_t *rhs_t = get_type(env, binop.rhs);
1198 if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t;
1199 else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t;
1201 // `xor` between optionals/bools is a boolean expression like `if opt? xor opt?:` or `if x > 0 xor opt?:`
1202 if ((lhs_t->tag == OptionalType || lhs_t->tag == BoolType)
1203 && (rhs_t->tag == OptionalType || rhs_t->tag == BoolType)) {
1204 return Type(BoolType);
1207 if (type_eq(lhs_t, rhs_t)) {
1208 binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, lhs_t);
1209 if (b) return lhs_t;
1212 // Bitwise XOR:
1213 if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType) && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
1214 && lhs_t->tag != NumType && rhs_t->tag != NumType) {
1215 if (can_compile_to_type(env, binop.rhs, lhs_t)) return lhs_t;
1216 else if (can_compile_to_type(env, binop.lhs, rhs_t)) return rhs_t;
1217 } else if (lhs_t->tag == TableType && rhs_t->tag == TableType && type_eq(lhs_t, rhs_t)) {
1218 return lhs_t;
1220 code_err(ast, "I couldn't figure out how to do `xor` between ", type_to_text(lhs_t), " and ",
1221 type_to_text(rhs_t));
1223 case Compare:
1224 case Equals:
1225 case NotEquals:
1226 case LessThan:
1227 case LessThanOrEquals:
1228 case GreaterThan:
1229 case GreaterThanOrEquals: {
1230 binary_operands_t binop = BINARY_OPERANDS(ast);
1231 type_t *lhs_t = get_type(env, binop.lhs);
1232 type_t *rhs_t = get_type(env, binop.rhs);
1233 if (type_eq(lhs_t, rhs_t)) return ast->tag == Compare ? Type(IntType, .bits = TYPE_IBITS32) : Type(BoolType);
1235 if ((binop.lhs->tag == Int && is_numeric_type(rhs_t)) || (binop.rhs->tag == Int && is_numeric_type(lhs_t))
1236 || can_compile_to_type(env, binop.rhs, lhs_t) || can_compile_to_type(env, binop.lhs, rhs_t))
1237 return ast->tag == Compare ? Type(IntType, .bits = TYPE_IBITS32) : Type(BoolType);
1239 code_err(ast, "I don't know how to compare ", type_to_text(lhs_t), " and ", type_to_text(rhs_t));
1241 case Power:
1242 case Multiply:
1243 case Divide:
1244 case Mod:
1245 case Mod1:
1246 case Plus:
1247 case Minus:
1248 case LeftShift:
1249 case UnsignedLeftShift:
1250 case RightShift:
1251 case UnsignedRightShift: {
1252 binary_operands_t binop = BINARY_OPERANDS(ast);
1253 type_t *lhs_t = get_type(env, binop.lhs);
1254 type_t *rhs_t = get_type(env, binop.rhs);
1256 if (ast->tag == LeftShift || ast->tag == UnsignedLeftShift || ast->tag == RightShift
1257 || ast->tag == UnsignedRightShift) {
1258 if (!is_int_type(rhs_t))
1259 code_err(binop.rhs, "I only know how to do bit shifting by integer amounts, not ", type_to_text(rhs_t));
1262 if (is_numeric_type(lhs_t) && binop.rhs->tag == Int) {
1263 return lhs_t;
1264 } else if (is_numeric_type(rhs_t) && binop.lhs->tag == Int) {
1265 return rhs_t;
1266 } else {
1267 switch (compare_precision(lhs_t, rhs_t)) {
1268 case NUM_PRECISION_LESS: return rhs_t;
1269 case NUM_PRECISION_MORE: return lhs_t;
1270 case NUM_PRECISION_EQUAL: return lhs_t;
1271 default: {
1272 if (can_compile_to_type(env, binop.rhs, lhs_t)) {
1273 return lhs_t;
1274 } else if (can_compile_to_type(env, binop.lhs, rhs_t)) {
1275 return rhs_t;
1277 break;
1282 if (ast->tag == Multiply && is_numeric_type(lhs_t)) {
1283 binding_t *b = get_namespace_binding(env, binop.rhs, "scaled_by");
1284 if (b && b->type->tag == FunctionType) {
1285 DeclareMatch(fn, b->type, FunctionType);
1286 if (type_eq(fn->ret, rhs_t)) {
1287 arg_ast_t *args = new (arg_ast_t, .value = binop.rhs, .next = new (arg_ast_t, .value = binop.lhs));
1288 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true})) return rhs_t;
1291 } else if (ast->tag == Multiply && is_numeric_type(rhs_t)) {
1292 binding_t *b = get_namespace_binding(env, binop.lhs, "scaled_by");
1293 if (b && b->type->tag == FunctionType) {
1294 DeclareMatch(fn, b->type, FunctionType);
1295 if (type_eq(fn->ret, lhs_t)) {
1296 arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
1297 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true})) return lhs_t;
1300 } else if ((ast->tag == Divide || ast->tag == Mod || ast->tag == Mod1) && is_numeric_type(rhs_t)) {
1301 binding_t *b = get_namespace_binding(env, binop.lhs, binop_info[ast->tag].method_name);
1302 if (b && b->type->tag == FunctionType) {
1303 DeclareMatch(fn, b->type, FunctionType);
1304 if (type_eq(fn->ret, lhs_t)) {
1305 arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
1306 if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true})) return lhs_t;
1311 type_t *overall_t =
1312 (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t
1313 : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL));
1314 if (overall_t == NULL)
1315 code_err(ast, "I don't know how to do math operations between ", type_to_text(lhs_t), " and ",
1316 type_to_text(rhs_t));
1318 binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
1319 if (b) return overall_t;
1321 if (is_numeric_type(lhs_t) && is_numeric_type(rhs_t)) return overall_t;
1323 code_err(ast, "I don't know how to do math operations between ", type_to_text(lhs_t), " and ",
1324 type_to_text(rhs_t));
1326 case Concat: {
1327 binary_operands_t binop = BINARY_OPERANDS(ast);
1328 type_t *lhs_t = get_type(env, binop.lhs);
1329 type_t *rhs_t = get_type(env, binop.rhs);
1331 type_t *overall_t =
1332 (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t
1333 : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL));
1334 if (overall_t == NULL)
1335 code_err(ast, "I don't know how to do operations between ", type_to_text(lhs_t), " and ",
1336 type_to_text(rhs_t));
1338 binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
1339 if (b) return overall_t;
1341 if (overall_t->tag == ListType || overall_t->tag == TableType || overall_t->tag == TextType) return overall_t;
1343 code_err(ast, "I don't know how to do concatenation between ", type_to_text(lhs_t), " and ",
1344 type_to_text(rhs_t));
1347 case Reduction: {
1348 DeclareMatch(reduction, ast, Reduction);
1349 type_t *iter_t = get_type(env, reduction->iter);
1351 if (reduction->op == Equals || reduction->op == NotEquals || reduction->op == LessThan
1352 || reduction->op == LessThanOrEquals || reduction->op == GreaterThan
1353 || reduction->op == GreaterThanOrEquals)
1354 return Type(OptionalType, .type = Type(BoolType));
1356 type_t *iterated = get_iterated_type(iter_t);
1357 if (!iterated)
1358 code_err(reduction->iter, "I don't know how to do a reduction over ", type_to_text(iter_t), " values");
1359 if (reduction->key && !(reduction->op == Min || reduction->op == Max)) {
1360 env_t *item_scope = fresh_scope(env);
1361 const char *op_str = binop_info[reduction->op].operator;
1362 set_binding(item_scope, op_str, iterated, EMPTY_TEXT);
1363 iterated = get_type(item_scope, reduction->key);
1365 return iterated->tag == OptionalType ? iterated : Type(OptionalType, .type = iterated);
1368 case Min:
1369 case Max: {
1370 // Unsafe! These types *should* have the same fields and this saves a lot of duplicate code:
1371 ast_t *lhs = ast->__data.Min.lhs, *rhs = ast->__data.Min.rhs;
1372 // Okay safe again
1374 type_t *lhs_t = get_type(env, lhs), *rhs_t = get_type(env, rhs);
1375 type_t *t = type_or_type(lhs_t, rhs_t);
1376 if (!t)
1377 code_err(ast, "The two sides of this operation are not compatible: ", type_to_text(lhs_t), " vs ",
1378 type_to_text(rhs_t));
1379 return t;
1382 case Lambda: return get_function_type(env, ast);
1384 case FunctionDef:
1385 case ConvertDef:
1386 case StructDef:
1387 case EnumDef:
1388 case LangDef: return Type(VoidType);
1390 case If: {
1391 DeclareMatch(if_, ast, If);
1393 env_t *truthy_scope = env;
1394 env_t *falsey_scope = env;
1395 if (if_->condition->tag == Declare) {
1396 DeclareMatch(decl, if_->condition, Declare);
1397 type_t *condition_type = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
1398 const char *varname = Match(decl->var, Var)->name;
1399 if (streq(varname, "_"))
1400 code_err(if_->condition, "To use `if var := ...:`, you must choose a real variable name, not `_`");
1402 truthy_scope = fresh_scope(env);
1403 if (condition_type->tag == OptionalType)
1404 set_binding(truthy_scope, varname, Match(condition_type, OptionalType)->type, EMPTY_TEXT);
1405 else set_binding(truthy_scope, varname, condition_type, EMPTY_TEXT);
1406 } else if (if_->condition->tag == Var) {
1407 type_t *condition_type = get_type(env, if_->condition);
1408 if (condition_type->tag == OptionalType) {
1409 truthy_scope = fresh_scope(env);
1410 const char *varname = Match(if_->condition, Var)->name;
1411 set_binding(truthy_scope, varname, Match(condition_type, OptionalType)->type, EMPTY_TEXT);
1415 type_t *true_t = get_type(truthy_scope, if_->body);
1416 ast_t *else_body = if_->else_body;
1417 if (!else_body) {
1418 if (true_t->tag == AbortType) return Type(VoidType);
1419 else_body = WrapAST(ast, None, .type = true_t);
1421 type_t *false_t = get_type(falsey_scope, if_->else_body);
1422 type_t *t_either = type_or_type(true_t, false_t);
1423 if (!t_either)
1424 code_err(if_->else_body, "I was expecting this block to have a ", type_to_text(true_t),
1425 " value (based on earlier clauses), but it actually has a ", type_to_text(false_t), " value.");
1426 return t_either;
1429 case When: {
1430 DeclareMatch(when, ast, When);
1431 type_t *subject_t = get_type(env, when->subject);
1432 if (subject_t->tag != EnumType) {
1433 type_t *t = NULL;
1434 for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
1435 t = type_or_type(t, get_type(env, clause->body));
1437 if (when->else_body) t = type_or_type(t, get_type(env, when->else_body));
1438 else if (t && t->tag != OptionalType) t = Type(OptionalType, .type = t);
1439 return t;
1442 type_t *overall_t = NULL;
1443 tag_t *const tags = Match(subject_t, EnumType)->tags;
1445 typedef struct match_s {
1446 tag_t *tag;
1447 bool handled;
1448 struct match_s *next;
1449 } match_t;
1450 match_t *matches = NULL;
1451 for (tag_t *tag = tags; tag; tag = tag->next)
1452 matches = new (match_t, .tag = tag, .handled = false, .next = matches);
1454 for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
1455 const char *tag_name;
1456 if (clause->pattern->tag == Var) tag_name = Match(clause->pattern, Var)->name;
1457 else if (clause->pattern->tag == FunctionCall && Match(clause->pattern, FunctionCall)->fn->tag == Var)
1458 tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
1459 else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_text(subject_t), " enum");
1461 Text_t valid_tags = EMPTY_TEXT;
1462 for (match_t *m = matches; m; m = m->next) {
1463 if (streq(m->tag->name, tag_name)) {
1464 if (m->handled) code_err(clause->pattern, "This tag was already handled earlier");
1465 m->handled = true;
1466 goto found_matching_tag;
1468 if (valid_tags.length > 0) valid_tags = Texts(valid_tags, ", ");
1469 valid_tags = Texts(valid_tags, m->tag->name);
1472 code_err(clause->pattern, "There is no tag '", tag_name, "' for the type ", type_to_text(subject_t),
1473 " (valid tags: ", valid_tags, ")");
1474 found_matching_tag:;
1477 for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
1478 env_t *clause_scope = when_clause_scope(env, subject_t, clause);
1479 type_t *clause_type = get_type(clause_scope, clause->body);
1480 type_t *merged = type_or_type(overall_t, clause_type);
1481 if (!merged)
1482 code_err(clause->body, "The type of this branch is ", type_to_text(clause_type),
1483 ", which conflicts with the earlier branch type of ", type_to_text(overall_t));
1484 overall_t = merged;
1487 if (when->else_body) {
1488 bool any_unhandled = false;
1489 for (match_t *m = matches; m; m = m->next) {
1490 if (!m->handled) {
1491 any_unhandled = true;
1492 break;
1495 // HACK: `while when ...` is handled by the parser adding an implicit
1496 // `else: stop`, which has an empty source code span.
1497 if (!any_unhandled && when->else_body->end > when->else_body->start)
1498 code_err(when->else_body, "This 'else' block will never run because every tag is handled");
1500 type_t *else_t = get_type(env, when->else_body);
1501 type_t *merged = type_or_type(overall_t, else_t);
1502 if (!merged)
1503 code_err(when->else_body, "I was expecting this block to have a ", type_to_text(overall_t),
1504 " value (based on earlier clauses), but it actually has a ", type_to_text(else_t), " value.");
1505 return merged;
1506 } else {
1507 Text_t unhandled = EMPTY_TEXT;
1508 for (match_t *m = matches; m; m = m->next) {
1509 if (!m->handled)
1510 unhandled =
1511 unhandled.length > 0 ? Texts(unhandled, ", ", m->tag->name) : Text$from_str(m->tag->name);
1513 if (unhandled.length > 0) code_err(ast, "This 'when' statement doesn't handle the tags: ", unhandled);
1514 return overall_t;
1518 case While:
1519 case Repeat:
1520 case For: return Type(VoidType);
1521 case InlineCCode: {
1522 DeclareMatch(inline_code, ast, InlineCCode);
1523 if (inline_code->type) return inline_code->type;
1524 type_ast_t *type_ast = inline_code->type_ast;
1525 return type_ast ? parse_type_ast(env, type_ast) : Type(VoidType);
1527 case Unknown: code_err(ast, "I can't figure out the type of: ", ast_to_sexp_str(ast));
1528 case ExplicitlyTyped: return Match(ast, ExplicitlyTyped)->type;
1529 case Metadata: return Type(VoidType);
1531 #ifdef __GNUC__
1532 #pragma GCC diagnostic pop
1533 #endif
1534 code_err(ast, "I can't figure out the type of: ", ast_to_sexp_str(ast));
1535 return NULL;
1538 PUREFUNC bool is_discardable(env_t *env, ast_t *ast) {
1539 switch (ast->tag) {
1540 case UPDATE_CASES:
1541 case Assign:
1542 case Declare:
1543 case FunctionDef:
1544 case ConvertDef:
1545 case StructDef:
1546 case EnumDef:
1547 case LangDef:
1548 case Use:
1549 case Metadata: return true;
1550 default: break;
1552 return is_discardable_type(get_type(env, ast));
1555 type_t *get_arg_ast_type(env_t *env, arg_ast_t *arg) {
1556 assert(arg->type || arg->value);
1557 if (arg->type) return parse_type_ast(env, arg->type);
1558 return get_type(env, arg->value);
1561 type_t *get_arg_type(env_t *env, arg_t *arg) {
1562 assert(arg->type || arg->default_val);
1563 if (arg->type) return arg->type;
1564 return get_type(env, arg->default_val);
1567 bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, call_opts_t options) {
1568 Table_t used_args = EMPTY_TABLE;
1570 // Populate keyword args:
1571 for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
1572 if (!call_arg->name) continue;
1574 for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
1575 if (!(streq(call_arg->name, spec_arg->name) || (spec_arg->alias && streq(call_arg->name, spec_arg->alias))))
1576 continue;
1577 type_t *spec_type = get_arg_type(env, spec_arg);
1578 env_t *arg_scope = with_enum_scope(env, spec_type);
1579 type_t *call_type = get_arg_ast_type(arg_scope, call_arg);
1580 if (options.promotion) {
1581 if (!can_compile_to_type(arg_scope, call_arg->value, spec_type))
1582 return false; // Positional arg trying to fill in
1583 } else {
1584 type_t *complete_call_type =
1585 is_incomplete_type(call_type) ? most_complete_type(call_type, spec_type) : call_type;
1586 if (!complete_call_type) return false;
1587 if (!type_eq(complete_call_type, spec_type)) return false;
1589 Table$str_set(&used_args, call_arg->name, call_arg);
1590 goto next_call_arg;
1592 return false;
1593 next_call_arg:;
1596 arg_ast_t *unused_args = call_args;
1597 for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
1598 arg_ast_t *keyworded = Table$str_get(used_args, spec_arg->name);
1599 if (keyworded) continue;
1601 if (spec_arg->name[0] != '_' || options.underscores) {
1602 type_t *spec_type = get_arg_type(env, spec_arg);
1603 env_t *arg_scope = with_enum_scope(env, spec_type);
1604 for (; unused_args; unused_args = unused_args->next) {
1605 if (unused_args->name) continue; // Already handled the keyword args
1606 if (options.promotion) {
1607 if (!can_compile_to_type(arg_scope, unused_args->value, spec_type)) {
1608 return false; // Positional arg trying to fill in
1610 } else {
1611 type_t *call_type = get_arg_ast_type(arg_scope, unused_args);
1612 type_t *complete_call_type =
1613 is_incomplete_type(call_type) ? most_complete_type(call_type, spec_type) : call_type;
1614 if (!complete_call_type) return false;
1615 if (!type_eq(complete_call_type, spec_type)) return false; // Positional arg trying to fill in
1617 Table$str_set(&used_args, spec_arg->name, unused_args);
1618 unused_args = unused_args->next;
1619 goto found_it;
1623 if (spec_arg->default_val) goto found_it;
1625 return false;
1626 found_it:
1627 continue;
1630 while (unused_args && unused_args->name)
1631 unused_args = unused_args->next;
1633 return (unused_args == NULL);
1636 PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast) {
1637 switch (ast->tag) {
1638 case Var: return true;
1639 case InlineCCode: return true;
1640 case FieldAccess: {
1641 DeclareMatch(access, ast, FieldAccess);
1642 type_t *fielded_type = get_type(env, access->fielded);
1643 if (fielded_type->tag == PointerType) {
1644 type_t *val = value_type(fielded_type);
1645 return val->tag == StructType;
1646 } else if (fielded_type->tag == StructType) {
1647 return can_be_mutated(env, access->fielded);
1648 } else {
1649 return false;
1652 case Index: {
1653 DeclareMatch(index, ast, Index);
1654 type_t *indexed_type = get_type(env, index->indexed);
1655 return (indexed_type->tag == PointerType);
1657 default: return false;
1661 type_t *parse_type_string(env_t *env, const char *str) {
1662 type_ast_t *ast = parse_type_str(str);
1663 return ast ? parse_type_ast(env, ast) : NULL;
1666 PUREFUNC bool is_constant(env_t *env, ast_t *ast) {
1667 switch (ast->tag) {
1668 case Bool:
1669 case Num:
1670 case None: return true;
1671 case Int: {
1672 DeclareMatch(info, ast, Int);
1673 Int_t int_val = Int$parse(Text$from_str(info->str), NONE_INT, NULL);
1674 if (int_val.small == 0) return false; // Failed to parse
1675 return (Int$compare_value(int_val, I(BIGGEST_SMALL_INT)) <= 0);
1677 case TextJoin: {
1678 DeclareMatch(text, ast, TextJoin);
1679 if (!text->children) return true; // Empty string, OK
1680 if (text->children->next) return false; // Concatenation, not constant
1681 return is_constant(env, text->children->ast);
1683 case TextLiteral: {
1684 Text_t literal = Match(ast, TextLiteral)->text;
1685 TextIter_t state = NEW_TEXT_ITER_STATE(literal);
1686 for (int64_t i = 0; i < (int64_t)literal.length; i++) {
1687 int32_t g = Text$get_grapheme_fast(&state, i);
1688 if (g < 0 || g > 127 || !isascii(g)) return false;
1690 return true; // Literal ASCII string, OK
1692 case Not: return is_constant(env, Match(ast, Not)->value);
1693 case Negative: return is_constant(env, Match(ast, Negative)->value);
1694 case BINOP_CASES: {
1695 binary_operands_t binop = BINARY_OPERANDS(ast);
1696 switch (ast->tag) {
1697 case Power:
1698 case Concat:
1699 case Min:
1700 case Max:
1701 case Compare: return false;
1702 default: return is_constant(env, binop.lhs) && is_constant(env, binop.rhs);
1705 case Use:
1706 case Metadata: return true;
1707 case FunctionCall: return false;
1708 case InlineCCode: return true;
1709 default: return false;
1713 PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed) {
1714 if (is_incomplete_type(needed)) return false;
1716 if (needed->tag == OptionalType && ast->tag == None) return true;
1718 env = with_enum_scope(env, needed);
1719 if (is_numeric_type(needed) && ast->tag == Int) return true;
1720 if (needed->tag == NumType && ast->tag == Num) return true;
1722 type_t *non_optional_needed = non_optional(needed);
1723 if (non_optional_needed->tag == ListType && ast->tag == List) {
1724 type_t *item_type = Match(non_optional_needed, ListType)->item_type;
1725 for (ast_list_t *item = Match(ast, List)->items; item; item = item->next) {
1726 if (!can_compile_to_type(env, item->ast, item_type)) return false;
1728 return true;
1729 } else if (non_optional_needed->tag == TableType && ast->tag == Table) {
1730 type_t *key_type = Match(non_optional_needed, TableType)->key_type;
1731 type_t *value_type = Match(non_optional_needed, TableType)->value_type;
1732 for (ast_list_t *entry = Match(ast, Table)->entries; entry; entry = entry->next) {
1733 if (entry->ast->tag != TableEntry) continue; // TODO: fix this
1734 DeclareMatch(e, entry->ast, TableEntry);
1735 if (!can_compile_to_type(env, e->key, key_type)
1736 || !(e->value ? can_compile_to_type(env, e->value, value_type) : type_eq(value_type, PRESENT_TYPE)))
1737 return false;
1739 return true;
1742 type_t *actual = get_type(env, ast);
1743 if (type_eq(actual, needed)) return true;
1744 if (actual->tag == OptionalType && needed->tag == OptionalType) return can_promote(actual, needed);
1746 if (non_optional_needed->tag == PointerType) {
1747 DeclareMatch(ptr, non_optional_needed, PointerType);
1748 if (ast->tag == HeapAllocate)
1749 return !ptr->is_stack && can_compile_to_type(env, Match(ast, HeapAllocate)->value, ptr->pointed);
1750 else if (ast->tag == StackReference)
1751 return ptr->is_stack && can_compile_to_type(env, Match(ast, StackReference)->value, ptr->pointed);
1752 else return can_promote(actual, non_optional_needed);
1753 } else if (actual->tag == OptionalType && non_optional_needed->tag != OptionalType) {
1754 return false;
1755 } else {
1756 return can_promote(actual, non_optional_needed);
1760 OptionalText_t suggest_best_name(const char *wrong, List_t names) {
1761 if (names.length == 0) return NONE_TEXT;
1762 Text_t target = Text$from_str(wrong);
1763 Text_t best = *(Text_t *)names.data;
1764 Text_t lang = Text("C");
1765 double best_dist = Text$distance(target, best, lang);
1766 for (int64_t i = 1; i < (int64_t)names.length; i++) {
1767 Text_t text = *(Text_t *)(names.data + i * names.stride);
1768 double dist = Text$distance(target, text, lang);
1769 if (dist < best_dist) {
1770 best = text;
1771 best_dist = dist;
1775 // Too far away:
1776 if (best_dist > 6.0 || best_dist > 0.6 * (double)target.length || best_dist > 0.6 * (double)best.length)
1777 return NONE_TEXT;
1778 return Texts("\nDid you mean '", best, "'?");
1781 List_t get_field_names(env_t *env, type_t *t) {
1782 t = value_type(t);
1783 switch (t->tag) {
1784 case PointerType: return get_field_names(env, Match(t, PointerType)->pointed);
1785 case TextType: return List(Text("text"), Text("length"));
1786 case StructType: {
1787 DeclareMatch(struct_t, t, StructType);
1788 List_t fields = EMPTY_LIST;
1789 for (arg_t *field = struct_t->fields; field; field = field->next) {
1790 Text_t field_text = Text$from_str(field->name);
1791 List$insert(&fields, &field_text, I(0), sizeof(Text_t));
1793 return fields;
1795 case EnumType: {
1796 DeclareMatch(e, t, EnumType);
1797 List_t tags = EMPTY_LIST;
1798 for (tag_t *tag = e->tags; tag; tag = tag->next) {
1799 Text_t tag_text = Text$from_str(tag->name);
1800 List$insert(&tags, &tag_text, I(0), sizeof(Text_t));
1802 return tags;
1804 case TableType: return List(Text("length"), Text("keys"), Text("values"), Text("fallback"));
1805 case ListType: return List(Text("length"));
1806 default: {
1807 env_t *ns_env = get_namespace_by_type(env, t);
1808 List_t fields = EMPTY_LIST;
1809 for (int64_t i = 0; i < (int64_t)ns_env->locals->entries.length; i++) {
1810 struct {
1811 const char *key;
1812 binding_t *value;
1813 } *entry = (ns_env->locals->entries.data + i * ns_env->locals->entries.stride);
1814 if (entry->value->type->tag == FunctionType || entry->value->type->tag == ClosureType) continue;
1815 Text_t name = Text$from_str(entry->key);
1816 List$insert(&fields, &name, I(0), sizeof(Text_t));
1818 return fields;
1823 List_t get_method_names(env_t *env, type_t *t) {
1824 t = value_type(t);
1825 switch (t->tag) {
1826 case PointerType: return get_method_names(env, Match(t, PointerType)->pointed);
1827 case ListType: {
1828 return List(Text("binary_search"), Text("by"), Text("clear"), Text("counts"), Text("find"), Text("where"),
1829 Text("from"), Text("has"), Text("heap_pop"), Text("heap_push"), Text("heapify"), Text("insert"),
1830 Text("insert_all"), Text("pop"), Text("random"), Text("remove_at"), Text("remove_item"),
1831 Text("reversed"), Text("sample"), Text("shuffle"), Text("shuffled"), Text("slice"), Text("sort"),
1832 Text("sorted"), Text("to"), Text("unique"));
1834 case TableType: {
1835 return List(Text("clear"), Text("get"), Text("get_or_set"), Text("has"), Text("remove"), Text("set"),
1836 Text("sorted"), Text("with_fallback"), Text("without"), Text("intersection"), Text("difference"),
1837 Text("with"));
1839 default: {
1840 env_t *ns_env = get_namespace_by_type(env, t);
1841 List_t methods = EMPTY_LIST;
1842 for (int64_t i = 0; i < (int64_t)ns_env->locals->entries.length; i++) {
1843 struct {
1844 const char *key;
1845 binding_t *value;
1846 } *entry = (ns_env->locals->entries.data + i * ns_env->locals->entries.stride);
1847 if (entry->value->type->tag != FunctionType && entry->value->type->tag != ClosureType) continue;
1848 Text_t name = Text$from_str(entry->key);
1849 List$insert(&methods, &name, I(0), sizeof(Text_t));
1851 return methods;