diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/6g/cgen.c | 2 | ||||
| -rw-r--r-- | src/cmd/gc/bits.c | 25 | ||||
| -rw-r--r-- | src/cmd/gc/builtin.c.boot | 28 | ||||
| -rw-r--r-- | src/cmd/gc/closure.c | 6 | ||||
| -rw-r--r-- | src/cmd/gc/const.c | 11 | ||||
| -rw-r--r-- | src/cmd/gc/dcl.c | 19 | ||||
| -rw-r--r-- | src/cmd/gc/export.c | 29 | ||||
| -rw-r--r-- | src/cmd/gc/go.h | 25 | ||||
| -rw-r--r-- | src/cmd/gc/lex.c | 26 | ||||
| -rw-r--r-- | src/cmd/gc/print.c | 7 | ||||
| -rw-r--r-- | src/cmd/gc/range.c | 10 | ||||
| -rw-r--r-- | src/cmd/gc/runtime.go | 32 | ||||
| -rw-r--r-- | src/cmd/gc/subr.c | 488 | ||||
| -rw-r--r-- | src/cmd/gc/typecheck.c | 326 | ||||
| -rw-r--r-- | src/cmd/gc/walk.c | 386 | ||||
| -rw-r--r-- | src/pkg/math/fltasm_amd64.s | 67 | ||||
| -rw-r--r-- | src/pkg/runtime/iface.c | 208 |
17 files changed, 757 insertions, 938 deletions
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c index 282f6d7be..aacc0d06f 100644 --- a/src/cmd/6g/cgen.c +++ b/src/cmd/6g/cgen.c @@ -431,7 +431,7 @@ agen(Node *n, Node *res) if(n == N || n->type == T) return; - if(!isptr[res->type->etype]) + if(!isptr[res->type->etype] && res->type->etype != TUINTPTR) fatal("agen: not tptr: %T", res->type); while(n->op == OCONVNOP) diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c index 57caf58dc..59a8e04ef 100644 --- a/src/cmd/gc/bits.c +++ b/src/cmd/gc/bits.c @@ -133,25 +133,22 @@ bitno(int32 b) int Qconv(Fmt *fp) { - char str[STRINGSZ], ss[STRINGSZ], *s; Bits bits; - int i; + int i, first; - str[0] = 0; + first = 1; bits = va_arg(fp->args, Bits); while(bany(&bits)) { i = bnum(bits); - if(str[0]) - strcat(str, " "); - if(var[i].sym == S) { - sprint(ss, "$%lld", var[i].offset); - s = ss; - } else - s = var[i].sym->name; - if(strlen(str) + strlen(s) + 1 >= STRINGSZ) - break; - strcat(str, s); + if(first) + first = 0; + else + fmtprint(fp, " "); + if(var[i].sym == S) + fmtprint(fp, "$%lld", var[i].offset); + else + fmtprint(fp, var[i].sym->name); bits.b[i/32] &= ~(1L << (i%32)); } - return fmtstrcpy(fp, str); + return 0; } diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot index 1e7a14947..3e2d98872 100644 --- a/src/cmd/gc/builtin.c.boot +++ b/src/cmd/gc/builtin.c.boot @@ -33,18 +33,22 @@ char *runtimeimport = "func \"\".stringiter (? string, ? int) int\n" "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n" "func \"\".slicecopy (to any, fr any, wid uint32) int\n" - "func \"\".ifaceI2E (iface any) any\n" - "func \"\".ifaceE2I (typ *uint8, iface any) any\n" - "func \"\".ifaceT2E (typ *uint8, elem any) any\n" - "func \"\".ifaceE2T (typ *uint8, elem any) any\n" - "func \"\".ifaceE2I2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".ifaceE2T2 (typ *uint8, elem any) (ret any, ok bool)\n" - "func \"\".ifaceT2I (typ1 *uint8, typ2 *uint8, elem any) any\n" - "func \"\".ifaceI2T (typ *uint8, iface any) any\n" - "func \"\".ifaceI2T2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".ifaceI2I (typ *uint8, iface any) any\n" - "func \"\".ifaceI2Ix (typ *uint8, iface any) any\n" - "func \"\".ifaceI2I2 (typ *uint8, iface any) (ret any, ok bool)\n" + "func \"\".convI2E (elem any) any\n" + "func \"\".convI2I (typ *uint8, elem any) any\n" + "func \"\".convT2E (typ *uint8, elem any) any\n" + "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n" + "func \"\".assertE2E (typ *uint8, iface any) any\n" + "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n" + "func \"\".assertE2I (typ *uint8, iface any) any\n" + "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n" + "func \"\".assertE2T (typ *uint8, iface any) any\n" + "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n" + "func \"\".assertI2E (typ *uint8, iface any) any\n" + "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n" + "func \"\".assertI2I (typ *uint8, iface any) any\n" + "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n" + "func \"\".assertI2T (typ *uint8, iface any) any\n" + "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n" "func \"\".ifaceeq (i1 any, i2 any) bool\n" "func \"\".efaceeq (i1 any, i2 any) bool\n" "func \"\".ifacethash (i1 any) uint32\n" diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index c194a0df3..a24a03a49 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -119,6 +119,7 @@ walkclosure(Node *func, NodeList **init) Node *xtype, *v, *addr, *xfunc, *call, *clos; NodeList *l, *in; static int closgen; + char *p; /* * wrap body in external function @@ -134,8 +135,9 @@ walkclosure(Node *func, NodeList **init) if(v->op == 0) continue; addr = nod(ONAME, N, N); - snprint(namebuf, sizeof namebuf, "&%s", v->sym->name); - addr->sym = lookup(namebuf); + p = smprint("&%s", v->sym->name); + addr->sym = lookup(p); + free(p); addr->ntype = nod(OIND, typenod(v->type), N); addr->class = PPARAM; addr->addable = 1; diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index be351def6..c33d4d3a7 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -93,8 +93,11 @@ convlit1(Node **np, Type *t, int explicit) return; case OLITERAL: // target is invalid type for a constant? leave alone. - if(!okforconst[t->etype] && n->type->etype != TNIL) + if(!okforconst[t->etype] && n->type->etype != TNIL) { + defaultlit(&n, T); + *np = n; return; + } break; case OLSH: case ORSH: @@ -109,10 +112,8 @@ convlit1(Node **np, Type *t, int explicit) } // avoided repeated calculations, errors - if(cvttype(n->type, t) == 1) { - n->type = t; + if(eqtype(n->type, t)) return; - } ct = consttype(n); if(ct < 0) @@ -968,6 +969,8 @@ defaultlit(Node **np, Type *t) break; case CTBOOL: n->type = types[TBOOL]; + if(t != T && t->etype == TBOOL) + n->type = t; break; case CTINT: n->type = types[TINT]; diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index bb81d2a22..48391d510 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -281,6 +281,7 @@ updatetype(Type *n, Type *t) local = n->local; vargen = n->vargen; *n = *t; + n->orig = t->orig; n->sym = s; n->local = local; n->siggen = 0; @@ -759,7 +760,7 @@ typedcl2(Type *pt, Type *t) if(pt->etype == TFORW) goto ok; - if(!cvttype(pt, t)) + if(!eqtype(pt->orig, t)) yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t); return; @@ -1154,7 +1155,7 @@ Sym* methodsym(Sym *nsym, Type *t0) { Sym *s; - char buf[NSYMB]; + char *p; Type *t; t = t0; @@ -1177,8 +1178,10 @@ methodsym(Sym *nsym, Type *t0) if(t != t0 && t0->sym) t0 = ptrto(t); - snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name); - return pkglookup(buf, s->pkg); + p = smprint("%#hT·%s", t0, nsym->name); + s = pkglookup(p, s->pkg); + free(p); + return s; bad: yyerror("illegal receiver type: %T", t0); @@ -1200,7 +1203,7 @@ Node* methodname1(Node *n, Node *t) { char *star; - char buf[NSYMB]; + char *p; star = ""; if(t->op == OIND) { @@ -1209,8 +1212,10 @@ methodname1(Node *n, Node *t) } if(t->sym == S || isblank(n)) return newname(n->sym); - snprint(buf, sizeof(buf), "%s%S·%S", star, t->sym, n->sym); - return newname(pkglookup(buf, t->sym->pkg)); + p = smprint("%s%S·%S", star, t->sym, n->sym); + n = newname(pkglookup(p, t->sym->pkg)); + free(p); + return n; } /* diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index d11ddf2ea..9992c5219 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -182,10 +182,22 @@ dumpexporttype(Sym *s) Bprint(bout, "type %#T %l#T\n", t, t); } +static int +methcmp(const void *va, const void *vb) +{ + Type *a, *b; + + a = *(Type**)va; + b = *(Type**)vb; + return strcmp(a->sym->name, b->sym->name); +} + void dumpsym(Sym *s) { Type *f, *t; + Type **m; + int i, n; if(s->flags & SymExported) return; @@ -207,14 +219,23 @@ dumpsym(Sym *s) break; case OTYPE: t = s->def->type; - // TODO(rsc): sort methods by name - for(f=t->method; f!=T; f=f->down) + n = 0; + for(f=t->method; f!=T; f=f->down) { dumpprereq(f); + n++; + } + m = mal(n*sizeof m[0]); + i = 0; + for(f=t->method; f!=T; f=f->down) + m[i++] = f; + qsort(m, n, sizeof m[0], methcmp); dumpexporttype(s); - for(f=t->method; f!=T; f=f->down) + for(i=0; i<n; i++) { + f = m[i]; Bprint(bout, "\tfunc (%#T) %hS %#hhT\n", f->type->type->type, f->sym, f->type); + } break; case ONAME: dumpexportvar(s); @@ -357,7 +378,7 @@ importvar(Sym *s, Type *t, int ctxt) importsym(s, ONAME); if(s->def != N && s->def->op == ONAME) { - if(cvttype(t, s->def->type)) + if(eqtype(t, s->def->type)) return; yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", s, s->def->type, t); diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 5aa95eee3..18e87f0ca 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -158,6 +158,7 @@ struct Type uchar isddd; // TFIELD is ... argument Node* nod; // canonical OTYPE node + Type* orig; // original type (type literal or predefined type) int lineno; // TFUNCT @@ -361,11 +362,12 @@ enum OCLOSURE, OCMPIFACE, OCMPSTR, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, - OCONV, OCONVNOP, OCONVIFACE, OCONVSLICE, + OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE, OCOPY, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, ODOTTYPE, + ODOTTYPE2, OEQ, ONE, OLT, OLE, OGE, OGT, OIND, OINDEX, OINDEXSTR, OINDEXMAP, @@ -904,26 +906,21 @@ NodeList* list(NodeList*, Node*); NodeList* concat(NodeList*, NodeList*); int count(NodeList*); Node* liststmt(NodeList*); - Type** getthis(Type*); Type** getoutarg(Type*); Type** getinarg(Type*); - Type* getthisx(Type*); Type* getoutargx(Type*); Type* getinargx(Type*); - Type* structfirst(Iter*, Type**); Type* structnext(Iter*); Type* funcfirst(Iter*, Type*); Type* funcnext(Iter*); - int brcom(int); int brrev(int); void setmaxarg(Type*); int dotoffset(Node*, int*, Node**); void tempname(Node*, Type*); - int Econv(Fmt*); int Jconv(Fmt*); int Lconv(Fmt*); @@ -934,23 +931,22 @@ int Nconv(Fmt*); void exprfmt(Fmt*, Node*, int); int Wconv(Fmt*); int Zconv(Fmt*); - int lookdot0(Sym*, Type*, Type**); int adddot1(Sym*, Type*, int, Type**); Node* adddot(Node*); void expandmeth(Sym*, Type*); void genwrapper(Type*, Type*, Sym*); - int simsimtype(Type*); - int powtwo(Node*); Type* tounsigned(Type*); void smagic(Magic*); void umagic(Magic*); - void redeclare(Sym*, char*); Sym* ngotype(Node*); - +int convertop(Type*, Type*, char**); +int assignop(Type*, Type*, char**); +Node* assignconv(Node*, Type*, char*); +int implements(Type*, Type*, Type**, Type**); /* * dcl.c @@ -1053,7 +1049,6 @@ void walkstmt(Node**); void walkstmtlist(NodeList*); void walkexprlist(NodeList*, NodeList**); void walkconv(Node**, NodeList**); -void walkdottype(Node*, NodeList**); void walkas(Node*); void walkswitch(Node*); void walkrange(Node*); @@ -1071,8 +1066,6 @@ Type* fixchan(Type*); Node* ifacecvt(Type*, Node*, int, NodeList**); int ifaceas(Type*, Type*, int); int ifaceas1(Type*, Type*, int); -void ifacecheck(Type*, Type*, int, int); -void runifacechecks(void); Node* convas(Node*, NodeList**); Node* colas(NodeList*, NodeList*); void colasdefn(NodeList*, Node*); @@ -1090,10 +1083,10 @@ void typecheckswitch(Node*); void typecheckselect(Node*); void typecheckrange(Node*); Node* typecheckconv(Node*, Node*, Type*, int, char*); -int checkconv(Type*, Type*, int, int*, int*, char*); Node* typecheck(Node**, int); int islvalue(Node*); void queuemethod(Node*); +int exportassignok(Type*, char*); /* * const.c @@ -1242,4 +1235,4 @@ int duintptr(Sym *s, int off, uint64 v); int duintxx(Sym *s, int off, uint64 v, int wid); void genembedtramp(Type*, Type*, Sym*); int gen_as_init(Node*); -int anyregalloc(); +int anyregalloc(void); diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index f50c857a6..7f8527174 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -148,8 +148,21 @@ main(int argc, char *argv[]) typecheckok = 1; if(debug['f']) frame(1); + + // Process top-level declarations in three phases. + // Phase 1: const, type, and names and types of funcs. + // This will gather all the information about types + // and methods but doesn't depend on any of it. + // Phase 2: Variable assignments. + // To check interface assignments, depends on phase 1. + // Phase 3: Function bodies. defercheckwidth(); - typechecklist(xtop, Etop); + for(l=xtop; l; l=l->next) + if(l->n->op != ODCL && l->n->op != OAS) + typecheck(&l->n, Etop); + for(l=xtop; l; l=l->next) + if(l->n->op == ODCL || l->n->op == OAS) + typecheck(&l->n, Etop); resumecheckwidth(); for(l=xtop; l; l=l->next) if(l->n->op == ODCLFUNC) @@ -164,7 +177,6 @@ main(int argc, char *argv[]) } dclchecks(); - runifacechecks(); if(nerrors) errorexit(); @@ -1155,7 +1167,7 @@ loop: int escchar(int e, int *escflg, vlong *val) { - int i, c; + int i, u, c; vlong l; *escflg = 0; @@ -1177,6 +1189,7 @@ escchar(int e, int *escflg, vlong *val) return 0; } + u = 0; c = getr(); switch(c) { case 'x': @@ -1186,10 +1199,12 @@ escchar(int e, int *escflg, vlong *val) case 'u': i = 4; + u = 1; goto hex; case 'U': i = 8; + u = 1; goto hex; case '0': @@ -1239,6 +1254,10 @@ hex: ungetc(c); break; } + if(u && l > Runemax) { + yyerror("invalid Unicode code point in escape sequence: %#llx", l); + l = Runeerror; + } *val = l; return 0; @@ -1388,7 +1407,6 @@ lexinit(void) // (the type of x in var x string or var x = "hello"). // this is the ideal form // (the type of x in const x = "hello"). - // TODO(rsc): this may need some more thought. idealstring = typ(TSTRING); idealbool = typ(TBOOL); diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index 83ab1cb86..97d92e1dc 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -39,6 +39,8 @@ exprfmt(Fmt *f, Node *n, int prec) case ODOTPTR: case ODOTINTER: case ODOTMETH: + case ODOTTYPE: + case ODOTTYPE2: case OARRAYBYTESTR: case OCAP: case OCLOSE: @@ -54,7 +56,6 @@ exprfmt(Fmt *f, Node *n, int prec) case OCONV: case OCONVNOP: case OCONVSLICE: - case OCONVIFACE: case OMAKESLICE: case ORUNESTR: case OADDR: @@ -64,6 +65,7 @@ exprfmt(Fmt *f, Node *n, int prec) case ONOT: case OPLUS: case ORECV: + case OCONVIFACE: nprec = 7; break; @@ -277,6 +279,7 @@ exprfmt(Fmt *f, Node *n, int prec) break; case ODOTTYPE: + case ODOTTYPE2: exprfmt(f, n->left, 7); fmtprint(f, ".("); if(n->right != N) @@ -336,9 +339,9 @@ exprfmt(Fmt *f, Node *n, int prec) break; case OCONV: + case OCONVIFACE: case OCONVNOP: case OCONVSLICE: - case OCONVIFACE: case OARRAYBYTESTR: case ORUNESTR: if(n->type == T || n->type->sym == S) diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index 2794504d2..09d54b3ee 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -11,7 +11,7 @@ void typecheckrange(Node *n) { - int op, et; + char *why; Type *t, *t1, *t2; Node *v1, *v2; NodeList *ll; @@ -66,13 +66,13 @@ typecheckrange(Node *n) if(v1->defn == n) v1->type = t1; - else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et, "range") < 0) - yyerror("cannot assign type %T to %+N", t1, v1); + else if(v1->type != T && assignop(t1, v1->type, &why) == 0) + yyerror("cannot assign type %T to %+N in range%s", t1, v1, why); if(v2) { if(v2->defn == n) v2->type = t2; - else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et, "range") < 0) - yyerror("cannot assign type %T to %+N", t1, v1); + else if(v2->type != T && assignop(t2, v2->type, &why) == 0) + yyerror("cannot assign type %T to %+N in range%s", t2, v2, why); } out: diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 392de17a0..5783faafd 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -47,18 +47,26 @@ func stringiter(string, int) int func stringiter2(string, int) (retk int, retv int) func slicecopy(to any, fr any, wid uint32) int -func ifaceI2E(iface any) (ret any) -func ifaceE2I(typ *byte, iface any) (ret any) -func ifaceT2E(typ *byte, elem any) (ret any) -func ifaceE2T(typ *byte, elem any) (ret any) -func ifaceE2I2(typ *byte, iface any) (ret any, ok bool) -func ifaceE2T2(typ *byte, elem any) (ret any, ok bool) -func ifaceT2I(typ1 *byte, typ2 *byte, elem any) (ret any) -func ifaceI2T(typ *byte, iface any) (ret any) -func ifaceI2T2(typ *byte, iface any) (ret any, ok bool) -func ifaceI2I(typ *byte, iface any) (ret any) -func ifaceI2Ix(typ *byte, iface any) (ret any) -func ifaceI2I2(typ *byte, iface any) (ret any, ok bool) +// interface conversions +func convI2E(elem any) (ret any) +func convI2I(typ *byte, elem any) (ret any) +func convT2E(typ *byte, elem any) (ret any) +func convT2I(typ *byte, typ2 *byte, elem any) (ret any) + +// interface type assertions x.(T) +func assertE2E(typ *byte, iface any) (ret any) +func assertE2E2(typ *byte, iface any) (ret any, ok bool) +func assertE2I(typ *byte, iface any) (ret any) +func assertE2I2(typ *byte, iface any) (ret any, ok bool) +func assertE2T(typ *byte, iface any) (ret any) +func assertE2T2(typ *byte, iface any) (ret any, ok bool) +func assertI2E(typ *byte, iface any) (ret any) +func assertI2E2(typ *byte, iface any) (ret any, ok bool) +func assertI2I(typ *byte, iface any) (ret any) +func assertI2I2(typ *byte, iface any) (ret any, ok bool) +func assertI2T(typ *byte, iface any) (ret any) +func assertI2T2(typ *byte, iface any) (ret any, ok bool) + func ifaceeq(i1 any, i2 any) (ret bool) func efaceeq(i1 any, i2 any) (ret bool) func ifacethash(i1 any) (ret uint32) diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index ac700b4c0..96d03617c 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -524,6 +524,7 @@ typ(int et) t->etype = et; t->width = BADWIDTH; t->lineno = lineno; + t->orig = t; return t; } @@ -863,16 +864,13 @@ goopnames[] = int Oconv(Fmt *fp) { - char buf[500]; int o; o = va_arg(fp->args, int); if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil) return fmtstrcpy(fp, goopnames[o]); - if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) { - snprint(buf, sizeof(buf), "O-%d", o); - return fmtstrcpy(fp, buf); - } + if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) + return fmtprint(fp, "O-%d", o); return fmtstrcpy(fp, opnames[o]); } @@ -992,14 +990,11 @@ etnames[] = int Econv(Fmt *fp) { - char buf[500]; int et; et = va_arg(fp->args, int); - if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) { - snprint(buf, sizeof(buf), "E-%d", et); - return fmtstrcpy(fp, buf); - } + if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) + return fmtprint(fp, "E-%d", et); return fmtstrcpy(fp, etnames[et]); } @@ -1139,6 +1134,13 @@ Tpretty(Fmt *fp, Type *t) { Type *t1; Sym *s; + + if(debug['U']) { + debug['U'] = 0; + fmtprint(fp, "%T (orig=%T)", t, t->orig); + debug['U'] = 1; + return 0; + } if(t->etype != TFIELD && t->sym != S @@ -1775,113 +1777,73 @@ iscomposite(Type *t) return 0; } +// Return 1 if t1 and t2 are identical, following the spec rules. +// +// Any cyclic type must go through a named type, and if one is +// named, it is only identical to the other if they are the same +// pointer (t1 == t2), so there's no chance of chasing cycles +// ad infinitum, so no need for a depth counter. int -eqtype1(Type *t1, Type *t2, int d, int names) +eqtype(Type *t1, Type *t2) { - if(d >= 20) - return 1; if(t1 == t2) return 1; - if(t1 == T || t2 == T) - return 0; - if(t1->etype != t2->etype) - return 0; - if(names && t1->etype != TFIELD && t1->sym && t2->sym && t1 != t2) + if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym) return 0; + switch(t1->etype) { case TINTER: case TSTRUCT: - t1 = t1->type; - t2 = t2->type; - for(;;) { - if(!eqtype1(t1, t2, d+1, names)) + for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { + if(t1->etype != TFIELD || t2->etype != TFIELD) + fatal("struct/interface missing field: %T %T", t1, t2); + if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type)) return 0; - if(t1 == T) - return 1; - if(t1->embedded != t2->embedded) - return 0; - if(t1->nname != N && t1->nname->sym != S) { - if(t2->nname == N || t2->nname->sym == S) - return 0; - if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0) - return 0; - } - t1 = t1->down; - t2 = t2->down; } - return 1; + return t1 == T && t2 == T; case TFUNC: // Loop over structs: receiver, in, out. - t1 = t1->type; - t2 = t2->type; - for(;;) { + for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { Type *ta, *tb; - if(t1 == t2) - break; - if(t1 == T || t2 == T) - return 0; + if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) - return 0; + fatal("func missing struct: %T %T", t1, t2); - // Loop over fields in structs, checking type only. - ta = t1->type; - tb = t2->type; - while(ta != tb) { - if(ta == T || tb == T) + // Loop over fields in structs, ignoring argument names. + for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) { + if(ta->etype != TFIELD || tb->etype != TFIELD) + fatal("func struct missing field: %T %T", ta, tb); + if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type)) return 0; - if(ta->etype != TFIELD || tb->etype != TFIELD || ta->isddd != tb->isddd) - return 0; - if(!eqtype1(ta->type, tb->type, d+1, names)) - return 0; - ta = ta->down; - tb = tb->down; } - - t1 = t1->down; - t2 = t2->down; + if(ta != T || tb != T) + return 0; } - return 1; - + return t1 == T && t2 == T; + case TARRAY: if(t1->bound != t2->bound) return 0; break; - + case TCHAN: if(t1->chan != t2->chan) return 0; break; - - case TMAP: - if(!eqtype1(t1->down, t2->down, d+1, names)) - return 0; - break; } - return eqtype1(t1->type, t2->type, d+1, names); -} -int -eqtype(Type *t1, Type *t2) -{ - return eqtype1(t1, t2, 0, 1); -} - -/* - * can we convert from type src to dst with - * a trivial conversion (no bits changing)? - */ -int -cvttype(Type *dst, Type *src) -{ - return eqtype1(dst, src, 0, 0); + return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type); } +// Are t1 and t2 equal struct types when field names are ignored? +// For deciding whether the result struct from g can be copied +// directly when compiling f(g()). int eqtypenoname(Type *t1, Type *t2) { if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT) - return eqtype(t1, t2); + return 0; t1 = t1->type; t2 = t2->type; @@ -1895,6 +1857,216 @@ eqtypenoname(Type *t1, Type *t2) } } +// Is type src assignment compatible to type dst? +// If so, return op code to use in conversion. +// If not, return 0. +// +// It is the caller's responsibility to call exportassignok +// to check for assignments to other packages' unexported fields, +int +assignop(Type *src, Type *dst, char **why) +{ + Type *missing, *have; + + if(why != nil) + *why = ""; + + if(src == dst) + return OCONVNOP; + if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T) + return 0; + + // 1. src type is identical to dst. + if(eqtype(src, dst)) + return OCONVNOP; + + // 2. src and dst have identical underlying types + // and either src or dst is not a named type. + if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S)) + return OCONVNOP; + + // 3. dst is an interface type and src implements dst. + if(dst->etype == TINTER && src->etype != TNIL) { + if(implements(src, dst, &missing, &have)) + return OCONVIFACE; + if(why != nil) { + if(isptrto(src, TINTER)) + *why = smprint(": %T is pointer to interface, not interface", src); + else if(have) + *why = smprint(": %T does not implement %T (wrong type for %S method)\n" + "\thave %T\n\twant %T", src, dst, missing->sym, have->type, missing->type); + else + *why = smprint(": %T does not implement %T (missing %S method)", + src, dst, missing->sym); + } + return 0; + } + if(src->etype == TINTER && dst->etype != TBLANK) { + if(why != nil) + *why = ": need type assertion"; + return 0; + } + + // 4. src is a bidirectional channel value, dst is a channel type, + // src and dst have identical element types, and + // either src or dst is not a named type. + if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN) + if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S)) + return OCONVNOP; + + // 5. src is the predeclared identifier nil and dst is a nillable type. + if(src->etype == TNIL) { + switch(dst->etype) { + case TARRAY: + if(dst->bound != -100) // not slice + break; + case TPTR32: + case TPTR64: + case TFUNC: + case TMAP: + case TCHAN: + case TINTER: + return OCONVNOP; + } + } + + // 6. rule about untyped constants - already converted by defaultlit. + + // 7. Any typed value can be assigned to the blank identifier. + if(dst->etype == TBLANK) + return OCONVNOP; + + // 8. Array to slice. + // TODO(rsc): Not for long. + if(!src->sym || !dst->sym) + if(isptr[src->etype] && isfixedarray(src->type) && isslice(dst)) + if(eqtype(src->type->type, dst->type)) + return OCONVSLICE; + + return 0; +} + +// Can we convert a value of type src to a value of type dst? +// If so, return op code to use in conversion (maybe OCONVNOP). +// If not, return 0. +int +convertop(Type *src, Type *dst, char **why) +{ + int op; + + if(why != nil) + *why = ""; + + if(src == dst) + return OCONVNOP; + if(src == T || dst == T) + return 0; + + // 1. src can be assigned to dst. + if((op = assignop(src, dst, why)) != 0) + return op; + + // The rules for interfaces are no different in conversions + // than assignments. If interfaces are involved, stop now + // with the good message from assignop. + // Otherwise clear the error. + if(src->etype == TINTER || dst->etype == TINTER) + return 0; + if(why != nil) + *why = ""; + + // 2. src and dst have identical underlying types. + if(eqtype(src->orig, dst->orig)) + return OCONVNOP; + + // 3. src and dst are unnamed pointer types + // and their base types have identical underlying types. + if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S) + if(eqtype(src->type->orig, dst->type->orig)) + return OCONVNOP; + + // 4. src and dst are both integer or floating point types. + if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) { + if(simtype[src->etype] == simtype[dst->etype]) + return OCONVNOP; + return OCONV; + } + + // 5. src and dst are both complex types. + if(iscomplex[src->etype] && iscomplex[dst->etype]) { + if(simtype[src->etype] == simtype[dst->etype]) + return OCONVNOP; + return OCONV; + } + + // 6. src is an integer or has type []byte or []int + // and dst is a string type. + if(isint[src->etype] && dst->etype == TSTRING) + return ORUNESTR; + + if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) { + switch(src->type->etype) { + case TUINT8: + return OARRAYBYTESTR; + case TINT: + return OARRAYRUNESTR; + } + } + + // 7. src is a string and dst is []byte or []int. + // String to slice. + if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) { + switch(dst->type->etype) { + case TUINT8: + return OSTRARRAYBYTE; + case TINT: + return OSTRARRAYRUNE; + } + } + + // 8. src is a pointer or uintptr and dst is unsafe.Pointer. + if((isptr[src->etype] || src->etype == TUINTPTR) && isptrto(dst, TANY)) + return OCONVNOP; + + // 9. src is unsafe.Pointer and dst is a pointer or uintptr. + if(isptrto(src, TANY) && (isptr[dst->etype] || dst->etype == TUINTPTR)) + return OCONVNOP; + + + return 0; +} + +// Convert node n for assignment to type t. +Node* +assignconv(Node *n, Type *t, char *context) +{ + int op; + Node *r; + char *why; + + if(n == N || n->type == T) + return n; + + defaultlit(&n, t); + if(t->etype == TBLANK) + return n; + + exportassignok(n->type, context); + if(eqtype(n->type, t)) + return n; + + op = assignop(n->type, t, &why); + if(op == 0) { + yyerror("cannot use %+N as type %T in %s%s", n, t, context, why); + op = OCONV; + } + + r = nod(op, n, N); + r->type = t; + r->typecheck = 1; + return r; +} + static int subtype(Type **stp, Type *t, int d) { @@ -2026,6 +2198,8 @@ shallow(Type *t) return T; nt = typ(0); *nt = *t; + if(t->orig == t) + nt->orig = nt; return nt; } @@ -2941,43 +3115,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) funccompile(fn, 0); } -/* - * delayed interface type check. - * remember that there is an interface conversion - * on the given line. once the file is completely read - * and all methods are known, we can check that - * the conversions are valid. - */ - -typedef struct Icheck Icheck; -struct Icheck -{ - Icheck *next; - Type *dst; - Type *src; - int lineno; - int explicit; -}; -Icheck *icheck; -Icheck *ichecktail; - -void -ifacecheck(Type *dst, Type *src, int lineno, int explicit) -{ - Icheck *p; - - p = mal(sizeof *p); - if(ichecktail) - ichecktail->next = p; - else - icheck = p; - p->dst = dst; - p->src = src; - p->lineno = lineno; - p->explicit = explicit; - ichecktail = p; -} - Type* ifacelookdot(Sym *s, Type *t, int *followptr) { @@ -3012,20 +3149,42 @@ ifacelookdot(Sym *s, Type *t, int *followptr) return T; } -// check whether non-interface type t -// satisifes inteface type iface. int -ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename) +implements(Type *t, Type *iface, Type **m, Type **samename) { - Type *t, *im, *tm, *rcvr, *imtype; + Type *t0, *im, *tm, *rcvr, *imtype; int followptr; - t = methtype(t0); + t0 = t; + if(t == T) + return 0; // if this is too slow, // could sort these first // and then do one loop. + if(t->etype == TINTER) { + for(im=iface->type; im; im=im->down) { + for(tm=t->type; tm; tm=tm->down) { + if(tm->sym == im->sym) { + if(eqtype(tm->type, im->type)) + goto found; + *m = im; + *samename = tm; + return 0; + } + } + *m = im; + *samename = nil; + return 0; + found:; + } + return 1; + } + + t = methtype(t); + if(t != T) + expandmeth(t->sym, t); for(im=iface->type; im; im=im->down) { imtype = methodfunc(im->type, 0); tm = ifacelookdot(im->sym, t, &followptr); @@ -3048,87 +3207,6 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename) return 1; } -// check whether interface type i1 satisifes interface type i2. -int -ifaceokI2I(Type *i1, Type *i2, Type **m) -{ - Type *m1, *m2; - - // if this is too slow, - // could sort these first - // and then do one loop. - - for(m2=i2->type; m2; m2=m2->down) { - for(m1=i1->type; m1; m1=m1->down) - if(m1->sym == m2->sym && eqtype(m1, m2)) - goto found; - *m = m2; - return 0; - found:; - } - return 1; -} - -void -runifacechecks(void) -{ - Icheck *p; - int lno, wrong, needexplicit; - Type *m, *t, *iface, *samename; - - lno = lineno; - for(p=icheck; p; p=p->next) { - lineno = p->lineno; - wrong = 0; - needexplicit = 0; - m = nil; - samename = nil; - if(isinter(p->dst) && isinter(p->src)) { - iface = p->dst; - t = p->src; - needexplicit = !ifaceokI2I(t, iface, &m); - } - else if(isinter(p->dst)) { - t = p->src; - iface = p->dst; - wrong = !ifaceokT2I(t, iface, &m, &samename); - } else { - t = p->dst; - iface = p->src; - wrong = !ifaceokT2I(t, iface, &m, &samename); - needexplicit = 1; - } - if(wrong) { - if(p->explicit) { - if(samename) - yyerror("%T cannot contain %T\n\tmissing %S%hhT\n\tdo have %S%hhT", - iface, t, m->sym, m->type, samename->sym, samename->type); - else - yyerror("%T cannot contain %T\n\tmissing %S%hhT", iface, t, m->sym, m->type); - } else { - if(samename) - yyerror("%T is not %T\n\tmissing %S%hhT\n\tdo have %S%hhT", - t, iface, m->sym, m->type, samename->sym, samename->type); - else - yyerror("%T is not %T\n\tmissing %S%hhT", t, iface, m->sym, m->type); - } - } - else if(!p->explicit && needexplicit) { - if(m) { - if(samename) - yyerror("need type assertion to use %T as %T\n\tmissing %S %hhT\n\tdo have %S%hhT", - p->src, p->dst, m->sym, m->type, samename->sym, samename->type); - else - yyerror("need type assertion to use %T as %T\n\tmissing %S%hhT", - p->src, p->dst, m->sym, m->type); - } else - yyerror("need type assertion to use %T as %T", - p->src, p->dst); - } - } - lineno = lno; -} - /* * even simpler simtype; get rid of ptr, bool. * assuming that the front end has rejected diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 19155f07b..d285ad0a7 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -21,7 +21,6 @@ static int onearg(Node*); static int twoarg(Node*); static int lookdot(Node*, Type*, int); static void typecheckaste(int, Type*, NodeList*, char*); -static int exportassignok(Type*, char*); static Type* lookdot1(Sym *s, Type *t, Type *f, int); static int nokeys(NodeList*); static void typecheckcomplit(Node**); @@ -32,7 +31,6 @@ static void typecheckfunc(Node*); static void checklvalue(Node*, char*); static void checkassign(Node*); static void checkassignlist(NodeList*); -static void toslice(Node**); static void stringtoarraylit(Node**); void @@ -57,6 +55,7 @@ typecheck(Node **np, int top) Type *t; Sym *sym; Val v; + char *why; // cannot type check until all the source has been parsed if(!typecheckok) @@ -549,8 +548,8 @@ reswitch: case TMAP: n->etype = 0; defaultlit(&n->right, t->down); - if(n->right->type != T && !eqtype(n->right->type, t->down)) - yyerror("invalid map index %#N - need type %T", n->right, t->down); + if(n->right->type != T) + n->right = assignconv(n->right, t->down, "map index"); n->type = t->type; n->op = OINDEXMAP; break; @@ -644,8 +643,6 @@ reswitch: l = n->left; if((t = l->type) == T) goto error; - // TODO(rsc): 64-bit slice index needs to be checked - // for overflow in generated code if(istype(t, TSTRING)) { n->type = t; n->op = OSLICESTR; @@ -866,21 +863,19 @@ reswitch: typecheck(&n->right, Erv); if(n->left->type == T || n->right->type == T) goto error; - toslice(&n->left); - toslice(&n->right); defaultlit(&n->left, T); defaultlit(&n->right, T); if(!isslice(n->left->type) || !isslice(n->right->type)) { if(!isslice(n->left->type) && !isslice(n->right->type)) - yyerror("arguments to copy must be array pointer or slice; have %lT, %lT", n->left->type, n->right->type); + yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type); else if(!isslice(n->left->type)) - yyerror("first argument to copy should be array pointer or slice; have %lT", n->left->type); + yyerror("first argument to copy should be slice; have %lT", n->left->type); else - yyerror("second argument to copy should be array pointer or slice; have %lT", n->right->type); + yyerror("second argument to copy should be slice; have %lT", n->right->type); goto error; } - if(!eqtype(n->left->type, n->right->type)) { - yyerror("arguments to copy have different element types %lT and %lT", n->left->type, n->right->type); + if(!eqtype(n->left->type->type, n->right->type->type)) { + yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type); goto error; } goto ret; @@ -892,10 +887,17 @@ reswitch: convlit1(&n->left, n->type, 1); if((t = n->left->type) == T || n->type == T) goto error; - n = typecheckconv(n, n->left, n->type, 1, "conversion"); - if(n->type == T) - goto error; + if((n->op = convertop(t, n->type, &why)) == 0) { + yyerror("cannot convert %+N to type %T%s", n->left, n->type, why); + op = OCONV; + } switch(n->op) { + case OCONVNOP: + if(n->left->op == OLITERAL) { + n->op = OLITERAL; + n->val = n->left->val; + } + break; case OSTRARRAYBYTE: case OSTRARRAYRUNE: if(n->left->op == OLITERAL) @@ -1031,7 +1033,7 @@ reswitch: if(onearg(n) < 0) goto error; typecheck(&n->left, Erv); - defaultlit(&n->left, types[TINTER]); + defaultlit(&n->left, T); if(n->left->type == T) goto error; goto ret; @@ -1242,25 +1244,6 @@ implicitstar(Node **nn) *nn = n; } -static void -toslice(Node **nn) -{ - Node *n; - Type *t; - - n = *nn; - if(n->type == T) - return; - if(isptr[n->type->etype] && isfixedarray(n->type->type)) { - // convert to slice - t = typ(TARRAY); - t->bound = -1; - t->type = n->type->type->type; - n = typecheckconv(nil, n, t, 0, "conversion of array pointer to slice"); - *nn = n; - } -} - static int onearg(Node *n) { @@ -1398,208 +1381,6 @@ nokeys(NodeList *l) } /* - * check implicit or explicit conversion from node type nt to type t. - */ -int -checkconv(Type *nt, Type *t, int explicit, int *op, int *et, char *desc) -{ - *op = OCONV; - *et = 0; - - // preexisting error - if(t == T || t->etype == TFORW) - return 0; - - /* - * implicit conversions - */ - if(nt == T) - return 0; - - if(t->etype == TBLANK) { - *op = OCONVNOP; - return 0; - } - - if(eqtype(t, nt)) { - exportassignok(t, desc); - *op = OCONVNOP; - if(!explicit || t == nt) - return 0; - return 1; - } - - // interfaces are not subject to the name restrictions below. - // accept anything involving interfaces and let ifacecvt - // generate a good message. some messages have to be - // delayed anyway. - // TODO(rsc): now that everything is delayed for whole-package - // compilation, the messages could be generated right here. - if(isnilinter(t) || isnilinter(nt) || isinter(t) || isinter(nt)) { - *et = ifaceas1(t, nt, 0); - *op = OCONVIFACE; - return 1; - } - - // otherwise, if concrete types have names, they must match. - if(!explicit && t->sym && nt->sym && t != nt) - return -1; - - // channel must not lose directionality - if(t->etype == TCHAN && nt->etype == TCHAN) { - if(t->chan & ~nt->chan) - return -1; - if(eqtype(t->type, nt->type)) { - *op = OCONVNOP; - return 1; - } - } - - // array to slice - if(isslice(t) && isptr[nt->etype] && isfixedarray(nt->type) - && eqtype(t->type, nt->type->type)) { - *op = OCONVSLICE; - return 1; - } - - /* - * explicit conversions - */ - if(!explicit) - return -1; - - // same representation - if(cvttype(t, nt)) { - *op = OCONVNOP; - return 1; - } - - // simple fix-float - if(isint[t->etype] || isfloat[t->etype]) - if(isint[nt->etype] || isfloat[nt->etype]) - return 1; - - // simple complex-complex - if(iscomplex[t->etype]) - if(iscomplex[nt->etype]) - return 1; - - // to string - if(istype(t, TSTRING)) { - // integer rune - if(isint[nt->etype]) { - *op = ORUNESTR; - return 1; - } - - // *[10]byte -> string - // in preparation for next step - if(isptr[nt->etype] && isfixedarray(nt->type)) { - switch(nt->type->type->etype) { - case TUINT8: - *op = OARRAYBYTESTR; - return 1; - case TINT: - *op = OARRAYRUNESTR; - return 1; - } - } - - // []byte -> string - if(isslice(nt)) { - switch(nt->type->etype) { - case TUINT8: - *op = OARRAYBYTESTR; - return 1; - case TINT: - *op = OARRAYRUNESTR; - return 1; - } - } - } - - // from string - if(istype(nt, TSTRING) && isslice(t) && t->sym == S) { - switch(t->type->etype) { - case TUINT8: - *op = OSTRARRAYBYTE; - return 1; - case TINT: - *op = OSTRARRAYRUNE; - return 1; - } - } - - // convert to unsafe pointer - if(isptrto(t, TANY) - && (isptr[nt->etype] || nt->etype == TUINTPTR)) - return 1; - - // convert from unsafe pointer - if(isptrto(nt, TANY) - && (isptr[t->etype] || t->etype == TUINTPTR)) - return 1; - - return -1; -} - -Node* -typecheckconv(Node *nconv, Node *n, Type *t, int explicit, char *desc) -{ - int et, op; - Node *n1; - char *prefix; - - convlit1(&n, t, explicit); - if(n->type == T) - return n; - - - if(n->op == OLITERAL) - if(explicit || isideal(n->type)) - if(cvttype(t, n->type)) { - // can convert literal in place - // TODO(rsc) is this needed? - n1 = nod(OXXX, N, N); - *n1 = *n; - n1->type = t; - return n1; - } - - prefix = ""; - if(desc != nil) - prefix = " in "; - else - desc = ""; - switch(checkconv(n->type, t, explicit, &op, &et, desc)) { - case -1: - if(explicit) - yyerror("cannot convert %+N to type %T%s%s", n, t, prefix, desc); - else - yyerror("cannot use %+N as type %T%s%s", n, t, prefix, desc); - return n; - - case 0: - if(nconv) { - nconv->op = OCONVNOP; - return nconv; - } - return n; - } - - if(op == OCONVIFACE) - defaultlit(&n, T); - - if(nconv == N) - nconv = nod(OCONV, n, N); - nconv->op = op; - nconv->etype = et; - nconv->type = t; - nconv->typecheck = 1; - return nconv; -} - -/* * typecheck assignment: type list = expression list */ static void @@ -1608,6 +1389,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc) Type *t, *tl, *tn; Node *n; int lno; + char *why; lno = lineno; @@ -1619,21 +1401,20 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc) setlineno(n); tn = n->type->type; for(tl=tstruct->type; tl; tl=tl->down) { - int xx, yy; if(tl->isddd) { // TODO(rsc): delete if (but not body) in DDD cleanup. if(tl->type->etype != TINTER) - for(; tn; tn=tn->down) - if(checkconv(tn->type, tl->type->type, 0, &xx, &yy, desc) < 0) - yyerror("cannot use %T as type %T in %s", tn->type, tl->type->type, desc); + for(; tn; tn=tn->down) + if(assignop(tn->type, tl->type->type, &why) == 0) + yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why); goto out; } if(tn == T) { yyerror("not enough arguments to %#O", op); goto out; } - if(checkconv(tn->type, tl->type, 0, &xx, &yy, desc) < 0) - yyerror("cannot use type %T as type %T in %s", tn->type, tl->type, desc); + if(assignop(tn->type, tl->type, &why) == 0) + yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); tn = tn->down; } if(tn != T) @@ -1652,13 +1433,12 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc) if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t)) goto out; for(; nl; nl=nl->next) { - int xx, yy; setlineno(nl->n); defaultlit(&nl->n, t->type); // TODO(rsc): drop first if in DDD cleanup if(t->etype != TINTER) - if(checkconv(nl->n->type, t->type, 0, &xx, &yy, desc) < 0) - yyerror("cannot use %+N as type %T in %s", nl->n, t->type, desc); + if(assignop(nl->n->type, t->type, &why) == 0) + yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why); } goto out; } @@ -1669,7 +1449,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc) n = nl->n; setlineno(nl->n); if(n->type != T) - nl->n = typecheckconv(nil, n, t, 0, desc); + nl->n = assignconv(n, t, desc); nl = nl->next; } if(nl != nil) { @@ -1686,7 +1466,7 @@ out: * cannot be implicitly assigning to any type with * an unavailable field. */ -static int +int exportassignok(Type *t, char *desc) { Type *f; @@ -1882,11 +1662,11 @@ typecheckcomplit(Node **np) } typecheck(&l->right, Erv); defaultlit(&l->right, t->type); - l->right = typecheckconv(nil, l->right, t->type, 0, "array index"); + l->right = assignconv(l->right, t->type, "array index"); } else { typecheck(&ll->n, Erv); defaultlit(&ll->n, t->type); - ll->n = typecheckconv(nil, ll->n, t->type, 0, "array index"); + ll->n = assignconv(ll->n, t->type, "array index"); ll->n = nod(OKEY, nodintconst(i), ll->n); ll->n->left->type = types[TINT]; ll->n->left->typecheck = 1; @@ -1922,8 +1702,8 @@ typecheckcomplit(Node **np) typecheck(&l->right, Erv); defaultlit(&l->left, t->down); defaultlit(&l->right, t->type); - l->left = typecheckconv(nil, l->left, t->down, 0, "map key"); - l->right = typecheckconv(nil, l->right, t->type, 0, "map value"); + l->left = assignconv(l->left, t->down, "map key"); + l->right = assignconv(l->right, t->type, "map value"); keydup(l->left, hash, nelem(hash)); } n->op = OMAPLIT; @@ -1944,7 +1724,7 @@ typecheckcomplit(Node **np) s = f->sym; if(s != nil && !exportname(s->name) && s->pkg != localpkg) yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t); - ll->n = typecheckconv(nil, ll->n, f->type, 0, "field value"); + ll->n = assignconv(ll->n, f->type, "field value"); ll->n = nod(OKEY, newname(f->sym), ll->n); ll->n->left->typecheck = 1; f = f->down; @@ -1977,7 +1757,7 @@ typecheckcomplit(Node **np) } s = f->sym; fielddup(newname(s), hash, nelem(hash)); - l->right = typecheckconv(nil, l->right, f->type, 0, "field value"); + l->right = assignconv(l->right, f->type, "field value"); } } n->op = OSTRUCTLIT; @@ -2139,8 +1919,8 @@ typecheckas(Node *n) typecheck(&n->right, Erv); if(n->right && n->right->type != T) { if(n->left->type != T) - n->right = typecheckconv(nil, n->right, n->left->type, 0, "assignment"); - else + n->right = assignconv(n->right, n->left->type, "assignment"); + else if(!isblank(n->left)) exportassignok(n->right->type, "assignment"); } if(n->left->defn == n && n->left->ntype == N) { @@ -2157,9 +1937,21 @@ typecheckas(Node *n) } static void +checkassignto(Type *src, Node *dst) +{ + char *why; + + if(assignop(src, dst->type, &why) == 0) { + yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why); + return; + } + exportassignok(dst->type, "multiple assignment"); +} + +static void typecheckas2(Node *n) { - int cl, cr, op, et; + int cl, cr; NodeList *ll, *lr; Node *l, *r; Iter s; @@ -2182,7 +1974,7 @@ typecheckas2(Node *n) // easy for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) { if(ll->n->type != T && lr->n->type != T) - lr->n = typecheckconv(nil, lr->n, ll->n->type, 0, nil); + lr->n = assignconv(lr->n, ll->n->type, "assignment"); if(ll->n->defn == n && ll->n->ntype == N) { defaultlit(&lr->n, T); ll->n->type = lr->n->type; @@ -2200,9 +1992,9 @@ typecheckas2(Node *n) if(l->type == T) goto out; n->op = OAS2MAPW; - n->rlist->n = typecheckconv(nil, r, l->type, 0, nil); + n->rlist->n = assignconv(r, l->type, "assignment"); r = n->rlist->next->n; - n->rlist->next->n = typecheckconv(nil, r, types[TBOOL], 0, nil); + n->rlist->next->n = assignconv(r, types[TBOOL], "assignment"); goto out; } @@ -2223,8 +2015,7 @@ typecheckas2(Node *n) t = structfirst(&s, &r->type); for(ll=n->list; ll; ll=ll->next) { if(ll->n->type != T) - if(checkconv(t->type, ll->n->type, 0, &op, &et, nil) < 0) - yyerror("cannot assign type %T to %+N", t->type, ll->n); + checkassignto(t->type, ll->n); if(ll->n->defn == n && ll->n->ntype == N) ll->n->type = t->type; t = structnext(&s); @@ -2246,14 +2037,15 @@ typecheckas2(Node *n) goto common; case ODOTTYPE: n->op = OAS2DOTTYPE; + r->op = ODOTTYPE2; common: - if(l->type != T && checkconv(r->type, l->type, 0, &op, &et, nil) < 0) - yyerror("cannot assign %+N to %+N", r, l); + if(l->type != T) + checkassignto(r->type, l); if(l->defn == n) l->type = r->type; l = n->list->next->n; - if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et, nil) < 0) - yyerror("cannot assign bool value to %+N", l); + if(l->type != T) + checkassignto(types[TBOOL], l); if(l->defn == n && l->ntype == N) l->type = types[TBOOL]; goto out; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 21bd0b56e..a4e509650 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -9,26 +9,6 @@ static Node* conv(Node*, Type*); static Node* mapfn(char*, Type*); static Node* makenewvar(Type*, NodeList**, Node**); -enum -{ - Inone, - I2T, - I2T2, - I2I, - I2Ix, - I2I2, - T2I, - I2Isame, - E2T, - E2T2, - E2I, - E2I2, - I2E, - I2E2, - T2E, - E2Esame, -}; - // can this code branch reach the end // without an undcontitional RETURN // this is hard, so it is conservative @@ -169,8 +149,7 @@ walkdeftype(Node *n) t->printed = 0; t->deferwidth = 0; - // double-check use of type as map key - // TODO(rsc): also use of type as receiver? + // double-check use of type as map key. if(maplineno) { lineno = maplineno; maptype(n->type, types[TBOOL]); @@ -441,7 +420,10 @@ walkstmt(Node **np) walkstmtlist(n->ninit); if(n->ntest != N) { walkstmtlist(n->ntest->ninit); - walkexpr(&n->ntest, &n->ninit); + init = n->ntest->ninit; + n->ntest->ninit = nil; + walkexpr(&n->ntest, &init); + n->ntest->ninit = concat(init, n->ntest->ninit); } walkstmt(&n->nincr); walkstmtlist(n->nbody); @@ -483,7 +465,7 @@ walkstmt(Node **np) break; } ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit); - n->list = reorder4(ll); + n->list = ll; break; case OSELECT: @@ -541,6 +523,7 @@ walkexpr(Node **np, NodeList **init) int et; int32 lno; Node *n, *fn; + char buf[100], *p; n = *np; @@ -671,6 +654,7 @@ walkexpr(Node **np, NodeList **init) // the output bool, so we clear it before the call. Node *b; b = nodbool(0); + typecheck(&b, Erv); lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init); n->list = concat(n->list, lr); } @@ -710,7 +694,6 @@ walkexpr(Node **np, NodeList **init) goto ret; case OAS2: - as2: *init = concat(*init, n->ninit); n->ninit = nil; walkexprlistsafe(n->list, init); @@ -802,41 +785,77 @@ walkexpr(Node **np, NodeList **init) n->ninit = nil; r = n->rlist->n; walkexprlistsafe(n->list, init); - walkdottype(r, init); - et = ifaceas1(r->type, r->left->type, 1); - switch(et) { - case I2Isame: - case E2Esame: - case I2E: - n->rlist = list(list1(r->left), nodbool(1)); - typechecklist(n->rlist, Erv); - goto as2; - case I2T: - et = I2T2; - break; - case I2Ix: - et = I2I2; - break; - case E2I: - et = E2I2; - break; - case E2T: - et = E2T2; - break; - default: - et = Inone; - break; - } - if(et == Inone) - break; - r = ifacecvt(r->type, r->left, et, init); + r->op = ODOTTYPE2; + walkexpr(&r, init); ll = ascompatet(n->op, n->list, &r->type, 0, init); n = liststmt(concat(list1(r), ll)); goto ret; case ODOTTYPE: - walkdottype(n, init); - walkconv(&n, init); + case ODOTTYPE2: + // Build name of function: assertI2E2 etc. + strcpy(buf, "assert"); + p = buf+strlen(buf); + if(isnilinter(n->left->type)) + *p++ = 'E'; + else + *p++ = 'I'; + *p++ = '2'; + if(isnilinter(n->type)) + *p++ = 'E'; + else if(isinter(n->type)) + *p++ = 'I'; + else + *p++ = 'T'; + if(n->op == ODOTTYPE2) + *p++ = '2'; + *p = '\0'; + + fn = syslook(buf, 1); + ll = list1(typename(n->type)); + ll = list(ll, n->left); + argtype(fn, n->left->type); + argtype(fn, n->type); + n = nod(OCALL, fn, N); + n->list = ll; + typecheck(&n, Erv | Efnstruct); + walkexpr(&n, init); + goto ret; + + case OCONVIFACE: + // Build name of function: convI2E etc. + // Not all names are possible + // (e.g., we'll never generate convE2E or convE2I). + walkexpr(&n->left, init); + strcpy(buf, "conv"); + p = buf+strlen(buf); + if(isnilinter(n->left->type)) + *p++ = 'E'; + else if(isinter(n->left->type)) + *p++ = 'I'; + else + *p++ = 'T'; + *p++ = '2'; + if(isnilinter(n->type)) + *p++ = 'E'; + else + *p++ = 'I'; + *p = '\0'; + + fn = syslook(buf, 1); + ll = nil; + if(!isinter(n->left->type)) + ll = list(ll, typename(n->left->type)); + if(!isnilinter(n->type)) + ll = list(ll, typename(n->type)); + ll = list(ll, n->left); + argtype(fn, n->left->type); + argtype(fn, n->type); + dowidth(fn->type); + n = nod(OCALL, fn, N); + n->list = ll; + typecheck(&n, Erv); + walkexpr(&n, init); goto ret; case OCONV: @@ -1176,7 +1195,7 @@ walkexpr(Node **np, NodeList **init) case ORUNESTR: // sys_intstring(v) n = mkcall("intstring", n->type, init, - conv(n->left, types[TINT64])); // TODO(rsc): int64?! + conv(n->left, types[TINT64])); goto ret; case OARRAYBYTESTR: @@ -1234,11 +1253,6 @@ walkexpr(Node **np, NodeList **init) n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right); goto ret; - case OCONVIFACE: - walkexpr(&n->left, init); - n = ifacecvt(n->type, n->left, n->etype, init); - goto ret; - case OCLOSURE: n = walkclosure(n, init); goto ret; @@ -1271,70 +1285,6 @@ makenewvar(Type *t, NodeList **init, Node **nstar) return nvar; } -// TODO(rsc): cut -void -walkdottype(Node *n, NodeList **init) -{ - walkexpr(&n->left, init); - if(n->left == N) - return; - if(n->right != N) { - walkexpr(&n->right, init); - n->type = n->right->type; - n->right = N; - } -} - -// TODO(rsc): cut -void -walkconv(Node **np, NodeList **init) -{ - int et; - char *what; - Type *t; - Node *l; - Node *n; - - n = *np; - t = n->type; - if(t == T) - return; - walkexpr(&n->left, init); - l = n->left; - if(l == N) - return; - if(l->type == T) - return; - - // if using .(T), interface assertion. - if(n->op == ODOTTYPE) { - et = ifaceas1(t, l->type, 1); - if(et == I2Isame || et == E2Esame) { - n->op = OCONVNOP; - return; - } - if(et != Inone) { - n = ifacecvt(t, l, et, init); - *np = n; - return; - } - goto bad; - } - - fatal("walkconv"); - -bad: - if(n->diag) - return; - n->diag = 1; - if(n->op == ODOTTYPE) - what = "type assertion"; - else - what = "conversion"; - if(l->type != T) - yyerror("invalid %s: %T to %T", what, l->type, t); -} - Node* ascompatee1(int op, Node *l, Node *r, NodeList **init) { @@ -1418,6 +1368,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) if(fncall(l, r->type)) { tmp = nod(OXXX, N, N); tempname(tmp, r->type); + typecheck(&tmp, Erv); a = nod(OAS, l, tmp); a = convas(a, init); mm = list(mm, a); @@ -1517,6 +1468,7 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init) var = nod(OXXX, N, N); tempname(var, st); var->sym = lookup(".ddd"); + typecheck(&var, Erv); // assign the fields to the struct. // use the init list so that reorder1 doesn't reorder @@ -1927,166 +1879,11 @@ bad: return T; } -/* - * assigning src to dst involving interfaces? - * return op to use. - */ -int -ifaceas1(Type *dst, Type *src, int explicit) -{ - if(src == T || dst == T) - return Inone; - - if(explicit && !isinter(src)) - yyerror("cannot use .(T) on non-interface type %T", src); - - if(isinter(dst)) { - if(isinter(src)) { - if(isnilinter(dst)) { - if(isnilinter(src)) - return E2Esame; - return I2E; - } - if(eqtype(dst, src)) - return I2Isame; - ifacecheck(dst, src, lineno, explicit); - if(isnilinter(src)) - return E2I; - if(explicit) - return I2Ix; - return I2I; - } - if(isnilinter(dst)) - return T2E; - ifacecheck(dst, src, lineno, explicit); - return T2I; - } - if(isinter(src)) { - ifacecheck(dst, src, lineno, explicit); - if(isnilinter(src)) - return E2T; - return I2T; - } - return Inone; -} - -/* - * treat convert T to T as noop - */ -int -ifaceas(Type *dst, Type *src, int explicit) -{ - int et; - - et = ifaceas1(dst, src, explicit); - if(et == I2Isame || et == E2Esame) - et = Inone; - return et; -} - -static char* -ifacename[] = -{ - [I2T] = "ifaceI2T", - [I2T2] = "ifaceI2T2", - [I2I] = "ifaceI2I", - [I2Ix] = "ifaceI2Ix", - [I2I2] = "ifaceI2I2", - [I2Isame] = "ifaceI2Isame", - [E2T] = "ifaceE2T", - [E2T2] = "ifaceE2T2", - [E2I] = "ifaceE2I", - [E2I2] = "ifaceE2I2", - [I2E] = "ifaceI2E", - [I2E2] = "ifaceI2E2", - [T2I] = "ifaceT2I", - [T2E] = "ifaceT2E", - [E2Esame] = "ifaceE2Esame", -}; - -Node* -ifacecvt(Type *tl, Node *n, int et, NodeList **init) -{ - Type *tr; - Node *r, *on; - NodeList *args; - - tr = n->type; - - switch(et) { - default: - fatal("ifacecvt: unknown op %d\n", et); - - case I2Isame: - case E2Esame: - return n; - - case T2I: - // ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); - args = list1(typename(tl)); // sigi - args = list(args, typename(tr)); // sigt - args = list(args, n); // elem - - on = syslook("ifaceT2I", 1); - argtype(on, tr); - argtype(on, tl); - dowidth(on->type); - break; - - case I2T: - case I2T2: - case I2I: - case I2Ix: - case I2I2: - case E2T: - case E2T2: - case E2I: - case E2I2: - // iface[IT]2[IT][2](sigt *byte, iface any) (ret any[, ok bool]); - args = list1(typename(tl)); // sigi or sigt - args = list(args, n); // iface - - on = syslook(ifacename[et], 1); - argtype(on, tr); - argtype(on, tl); - break; - - case I2E: - // TODO(rsc): Should do this in back end, without a call. - // ifaceI2E(elem any) (ret any); - args = list1(n); // elem - - on = syslook("ifaceI2E", 1); - argtype(on, tr); - argtype(on, tl); - break; - - case T2E: - // TODO(rsc): Should do this in back end for pointer case, without a call. - // ifaceT2E(sigt *byte, elem any) (ret any); - args = list1(typename(tr)); // sigt - args = list(args, n); // elem - - on = syslook("ifaceT2E", 1); - argtype(on, tr); - argtype(on, tl); - break; - } - - dowidth(on->type); - r = nod(OCALL, on, N); - r->list = args; - typecheck(&r, Erv | Efnstruct); - walkexpr(&r, init); - return r; -} - Node* convas(Node *n, NodeList **init) { Node *l, *r; Type *lt, *rt; - int et; if(n->op != OAS) fatal("convas: not OAS %O", n->op); @@ -2115,15 +1912,12 @@ convas(Node *n, NodeList **init) n->left->left, n->left->right, n->right); goto out; } - + if(eqtype(lt, rt)) goto out; - - et = ifaceas(lt, rt, 0); - if(et != Inone) { - n->right = ifacecvt(lt, r, et, init); - goto out; - } + + n->right = assignconv(r, lt, "assignment"); + walkexpr(&n->right, init); out: ullmancalc(n); @@ -2292,24 +2086,6 @@ reorder3(NodeList *all) return concat(all, r); } -NodeList* -reorder4(NodeList *ll) -{ - /* - * from ascompat[te] - * return c,d - * return expression assigned to output - * parameters. there may be no problems. - * - * TODO(rsc): i don't believe that. - * func f() (a, b int) { - * a, b = 1, 2; - * return b, a; - * } - */ - return ll; -} - /* * walk through argin parameters. * generate and return code to allocate diff --git a/src/pkg/math/fltasm_amd64.s b/src/pkg/math/fltasm_amd64.s new file mode 100644 index 000000000..66442cd30 --- /dev/null +++ b/src/pkg/math/fltasm_amd64.s @@ -0,0 +1,67 @@ +// Derived from Inferno's libkern/getfcr-amd64.s +// http://code.google.com/p/inferno-os/source/browse/libkern/getfcr-amd64.s +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. +// Portions Copyright 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +TEXT ·SetFPControl(SB), 7, $8 + // Set new + MOVL p+0(FP), DI + XORL $(0x3F<<7), DI + ANDL $0xFFC0, DI + WAIT + STMXCSR 0(SP) + MOVL 0(SP), AX + ANDL $~0x3F, AX + ORL DI, AX + MOVL AX, 0(SP) + LDMXCSR 0(SP) + RET + +TEXT ·GetFPControl(SB), 7, $0 + WAIT + STMXCSR 0(SP) + MOVWLZX 0(SP), AX + ANDL $0xFFC0, AX + XORL $(0x3F<<7), AX + MOVL AX, ret+0(FP) + RET + +TEXT ·SetFPStatus(SB), $0 + MOVL p+0(FP), DI + ANDL $0x3F, DI + WAIT + STMXCSR 0(SP) + MOVL 0(SP), AX + ANDL $~0x3F, AX + ORL DI, AX + MOVL AX, 0(SP) + LDMXCSR 0(SP) + RET + +TEXT ·GetFPStatus(SB), $0 + WAIT + STMXCSR 0(SP) + MOVL 0(SP), AX + ANDL $0x3F, AX + MOVL AX, ret+0(FP) + RET diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c index 55a1362c6..35a710eca 100644 --- a/src/pkg/runtime/iface.c +++ b/src/pkg/runtime/iface.c @@ -177,26 +177,26 @@ copyout(Type *t, void **src, void *dst) algarray[alg].copy(wid, dst, *src); } -// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret Iface); +// func convT2I(typ *byte, typ2 *byte, elem any) (ret any) #pragma textflag 7 void -·ifaceT2I(InterfaceType *inter, Type *t, ...) +·convT2I(Type *t, InterfaceType *inter, ...) { byte *elem; Iface *ret; int32 wid; - elem = (byte*)(&t+1); + elem = (byte*)(&inter+1); wid = t->size; ret = (Iface*)(elem + rnd(wid, Structrnd)); ret->tab = itab(inter, t, 0); copyin(t, elem, &ret->data); } -// ifaceT2E(sigt *byte, elem any) (ret Eface); +// func convT2E(typ *byte, elem any) (ret any) #pragma textflag 7 void -·ifaceT2E(Type *t, ...) +·convT2E(Type *t, ...) { byte *elem; Eface *ret; @@ -205,15 +205,14 @@ void elem = (byte*)(&t+1); wid = t->size; ret = (Eface*)(elem + rnd(wid, Structrnd)); - ret->type = t; copyin(t, elem, &ret->data); } -// ifaceI2T(sigt *byte, iface any) (ret any); +// func ifaceI2T(typ *byte, iface any) (ret any) #pragma textflag 7 void -·ifaceI2T(Type *t, Iface i, ...) +·assertI2T(Type *t, Iface i, ...) { Itab *tab; byte *ret; @@ -236,10 +235,10 @@ void copyout(t, &i.data, ret); } -// ifaceI2T2(sigt *byte, i Iface) (ret any, ok bool); +// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool) #pragma textflag 7 void -·ifaceI2T2(Type *t, Iface i, ...) +·assertI2T2(Type *t, Iface i, ...) { byte *ret; bool *ok; @@ -259,10 +258,10 @@ void copyout(t, &i.data, ret); } -// ifaceE2T(sigt *byte, e Eface) (ret any); +// func ifaceE2T(typ *byte, iface any) (ret any) #pragma textflag 7 void -·ifaceE2T(Type *t, Eface e, ...) +·assertE2T(Type *t, Eface e, ...) { byte *ret; Eface err; @@ -284,10 +283,10 @@ void copyout(t, &e.data, ret); } -// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); +// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); #pragma textflag 7 void -·ifaceE2T2(Type *t, Eface e, ...) +·assertE2T2(Type *t, Eface e, ...) { byte *ret; bool *ok; @@ -307,50 +306,82 @@ void copyout(t, &e.data, ret); } -// ifaceI2E(sigi *byte, iface any) (ret any); -// TODO(rsc): Move to back end, throw away function. +// func convI2E(elem any) (ret any) +#pragma textflag 7 void -·ifaceI2E(Iface i, Eface ret) +·convI2E(Iface i, Eface ret) { Itab *tab; ret.data = i.data; - tab = i.tab; - if(tab == nil) + if((tab = i.tab) == nil) ret.type = nil; else ret.type = tab->type; FLUSH(&ret); } -// ifaceI2I(sigi *byte, iface any) (ret any); -// called only for implicit (no type assertion) conversions. -// converting nil is okay. +// func ifaceI2E(typ *byte, iface any) (ret any) +#pragma textflag 7 void -·ifaceI2I(InterfaceType *inter, Iface i, Iface ret) +·assertI2E(InterfaceType* inter, Iface i, Eface ret) { Itab *tab; + Eface err; tab = i.tab; if(tab == nil) { - // If incoming interface is uninitialized (zeroed) - // make the outgoing interface zeroed as well. - ret.tab = nil; - ret.data = nil; + // explicit conversions require non-nil interface value. + ·newTypeAssertionError(nil, nil, inter, + nil, nil, inter->string, + nil, &err); + ·panic(err); + } + ret.data = i.data; + ret.type = tab->type; + FLUSH(&ret); +} + +// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool) +#pragma textflag 7 +void +·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok) +{ + Itab *tab; + + USED(inter); + tab = i.tab; + if(tab == nil) { + ret.type = nil; + ok = 0; } else { - ret = i; - if(tab->inter != inter) - ret.tab = itab(inter, tab->type, 0); + ret.type = tab->type; + ok = 1; } + ret.data = i.data; + FLUSH(&ret); + FLUSH(&ok); +} +// func convI2I(typ *byte, elem any) (ret any) +#pragma textflag 7 +void +·convI2I(InterfaceType* inter, Iface i, Iface ret) +{ + Itab *tab; + + ret.data = i.data; + if((tab = i.tab) == nil) + ret.tab = nil; + else if(tab->inter == inter) + ret.tab = tab; + else + ret.tab = itab(inter, tab->type, 0); FLUSH(&ret); } -// ifaceI2Ix(sigi *byte, iface any) (ret any); -// called only for explicit conversions (with type assertion). -// converting nil is not okay. void -·ifaceI2Ix(InterfaceType *inter, Iface i, Iface ret) +ifaceI2I(InterfaceType *inter, Iface i, Iface *ret) { Itab *tab; Eface err; @@ -362,45 +393,40 @@ void nil, nil, inter->string, nil, &err); ·panic(err); - } else { - ret = i; - if(tab->inter != inter) - ret.tab = itab(inter, tab->type, 0); } + ret->data = i.data; + ret->tab = itab(inter, tab->type, 0); +} - FLUSH(&ret); +// func ifaceI2I(sigi *byte, iface any) (ret any) +#pragma textflag 7 +void +·assertI2I(InterfaceType* inter, Iface i, Iface ret) +{ + ifaceI2I(inter, i, &ret); } -// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); +// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool) +#pragma textflag 7 void -·ifaceI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok) +·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok) { Itab *tab; tab = i.tab; - if(tab == nil) { - // If incoming interface is nil, the conversion fails. - ret.tab = nil; - ret.data = nil; - ok = false; + if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) { + ret.data = i.data; + ret.tab = tab; + ok = 1; } else { - ret = i; - ok = true; - if(tab->inter != inter) { - ret.tab = itab(inter, tab->type, 1); - if(ret.tab == nil) { - ret.data = nil; - ok = false; - } - } + ret.data = 0; + ret.tab = 0; + ok = 0; } - FLUSH(&ret); FLUSH(&ok); } -// ifaceE2I(sigi *byte, iface any) (ret any); -// Called only for explicit conversions (with type assertion). void ifaceE2I(InterfaceType *inter, Eface e, Iface *ret) { @@ -414,45 +440,71 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret) nil, nil, inter->string, nil, &err); ·panic(err); - } else { - ret->data = e.data; - ret->tab = itab(inter, t, 0); } + ret->data = e.data; + ret->tab = itab(inter, t, 0); } -// ifaceE2I(sigi *byte, iface any) (ret any); -// Called only for explicit conversions (with type assertion). +// func ifaceE2I(sigi *byte, iface any) (ret any) +#pragma textflag 7 void -·ifaceE2I(InterfaceType *inter, Eface e, Iface ret) +·assertE2I(InterfaceType* inter, Eface e, Iface ret) { ifaceE2I(inter, e, &ret); } -// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); +// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool) +#pragma textflag 7 void -·ifaceE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok) +·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok) { - Type *t; - - t = e.type; - ok = true; - if(t == nil) { - // If incoming interface is nil, the conversion fails. + if(e.type == nil) { + ok = 0; ret.data = nil; ret.tab = nil; - ok = false; + } else if((ret.tab = itab(inter, e.type, 1)) == nil) { + ok = 0; + ret.data = nil; } else { + ok = 1; ret.data = e.data; - ret.tab = itab(inter, t, 1); - if(ret.tab == nil) { - ret.data = nil; - ok = false; - } } FLUSH(&ret); FLUSH(&ok); } +// func ifaceE2E(typ *byte, iface any) (ret any) +#pragma textflag 7 +void +·assertE2E(InterfaceType* inter, Eface e, Eface ret) +{ + Type *t; + Eface err; + + t = e.type; + if(t == nil) { + // explicit conversions require non-nil interface value. + ·newTypeAssertionError(nil, nil, inter, + nil, nil, inter->string, + nil, &err); + ·panic(err); + } + ret = e; + FLUSH(&ret); +} + +// func ifaceE2E2(iface any) (ret any, ok bool) +#pragma textflag 7 +void +·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok) +{ + USED(inter); + ret = e; + ok = e.type != nil; + FLUSH(&ret); + FLUSH(&ok); +} + static uintptr ifacehash1(void *data, Type *t) { |
