Пример #1
0
static Node *assign(Simp *s, Node *lhs, Node *rhs)
{
    Node *t, *u, *v, *r;

    if (exprop(lhs) == Otup) {
        r = destructure(s, lhs, rhs);
    } else {
        t = lval(s, lhs);
        u = rval(s, rhs, t);

        /* if we stored the result into t, rval() should return that,
         * so we know our work is done. */
        if (u == t) {
            r = t;
        } else if (stacknode(lhs)) {
            t = addr(s, t, exprtype(lhs));
            u = addr(s, u, exprtype(lhs));
            v = disp(lhs->line, size(lhs));
            r = mkexpr(lhs->line, Oblit, t, u, v, NULL);
        } else {
            r = set(t, u);
        }
    }
    return r;
}
Пример #2
0
static Node *slicebase(Simp *s, Node *n, Node *off)
{
    Node *t, *u, *v;
    Type *ty;
    int sz;

    t = rval(s, n, NULL);
    u = NULL;
    ty = tybase(exprtype(n));
    switch (ty->type) {
        case Typtr:     u = t; break;
        case Tyarray:   u = addr(s, t, base(exprtype(n))); break;
        case Tyslice:   u = load(addr(s, t, mktyptr(n->line, base(exprtype(n))))); break;
        default: die("Unslicable type %s", tystr(n->expr.type));
    }
    /* safe: all types we allow here have a sub[0] that we want to grab */
    if (off) {
      off = ptrsized(s, rval(s, off, NULL));
      sz = tysize(n->expr.type->sub[0]);
      v = mul(off, disp(n->line, sz));
      return add(u, v);
    } else {
      return u;
    }
}
Пример #3
0
Файл: fold.c Проект: 8l/mc
static Node *foldcast(Node *n)
{
	Type *to, *from;
	Node *sub;

	sub = n->expr.args[0];
	to = exprtype(n);
	from = exprtype(sub);

	switch (tybase(to)->type) {
	case Tybool:
	case Tyint8: case Tyint16: case Tyint32: case Tyint64:
	case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
	case Tyint: case Tyuint: case Tychar: case Tybyte:
	case Typtr:
		switch (tybase(from)->type) {
		case Tybool:
		case Tyint8: case Tyint16: case Tyint32: case Tyint64:
		case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
		case Tyint: case Tyuint: case Tychar: case Tybyte:
		case Typtr:
			if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) {
				sub->expr.type = to;
				return sub;
			} else {
				return n;
			}
		default:
			return n;
		}
	default:
		return n;
	}
	return n;
}
Пример #4
0
/* Takes a tuple and binds the i'th element of it to the
 * i'th name on the rhs of the assignment. */
