aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-04-03 15:40:57 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-04-03 15:40:57 -0400
commit8ab991fba503f446c70f877969e4314d0cc7d2f3 (patch)
tree77bc0cf33af92de8dea4ad0965518d8dee79bb5e
parent8d173710fe8cfd96bd54f9dd1cf0eccacfdd6e73 (diff)
Allow using an untyped empty array/set/table literal for places where
the expected type is known
-rw-r--r--src/compile.c18
-rw-r--r--src/parse.c13
-rw-r--r--src/typecheck.c12
3 files changed, 31 insertions, 12 deletions
diff --git a/src/compile.c b/src/compile.c
index 6c3b51fd..bf6f0b7f 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -866,6 +866,7 @@ static CORD _compile_statement(env_t *env, ast_t *ast)
return compile_statement(env, WrapAST(ast, DocTest, .expr=decl->value, .expected=test->expected, .skip_source=test->skip_source));
CORD var = CORD_all("_$", Match(decl->var, Var)->name);
type_t *t = get_type(env, decl->value);
+ if (!t) code_err(decl->value, "I couldn't figure out the type of this value!");
CORD val_code = compile_maybe_incref(env, decl->value, t);
if (t->tag == FunctionType) {
assert(promote(env, decl->value, &val_code, t, Type(ClosureType, t)));
@@ -1840,6 +1841,16 @@ CORD compile_to_type(env_t *env, ast_t *ast, type_t *t)
}
} else if (ast->tag == None && Match(ast, None)->type == NULL) {
return compile_none(t);
+ } else if (t->tag == ArrayType && ast->tag == Array && !Match(ast, Array)->item_type && !Match(ast, Array)->items) {
+ return compile(env, ast);
+ } else if (t->tag == TableType && ast->tag == Table) {
+ auto table = Match(ast, Table);
+ if (!table->key_type && !table->value_type && !table->default_value && !table->fallback && !table->entries)
+ return compile(env, ast);
+ } else if (t->tag == SetType && ast->tag == Set) {
+ auto set = Match(ast, Set);
+ if (!set->item_type && !set->items)
+ return compile(env, ast);
}
type_t *actual = get_type(env, ast);
@@ -2695,13 +2706,13 @@ CORD compile(env_t *env, ast_t *ast)
"})");
}
case Array: {
- type_t *array_type = get_type(env, ast);
- type_t *item_type = Match(array_type, ArrayType)->item_type;
-
auto array = Match(ast, Array);
if (!array->items)
return "(Array_t){.length=0}";
+ type_t *array_type = get_type(env, ast);
+ type_t *item_type = Match(array_type, ArrayType)->item_type;
+
int64_t n = 0;
for (ast_list_t *item = array->items; item; item = item->next) {
++n;
@@ -3758,6 +3769,7 @@ CORD compile(env_t *env, ast_t *ast)
CORD compile_type_info(type_t *t)
{
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "Attempt to compile a NULL type");
if (t == PATH_TYPE) return "&Path$info";
else if (t == PATH_TYPE_TYPE) return "&PathType$info";
diff --git a/src/parse.c b/src/parse.c
index 04e35953..43cd150d 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -710,15 +710,13 @@ PARSER(parse_array) {
whitespace(&pos);
expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this array");
- if (!item_type && !items)
- parser_err(ctx, start, pos, "Empty arrays must specify what type they would contain (e.g. [:Int])");
-
REVERSE_LIST(items);
return NewAST(ctx->file, start, pos, Array, .item_type=item_type, .items=items);
}
PARSER(parse_table) {
const char *start = pos;
+ if (match(&pos, "{/}")) return NULL;
if (!match(&pos, "{")) return NULL;
whitespace(&pos);
@@ -759,9 +757,6 @@ PARSER(parse_table) {
REVERSE_LIST(entries);
- if (!key_type && !value_type && !entries)
- return NULL;
-
whitespace(&pos);
ast_t *fallback = NULL, *default_value = NULL;
@@ -798,6 +793,9 @@ PARSER(parse_table) {
PARSER(parse_set) {
const char *start = pos;
+ if (match(&pos, "{/}"))
+ return NewAST(ctx->file, start, pos, Set);
+
if (!match(&pos, "{")) return NULL;
whitespace(&pos);
@@ -833,9 +831,6 @@ PARSER(parse_set) {
REVERSE_LIST(items);
- if (!item_type && !items)
- return NULL;
-
whitespace(&pos);
expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this set");
diff --git a/src/typecheck.c b/src/typecheck.c
index d2a976b8..8a2ee32b 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -739,6 +739,10 @@ type_t *get_type(env_t *env, ast_t *ast)
}
if (has_stack_memory(item_type))
code_err(ast, "Arrays cannot hold stack references, because the array may outlive the stack frame the reference was created in.");
+
+ if (!item_type)
+ code_err(ast, "I couldn't figure out the item type for this array!");
+
return Type(ArrayType, .item_type=item_type);
}
case Set: {
@@ -766,6 +770,10 @@ type_t *get_type(env_t *env, ast_t *ast)
item_type = item_merged;
}
}
+
+ if (!item_type)
+ code_err(ast, "I couldn't figure out the item type for this set!");
+
if (has_stack_memory(item_type))
code_err(ast, "Sets cannot hold stack references because the set may outlive the reference's stack frame.");
return Type(SetType, .item_type=item_type);
@@ -809,6 +817,10 @@ type_t *get_type(env_t *env, ast_t *ast)
value_type = val_merged;
}
}
+
+ if (!key_type || !value_type)
+ code_err(ast, "I couldn't figure out the key and value types for this table!");
+
if (has_stack_memory(key_type) || has_stack_memory(value_type))
code_err(ast, "Tables cannot hold stack references because the table may outlive the reference's stack frame.");
return Type(TableType, .key_type=key_type, .value_type=value_type, .default_value=table->default_value, .env=env);