ref: 4a8f78d53d61423fdeb6c59881661d6cd5cbd430
parent: 5c477090a5c2afbd60ccbe6e078cc94a73f4c08b
author: Ori Bernstein <[email protected]>
date: Sun Sep 28 13:01:40 EDT 2014
Fix premature unification in generics. We used to unify generics prematurely, meaning that if we had a generic being used before the declaration was fully inferred, we would fix it's type at the first use. This would cause errors when we tried to use it with a different type. A demonstration of this bug is below: const main = { id("asdf") /* we decided that id (byte[:] -> $t) */ id(123) /* type error: (byte[:] -> $t) is not compatible with (intline -> $t) */ } generic id = {x : @a -> x }
--- a/parse/dump.c
+++ b/parse/dump.c
@@ -233,3 +233,8 @@
{
outnode(n, fd, 0);
}
+
+void dumpn(Node *n)
+{
+ dump(n, stdout);
+}
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -104,6 +104,16 @@
return s;
}
+static void addspecialization(Inferstate *st, Node *n, Stab *stab)
+{
+ Node *dcl;
+
+ dcl = decls[n->expr.did];
+ lappend(&st->specializationscope, &st->nspecializationscope, stab);
+ lappend(&st->specializations, &st->nspecializations, n);
+ lappend(&st->genericdecls, &st->ngenericdecls, dcl);
+}
+
static void delayedcheck(Inferstate *st, Node *n, Stab *s)
{
lappend(&st->postcheck, &st->npostcheck, n);
@@ -1002,13 +1012,18 @@
t = tyfreshen(st, tf(st, s->decl.type));
else
t = s->decl.type;
- settype(st, n, t);
n->expr.did = s->decl.did;
n->expr.isconst = s->decl.isconst;
if (s->decl.isgeneric && !st->ingeneric) {
- lappend(&st->specializationscope, &st->nspecializationscope, curstab());
- lappend(&st->specializations, &st->nspecializations, n);
- lappend(&st->genericdecls, &st->ngenericdecls, s);
+ addspecialization(st, n, curstab());
+ if (t->type == Tyvar) {
+ settype(st, n, mktyvar(n->line));
+ delayedcheck(st, n, curstab());
+ } else {
+ settype(st, n, t);
+ }
+ } else {
+ settype(st, n, t);
}
return t;
}
@@ -1800,6 +1815,14 @@
}
}
+static void checkvar(Inferstate *st, Node *n)
+{
+ Node *dcl;
+
+ dcl = decls[n->expr.did];
+ unify(st, n, type(st, n), tyfreshen(st, type(st, dcl)));
+}
+
static void postcheck(Inferstate *st, Node *file)
{
size_t i;
@@ -1814,6 +1837,8 @@
checkcast(st, n);
else if (n->type == Nexpr && exprop(n) == Ostruct)
checkstruct(st, n);
+ else if (n->type == Nexpr && exprop(n) == Ovar)
+ checkvar(st, n);
else
die("Thing we shouldn't be checking in postcheck\n");
popstab();
--- a/test/genericcall.myr
+++ b/test/genericcall.myr
@@ -4,12 +4,12 @@
-> 42
}
-generic id = {a:@a
- -> f()
-}
-
const main = {
id("adsf")
std.exit(id(42))
+}
+
+generic id = {a:@a
+ -> f()
}