static Node *destructure(Simp *s, Node *lhs, Node *rhs)
{
    Node *plv, *prv, *lv, *sz, *stor, **args;
    size_t off, i;

    args = lhs->expr.args;
    rhs = rval(s, rhs, NULL);
    off = 0;
    for (i = 0; i < lhs->expr.nargs; i++) {
        lv = lval(s, args[i]);
        off = tyalign(off, size(lv));
        prv = add(addr(s, rhs, exprtype(args[i])), disp(rhs->line, off));
        if (stacknode(args[i])) {
            sz = disp(lhs->line, size(lv));
            plv = addr(s, lv, exprtype(lv));
            stor = mkexpr(lhs->line, Oblit, plv, prv, sz, NULL);
        } else {
            stor = set(lv, load(prv));
        }
        append(s, stor);
        off += size(lv);
    }

    return NULL;
}
Пример #5
0
Файл: flatten.c Проект: oridb/mc
static Node *
comparecomplex(Flattenctx *s, Node *n, Op op)
{
	Type *ty;
	Node *l, *r, *e;

	/* special case: unions with nullary constructors can be compared easily. */
	ty = tybase(exprtype(n->expr.args[0]));
	if (ty->type == Tyunion && isenum(ty)) {
		l = mkexpr(n->loc, Outag, rval(s, n->expr.args[0]), NULL);
		r = mkexpr(n->loc, Outag, rval(s, n->expr.args[1]), NULL);
		l->expr.type = mktype(n->loc, Tyuint32);
		r->expr.type = mktype(n->loc, Tyuint32);
		if (op == Oeq)
			e = mkexpr(n->loc, Oueq, l, r, NULL);
		else if (op == One)
			e = mkexpr(n->loc, Oune, l, r, NULL);
		else
			fatal(n, "unsupported operator %s for enum union", opstr[op]);
		e->expr.type = mktype(n->loc, Tybool);
		return e;
	}
	fatal(n, "cannot compare values of type %s for equality\n",
	    tystr(exprtype(n->expr.args[0])));
	return NULL;
}
Пример #6
0
Файл: flatten.c Проект: oridb/mc
static Node *
asn(Node *a, Node *b)
{
	Node *n;

	assert(a != NULL && b != NULL);
	if (tybase(exprtype(a))->type == Tyvoid)
		return a;

	n = mkexpr(a->loc, Oasn, a, b, NULL);
	n->expr.type = exprtype(a);
	return n;
}
Пример #7
0
static Node *seqlen(Simp *s, Node *n, Type *ty)
{
    Node *t, *r;

    if (exprtype(n)->type == Tyslice) {
        t = slicelen(s, n);
        r = simpcast(s, t, ty);
    } else if (exprtype(n)->type == Tyarray) {
        t = exprtype(n)->asize;
        r = simpcast(s, t, ty);
    } else {
        r = NULL;
    }
    return r;
}
Пример #8
0
Файл: match.c Проект: 8l/myrddin
Node *gensimpmatch(Node *m)
{
    Dtree *t, *leaf;
    Node **pat, **cap;
    size_t npat, ncap;
    size_t i;
    Node *n;

    pat = m->matchstmt.matches;
    npat = m->matchstmt.nmatches;
    t = mkdtree();
    for (i = 0; i < npat; i++) {
        cap = NULL;
        ncap = 0;
        leaf = addpat(t, pat[i]->match.pat, m->matchstmt.val, &cap, &ncap);
        /* TODO: NULL is returned by unsupported patterns. */
        if (!leaf)
            return NULL;
        if (leaf->act)
            fatal(pat[i], "pattern matched by earlier case on line %d", leaf->act->loc.line);
        leaf->act = pat[i]->match.block;
        leaf->cap = cap;
        leaf->ncap = ncap;
    }
    if (!exhaustivematch(m, t, exprtype(m->matchstmt.val)))
        fatal(m, "nonexhaustive pattern set in match statement");
    n = genmatch(m->loc, t);
    dump(n, stdout);
    return n;
}
Пример #9
0
/* Simplifies taking a slice of an array, pointer,
 * or other slice down to primitive pointer operations */
