3038 lines · 68.8 KB · C
RawDownload
#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <inttypes.h>#include <inttypes.h>#include <ctype.h>#include <string.h>#include <assert.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <assert.h> #include "util.h"#include "parse.h" typedef struct Traitmap Traitmap;typedef struct Postcheck Postcheck; struct Traitmap {	Bitset *traits;	Traitmap *sub[Ntypes]; 	Htab *name;	/* name => bitset(traits) */	Type **filter;	size_t nfilter;	Trait **filtertr;	size_t nfiltertr;}; struct Postcheck {	Node *node;	Stab *stab;	Tyenv *env;};  int allowhidden; static void infernode(Node **np, Type *ret, int *sawret);static void inferexpr(Node **np, Type *ret, int *sawret);static void inferdecl(Node *n);static int tryconstrain(Type *ty, Trait *tr, int update); static Type *tyfreshen(Tysubst *subst, Type *orig);static Type *tf(Type *t);static Type *basetype(Type *a); static Type *unify(Node *ctx, Type *a, Type *b);static Type *tyfix(Node *ctx, Type *orig, int noerr);static void typesub(Node *n, int noerr); /* tracking where we are in the inference */static int ingeneric;static int inaggr;static int indentdepth;static Srcloc *unifysrc;static size_t nunifysrc; /* post-inference checking/unification */static Htab *delayed;static Postcheck **postcheck;static size_t npostcheck; /* generic declarations to be specialized */static Node **genericdecls;static size_t ngenericdecls;static Node **impldecl;static size_t nimpldecl; /* specializations of generics */static Node **specializations;static size_t nspecializations;static Stab **specializationscope;static size_t nspecializationscope;static Traitmap *traitmap;static Bitset *tytraits[Ntypes];  static voidctxstrcall(char *buf, size_t sz, Node *n){	char *p, *end, *sep, *t;	size_t nargs, i;	Node **args;	Type *et; 	args = n->expr.args;	nargs = n->expr.nargs;	p = buf;	end = buf + sz;	sep = ""; 	if (exprop(args[0]) == Ovar)		p += bprintf(p, end - p, "%s(", namestr(args[0]->expr.args[0]));	else		p += bprintf(p, end - p, "<e>(");	for (i = 1; i < nargs; i++) {		et = tyfix(NULL, exprtype(args[i]), 1);		if (et != NULL)			t = tystr(et);		else			t = strdup("?"); 		if (exprop(args[i]) == Ovar)			p += bprintf(p, end - p, "%s%s:%s", sep, namestr(args[i]->expr.args[0]), t);		else			p += bprintf(p, end - p, "%s<e%zd>:%s", sep, i, t);		sep = ", ";		free(t);	}	if (exprtype(args[0])->nsub)		t = tystr(tyfix(NULL, exprtype(args[0])->sub[0], 1));	else		t = strdup("unknown");	p += bprintf(p, end - p, "): %s", t);	free(t);} static char *nodetystr(Node *n){	Type *t; 	t = NULL;	if (n->type == Nexpr && exprtype(n) != NULL)		t = tysearch(exprtype(n));	else if (n->type == Ndecl && decltype(n) != NULL)		t = tysearch(decltype(n)); 	if (t && tybase(t)->type != Tyvar)		return tystr(t);	else		return strdup("unknown");} static voidmarksrc(Type *t, Srcloc l){	t = tf(t);	if (t->tid >= nunifysrc) {		unifysrc = zrealloc(unifysrc, nunifysrc*sizeof(Srcloc), (t->tid + 1)*sizeof(Srcloc));		nunifysrc = t->tid + 1;	}	if (unifysrc[t->tid].line <= 0)		unifysrc[t->tid] = l;} static char *srcstr(Type *ty){	char src[128];	Srcloc l;	char *s; 	src[0] = 0;	if (nunifysrc > ty->tid && unifysrc[ty->tid].line > 0) {		l = unifysrc[ty->tid];		s = tystr(ty);		snprintf(src, sizeof src, "\n\t%s from %s:%d", s, fname(l), lnum(l));		free(s);	}	return strdup(src);} /* Tries to give a good string describing the context * for the sake of error messages. */static char *ctxstr(Node *n){	char *t, *t1, *t2, *t3;	char *s, *d;	size_t nargs;	Node **args;	char buf[512]; 	if (!n)		return strdup("???");	switch (n->type) {	default:		s = strdup(nodestr[n->type]);		break;	case Ndecl:		 d = declname(n);		 t = nodetystr(n);		 bprintf(buf, sizeof buf, "%s:%s", d, t);		 s = strdup(buf);		 free(t);		 break;	case Nname:	s = strdup(namestr(n));	break;	case Nexpr:		args = n->expr.args;		nargs = n->expr.nargs;		t1 = NULL;		t2 = NULL;		t3 = NULL;		if (exprop(n) == Ovar)			d = namestr(args[0]);		else			d = opstr[exprop(n)];		t = nodetystr(n);		if (nargs >= 1)			t1 = nodetystr(args[0]);		if (nargs >= 2)			t2 = nodetystr(args[1]);		if (nargs >= 3)			t3 = nodetystr(args[2]); 		switch (opclass[exprop(n)]) {		case OTpre:	bprintf(buf, sizeof buf, "%s<e:%s>", oppretty[exprop(n)], t1);	break;		case OTpost:	bprintf(buf, sizeof buf, "<e:%s>%s", t1, oppretty[exprop(n)]);	break;		case OTzarg:	bprintf(buf, sizeof buf, "%s", oppretty[exprop(n)]);	break;		case OTbin:			bprintf(buf, sizeof buf, "<e1:%s> %s <e2:%s>", t1, oppretty[exprop(n)], t2);			break;		case OTmisc:			switch (exprop(n)) {			case Ovar:	bprintf(buf, sizeof buf, "%s:%s", namestr(args[0]), t);	break;			case Ocall:	ctxstrcall(buf, sizeof buf,n);	break;			case Oidx:				if (exprop(args[0]) == Ovar)					bprintf(buf, sizeof buf, "%s[<e1:%s>]", namestr(args[0]->expr.args[0]), t2);				else					bprintf(buf, sizeof buf, "<sl:%s>[<e1%s>]", t1, t2);				break;			case Oslice:				if (exprop(args[0]) == Ovar)					bprintf(buf, sizeof buf, "%s[<e1:%s>:<e2:%s>]", namestr(args[0]->expr.args[0]), t2, t3);				else					bprintf( buf, sizeof buf, "<sl:%s>[<e1%s>:<e2:%s>]", t1, t2, t3);				break;			case Omemb:				bprintf(buf, sizeof buf, "<%s>.%s", t1, namestr(args[1]));				break;			case Otupmemb:				bprintf(buf, sizeof buf, "<%s>.%llu", t1, args[1]->lit.intval);				break;			default:				bprintf(buf, sizeof buf, "%s:%s", d, t);				break;			}			break;		default: bprintf(buf, sizeof buf, "%s", d); break;		}		free(t);		free(t1);		free(t2);		free(t3);		s = strdup(buf);		break;	}	return s;} static voidaddspecialization(Node *n, Stab *stab){	Node *dcl; 	dcl = decls[n->expr.did];	lappend(&specializationscope, &nspecializationscope, stab);	lappend(&specializations, &nspecializations, n);	lappend(&genericdecls, &ngenericdecls, dcl);} static voidadddispspecialization(Node *n, Stab *stab){	Trait *tr;	Type *ty; 	tr = traittab[Tcdisp];	ty = exprtype(n);	assert(tr->nproto == 1);	if (hthas(tr->proto[0]->decl.impls, ty))		return;	lappend(&specializationscope, &nspecializationscope, stab);	lappend(&specializations, &nspecializations, n);	lappend(&genericdecls, &ngenericdecls, tr->proto[0]);} static voidadditerspecialization(Node *n, Stab *stab){	Trait *tr;	Type *ty;	size_t i; 	tr = traittab[Tciter];	ty = exprtype(n->iterstmt.seq);	if (ty->type == Tyslice || ty->type == Tyarray || ty->type == Typtr)		return;	ty = tyfreshen(NULL, ty);	for (i = 0; i < tr->nproto; i++) {		ty = exprtype(n->iterstmt.seq);		if (hthas(tr->proto[i]->decl.impls, ty))			continue;		lappend(&specializationscope, &nspecializationscope, stab);		lappend(&specializations, &nspecializations, n);		lappend(&genericdecls, &ngenericdecls, tr->proto[i]);	}} static voiddelayedcheck(Node *n){	Postcheck *pc; 	pc = xalloc(sizeof(Postcheck));	pc->node = n;	pc->stab = curstab();	pc->env = curenv();	lappend(&postcheck, &npostcheck, pc);} static voidtypeerror(Type *a, Type *b, Node *ctx, char *msg){	char *t1, *t2, *s1, *s2, *c; 	t1 = tystr(tyfix(NULL, a, 1));	t2 = tystr(tyfix(NULL, b, 1));	s1 = srcstr(a);	s2 = srcstr(b);	c = ctxstr(ctx);	if (msg)		fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s: %s%s%s", t1, t2, c, msg, s1, s2);	else		fatal(ctx, "type \"%s\" incompatible with \"%s\" near %s%s%s", t1, t2, c, s1, s2);	free(t1);	free(t2);	free(s1);	free(s2);	free(c);} /* Set a scope's enclosing scope up correctly. */static voidsetsuperenv(Tyenv *e, Tyenv *super){	if (e)		e->super = super;} /* Set a scope's enclosing scope up correctly. */static voidsetsuper(Stab *st, Stab *super){	Stab *s; 	/* verify that we don't accidentally create loops */	for (s = super; s; s = s->super)		assert(s->super != st);	st->super = super;}  /* Checks if a type that directly contains itself. * Recursive types that contain themselves through * pointers or slices are fine, but any other self-inclusion * would lead to a value of infinite size */static intoccurs_rec(Type *sub, Bitset *bs){	size_t i; 	sub = tf(sub);	if (bshas(bs, sub->tid))		return 1;	bsput(bs, sub->tid);	switch (sub->type) {	case Typtr:	case Tyslice:		break;	case Tystruct:		for (i = 0; i < sub->nmemb; i++)			if (occurs_rec(decltype(sub->sdecls[i]), bs))				return 1;		break;	case Tyunion:		for (i = 0; i < sub->nmemb; i++) {			if (!sub->udecls[i]->etype)				continue;			if (occurs_rec(sub->udecls[i]->etype, bs))				return 1;		}		break;	default:		for (i = 0; i < sub->nsub; i++)			if (occurs_rec(sub->sub[i], bs))				return 1;		break;	}	bsdel(bs, sub->tid);	return 0;} static intoccursin(Type *a, Type *b){	Bitset *bs;	int r; 	bs = mkbs();	a = tf(a);	bsput(bs, a->tid);	r = occurs_rec(b, bs);	bsfree(bs);	return r;} static intoccurs(Type *t){	Bitset *bs;	int r; 	bs = mkbs();	r = occurs_rec(t, bs);	bsfree(bs);	return r;} static intneedfreshenrec(Type *t, Bitset *visited){	size_t i; 	t = tysearch(t);	if (bshas(visited, t->tid))		return 0;	bsput(visited, t->tid);	switch (t->type) {	case Typaram: return 1;	case Tygeneric: return 1;	case Tyname:		for (i = 0; i < t->narg; i++)			if (needfreshenrec(t->arg[i], visited))				return 1;		return needfreshenrec(t->sub[0], visited);	case Tystruct:		for (i = 0; i < t->nmemb; i++)			if (needfreshenrec(decltype(t->sdecls[i]), visited))				return 1;		break;	case Tyunion:		for (i = 0; i < t->nmemb; i++)			if (t->udecls[i]->etype && needfreshenrec(t->udecls[i]->etype, visited))				return 1;		break;	default:		for (i = 0; i < t->nsub; i++)			if (needfreshenrec(t->sub[i], visited))				return 1;		break;	}	return 0;} static intneedfreshen(Type *t){	Bitset *visited;	int ret; 	visited = mkbs();	ret = needfreshenrec(t, visited);	bsfree(visited);	return ret;} /* Freshens the type of a declaration. */static Type *tyfreshen(Tysubst *subst, Type *orig){	Type *ty, *base; 	if (!needfreshen(orig))		return orig;	pushenv(orig->env);	if (!subst) {		subst = mksubst();		ty = tyspecialize(orig, subst, delayed);		substfree(subst);	} else {		ty = tyspecialize(orig, subst, delayed);	}	ty->spec = orig->spec;	ty->nspec = orig->nspec;	base = basetype(ty);	if (base)		ty->seqaux = base;	popenv(orig->env);	return ty;} /* Resolves a type and all its subtypes recursively. */static voidtyresolve(Type *t)

Lines 1–500 of 3038.