shithub: mc

Download patch

ref: d359a98ab9cfc42de66ad35333bd6d6c0571b7ca
parent: 4adc2f773870b45442ed27e5e794ade92e4fe2f0
author: Ori Bernstein <[email protected]>
date: Sun Oct 29 14:17:29 EDT 2017

Fix traits when exported cross-namespaces.

--- a/parse/export.c
+++ b/parse/export.c
@@ -278,9 +278,8 @@
 	free(k);
 
 	/* tag the impls */
-	k = htkeys(st->impl, &n);
-	for (i = 0; i < n; i++) {
-		s = getimpl(st, k[i]);
+	for (i = 0; i < file->file.nimpl; i++) {
+		s = file->file.impl[i];
 		if (s->impl.vis != Visexport)
 			continue;
 		tagnode(st, s, 0, hidelocal);
@@ -289,7 +288,4 @@
 		for (j = 0; j < tr->naux; j++)
 			tr->aux[j]->vis = tr->vis;
 	}
-	free(k);
-
 }
-
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -1923,19 +1923,21 @@
 	Node *dcl, *proto, *name, *sym;
 	Tysubst *subst;
 	Type *ty;
-	Trait *t;
+	Trait *tr;
 	size_t i, j;
 	int generic;
+	char *traitns;
 
-	t = gettrait(curstab(), n->impl.traitname);
-	if (!t)
+	tr = gettrait(curstab(), n->impl.traitname);
+	if (!tr)
 		fatal(n, "no trait %s\n", namestr(n->impl.traitname));
-	n->impl.trait = t;
+	n->impl.trait = tr;
+	traitns = tr->name->name.ns;
 
 	dcl = NULL;
-	if (n->impl.naux != t->naux)
+	if (n->impl.naux != tr->naux)
 		fatal(n, "%s incompatibly specialized with %zd types instead of %zd types",
-			namestr(n->impl.traitname), n->impl.naux, t->naux);
+			namestr(n->impl.traitname), n->impl.naux, tr->naux);
 	n->impl.type = tf(n->impl.type);
 	pushenv(n->impl.type->env);
 	for (i = 0; i < n->impl.naux; i++)
@@ -1953,24 +1955,24 @@
 		   here.
 		*/
 		if (file->file.globls->name)
-			setns(dcl->decl.name, file->file.globls->name);
-		for (j = 0; j < t->nproto; j++) {
-			if (nsnameeq(dcl->decl.name, t->proto[j]->decl.name)) {
-				proto = t->proto[j];
+			setns(dcl->decl.name, traitns);
+		for (j = 0; j < tr->nproto; j++) {
+			if (nsnameeq(dcl->decl.name, tr->proto[j]->decl.name)) {
+				proto = tr->proto[j];
 				break;
 			}
 		}
 		if (!proto)
 			fatal(n, "declaration %s missing in %s, near %s", namestr(dcl->decl.name),
-					namestr(t->name), ctxstr(n));
+					namestr(tr->name), ctxstr(n));
 
 		/* infer and unify types */
 		pushenv(proto->decl.env);
-		verifytraits(n, t->param, n->impl.type);
+		verifytraits(n, tr->param, n->impl.type);
 		subst = mksubst();
-		substput(subst, t->param, n->impl.type);
-		for (j = 0; j < t->naux; j++)
-			substput(subst, t->aux[j], n->impl.aux[j]);
+		substput(subst, tr->param, n->impl.type);
+		for (j = 0; j < tr->naux; j++)
+			substput(subst, tr->aux[j], n->impl.aux[j]);
 		ty = tyspecialize(type(proto), subst, delayed, NULL);
 		substfree(subst);
 		popenv(proto->decl.env);
@@ -1987,7 +1989,7 @@
 		sym = getdcl(file->file.globls, name);
 		if (sym)
 			fatal(n, "trait %s already specialized with %s on %s:%d",
-				namestr(t->name), tystr(n->impl.type),
+				namestr(tr->name), tystr(n->impl.type),
 				fname(sym->loc), lnum(sym->loc));
 		dcl->decl.name = name;
 		putdcl(file->file.globls, dcl);
@@ -1998,7 +2000,7 @@
 			lappend(&proto->decl.gimpl, &proto->decl.ngimpl, dcl);
 			lappend(&proto->decl.gtype, &proto->decl.ngtype, ty);
 		}