static Node *simpslice(Simp *s, Node *n, Node *dst)
{
    Node *t;
    Node *start, *end;
    Node *base, *sz, *len;
    Node *stbase, *stlen;

    if (dst)
        t = dst;
    else
        t = temp(s, n);
    /* *(&slice) = (void*)base + off*sz */
    base = slicebase(s, n->expr.args[0], n->expr.args[1]);
    start = ptrsized(s, rval(s, n->expr.args[1], NULL));
    end = ptrsized(s, rval(s, n->expr.args[2], NULL));
    len = sub(end, start);
    /* we can be storing through a pointer, in the case
     * of '*foo = bar'. */
    if (tybase(exprtype(t))->type == Typtr) {
        stbase = set(simpcast(s, t, mktyptr(t->line, tyintptr)), base);
        sz = addk(simpcast(s, t, mktyptr(t->line, tyintptr)), Ptrsz);
    } else {
        stbase = set(deref(addr(s, t, tyintptr)), base);
        sz = addk(addr(s, t, tyintptr), Ptrsz);
    }
    /* *(&slice + ptrsz) = len */
    stlen = set(deref(sz), len);
    append(s, stbase);
    append(s, stlen);
    return t;
}
Пример #10
0
static Node *addk(Node *n, uvlong v)
{
    Node *k;

    k = mkintlit(n->line, v);
    k->expr.type = exprtype(n);
    return add(n, k);
}
Пример #11
0
Файл: match.c Проект: 8l/myrddin
static Dtree *addunion(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
{
    Node *elt, *tag, *id;
    int32_t t1, t2;
    Dtree *sub;
    Ucon *uc;
    size_t i;

    if (t->any)
        return t->any;
    uc = finducon(tybase(exprtype(pat)), pat->expr.args[0]);
    t2 = uc->id;
    /* if we have the value already... */
    sub = NULL;
    for (i = 0; i < t->nval; i++) {
        tag = t->val[i]->expr.args[0];
        t1 = tag->lit.intval;
        if (t1 == t2) {
            if (pat->expr.nargs > 1) {
                elt = uvalue(val, exprtype(pat->expr.args[1])); 
                return addpat(t->sub[i], pat->expr.args[1], elt, cap, ncap);
            } else {
                return t->sub[i];
            }
        }
    }

    /* otherwise create a new match */
    sub = mkdtree();
    sub->patexpr = pat;
    tag = mkexpr(pat->loc, Outag, val, NULL);
    tag->expr.type = mktype(pat->loc, Tyint32);

    id = mkintlit(pat->loc, uc->id);
    id->expr.type = mktype(pat->loc, Tyint32);

    lappend(&t->val, &t->nval, id);
    lappend(&t->sub, &t->nsub, sub);
    lappend(&t->load, &t->nload, tag);
    if (pat->expr.nargs == 2) {
        elt = uvalue(val, exprtype(pat->expr.args[1])); 
        sub = addpat(sub, pat->expr.args[1], elt, cap, ncap);
    }
    return sub;
}
Пример #12
0
Файл: flatten.c Проект: oridb/mc
static Node *
seqlen(Flattenctx *s, Node *n, Type *ty)
{
	Node *r;

	if (!ty)
		ty = n->expr.type;
	if (exprtype(n)->type == Tyarray) {
		r = mkexpr(n->loc, Osllen, rval(s, n), NULL);
		r->expr.type = ty;
	} else if (exprtype(n)->type == Tyslice) {
		r = mkexpr(n->loc, Osllen, rval(s, n), NULL);
		r->expr.type = ty;
	} else {
		die("invalid seq type for len");
	}
	return r;
}
Пример #13
0
Файл: flatten.c Проект: oridb/mc
static Node *
subk(Node *n, uvlong v)
{
	Node *k;

	k = mkintlit(n->loc, v);
	k->expr.type = exprtype(n);
	return sub(n, k);
}
Пример #14
0
static Node *membaddr(Simp *s, Node *n)
{
    Node *t, *u, *r;
    Node **args;
    Type *ty;

    args = n->expr.args;
    ty = tybase(exprtype(args[0]));
    if (ty->type == Typtr) {
        t = lval(s, args[0]);
    } else {
        t = addr(s, lval(s, args[0]), exprtype(n));
    }
    u = disp(n->line, offset(args[0], args[1]));
    r = add(t, u);
    r->expr.type = mktyptr(n->line, n->expr.type);
    return r;
}
Пример #15
0
static Node *set(Node *a, Node *b)
{
    Node *n;

    assert(a != NULL && b != NULL);
    assert(exprop(a) == Ovar || exprop(a) == Oderef);
    n = mkexpr(a->line, Oset, a, b, NULL);
    n->expr.type = exprtype(a);
    return n;
}
Пример #16
0
Файл: match.c Проект: 8l/myrddin
static Node *arrayelt(Node *n, size_t i)
{
    Node *idx, *elt;

    idx = mkintlit(n->loc, i);
    idx->expr.type = mktype(n->loc, Tyuint64);
    elt = mkexpr(n->loc, Oidx, n, idx, NULL);
    elt->expr.type = tybase(exprtype(n))->sub[0];
    return elt;
}
Пример #17
0
static int issmallconst(Node *dcl)
{
    Type *t;

    if (!dcl->decl.isconst)
        return 0;
    if (!dcl->decl.init)
        return 0;
    t = tybase(exprtype(dcl->decl.init));
    if (t->type <= Tyfloat64)
        return 1;
    return 0;
}
Пример #18
0
static Node *idxaddr(Simp *s, Node *seq, Node *idx)
{
    Node *a, *t, *u, *v; /* temps */
    Node *r; /* result */
    Type *ty;
    size_t sz;

    a = rval(s, seq, NULL);
    ty = exprtype(seq)->sub[0];
    if (exprtype(seq)->type == Tyarray)
        t = addr(s, a, ty);
    else if (seq->expr.type->type == Tyslice)
        t = load(addr(s, a, mktyptr(seq->line, ty)));
    else
        die("Can't index type %s\n", tystr(seq->expr.type));
    assert(t->expr.type->type == Typtr);
    u = rval(s, idx, NULL);
    u = ptrsized(s, u);
    sz = tysize(ty);
    v = mul(u, disp(seq->line, sz));
    r = add(t, v);
    return r;
}
Пример #19
0
Файл: match.c Проект: 8l/myrddin
static int isexhaustive(Dtree *dt)
{
    Type *subt;
    size_t i;

    if (dt->any)
        return 1;

    if (dt->nsub > 0) {
        subt = tybase(exprtype(dt->sub[0]->patexpr));
        if (dt->nsub != nconstructors(subt))
            return 0;
    }
    switch (exprop(dt->patexpr)) {
        case Ovar:
            return 1;
        case Olit:
            return 1;
        case Oucon:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        case Otup:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        case Oarr:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        case Ostruct:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        default:
            die("Invalid pattern in exhaustivenes check. BUG.");
            break;
    }
    return 0;
}
Пример #20
0
static void checkundef(Node *n, Reaching *r, Bitset *reach, Bitset *kill)
{
    size_t i, j, did;
    Node *def;
    Type *t;

    if (n->type != Nexpr)
        return;
    if (exprop(n) == Ovar) {
        did = n->expr.did;
        for (j = 0; j < r->ndefs[did]; j++) {
            t = tybase(exprtype(n));
            if (t->type == Tystruct || t->type == Tyunion || t->type == Tyarray || t->type == Tytuple)
                continue;
            if (bshas(kill, r->defs[did][j]))
                continue;
            if (!bshas(reach, r->defs[did][j]))
                continue;
            def = nodes[r->defs[did][j]];
            if (exprop(def) == Oundef)
                fatal(n, "%s used before definition", namestr(n->expr.args[0]));
        }
    } else {
        switch (exprop(n)) {
            case Oset:
            case Oasn:
            case Oblit:
                checkundef(n->expr.args[1], r, reach, kill);
                break;
            case Oaddr:
            case Oslice:
                /* these don't actually look at the of args[0], so they're ok. */
                for (i = 1; i < n->expr.nargs; i++)
                    checkundef(n->expr.args[i], r, reach, kill);
                break;
            case Ocall:
                for (i = 1; i < n->expr.nargs; i++)
                    if (exprop(n->expr.args[i]) != Oaddr)
                        checkundef(n->expr.args[i], r, reach, kill);
                break;
            default:
                for (i = 0; i < n->expr.nargs; i++)
                    checkundef(n->expr.args[i], r, reach, kill);
                break;
        }
    }
}
Пример #21
0
static Node *assignat(Simp *s, Node *r, size_t off, Node *val)
{
    Node *pval, *pdst;
    Node *sz;
    Node *st;

    val = rval(s, val, NULL);
    pdst = add(r, disp(val->line, off));

    if (stacknode(val)) {
        sz = disp(val->line, size(val));
        pval = addr(s, val, exprtype(val));
        st = mkexpr(val->line, Oblit, pdst, pval, sz, NULL);
    } else {
        st = set(deref(pdst), val);
    }
    append(s, st);
    return r;
}
Пример #22
0
/* Simplify tuple construction to a stack allocated
 * value by evaluating the rvalue of each node on the
 * rhs and assigning it to the correct offset from the
 * head of the tuple. */
static Node *simptup(Simp *s, Node *n, Node *dst)
{
    Node **args;
    Node *r;
    size_t i, off;

    args = n->expr.args;
    if (!dst)
        dst = temp(s, n);
    r = addr(s, dst, exprtype(dst));

    off = 0;
    for (i = 0; i < n->expr.nargs; i++) {
        off = tyalign(off, size(args[i]));
        assignat(s, r, off, args[i]);
        off += size(args[i]);
    }
    return dst;
}
Пример #23
0
Файл: flatten.c Проект: oridb/mc
static void
dispose(Flattenctx *s, Stab *st, size_t n)
{
	Node *e, *call, *func;
	Trait *tr;
	Type *ty;
	size_t i;

	tr = traittab[Tcdisp];
	/* dispose in reverse order of appearance */
	for (i = st->nautotmp; i-- > n;) {
		e = st->autotmp[i];
		ty = exprtype(e);
		func = traitfn(Zloc, tr, "__dispose__", ty);
		call = mkexpr(Zloc, Ocall, func, e, NULL);
		call->expr.type = mktype(Zloc, Tyvoid);
		flatten(s, call);
	}
}
Пример #24
0
static Node *visit(Simp *s, Node *n)
{
    size_t i;
    Node *r;

    for (i = 0; i < n->expr.nargs; i++)
        n->expr.args[i] = rval(s, n->expr.args[i], NULL);
    if (ispure(n)) {
        r = n;
    } else {
        if (exprtype(n)->type == Tyvoid) {
            r = NULL;
            append(s, n);
        } else {
            r = temp(s, n);
            append(s, set(r, n));
        }
    }
    return r;
}
Пример #25
0
Файл: match.c Проект: 8l/myrddin
static Dtree *addstruct(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
{
    Node *elt, *memb;
    Type *ty;
    size_t i, j;

    if (t->any)
        return t->any;
    for (i = 0; i < pat->expr.nargs; i++) {
        elt = pat->expr.args[i];
        for (j = 0; j < t->nval; j++) {
            if (!strcmp(namestr(elt->expr.idx), namestr(t->val[j]->expr.idx))) {
                ty = exprtype(pat->expr.args[i]);
                memb = structmemb(val, elt->expr.idx, ty);
                t = addpat(t, pat->expr.args[i], memb, cap, ncap);
                break;
            }
        }
    }
    return t;
}
Пример #26
0
Файл: match.c Проект: 8l/myrddin
void dtdumpnode(Dtree *dt, FILE *f, int depth, int iswild)
{
    Node *e;
    size_t i;
    char *s;

    if (dt->patexpr) {
        e = dt->patexpr;
        s = tystr(exprtype(e));
        indentf(depth, "%s%s %s : %s\n", iswild ? "WILDCARD " : "", opstr[exprop(e)], dtnodestr(e), s);
        free(s);
    } 
    if (dt->cap)
        for (i = 0; i < dt->ncap; i++)
            indentf(depth + 1, "capture %s\n", dtnodestr(dt->cap[i]));
    if (dt->act)
        indentf(depth + 1, "action\n");
    for (i = 0; i < dt->nsub; i++)
        dtdumpnode(dt->sub[i], f, depth + 1, 0);
    if (dt->any)
        dtdumpnode(dt->any, f, depth + 1, 1);
}
Пример #27
0
Файл: flatten.c Проект: oridb/mc
static Node *
visit(Flattenctx *s, Node *n)
{
	size_t i;
	Node *r;

	for (i = 0; i < n->expr.nargs; i++)
		n->expr.args[i] = rval(s, n->expr.args[i]);
	if (opispure[exprop(n)]) {
		r = n;
	} else {
		if (exprtype(n)->type == Tyvoid) {
			r = mkexpr(n->loc, Olit, mkvoid(n->loc), NULL);
			r->expr.type = mktype(n->loc, Tyvoid);
			append(s, n);
		} else {
			r = temp(s, n);
			append(s, asn(r, n));
		}
	}
	return r;
}
Пример #28
0
/* gets the byte offset of 'memb' within the aggregate type 'aggr' */
static size_t offset(Node *aggr, Node *memb)
{
    Type *ty;
    Node **nl;
    size_t i;
    size_t off;

    ty = tybase(exprtype(aggr));
    if (ty->type == Typtr)
        ty = tybase(ty->sub[0]);

    assert(ty->type == Tystruct);
    nl = ty->sdecls;
    off = 0;
    for (i = 0; i < ty->nmemb; i++) {
        off = tyalign(off, size(nl[i]));
        if (!strcmp(namestr(memb), declname(nl[i])))
            return off;
        off += size(nl[i]);
    }
    die("Could not find member %s in struct", namestr(memb));
    return -1;
}
Пример #29
0
Файл: match.c Проект: 8l/myrddin
static Dtree *addpat(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
{
    Dtree *ret;
    Node *dcl;

    if (pat == NULL)
        return t;
    pat = fold(pat, 1);
    switch (exprop(pat)) {
        case Ovar:
            dcl = decls[pat->expr.did];
            if (dcl->decl.isconst)
                ret = addpat(t, dcl->decl.init, val, cap, ncap);
            else
                ret = addwild(t, pat, val, cap, ncap);
            break;
        case Oucon:
            ret = addunion(t, pat, val, cap, ncap);
            break;
        case Olit:
            ret = addlit(t, pat, val, cap, ncap);
            break;
        case Otup:
            ret = addtup(t, pat, val, cap, ncap);
            break;
        case Oarr:
            ret = addarr(t, pat, val, cap, ncap);
            break;
        case Ostruct:
            ret = addstruct(t, pat, val, cap, ncap);
            break;
        case Ogap:
            ret = addwild(t, pat, val, NULL, NULL);
            break;
        default:
            ret = NULL;
            fatal(pat, "unsupported pattern %s of type %s", opstr[exprop(pat)], tystr(exprtype(pat)));
            break;
    }
    return ret;
}
Пример #30
0
static Node *simpcast(Simp *s, Node *val, Type *to)
{
    Node *r;
    Type *t;

    r = NULL;
    /* do the type conversion */
    switch (tybase(to)->type) {
        case Tybool:
        case Tyint8: case Tyint16: case Tyint32: case Tyint64:
        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
        case Tyint: case Tyuint: case Tylong: case Tyulong:
        case Tychar: case Tybyte:
        case Typtr:
            t = tybase(exprtype(val));
            switch (t->type) {
                /* ptr -> slice conversion is disallowed */
                case Tyslice:
                    if (t->type == Typtr)
                        fatal(val->line, "Bad cast from %s to %s",
                              tystr(exprtype(val)), tystr(to));
                    r = slicebase(s, val, NULL);
                    break;
                /* signed conversions */
                case Tyint8: case Tyint16: case Tyint32: case Tyint64:
                case Tyint: case Tylong:
                    r = intconvert(s, val, to, 1);
                    break;
                /* unsigned conversions */
                case Tybool:
                case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
                case Tyuint: case Tyulong: case Tychar: case Tybyte:
                case Typtr:
                    r = intconvert(s, val, to, 0);
                    break;
                case Tyfloat32: case Tyfloat64:
                    if (tybase(to)->type == Typtr)
                        fatal(val->line, "Bad cast from %s to %s",
                              tystr(exprtype(val)), tystr(to));
                    r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL);
                    r->expr.type = to;
                    break;
                default:
                    fatal(val->line, "Bad cast from %s to %s",
                          tystr(exprtype(val)), tystr(to));
            }
            break;
        case Tyfloat32: case Tyfloat64:
            t = tybase(exprtype(val));
            switch (t->type) {
                case Tyint8: case Tyint16: case Tyint32: case Tyint64:
                case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
                case Tyint: case Tyuint: case Tylong: case Tyulong:
                case Tychar: case Tybyte:
                    r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL);
                    r->expr.type = to;
                    break;
                default:
                    fatal(val->line, "Bad cast from %s to %s",
                          tystr(exprtype(val)), tystr(to));
                    break;
            }
            break;
        /* no other destination types are handled as things stand */
        default:
            fatal(val->line, "Bad cast from %s to %s",
                  tystr(exprtype(val)), tystr(to));
    }
    return r;
}