summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--parse.c2
-rw-r--r--test.toc1
-rw-r--r--types.c18
-rw-r--r--types.h3
4 files changed, 22 insertions, 2 deletions
diff --git a/parse.c b/parse.c
index 09767a7..b336fbf 100644
--- a/parse.c
+++ b/parse.c
@@ -822,6 +822,8 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
} else {
if (!parse_decl_list(p, &f->params, DECL_END_RPAREN_COMMA))
return false;
+ arr_foreach(f->params, Declaration, param)
+ param->flags |= DECL_IS_PARAM;
}
if (t->token->kind == TOKEN_EOF) {
diff --git a/test.toc b/test.toc
index bc26708..b23b62c 100644
--- a/test.toc
+++ b/test.toc
@@ -12,6 +12,7 @@ puti @= fn(x: int) {
main @= fn() {
puti(g(int));
puti(g());
+ puti(g(u8));
};
g @= fn(t @= int) int {
diff --git a/types.c b/types.c
index a29c9d7..abcd474 100644
--- a/types.c
+++ b/types.c
@@ -27,6 +27,13 @@ static bool type_eq(Type *a, Type *b) {
return true; /* allow things such as 3 + #C("5") */
assert(a->flags & TYPE_IS_RESOLVED);
assert(b->flags & TYPE_IS_RESOLVED);
+
+ if (a->kind == TYPE_USER && a->user.is_alias)
+ return type_eq(type_user_underlying(a), b);
+ if (b->kind == TYPE_USER && b->user.is_alias)
+ return type_eq(a, type_user_underlying(b));
+
+
if (a->kind != b->kind) return false;
if (a->flags & TYPE_IS_FLEXIBLE) {
if (b->flags & TYPE_IS_FLEXIBLE) return true;
@@ -464,6 +471,9 @@ static bool type_resolve(Typer *tr, Type *t, Location where) {
/* finally, set decl and index */
t->user.decl = decl;
t->user.index = index;
+ if (decl->flags & DECL_IS_PARAM) {
+ t->user.is_alias = true; /* type parameters are aliases */
+ }
} break;
case TYPE_STRUCT:
arr_foreach(t->struc.fields, Field, f) {
@@ -511,9 +521,15 @@ static Status type_cast_status(Type *from, Type *to) {
if (to->kind == TYPE_UNKNOWN)
return STATUS_NONE;
if (from->kind == TYPE_USER) {
- return type_eq(to, type_user_underlying(from)) ? STATUS_NONE : STATUS_ERR;
+ if (from->user.is_alias) {
+ return type_cast_status(type_user_underlying(from), to);
+ }
+ return type_eq(type_user_underlying(from), to) ? STATUS_NONE : STATUS_ERR;
}
if (to->kind == TYPE_USER) {
+ if (to->user.is_alias) {
+ return type_cast_status(from, type_user_underlying(to));
+ }
return type_eq(from, type_user_underlying(to)) ? STATUS_NONE : STATUS_ERR;
}
switch (from->kind) {
diff --git a/types.h b/types.h
index bd76826..2ddb1a3 100644
--- a/types.h
+++ b/types.h
@@ -354,7 +354,7 @@ typedef struct Type {
};
Identifier ident;
};
-
+ bool is_alias; /* is this an alias for a type, rather than a new type */
} user;
struct {
Field *fields;
@@ -613,6 +613,7 @@ enum {
DECL_FOUND_TYPE = 0x10,
DECL_ERRORED_ABOUT_SELF_REFERENCE = 0x20, /* has there been an error about this decl referencing itself? */
DECL_FOUND_VAL = 0x40,
+ DECL_IS_PARAM = 0x80
};
/* OPTIM: Instead of using dynamic arrays, do two passes. */