summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--copy.c18
-rw-r--r--instance_table.c6
-rw-r--r--main.c12
-rw-r--r--parse.c3
-rw-r--r--test.toc19
-rwxr-xr-xtests/test.sh1
-rw-r--r--types.c213
-rw-r--r--types.h3
8 files changed, 169 insertions, 106 deletions
diff --git a/copy.c b/copy.c
index 7380c05..ec64f54 100644
--- a/copy.c
+++ b/copy.c
@@ -235,6 +235,7 @@ static inline void copier_ident_translate(Copier *c, Identifier *i) {
*i = ident_translate_forced(*i, &c->block->idents);
}
+/* in must be untyped! */
static void copy_expr(Copier *c, Expression *out, Expression *in) {
Allocator *a = c->allocr;
*out = *in;
@@ -275,7 +276,22 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) {
copy_block(c, &wout->body, &win->body, 0);
} break;
case EXPR_FOR: {
- /* TODO */
+ ForExpr *fin = in->for_;
+ ForExpr *fout = out->for_ = allocr_malloc(a, sizeof *fout);
+ *fout = *fin;
+ Block *prev = c->block;
+ c->block = &fout->body;
+ idents_create(&fout->body.idents, c->allocr, &fout->body);
+ copy_decl(c, &fout->header, &fin->header);
+ if (fin->flags & FOR_IS_RANGE) {
+ fout->range.from = copy_expr_(c, fin->range.from);
+ if (fin->range.to) fout->range.to = copy_expr_(c, fin->range.to);
+ if (fin->range.step) fout->range.step = copy_expr_(c, fin->range.step);
+ } else {
+ fout->of = copy_expr_(c, fin->of);
+ }
+ c->block = prev;
+ copy_block(c, &fout->body, &fin->body, COPY_BLOCK_DONT_CREATE_IDENTS);
} break;
case EXPR_FN:
copy_fn_expr(c, out->fn = allocr_malloc(a, sizeof *out->fn), in->fn, 0);
diff --git a/instance_table.c b/instance_table.c
index 665fd9c..6a06f4b 100644
--- a/instance_table.c
+++ b/instance_table.c
@@ -19,7 +19,7 @@
static void *val_get_ptr(Value *v, Type *t);
static U64 val_hash(Value v, Type *t);
static bool val_eq(Value u, Value v, Type *t);
-static bool type_eq(Type *t1, Type *t2);
+static bool type_eq_exact(Type *t1, Type *t2);
static U64 f32_hash(F32 f) {
/* OPTIM */
@@ -230,7 +230,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) {
if (arr_len(vs) != n)
return false;
for (size_t i = 0; i < n; ++i) {
- if (!type_eq(us[i].type, vs[i].type))
+ if (!type_eq_exact(us[i].type, vs[i].type))
return false;
if (!val_eq(vs[i].val, us[i].val, us[i].type))
return false;
@@ -238,7 +238,7 @@ static bool val_ptr_eq(void *u, void *v, Type *t) {
return true;
}
case BUILTIN_TYPE:
- return type_eq(*(Type **)u, *(Type **)v);
+ return type_eq_exact(*(Type **)u, *(Type **)v);
case BUILTIN_NMS:
return *(Namespace **)u == *(Namespace **)v;
}
diff --git a/main.c b/main.c
index dba2d94..24b1c79 100644
--- a/main.c
+++ b/main.c
@@ -8,21 +8,24 @@
/*
TODO:
-replace weird EXPR_FOR system with just a declaration- would make "for use p := points" easier.
- need to fix:
- - copy.c
+arr_add_val
+arr_last_val
+test for use ...
+test used ret decls
consider: don't do inference for function calls; get rid of was_expr -- now that we have struct params
EXPR_IDENT should be a string before typing, also struct member accesses
do we need the possibility that IdentSlot.decl is NULL?
use
- use with struct members (e.g. SuperPoint ::= struct { use p: Point; })
maybe change to #define check(x) do { if_unlikely(x) return 0; } while (0);
+always use pointers in cgen'd non-range for loops (sometimes also indices)
is there a problem where we can get TYPE_UNKNOWN in cgen, triggering an assert(0)?
-simple example, but maybe try other stuff: x := #C("5");
-also make sure you can't do x:#C("5");
local structs should not be named in C
+make sure you can do a[i] where a is &[5]int or &[]char or something
do we consistently handle x := &some_array_or_slice; x.len
-arr_add_val => doesn't return a pointer; takes a value!
+&void
simplify eval macros with val_to_u/i64
&&, ||
start making a standard library... (printf; stringbuilder would be nice to have)
@@ -41,6 +44,7 @@ make sure that floating point literals are exact as possible
have some way of doing Infinity and s/qNaN (you can
have them be in std/math.toc)
once you have a bunch of test code:
+- analyze memory usage by secretly passing __FILE__, __LINE__ to allocr_m/c/realloc
- try making more Expression members pointers
- branch data: #define if(x) bool join(cond, __LINE__) = x; register_branch(__FILE__, __LINE__, cond); if (join(cond, __LINE__))
error on x ::= {return; 3}
diff --git a/parse.c b/parse.c
index 2befa8b..8b95aa4 100644
--- a/parse.c
+++ b/parse.c
@@ -1085,7 +1085,7 @@ static Status ctype_to_type(Allocator *a, CType *ctype, Type *type, Location whe
case CTYPE_PTR:
type->kind = TYPE_PTR;
type->ptr = allocr_calloc(a, 1, sizeof *type->ptr);
- type->ptr->kind = TYPE_UNKNOWN;
+ type->ptr->kind = TYPE_VOID;
break;
case CTYPE_UNSIGNED: assert(0); break;
}
@@ -2912,6 +2912,7 @@ static inline Type *decl_type_at_index(Declaration *d, int i) {
assert(i >= 0);
if (d->type.kind == TYPE_TUPLE) {
int tuple_len = (int)arr_len(d->type.tuple);
+ (void)tuple_len;
#if 0
printf("decl_type_at_index: tuple_len:%d i:%d\n", tuple_len, i);
#endif
diff --git a/test.toc b/test.toc
index 33ccd3f..3f059a4 100644
--- a/test.toc
+++ b/test.toc
@@ -1,15 +1,12 @@
-#include "std/io.toc";
+#include "std/io.toc", io;
main ::= fn() {
- foo : [5][]char;
- for x := &foo {
- *x = "hello";
- }
- for x := foo {
- puts(x);
- }
- for c := "foobar" {
- puti(c as int);
+ s ::= struct {
+ foo, e: int;
+ bar ::= 3;
+ baz: float;
}
+
+ p: s;
+ io.puti(p["bar"]);
}
-main();
diff --git a/tests/test.sh b/tests/test.sh
index 3d728d3..8df4c46 100755
--- a/tests/test.sh
+++ b/tests/test.sh
@@ -36,6 +36,7 @@ compile_c() {
failed=false
do_tests() {
+ echo "----$1----"
valgrind -q --exit-on-first-error=yes --error-exitcode=1 $TOC "$1.toc" -o out.c || exit 1
for CC in "gcc -O0 -g" "tcc" "clang -O3 -s"; do
if [ "$1" = "sizeof" ]; then
diff --git a/types.c b/types.c
index 9e07bc0..4e87ac8 100644
--- a/types.c
+++ b/types.c
@@ -184,33 +184,15 @@ static size_t compiler_sizeof(Type *t) {
#define typer_arr_add(tr, a) typer_arr_add_(tr, (void **)(a), sizeof **(a))
-
-static bool type_eq(Type *a, Type *b) {
- if (a->kind == TYPE_UNKNOWN || b->kind == TYPE_UNKNOWN)
- return true; /* allow things such as 3 + #C("5") */
+/* are a and b EXACTLY equal (not counting flags)? */
+static bool type_eq_exact(Type *a, Type *b) {
assert(a->flags & TYPE_IS_RESOLVED);
assert(b->flags & TYPE_IS_RESOLVED);
if (a->kind != b->kind) return false;
- if (b->flags & TYPE_IS_FLEXIBLE) {
- Type *tmp = a;
- a = b;
- b = tmp;
- }
-
- if (a->flags & TYPE_IS_FLEXIBLE) {
- if (b->flags & TYPE_IS_FLEXIBLE) return true;
- assert(a->kind == TYPE_BUILTIN);
-
- if (type_builtin_is_float(a->builtin)) {
- return type_builtin_is_float(b->builtin);
- }
- assert(a->builtin == BUILTIN_I64);
- return type_builtin_is_numerical(b->builtin);
- }
switch (a->kind) {
case TYPE_VOID: return true;
- case TYPE_UNKNOWN: assert(0); return false;
+ case TYPE_UNKNOWN: return true;
case TYPE_BUILTIN:
return a->builtin == b->builtin;
case TYPE_STRUCT:
@@ -228,7 +210,7 @@ static bool type_eq(Type *a, Type *b) {
if ((const_a == CONSTNESS_NO && const_b == CONSTNESS_YES)
|| (const_a == CONSTNESS_YES && const_b == CONSTNESS_NO))
return false;
- if (!type_eq(&a_types[i], &b_types[i]))
+ if (!type_eq_exact(&a_types[i], &b_types[i]))
return false;
}
@@ -238,18 +220,18 @@ static bool type_eq(Type *a, Type *b) {
if (arr_len(a->tuple) != arr_len(b->tuple)) return false;
Type *a_types = a->tuple, *b_types = b->tuple;
for (size_t i = 0; i < arr_len(a->tuple); ++i) {
- if (!type_eq(&a_types[i], &b_types[i]))
+ if (!type_eq_exact(&a_types[i], &b_types[i]))
return false;
}
return true;
}
case TYPE_ARR:
if (a->arr.n != b->arr.n) return false;
- return type_eq(a->arr.of, b->arr.of);
+ return type_eq_exact(a->arr.of, b->arr.of);
case TYPE_SLICE:
- return type_eq(a->slice, b->slice);
+ return type_eq_exact(a->slice, b->slice);
case TYPE_PTR:
- return type_eq(a->ptr, b->ptr);
+ return type_eq_exact(a->ptr, b->ptr);
case TYPE_EXPR:
break;
}
@@ -257,15 +239,50 @@ static bool type_eq(Type *a, Type *b) {
return false;
}
-/* expected must equal got, or an error will be produced */
-static Status type_must_eq(Location where, Type *expected, Type *got) {
- if (!type_eq(expected, got)) {
- char *str_ex = type_to_str(expected);
- char *str_got = type_to_str(got);
- err_print(where, "Type mismatch: expected %s, but got %s.", str_ex, str_got);
- return false;
+/* are a and b equal, allowing implicit conversions? */
+static bool type_eq_implicit(Type *a, Type *b) {
+ if (a->kind == TYPE_UNKNOWN || b->kind == TYPE_UNKNOWN)
+ return true;
+ if (a->kind != b->kind) return false;
+ if (b->flags & TYPE_IS_FLEXIBLE) {
+ Type *tmp = b;
+ b = a;
+ a = tmp;
}
- return true;
+ if (a->flags & TYPE_IS_FLEXIBLE) {
+ assert(a->kind == TYPE_BUILTIN);
+ if (b->flags & TYPE_IS_FLEXIBLE) return true;
+
+ if (type_builtin_is_float(a->builtin)) {
+ return type_builtin_is_float(b->builtin);
+ }
+ assert(a->builtin == BUILTIN_I64);
+ return type_builtin_is_numerical(b->builtin);
+ }
+ if (a->kind == TYPE_PTR) {
+ /* &void casts to &anything */
+ if (a->ptr->kind == TYPE_VOID || b->ptr->kind == TYPE_VOID)
+ return true;
+ }
+ return type_eq_exact(a, b);
+}
+
+/* which is the "overriding" type? i.e. which type should the other one convert to? */
+static Type *overriding_type(Type *a, Type *b) {
+ if (a->kind == TYPE_UNKNOWN) return b;
+ if (b->kind == TYPE_UNKNOWN) return a;
+ if (a->flags & TYPE_IS_FLEXIBLE) {
+ assert(a->kind == TYPE_BUILTIN);
+ if (b->flags & TYPE_IS_FLEXIBLE) {
+ if (type_builtin_is_float(a->builtin))
+ return a;
+ }
+ return b;
+ }
+ if (b->flags & TYPE_IS_FLEXIBLE)
+ return a;
+ /* doesn't matter */
+ return a;
}
/* prints an error and returns false if the given expression is not an l-value */
@@ -1046,7 +1063,7 @@ static CastStatus type_cast_status(Type *from, Type *to) {
case TYPE_ARR:
return CAST_STATUS_ERR;
case TYPE_SLICE:
- if (to->kind == TYPE_PTR && type_eq(from->slice, to->ptr))
+ if (to->kind == TYPE_PTR && type_eq_exact(from->slice, to->ptr))
return CAST_STATUS_NONE;
return CAST_STATUS_ERR;
case TYPE_EXPR:
@@ -1092,7 +1109,7 @@ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) {
ret_type = t->fn.types;
has_named_ret_vals = f->ret_decls != NULL;
if (ret_expr) {
- if (!type_eq(ret_type, &ret_expr->type)) {
+ if (!type_eq_implicit(&ret_expr->type, ret_type)) {
char *got = type_to_str(&ret_expr->type);
char *expected = type_to_str(ret_type);
err_print(ret_expr->where, "Returning type %s, but function returns type %s.", got, expected);
@@ -1552,13 +1569,13 @@ static Status types_expr(Typer *tr, Expression *e) {
t->builtin = BUILTIN_CHAR;
break;
case EXPR_FOR: {
+ bool in_header = true;{ /* additional block because c++ */
ForExpr *fo = e->for_;
Declaration *header = &fo->header;
*(Declaration **)typer_arr_add(tr, &tr->in_decls) = header;
fo->body.uses = NULL;
typer_block_enter(tr, &fo->body);
- bool in_header = true;
bool annotated_index = true;
{
size_t nidents = arr_len(header->idents);
@@ -1652,10 +1669,12 @@ static Status types_expr(Typer *tr, Expression *e) {
}
if (val_type->flags) {
- if (!type_eq(val_type, &fo->range.from->type)) {
+ if (type_eq_implicit(&fo->range.from->type, val_type)) {
+ *val_type = *overriding_type(&fo->range.from->type, val_type);
+ } else {
char *exp = type_to_str(val_type);
char *got = type_to_str(&fo->range.from->type);
- err_print(e->where, "Type of for loop does not match the type of the from expression. Expected %s, but got %s.", exp, got);
+ err_print(e->where, "Type of from expression does not match type of for loop. Expected %s, but got %s.", exp, got);
free(exp); free(got);
goto for_fail;
}
@@ -1664,37 +1683,41 @@ static Status types_expr(Typer *tr, Expression *e) {
}
if (fo->range.step) {
- if (!type_eq(val_type, &fo->range.step->type)) {
+ if (type_eq_implicit(&fo->range.step->type, val_type)) {
+ *val_type = *overriding_type(&fo->range.step->type, val_type);
+ } else {
char *exp = type_to_str(val_type);
char *got = type_to_str(&fo->range.step->type);
- err_print(e->where, "Type of for loop does not match the type of the step expression. Expected %s, but got %s.", exp, got);
+ err_print(e->where, "Type of step expression does not match type of for loop. Expected %s, but got %s.", exp, got);
free(exp); free(got);
goto for_fail;
}
- if (val_type->flags & TYPE_IS_FLEXIBLE)
- *val_type = fo->range.step->type;
-
- Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval);
- if (!eval_expr(tr->evalr, fo->range.step, stepval)) {
- info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant.");
- goto for_fail;
- }
- val_cast(stepval, &fo->range.step->type, stepval, val_type);
- fo->range.stepval = stepval;
}
if (fo->range.to) {
- if (!type_eq(val_type, &fo->range.to->type)) {
+ if (type_eq_implicit(&fo->range.to->type, val_type)) {
+ *val_type = *overriding_type(&fo->range.to->type, val_type);
+ } else {
char *exp = type_to_str(val_type);
char *got = type_to_str(&fo->range.to->type);
- err_print(e->where, "Type of for loop does not match the type of the to expression. Expected %s, but got %s.", exp, got);
+ err_print(e->where, "Type of to expression does not match type of for loop. Expected %s, but got %s.", exp, got);
free(exp); free(got);
goto for_fail;
}
- if (val_type->flags & TYPE_IS_FLEXIBLE)
- *val_type = fo->range.to->type;
}
+
val_type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE;
+
+ if (fo->range.step) {
+ /* we can't put this above because *val_type might have changed. */
+ Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval);
+ if (!eval_expr(tr->evalr, fo->range.step, stepval)) {
+ info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant.");
+ goto for_fail;
+ }
+ val_cast(stepval, &fo->range.step->type, stepval, val_type);
+ fo->range.stepval = stepval;
+ }
} else {
if (!types_expr(tr, fo->of))
goto for_fail;
@@ -1835,7 +1858,9 @@ static Status types_expr(Typer *tr, Expression *e) {
iter_type = ptr_type;
}
if (header->flags & DECL_ANNOTATES_TYPE) {
- if (!type_eq(iter_type, val_type)) {
+ if (type_eq_implicit(iter_type, val_type)) {
+ *val_type = *overriding_type(iter_type, val_type);
+ } else {
char *exp = type_to_str(iter_type);
char *got = type_to_str(val_type);
err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.", exp, got);
@@ -1863,7 +1888,7 @@ static Status types_expr(Typer *tr, Expression *e) {
t->kind = TYPE_VOID;
typer_block_exit(tr);
- break;
+ }break;
for_fail:
if (in_header)
arr_remove_lasta(&tr->in_decls, tr->allocr);
@@ -2059,7 +2084,7 @@ static Status types_expr(Typer *tr, Expression *e) {
next_type->flags = TYPE_IS_RESOLVED;
next_type->was_expr = NULL;
}
- if (!type_eq(curr_type, next_type)) {
+ if (!type_eq_implicit(next_type, curr_type)) {
char *currstr = type_to_str(curr_type);
char *nextstr = type_to_str(next_type);
err_print(curr->next_elif->where, "Mismatched types in if/elif/else chain. Previous block was of type %s, but this one is of type %s.", currstr, nextstr);
@@ -2176,7 +2201,7 @@ static Status types_expr(Typer *tr, Expression *e) {
Argument *arg = &c->args[order[p]];
assert(arg->val.type.flags & TYPE_IS_RESOLVED);
assert(type->flags & TYPE_IS_RESOLVED);
- if (!type_eq(&arg->val.type, type)) {
+ if (!type_eq_implicit(&arg->val.type, type)) {
char *expected = type_to_str(type),
*got = type_to_str(&arg->val.type);
err_print(arg->where, "Wrong struct parameter type. Expected %s, but got %s.", expected, got);
@@ -2580,7 +2605,7 @@ static Status types_expr(Typer *tr, Expression *e) {
Expression *arg = &arg_exprs[p];
Type *expected = &param_types[p];
Type *got = &arg->type;
- if (!type_eq(expected, got)) {
+ if (!type_eq_implicit(got, expected)) {
char *estr = type_to_str(expected);
char *gstr = type_to_str(got);
err_print(arg->where, "Expected type %s as argument to function, but got %s.", estr, gstr);
@@ -2888,10 +2913,10 @@ static Status types_expr(Typer *tr, Expression *e) {
assert(rhs_type->flags & TYPE_IS_RESOLVED);
if (o == BINARY_SET) {
- valid = type_eq(lhs_type, rhs_type);
+ valid = type_eq_implicit(lhs_type, rhs_type);
} else {
/* numerical binary ops */
- if (lhs_type->kind == TYPE_BUILTIN && type_eq(lhs_type, rhs_type)) {
+ if (lhs_type->kind == TYPE_BUILTIN && type_eq_implicit(lhs_type, rhs_type)) {
/* int + int, etc. */
valid = true;
}
@@ -2905,7 +2930,7 @@ static Status types_expr(Typer *tr, Expression *e) {
if (o == BINARY_LT || o == BINARY_GT || o == BINARY_LE || o == BINARY_GE
|| o == BINARY_EQ || o == BINARY_NE) {
/* comparable types */
- if (type_eq(lhs_type, rhs_type)) {
+ if (type_eq_implicit(lhs_type, rhs_type)) {
switch (lhs_type->kind) {
case TYPE_PTR:
case TYPE_BUILTIN: /* all builtins are comparable */
@@ -2932,23 +2957,7 @@ static Status types_expr(Typer *tr, Expression *e) {
t->builtin = BUILTIN_BOOL;
break;
default: {
- int lhs_is_flexible = lhs_type->flags & TYPE_IS_FLEXIBLE;
- int rhs_is_flexible = rhs_type->flags & TYPE_IS_FLEXIBLE;
- if (lhs_is_flexible && rhs_is_flexible) {
- /* both flexible */
- *t = *lhs_type;
- if (rhs_type->builtin == BUILTIN_F32) {
- /* promote to float */
- t->builtin = BUILTIN_F32;
- }
-
- } else if (!lhs_is_flexible) {
- /* lhs inflexible, rhs ? */
- *t = *lhs_type;
- } else {
- /* lhs flexible, rhs ? */
- *t = *rhs_type;
- }
+ *t = *overriding_type(lhs_type, rhs_type);
if ((o == BINARY_MOD || o == BINARY_SET_MOD)
&& type_builtin_is_float(t->builtin)) {
err_print(e->where, "Cannot use operator % on floating-point numbers.");
@@ -3002,6 +3011,37 @@ static Status types_expr(Typer *tr, Expression *e) {
case TYPE_SLICE:
*t = *lhs_type->slice;
break;
+ case TYPE_BUILTIN:
+ if (lhs_type->builtin == BUILTIN_VARARGS) {
+ assert(lhs->kind == EXPR_IDENT);
+ Declaration *decl = lhs->ident->decl;
+ assert(decl->flags & DECL_IS_PARAM);
+ Value index_val;
+ if (!eval_expr(tr->evalr, rhs, &index_val))
+ return false;
+ /* NOTE: rhs->type was checked above */
+ I64 i = val_to_i64(index_val, rhs->type.builtin);
+ VarArg *varargs = decl->val.varargs;
+ if (i < 0 || i >= (I64)arr_len(varargs)) {
+ err_print(e->where, "Index out of bounds for varargs access (index = " I64_FMT ", length = %lu).", i, (unsigned long)arr_len(varargs));
+ return 0;
+ }
+ VarArg *vararg = &varargs[i];
+ if (decl->flags & DECL_IS_CONST) {
+ /* replace with value */
+ e->kind = EXPR_VAL;
+ e->type = *vararg->type;
+ copy_val(tr->allocr, &e->val, vararg->val, &e->type);
+ } else {
+ /* just use vararg's type */
+ rhs->kind = EXPR_VAL;
+ rhs->val.i64 = i;
+ rhs->type.builtin = BUILTIN_I64;
+ *t = *vararg->type;
+ }
+ break;
+ }
+ /* fallthrough */
default: {
char *s = type_to_str(lhs_type);
err_print(e->where, "Cannot subscript type %s", s);
@@ -3043,8 +3083,8 @@ static Status types_expr(Typer *tr, Expression *e) {
} else if (struct_type->kind == TYPE_STRUCT) {
StructDef *struc = struct_type->struc;
Identifier struct_ident = ident_translate(rhs->ident, &struc->body.idents);
- if (ident_is_declared(struct_ident)) {
- Field *field = struct_ident->decl->field;
+ Field *field = NULL;
+ if (ident_is_declared(struct_ident) && (field = struct_ident->decl->field)) {
field += ident_index_in_decl(struct_ident, struct_ident->decl);
e->binary.dot.field = field;
*t = *field->type;
@@ -3270,11 +3310,14 @@ static Status types_decl(Typer *tr, Declaration *d) {
}
assert(d->expr.type.flags & TYPE_IS_RESOLVED);
if (d->flags & DECL_ANNOTATES_TYPE) {
- if (!type_must_eq(d->expr.where, &d->type, &d->expr.type)) {
+ if (!type_eq_implicit(&d->expr.type, &d->type)) {
+ char *decl_type = type_to_str(&d->type),
+ *expr_type = type_to_str(&d->expr.type);
+ err_print(d->expr.where, "Declaration type %s does not match expression type %s.", decl_type, expr_type);
+ free(decl_type); free(expr_type);
success = false;
goto ret;
}
- d->expr.type = d->type;
} else {
if (d->expr.type.kind == TYPE_VOID) {
/* e.g. x := (fn(){})(); */
@@ -3468,7 +3511,7 @@ static Status types_stmt(Typer *tr, Statement *s) {
}
if (!types_expr(tr, &r->expr))
return false;
- if (!type_eq(&tr->fn->ret_type, &r->expr.type)) {
+ if (!type_eq_implicit(&tr->fn->ret_type, &r->expr.type)) {
char *got = type_to_str(&r->expr.type);
char *expected = type_to_str(&tr->fn->ret_type);
err_print(s->where, "Returning type %s in function which returns %s.", got, expected);
diff --git a/types.h b/types.h
index 38262e6..ed8d792 100644
--- a/types.h
+++ b/types.h
@@ -889,7 +889,8 @@ typedef struct ForExpr {
union {
/* (either) can be null */
struct Expression *step; /* before typing */
- Value *stepval; /* after typing */
+ Value *stepval; /* after typing. the type of this is header.type.tuple[0] (i.e. the value type for this for loop),
+ NOTE: this might be different from the original ForExpr.step.type, because of implicit type conversions. */
};
} range;
struct Expression *of;