diff options
| -rw-r--r-- | src/ast.c | 2 | ||||
| -rw-r--r-- | src/ast.h | 5 | ||||
| -rw-r--r-- | src/compile.c | 33 | ||||
| -rw-r--r-- | src/typecheck.c | 1 |
4 files changed, 41 insertions, 0 deletions
@@ -4,6 +4,7 @@ #include <stdarg.h> #include "ast.h" +#include "types.h" #include "stdlib/datatypes.h" #include "stdlib/integers.h" #include "stdlib/tables.h" @@ -193,6 +194,7 @@ CORD ast_to_xml(ast_t *ast) T(InlineCCode, "<InlineCode>%r</InlineCode>", xml_escape(data.code)) T(Deserialize, "<Deserialize><type>%r</type>%r</Deserialize>", type_ast_to_xml(data.type), ast_to_xml(data.value)) T(Extend, "<Extend name=\"%s\">%r</Extend>", data.name, ast_to_xml(data.body)) + T(ExplicitlyTyped, "<ExplicitlyTyped type=\"%r\">%r</ExplicitlyTyped>", type_to_cord(data.type), ast_to_xml(data.ast)) default: return "???"; #undef T } @@ -150,6 +150,7 @@ typedef enum { InlineCCode, Deserialize, Extend, + ExplicitlyTyped, } ast_e; struct ast_s { @@ -338,6 +339,10 @@ struct ast_s { const char *name; ast_t *body; } Extend; + struct { + ast_t *ast; + struct type_s *type; + } ExplicitlyTyped; } __data; }; diff --git a/src/compile.c b/src/compile.c index 20afec7a..ad3097a7 100644 --- a/src/compile.c +++ b/src/compile.c @@ -450,6 +450,10 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, Deserialize)->value); break; } + case ExplicitlyTyped: { + add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, ExplicitlyTyped)->ast); + break; + } case Use: case FunctionDef: case ConvertDef: case StructDef: case EnumDef: case LangDef: case Extend: { errx(1, "Definitions should not be reachable in a closure."); } @@ -2014,6 +2018,32 @@ CORD compile_to_type(env_t *env, ast_t *ast, type_t *t) type_t *actual = get_type(env, ast); + // Edge case: there are some situations where a method call needs to have + // the `self` value get compiled to a specific type that can't be fully + // inferred from the expression itself. We can infer what the specific type + // should be from what we know the specific type of the return value is, + // but it requires a bit of special logic. + // For example: + // x : [Int?] = [none]:sorted() + // Here, we know that `[none]` is `[Int?]`, but we need to thread that + // information through the compiler using an `ExplicitlyTyped` node. + if (ast->tag == MethodCall) { + auto methodcall = Match(ast, MethodCall); + type_t *self_type = get_type(env, methodcall->self); + // Currently, this is only implemented for cases where you have the return type + // and the self type equal to each other, because that's the main case I care + // about with array and set methods (e.g. `Array.sorted()`) + if (is_incomplete_type(self_type) && type_eq(self_type, actual)) { + type_t *completed_self = most_complete_type(self_type, t); + if (completed_self) { + ast_t *explicit_self = WrapAST(methodcall->self, ExplicitlyTyped, .ast=methodcall->self, .type=completed_self); + ast_t *new_methodcall = WrapAST(ast, MethodCall, .self=explicit_self, + .name=methodcall->name, .args=methodcall->args); + return compile_to_type(env, new_methodcall, t); + } + } + } + // Promote values to views-of-values if needed: if (t->tag == PointerType && Match(t, PointerType)->is_stack && actual->tag != PointerType) return CORD_all("stack(", compile_to_type(env, ast, Match(t, PointerType)->pointed), ")"); @@ -3316,6 +3346,9 @@ CORD compile(env_t *env, ast_t *ast) "generic_deserialize(", compile(env, value), ", &deserialized, ", compile_type_info(t), ");\n" "deserialized; })"); } + case ExplicitlyTyped: { + return compile_to_type(env, Match(ast, ExplicitlyTyped)->ast, get_type(env, ast)); + } case When: { auto original = Match(ast, When); ast_t *when_var = WrapAST(ast, Var, .name="when"); diff --git a/src/typecheck.c b/src/typecheck.c index aee96234..c6f8b10f 100644 --- a/src/typecheck.c +++ b/src/typecheck.c @@ -1482,6 +1482,7 @@ type_t *get_type(env_t *env, ast_t *ast) } case Unknown: code_err(ast, "I can't figure out the type of: ", ast_to_xml_str(ast)); case Deserialize: return parse_type_ast(env, Match(ast, Deserialize)->type); + case ExplicitlyTyped: return Match(ast, ExplicitlyTyped)->type; } #ifdef __GNUC__ #pragma GCC diagnostic pop |