-		dcl->decl.vis = t->vis;
+		dcl->decl.vis = tr->vis;
 		lappend(&impldecl, &nimpldecl, dcl);
 
 		if (generic)
--- a/parse/node.c
+++ b/parse/node.c
@@ -553,6 +553,7 @@
 void
 setns(Node *n, char *ns)
 {
+	assert(!ns || !n->name.ns || !strcmp(n->name.ns, ns));
 	if (!ns)
 		return;
 	n->name.ns = strdup(ns);
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -205,6 +205,8 @@
 			Node **init;	/* all __init__ function names of our deps. NB, this
 					   is a Nname, not an Ndecl */
 			size_t ninit;
+			Node **impl;	/* impls defined in this file, across all namespaces */
+			size_t nimpl;
 			Node *localinit;/* and the local one, if any */
 			Stab *globls;	/* global symtab */
 			Stab *builtins;	/* global symtab */
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -581,6 +581,9 @@
 		fatal(n, "trait %s already implemented over %s at %s:%d",
 			namestr(n->impl.traitname), tystr(n->impl.type),
 			fname(n->loc), lnum(n->loc));
+	/* if this is not a duplicate, record it for later export */
+	if (!impl)
+		lappend(&file->file.impl, &file->file.nimpl, n);
 	/*
 	 The impl is not defined in this file, so setting the
 	 trait name would be a bug here.
--- a/parse/use.c
+++ b/parse/use.c
@@ -1032,10 +1032,17 @@
 			impl = unpickle(f);
 			impl->impl.isextern = 1;
 			impl->impl.vis = vis;
-			/* specialized declarations always go into the global stab */
+			/*
+			 * Unfortunately, impls can insert their symbols into whatever
+			 * namespace the trait comes from. This complicates things a bit.
+			 */
 			for (i = 0; i < impl->impl.ndecls; i++) {
-				impl->impl.decls[i]->decl.isglobl = 1;
-				putdcl(file->file.globls, impl->impl.decls[i]);
+				dcl = impl->impl.decls[i];
+				dcl->decl.isglobl = 1;
+				ns = file->file.globls;
+				if (dcl->decl.name->name.ns)
+					ns = findstab(s, dcl->decl.name->name.ns);
+				putdcl(ns, dcl);
 			}
 			break;
 		case EOF:
@@ -1212,9 +1219,8 @@
 		}
 	}
 
-	k = htkeys(st->tr, &n);
-	for (i = 0; i < n; i++) {
-		tr = gettrait(st, k[i]);
+	for (i = 0; i < ntraittab; i++) {
+		tr = traittab[i];
 		if (tr->uid < Ntraits)
 			continue;
 		if (tr->vis == Visexport || tr->vis == Vishidden) {
@@ -1222,12 +1228,10 @@
 			traitpickle(f, tr);
 		}
 	}
-	free(k);
 
-	k = htkeys(st->impl, &n);
-	for (i = 0; i < n; i++) {
+	for (i = 0; i < nimpltab; i++) {
 		/* merging during inference should remove all protos */
-		s = getimpl(st, k[i]);
+		s = impltab[i];
 		assert(!s->impl.isproto);
 		if (s->impl.vis == Visexport || s->impl.vis == Vishidden) {
 			wrbyte(f, 'I');
@@ -1234,7 +1238,6 @@
 			pickle(f, s);
 		}
 	}
-	free(k);
 
 	k = htkeys(st->dcl, &n);
 	for (i = 0; i < n; i++) {