1
0
mirror of https://github.com/golang/go synced 2024-11-24 20:10:02 -07:00

gc: new typechecking rules

* Code for assignment, conversions now mirrors spec.
* Changed some snprint -> smprint.
* Renamed runtime functions to separate
  interface conversions from type assertions:
  convT2I, assertI2T, etc.
* Correct checking of \U sequences.

Fixes #840.
Fixes #830.
Fixes #778.

R=ken2
CC=golang-dev
https://golang.org/cl/1303042
This commit is contained in:
Russ Cox 2010-06-08 18:50:02 -07:00
parent 6aaef04469
commit 565b5dc076
29 changed files with 1483 additions and 1344 deletions

View File

@ -431,7 +431,7 @@ agen(Node *n, Node *res)
if(n == N || n->type == T) if(n == N || n->type == T)
return; return;
if(!isptr[res->type->etype]) if(!isptr[res->type->etype] && res->type->etype != TUINTPTR)
fatal("agen: not tptr: %T", res->type); fatal("agen: not tptr: %T", res->type);
while(n->op == OCONVNOP) while(n->op == OCONVNOP)

View File

@ -133,25 +133,22 @@ bitno(int32 b)
int int
Qconv(Fmt *fp) Qconv(Fmt *fp)
{ {
char str[STRINGSZ], ss[STRINGSZ], *s;
Bits bits; Bits bits;
int i; int i, first;
str[0] = 0; first = 1;
bits = va_arg(fp->args, Bits); bits = va_arg(fp->args, Bits);
while(bany(&bits)) { while(bany(&bits)) {
i = bnum(bits); i = bnum(bits);
if(str[0]) if(first)
strcat(str, " "); first = 0;
if(var[i].sym == S) { else
sprint(ss, "$%lld", var[i].offset); fmtprint(fp, " ");
s = ss; if(var[i].sym == S)
} else fmtprint(fp, "$%lld", var[i].offset);
s = var[i].sym->name; else
if(strlen(str) + strlen(s) + 1 >= STRINGSZ) fmtprint(fp, var[i].sym->name);
break;
strcat(str, s);
bits.b[i/32] &= ~(1L << (i%32)); bits.b[i/32] &= ~(1L << (i%32));
} }
return fmtstrcpy(fp, str); return 0;
} }

View File

@ -33,18 +33,22 @@ char *runtimeimport =
"func \"\".stringiter (? string, ? int) int\n" "func \"\".stringiter (? string, ? int) int\n"
"func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n" "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
"func \"\".slicecopy (to any, fr any, wid uint32) int\n" "func \"\".slicecopy (to any, fr any, wid uint32) int\n"
"func \"\".ifaceI2E (iface any) any\n" "func \"\".convI2E (elem any) any\n"
"func \"\".ifaceE2I (typ *uint8, iface any) any\n" "func \"\".convI2I (typ *uint8, elem any) any\n"
"func \"\".ifaceT2E (typ *uint8, elem any) any\n" "func \"\".convT2E (typ *uint8, elem any) any\n"
"func \"\".ifaceE2T (typ *uint8, elem any) any\n" "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
"func \"\".ifaceE2I2 (typ *uint8, iface any) (ret any, ok bool)\n" "func \"\".assertE2E (typ *uint8, iface any) any\n"
"func \"\".ifaceE2T2 (typ *uint8, elem any) (ret any, ok bool)\n" "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
"func \"\".ifaceT2I (typ1 *uint8, typ2 *uint8, elem any) any\n" "func \"\".assertE2I (typ *uint8, iface any) any\n"
"func \"\".ifaceI2T (typ *uint8, iface any) any\n" "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
"func \"\".ifaceI2T2 (typ *uint8, iface any) (ret any, ok bool)\n" "func \"\".assertE2T (typ *uint8, iface any) any\n"
"func \"\".ifaceI2I (typ *uint8, iface any) any\n" "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
"func \"\".ifaceI2Ix (typ *uint8, iface any) any\n" "func \"\".assertI2E (typ *uint8, iface any) any\n"
"func \"\".ifaceI2I2 (typ *uint8, iface any) (ret any, ok bool)\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 \"\".ifaceeq (i1 any, i2 any) bool\n"
"func \"\".efaceeq (i1 any, i2 any) bool\n" "func \"\".efaceeq (i1 any, i2 any) bool\n"
"func \"\".ifacethash (i1 any) uint32\n" "func \"\".ifacethash (i1 any) uint32\n"

View File

@ -119,6 +119,7 @@ walkclosure(Node *func, NodeList **init)
Node *xtype, *v, *addr, *xfunc, *call, *clos; Node *xtype, *v, *addr, *xfunc, *call, *clos;
NodeList *l, *in; NodeList *l, *in;
static int closgen; static int closgen;
char *p;
/* /*
* wrap body in external function * wrap body in external function
@ -134,8 +135,9 @@ walkclosure(Node *func, NodeList **init)
if(v->op == 0) if(v->op == 0)
continue; continue;
addr = nod(ONAME, N, N); addr = nod(ONAME, N, N);
snprint(namebuf, sizeof namebuf, "&%s", v->sym->name); p = smprint("&%s", v->sym->name);
addr->sym = lookup(namebuf); addr->sym = lookup(p);
free(p);
addr->ntype = nod(OIND, typenod(v->type), N); addr->ntype = nod(OIND, typenod(v->type), N);
addr->class = PPARAM; addr->class = PPARAM;
addr->addable = 1; addr->addable = 1;

View File

@ -93,8 +93,11 @@ convlit1(Node **np, Type *t, int explicit)
return; return;
case OLITERAL: case OLITERAL:
// target is invalid type for a constant? leave alone. // 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; return;
}
break; break;
case OLSH: case OLSH:
case ORSH: case ORSH:
@ -109,10 +112,8 @@ convlit1(Node **np, Type *t, int explicit)
} }
// avoided repeated calculations, errors // avoided repeated calculations, errors
if(cvttype(n->type, t) == 1) { if(eqtype(n->type, t))
n->type = t;
return; return;
}
ct = consttype(n); ct = consttype(n);
if(ct < 0) if(ct < 0)
@ -968,6 +969,8 @@ defaultlit(Node **np, Type *t)
break; break;
case CTBOOL: case CTBOOL:
n->type = types[TBOOL]; n->type = types[TBOOL];
if(t != T && t->etype == TBOOL)
n->type = t;
break; break;
case CTINT: case CTINT:
n->type = types[TINT]; n->type = types[TINT];

View File

@ -281,6 +281,7 @@ updatetype(Type *n, Type *t)
local = n->local; local = n->local;
vargen = n->vargen; vargen = n->vargen;
*n = *t; *n = *t;
n->orig = t->orig;
n->sym = s; n->sym = s;
n->local = local; n->local = local;
n->siggen = 0; n->siggen = 0;
@ -759,7 +760,7 @@ typedcl2(Type *pt, Type *t)
if(pt->etype == TFORW) if(pt->etype == TFORW)
goto ok; 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); yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
return; return;
@ -1154,7 +1155,7 @@ Sym*
methodsym(Sym *nsym, Type *t0) methodsym(Sym *nsym, Type *t0)
{ {
Sym *s; Sym *s;
char buf[NSYMB]; char *p;
Type *t; Type *t;
t = t0; t = t0;
@ -1177,8 +1178,10 @@ methodsym(Sym *nsym, Type *t0)
if(t != t0 && t0->sym) if(t != t0 && t0->sym)
t0 = ptrto(t); t0 = ptrto(t);
snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name); p = smprint("%#hT·%s", t0, nsym->name);
return pkglookup(buf, s->pkg); s = pkglookup(p, s->pkg);
free(p);
return s;
bad: bad:
yyerror("illegal receiver type: %T", t0); yyerror("illegal receiver type: %T", t0);
@ -1200,7 +1203,7 @@ Node*
methodname1(Node *n, Node *t) methodname1(Node *n, Node *t)
{ {
char *star; char *star;
char buf[NSYMB]; char *p;
star = ""; star = "";
if(t->op == OIND) { if(t->op == OIND) {
@ -1209,8 +1212,10 @@ methodname1(Node *n, Node *t)
} }
if(t->sym == S || isblank(n)) if(t->sym == S || isblank(n))
return newname(n->sym); return newname(n->sym);
snprint(buf, sizeof(buf), "%s%S·%S", star, t->sym, n->sym); p = smprint("%s%S·%S", star, t->sym, n->sym);
return newname(pkglookup(buf, t->sym->pkg)); n = newname(pkglookup(p, t->sym->pkg));
free(p);
return n;
} }
/* /*

View File

@ -182,10 +182,22 @@ dumpexporttype(Sym *s)
Bprint(bout, "type %#T %l#T\n", t, t); 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 void
dumpsym(Sym *s) dumpsym(Sym *s)
{ {
Type *f, *t; Type *f, *t;
Type **m;
int i, n;
if(s->flags & SymExported) if(s->flags & SymExported)
return; return;
@ -207,14 +219,23 @@ dumpsym(Sym *s)
break; break;
case OTYPE: case OTYPE:
t = s->def->type; t = s->def->type;
// TODO(rsc): sort methods by name n = 0;
for(f=t->method; f!=T; f=f->down) for(f=t->method; f!=T; f=f->down) {
dumpprereq(f); 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); 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", Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
f->type->type->type, f->sym, f->type); f->type->type->type, f->sym, f->type);
}
break; break;
case ONAME: case ONAME:
dumpexportvar(s); dumpexportvar(s);
@ -357,7 +378,7 @@ importvar(Sym *s, Type *t, int ctxt)
importsym(s, ONAME); importsym(s, ONAME);
if(s->def != N && s->def->op == ONAME) { if(s->def != N && s->def->op == ONAME) {
if(cvttype(t, s->def->type)) if(eqtype(t, s->def->type))
return; return;
yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
s, s->def->type, t); s, s->def->type, t);

View File

@ -158,6 +158,7 @@ struct Type
uchar isddd; // TFIELD is ... argument uchar isddd; // TFIELD is ... argument
Node* nod; // canonical OTYPE node Node* nod; // canonical OTYPE node
Type* orig; // original type (type literal or predefined type)
int lineno; int lineno;
// TFUNCT // TFUNCT
@ -361,11 +362,12 @@ enum
OCLOSURE, OCLOSURE,
OCMPIFACE, OCMPSTR, OCMPIFACE, OCMPSTR,
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
OCONV, OCONVNOP, OCONVIFACE, OCONVSLICE, OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE,
OCOPY, OCOPY,
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
ODOTTYPE, ODOTTYPE,
ODOTTYPE2,
OEQ, ONE, OLT, OLE, OGE, OGT, OEQ, ONE, OLT, OLE, OGE, OGT,
OIND, OIND,
OINDEX, OINDEXSTR, OINDEXMAP, OINDEX, OINDEXSTR, OINDEXMAP,
@ -904,26 +906,21 @@ NodeList* list(NodeList*, Node*);
NodeList* concat(NodeList*, NodeList*); NodeList* concat(NodeList*, NodeList*);
int count(NodeList*); int count(NodeList*);
Node* liststmt(NodeList*); Node* liststmt(NodeList*);
Type** getthis(Type*); Type** getthis(Type*);
Type** getoutarg(Type*); Type** getoutarg(Type*);
Type** getinarg(Type*); Type** getinarg(Type*);
Type* getthisx(Type*); Type* getthisx(Type*);
Type* getoutargx(Type*); Type* getoutargx(Type*);
Type* getinargx(Type*); Type* getinargx(Type*);
Type* structfirst(Iter*, Type**); Type* structfirst(Iter*, Type**);
Type* structnext(Iter*); Type* structnext(Iter*);
Type* funcfirst(Iter*, Type*); Type* funcfirst(Iter*, Type*);
Type* funcnext(Iter*); Type* funcnext(Iter*);
int brcom(int); int brcom(int);
int brrev(int); int brrev(int);
void setmaxarg(Type*); void setmaxarg(Type*);
int dotoffset(Node*, int*, Node**); int dotoffset(Node*, int*, Node**);
void tempname(Node*, Type*); void tempname(Node*, Type*);
int Econv(Fmt*); int Econv(Fmt*);
int Jconv(Fmt*); int Jconv(Fmt*);
int Lconv(Fmt*); int Lconv(Fmt*);
@ -934,23 +931,22 @@ int Nconv(Fmt*);
void exprfmt(Fmt*, Node*, int); void exprfmt(Fmt*, Node*, int);
int Wconv(Fmt*); int Wconv(Fmt*);
int Zconv(Fmt*); int Zconv(Fmt*);
int lookdot0(Sym*, Type*, Type**); int lookdot0(Sym*, Type*, Type**);
int adddot1(Sym*, Type*, int, Type**); int adddot1(Sym*, Type*, int, Type**);
Node* adddot(Node*); Node* adddot(Node*);
void expandmeth(Sym*, Type*); void expandmeth(Sym*, Type*);
void genwrapper(Type*, Type*, Sym*); void genwrapper(Type*, Type*, Sym*);
int simsimtype(Type*); int simsimtype(Type*);
int powtwo(Node*); int powtwo(Node*);
Type* tounsigned(Type*); Type* tounsigned(Type*);
void smagic(Magic*); void smagic(Magic*);
void umagic(Magic*); void umagic(Magic*);
void redeclare(Sym*, char*); void redeclare(Sym*, char*);
Sym* ngotype(Node*); 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 * dcl.c
@ -1053,7 +1049,6 @@ void walkstmt(Node**);
void walkstmtlist(NodeList*); void walkstmtlist(NodeList*);
void walkexprlist(NodeList*, NodeList**); void walkexprlist(NodeList*, NodeList**);
void walkconv(Node**, NodeList**); void walkconv(Node**, NodeList**);
void walkdottype(Node*, NodeList**);
void walkas(Node*); void walkas(Node*);
void walkswitch(Node*); void walkswitch(Node*);
void walkrange(Node*); void walkrange(Node*);
@ -1071,8 +1066,6 @@ Type* fixchan(Type*);
Node* ifacecvt(Type*, Node*, int, NodeList**); Node* ifacecvt(Type*, Node*, int, NodeList**);
int ifaceas(Type*, Type*, int); int ifaceas(Type*, Type*, int);
int ifaceas1(Type*, Type*, int); int ifaceas1(Type*, Type*, int);
void ifacecheck(Type*, Type*, int, int);
void runifacechecks(void);
Node* convas(Node*, NodeList**); Node* convas(Node*, NodeList**);
Node* colas(NodeList*, NodeList*); Node* colas(NodeList*, NodeList*);
void colasdefn(NodeList*, Node*); void colasdefn(NodeList*, Node*);
@ -1090,10 +1083,10 @@ void typecheckswitch(Node*);
void typecheckselect(Node*); void typecheckselect(Node*);
void typecheckrange(Node*); void typecheckrange(Node*);
Node* typecheckconv(Node*, Node*, Type*, int, char*); Node* typecheckconv(Node*, Node*, Type*, int, char*);
int checkconv(Type*, Type*, int, int*, int*, char*);
Node* typecheck(Node**, int); Node* typecheck(Node**, int);
int islvalue(Node*); int islvalue(Node*);
void queuemethod(Node*); void queuemethod(Node*);
int exportassignok(Type*, char*);
/* /*
* const.c * const.c
@ -1242,4 +1235,4 @@ int duintptr(Sym *s, int off, uint64 v);
int duintxx(Sym *s, int off, uint64 v, int wid); int duintxx(Sym *s, int off, uint64 v, int wid);
void genembedtramp(Type*, Type*, Sym*); void genembedtramp(Type*, Type*, Sym*);
int gen_as_init(Node*); int gen_as_init(Node*);
int anyregalloc(); int anyregalloc(void);

View File

@ -148,8 +148,21 @@ main(int argc, char *argv[])
typecheckok = 1; typecheckok = 1;
if(debug['f']) if(debug['f'])
frame(1); 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(); 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(); resumecheckwidth();
for(l=xtop; l; l=l->next) for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC) if(l->n->op == ODCLFUNC)
@ -164,7 +177,6 @@ main(int argc, char *argv[])
} }
dclchecks(); dclchecks();
runifacechecks();
if(nerrors) if(nerrors)
errorexit(); errorexit();
@ -1155,7 +1167,7 @@ loop:
int int
escchar(int e, int *escflg, vlong *val) escchar(int e, int *escflg, vlong *val)
{ {
int i, c; int i, u, c;
vlong l; vlong l;
*escflg = 0; *escflg = 0;
@ -1177,6 +1189,7 @@ escchar(int e, int *escflg, vlong *val)
return 0; return 0;
} }
u = 0;
c = getr(); c = getr();
switch(c) { switch(c) {
case 'x': case 'x':
@ -1186,10 +1199,12 @@ escchar(int e, int *escflg, vlong *val)
case 'u': case 'u':
i = 4; i = 4;
u = 1;
goto hex; goto hex;
case 'U': case 'U':
i = 8; i = 8;
u = 1;
goto hex; goto hex;
case '0': case '0':
@ -1239,6 +1254,10 @@ hex:
ungetc(c); ungetc(c);
break; break;
} }
if(u && l > Runemax) {
yyerror("invalid Unicode code point in escape sequence: %#llx", l);
l = Runeerror;
}
*val = l; *val = l;
return 0; return 0;
@ -1388,7 +1407,6 @@ lexinit(void)
// (the type of x in var x string or var x = "hello"). // (the type of x in var x string or var x = "hello").
// this is the ideal form // this is the ideal form
// (the type of x in const x = "hello"). // (the type of x in const x = "hello").
// TODO(rsc): this may need some more thought.
idealstring = typ(TSTRING); idealstring = typ(TSTRING);
idealbool = typ(TBOOL); idealbool = typ(TBOOL);

View File

@ -39,6 +39,8 @@ exprfmt(Fmt *f, Node *n, int prec)
case ODOTPTR: case ODOTPTR:
case ODOTINTER: case ODOTINTER:
case ODOTMETH: case ODOTMETH:
case ODOTTYPE:
case ODOTTYPE2:
case OARRAYBYTESTR: case OARRAYBYTESTR:
case OCAP: case OCAP:
case OCLOSE: case OCLOSE:
@ -54,7 +56,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OCONV: case OCONV:
case OCONVNOP: case OCONVNOP:
case OCONVSLICE: case OCONVSLICE:
case OCONVIFACE:
case OMAKESLICE: case OMAKESLICE:
case ORUNESTR: case ORUNESTR:
case OADDR: case OADDR:
@ -64,6 +65,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case ONOT: case ONOT:
case OPLUS: case OPLUS:
case ORECV: case ORECV:
case OCONVIFACE:
nprec = 7; nprec = 7;
break; break;
@ -277,6 +279,7 @@ exprfmt(Fmt *f, Node *n, int prec)
break; break;
case ODOTTYPE: case ODOTTYPE:
case ODOTTYPE2:
exprfmt(f, n->left, 7); exprfmt(f, n->left, 7);
fmtprint(f, ".("); fmtprint(f, ".(");
if(n->right != N) if(n->right != N)
@ -336,9 +339,9 @@ exprfmt(Fmt *f, Node *n, int prec)
break; break;
case OCONV: case OCONV:
case OCONVIFACE:
case OCONVNOP: case OCONVNOP:
case OCONVSLICE: case OCONVSLICE:
case OCONVIFACE:
case OARRAYBYTESTR: case OARRAYBYTESTR:
case ORUNESTR: case ORUNESTR:
if(n->type == T || n->type->sym == S) if(n->type == T || n->type->sym == S)

View File

@ -11,7 +11,7 @@
void void
typecheckrange(Node *n) typecheckrange(Node *n)
{ {
int op, et; char *why;
Type *t, *t1, *t2; Type *t, *t1, *t2;
Node *v1, *v2; Node *v1, *v2;
NodeList *ll; NodeList *ll;
@ -66,13 +66,13 @@ typecheckrange(Node *n)
if(v1->defn == n) if(v1->defn == n)
v1->type = t1; v1->type = t1;
else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et, "range") < 0) else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
yyerror("cannot assign type %T to %+N", t1, v1); yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
if(v2) { if(v2) {
if(v2->defn == n) if(v2->defn == n)
v2->type = t2; v2->type = t2;
else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et, "range") < 0) else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
yyerror("cannot assign type %T to %+N", t1, v1); yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
} }
out: out:

View File

@ -47,18 +47,26 @@ func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int) func stringiter2(string, int) (retk int, retv int)
func slicecopy(to any, fr any, wid uint32) int func slicecopy(to any, fr any, wid uint32) int
func ifaceI2E(iface any) (ret any) // interface conversions
func ifaceE2I(typ *byte, iface any) (ret any) func convI2E(elem any) (ret any)
func ifaceT2E(typ *byte, elem any) (ret any) func convI2I(typ *byte, elem any) (ret any)
func ifaceE2T(typ *byte, elem any) (ret any) func convT2E(typ *byte, elem any) (ret any)
func ifaceE2I2(typ *byte, iface any) (ret any, ok bool) func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
func ifaceE2T2(typ *byte, elem any) (ret any, ok bool)
func ifaceT2I(typ1 *byte, typ2 *byte, elem any) (ret any) // interface type assertions x.(T)
func ifaceI2T(typ *byte, iface any) (ret any) func assertE2E(typ *byte, iface any) (ret any)
func ifaceI2T2(typ *byte, iface any) (ret any, ok bool) func assertE2E2(typ *byte, iface any) (ret any, ok bool)
func ifaceI2I(typ *byte, iface any) (ret any) func assertE2I(typ *byte, iface any) (ret any)
func ifaceI2Ix(typ *byte, iface any) (ret any) func assertE2I2(typ *byte, iface any) (ret any, ok bool)
func ifaceI2I2(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 ifaceeq(i1 any, i2 any) (ret bool)
func efaceeq(i1 any, i2 any) (ret bool) func efaceeq(i1 any, i2 any) (ret bool)
func ifacethash(i1 any) (ret uint32) func ifacethash(i1 any) (ret uint32)

View File

@ -524,6 +524,7 @@ typ(int et)
t->etype = et; t->etype = et;
t->width = BADWIDTH; t->width = BADWIDTH;
t->lineno = lineno; t->lineno = lineno;
t->orig = t;
return t; return t;
} }
@ -863,16 +864,13 @@ goopnames[] =
int int
Oconv(Fmt *fp) Oconv(Fmt *fp)
{ {
char buf[500];
int o; int o;
o = va_arg(fp->args, int); o = va_arg(fp->args, int);
if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil) if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
return fmtstrcpy(fp, goopnames[o]); return fmtstrcpy(fp, goopnames[o]);
if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) { if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
snprint(buf, sizeof(buf), "O-%d", o); return fmtprint(fp, "O-%d", o);
return fmtstrcpy(fp, buf);
}
return fmtstrcpy(fp, opnames[o]); return fmtstrcpy(fp, opnames[o]);
} }
@ -992,14 +990,11 @@ etnames[] =
int int
Econv(Fmt *fp) Econv(Fmt *fp)
{ {
char buf[500];
int et; int et;
et = va_arg(fp->args, int); et = va_arg(fp->args, int);
if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) { if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
snprint(buf, sizeof(buf), "E-%d", et); return fmtprint(fp, "E-%d", et);
return fmtstrcpy(fp, buf);
}
return fmtstrcpy(fp, etnames[et]); return fmtstrcpy(fp, etnames[et]);
} }
@ -1139,6 +1134,13 @@ Tpretty(Fmt *fp, Type *t)
{ {
Type *t1; Type *t1;
Sym *s; 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 if(t->etype != TFIELD
&& t->sym != S && t->sym != S
@ -1775,113 +1777,73 @@ iscomposite(Type *t)
return 0; 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 int
eqtype1(Type *t1, Type *t2, int d, int names) eqtype(Type *t1, Type *t2)
{ {
if(d >= 20)
return 1;
if(t1 == t2) if(t1 == t2)
return 1; return 1;
if(t1 == T || t2 == T) if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
return 0;
if(t1->etype != t2->etype)
return 0;
if(names && t1->etype != TFIELD && t1->sym && t2->sym && t1 != t2)
return 0; return 0;
switch(t1->etype) { switch(t1->etype) {
case TINTER: case TINTER:
case TSTRUCT: case TSTRUCT:
t1 = t1->type; for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
t2 = t2->type; if(t1->etype != TFIELD || t2->etype != TFIELD)
for(;;) { fatal("struct/interface missing field: %T %T", t1, t2);
if(!eqtype1(t1, t2, d+1, names)) if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type))
return 0; 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: case TFUNC:
// Loop over structs: receiver, in, out. // Loop over structs: receiver, in, out.
t1 = t1->type; for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
t2 = t2->type;
for(;;) {
Type *ta, *tb; Type *ta, *tb;
if(t1 == t2)
break;
if(t1 == T || t2 == T)
return 0;
if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) 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. // Loop over fields in structs, ignoring argument names.
ta = t1->type; for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
tb = t2->type; if(ta->etype != TFIELD || tb->etype != TFIELD)
while(ta != tb) { fatal("func struct missing field: %T %T", ta, tb);
if(ta == T || tb == T) if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
return 0; 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;
} }
if(ta != T || tb != T)
t1 = t1->down; return 0;
t2 = t2->down;
} }
return 1; return t1 == T && t2 == T;
case TARRAY: case TARRAY:
if(t1->bound != t2->bound) if(t1->bound != t2->bound)
return 0; return 0;
break; break;
case TCHAN: case TCHAN:
if(t1->chan != t2->chan) if(t1->chan != t2->chan)
return 0; return 0;
break; break;
case TMAP:
if(!eqtype1(t1->down, t2->down, d+1, names))
return 0;
break;
} }
return eqtype1(t1->type, t2->type, d+1, names);
} return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
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);
} }
// 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 int
eqtypenoname(Type *t1, Type *t2) eqtypenoname(Type *t1, Type *t2)
{ {
if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT) if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
return eqtype(t1, t2); return 0;
t1 = t1->type; t1 = t1->type;
t2 = t2->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 static int
subtype(Type **stp, Type *t, int d) subtype(Type **stp, Type *t, int d)
{ {
@ -2026,6 +2198,8 @@ shallow(Type *t)
return T; return T;
nt = typ(0); nt = typ(0);
*nt = *t; *nt = *t;
if(t->orig == t)
nt->orig = nt;
return nt; return nt;
} }
@ -2941,43 +3115,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
funccompile(fn, 0); 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* Type*
ifacelookdot(Sym *s, Type *t, int *followptr) ifacelookdot(Sym *s, Type *t, int *followptr)
{ {
@ -3012,20 +3149,42 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
return T; return T;
} }
// check whether non-interface type t
// satisifes inteface type iface.
int 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; int followptr;
t = methtype(t0); t0 = t;
if(t == T)
return 0;
// if this is too slow, // if this is too slow,
// could sort these first // could sort these first
// and then do one loop. // 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) { for(im=iface->type; im; im=im->down) {
imtype = methodfunc(im->type, 0); imtype = methodfunc(im->type, 0);
tm = ifacelookdot(im->sym, t, &followptr); tm = ifacelookdot(im->sym, t, &followptr);
@ -3048,87 +3207,6 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
return 1; 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. * even simpler simtype; get rid of ptr, bool.
* assuming that the front end has rejected * assuming that the front end has rejected

View File

@ -21,7 +21,6 @@ static int onearg(Node*);
static int twoarg(Node*); static int twoarg(Node*);
static int lookdot(Node*, Type*, int); static int lookdot(Node*, Type*, int);
static void typecheckaste(int, Type*, NodeList*, char*); static void typecheckaste(int, Type*, NodeList*, char*);
static int exportassignok(Type*, char*);
static Type* lookdot1(Sym *s, Type *t, Type *f, int); static Type* lookdot1(Sym *s, Type *t, Type *f, int);
static int nokeys(NodeList*); static int nokeys(NodeList*);
static void typecheckcomplit(Node**); static void typecheckcomplit(Node**);
@ -32,7 +31,6 @@ static void typecheckfunc(Node*);
static void checklvalue(Node*, char*); static void checklvalue(Node*, char*);
static void checkassign(Node*); static void checkassign(Node*);
static void checkassignlist(NodeList*); static void checkassignlist(NodeList*);
static void toslice(Node**);
static void stringtoarraylit(Node**); static void stringtoarraylit(Node**);
void void
@ -57,6 +55,7 @@ typecheck(Node **np, int top)
Type *t; Type *t;
Sym *sym; Sym *sym;
Val v; Val v;
char *why;
// cannot type check until all the source has been parsed // cannot type check until all the source has been parsed
if(!typecheckok) if(!typecheckok)
@ -549,8 +548,8 @@ reswitch:
case TMAP: case TMAP:
n->etype = 0; n->etype = 0;
defaultlit(&n->right, t->down); defaultlit(&n->right, t->down);
if(n->right->type != T && !eqtype(n->right->type, t->down)) if(n->right->type != T)
yyerror("invalid map index %#N - need type %T", n->right, t->down); n->right = assignconv(n->right, t->down, "map index");
n->type = t->type; n->type = t->type;
n->op = OINDEXMAP; n->op = OINDEXMAP;
break; break;
@ -644,8 +643,6 @@ reswitch:
l = n->left; l = n->left;
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
// TODO(rsc): 64-bit slice index needs to be checked
// for overflow in generated code
if(istype(t, TSTRING)) { if(istype(t, TSTRING)) {
n->type = t; n->type = t;
n->op = OSLICESTR; n->op = OSLICESTR;
@ -866,21 +863,19 @@ reswitch:
typecheck(&n->right, Erv); typecheck(&n->right, Erv);
if(n->left->type == T || n->right->type == T) if(n->left->type == T || n->right->type == T)
goto error; goto error;
toslice(&n->left);
toslice(&n->right);
defaultlit(&n->left, T); defaultlit(&n->left, T);
defaultlit(&n->right, T); defaultlit(&n->right, T);
if(!isslice(n->left->type) || !isslice(n->right->type)) { if(!isslice(n->left->type) || !isslice(n->right->type)) {
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)) 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 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; goto error;
} }
if(!eqtype(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); yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
goto error; goto error;
} }
goto ret; goto ret;
@ -892,10 +887,17 @@ reswitch:
convlit1(&n->left, n->type, 1); convlit1(&n->left, n->type, 1);
if((t = n->left->type) == T || n->type == T) if((t = n->left->type) == T || n->type == T)
goto error; goto error;
n = typecheckconv(n, n->left, n->type, 1, "conversion"); if((n->op = convertop(t, n->type, &why)) == 0) {
if(n->type == T) yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
goto error; op = OCONV;
}
switch(n->op) { switch(n->op) {
case OCONVNOP:
if(n->left->op == OLITERAL) {
n->op = OLITERAL;
n->val = n->left->val;
}
break;
case OSTRARRAYBYTE: case OSTRARRAYBYTE:
case OSTRARRAYRUNE: case OSTRARRAYRUNE:
if(n->left->op == OLITERAL) if(n->left->op == OLITERAL)
@ -1031,7 +1033,7 @@ reswitch:
if(onearg(n) < 0) if(onearg(n) < 0)
goto error; goto error;
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
defaultlit(&n->left, types[TINTER]); defaultlit(&n->left, T);
if(n->left->type == T) if(n->left->type == T)
goto error; goto error;
goto ret; goto ret;
@ -1242,25 +1244,6 @@ implicitstar(Node **nn)
*nn = n; *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 static int
onearg(Node *n) onearg(Node *n)
{ {
@ -1397,208 +1380,6 @@ nokeys(NodeList *l)
return 1; return 1;
} }
/*
* 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 * typecheck assignment: type list = expression list
*/ */
@ -1608,6 +1389,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
Type *t, *tl, *tn; Type *t, *tl, *tn;
Node *n; Node *n;
int lno; int lno;
char *why;
lno = lineno; lno = lineno;
@ -1619,21 +1401,20 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
setlineno(n); setlineno(n);
tn = n->type->type; tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) { for(tl=tstruct->type; tl; tl=tl->down) {
int xx, yy;
if(tl->isddd) { if(tl->isddd) {
// TODO(rsc): delete if (but not body) in DDD cleanup. // TODO(rsc): delete if (but not body) in DDD cleanup.
if(tl->type->etype != TINTER) if(tl->type->etype != TINTER)
for(; tn; tn=tn->down) for(; tn; tn=tn->down)
if(checkconv(tn->type, tl->type->type, 0, &xx, &yy, desc) < 0) if(assignop(tn->type, tl->type->type, &why) == 0)
yyerror("cannot use %T as type %T in %s", tn->type, tl->type->type, desc); yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
goto out; goto out;
} }
if(tn == T) { if(tn == T) {
yyerror("not enough arguments to %#O", op); yyerror("not enough arguments to %#O", op);
goto out; goto out;
} }
if(checkconv(tn->type, tl->type, 0, &xx, &yy, desc) < 0) if(assignop(tn->type, tl->type, &why) == 0)
yyerror("cannot use type %T as type %T in %s", tn->type, tl->type, desc); yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
tn = tn->down; tn = tn->down;
} }
if(tn != T) 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)) if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
goto out; goto out;
for(; nl; nl=nl->next) { for(; nl; nl=nl->next) {
int xx, yy;
setlineno(nl->n); setlineno(nl->n);
defaultlit(&nl->n, t->type); defaultlit(&nl->n, t->type);
// TODO(rsc): drop first if in DDD cleanup // TODO(rsc): drop first if in DDD cleanup
if(t->etype != TINTER) if(t->etype != TINTER)
if(checkconv(nl->n->type, t->type, 0, &xx, &yy, desc) < 0) if(assignop(nl->n->type, t->type, &why) == 0)
yyerror("cannot use %+N as type %T in %s", nl->n, t->type, desc); yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why);
} }
goto out; goto out;
} }
@ -1669,7 +1449,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
n = nl->n; n = nl->n;
setlineno(nl->n); setlineno(nl->n);
if(n->type != T) if(n->type != T)
nl->n = typecheckconv(nil, n, t, 0, desc); nl->n = assignconv(n, t, desc);
nl = nl->next; nl = nl->next;
} }
if(nl != nil) { if(nl != nil) {
@ -1686,7 +1466,7 @@ out:
* cannot be implicitly assigning to any type with * cannot be implicitly assigning to any type with
* an unavailable field. * an unavailable field.
*/ */
static int int
exportassignok(Type *t, char *desc) exportassignok(Type *t, char *desc)
{ {
Type *f; Type *f;
@ -1882,11 +1662,11 @@ typecheckcomplit(Node **np)
} }
typecheck(&l->right, Erv); typecheck(&l->right, Erv);
defaultlit(&l->right, t->type); 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 { } else {
typecheck(&ll->n, Erv); typecheck(&ll->n, Erv);
defaultlit(&ll->n, t->type); 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 = nod(OKEY, nodintconst(i), ll->n);
ll->n->left->type = types[TINT]; ll->n->left->type = types[TINT];
ll->n->left->typecheck = 1; ll->n->left->typecheck = 1;
@ -1922,8 +1702,8 @@ typecheckcomplit(Node **np)
typecheck(&l->right, Erv); typecheck(&l->right, Erv);
defaultlit(&l->left, t->down); defaultlit(&l->left, t->down);
defaultlit(&l->right, t->type); defaultlit(&l->right, t->type);
l->left = typecheckconv(nil, l->left, t->down, 0, "map key"); l->left = assignconv(l->left, t->down, "map key");
l->right = typecheckconv(nil, l->right, t->type, 0, "map value"); l->right = assignconv(l->right, t->type, "map value");
keydup(l->left, hash, nelem(hash)); keydup(l->left, hash, nelem(hash));
} }
n->op = OMAPLIT; n->op = OMAPLIT;
@ -1944,7 +1724,7 @@ typecheckcomplit(Node **np)
s = f->sym; s = f->sym;
if(s != nil && !exportname(s->name) && s->pkg != localpkg) if(s != nil && !exportname(s->name) && s->pkg != localpkg)
yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t); 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 = nod(OKEY, newname(f->sym), ll->n);
ll->n->left->typecheck = 1; ll->n->left->typecheck = 1;
f = f->down; f = f->down;
@ -1977,7 +1757,7 @@ typecheckcomplit(Node **np)
} }
s = f->sym; s = f->sym;
fielddup(newname(s), hash, nelem(hash)); 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; n->op = OSTRUCTLIT;
@ -2139,8 +1919,8 @@ typecheckas(Node *n)
typecheck(&n->right, Erv); typecheck(&n->right, Erv);
if(n->right && n->right->type != T) { if(n->right && n->right->type != T) {
if(n->left->type != T) if(n->left->type != T)
n->right = typecheckconv(nil, n->right, n->left->type, 0, "assignment"); n->right = assignconv(n->right, n->left->type, "assignment");
else else if(!isblank(n->left))
exportassignok(n->right->type, "assignment"); exportassignok(n->right->type, "assignment");
} }
if(n->left->defn == n && n->left->ntype == N) { if(n->left->defn == n && n->left->ntype == N) {
@ -2156,10 +1936,22 @@ typecheckas(Node *n)
typecheck(&n->left, Erv | Easgn); typecheck(&n->left, Erv | Easgn);
} }
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 static void
typecheckas2(Node *n) typecheckas2(Node *n)
{ {
int cl, cr, op, et; int cl, cr;
NodeList *ll, *lr; NodeList *ll, *lr;
Node *l, *r; Node *l, *r;
Iter s; Iter s;
@ -2182,7 +1974,7 @@ typecheckas2(Node *n)
// easy // easy
for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) { for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
if(ll->n->type != T && lr->n->type != T) 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) { if(ll->n->defn == n && ll->n->ntype == N) {
defaultlit(&lr->n, T); defaultlit(&lr->n, T);
ll->n->type = lr->n->type; ll->n->type = lr->n->type;
@ -2200,9 +1992,9 @@ typecheckas2(Node *n)
if(l->type == T) if(l->type == T)
goto out; goto out;
n->op = OAS2MAPW; 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; 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; goto out;
} }
@ -2223,8 +2015,7 @@ typecheckas2(Node *n)
t = structfirst(&s, &r->type); t = structfirst(&s, &r->type);
for(ll=n->list; ll; ll=ll->next) { for(ll=n->list; ll; ll=ll->next) {
if(ll->n->type != T) if(ll->n->type != T)
if(checkconv(t->type, ll->n->type, 0, &op, &et, nil) < 0) checkassignto(t->type, ll->n);
yyerror("cannot assign type %T to %+N", t->type, ll->n);
if(ll->n->defn == n && ll->n->ntype == N) if(ll->n->defn == n && ll->n->ntype == N)
ll->n->type = t->type; ll->n->type = t->type;
t = structnext(&s); t = structnext(&s);
@ -2246,14 +2037,15 @@ typecheckas2(Node *n)
goto common; goto common;
case ODOTTYPE: case ODOTTYPE:
n->op = OAS2DOTTYPE; n->op = OAS2DOTTYPE;
r->op = ODOTTYPE2;
common: common:
if(l->type != T && checkconv(r->type, l->type, 0, &op, &et, nil) < 0) if(l->type != T)
yyerror("cannot assign %+N to %+N", r, l); checkassignto(r->type, l);
if(l->defn == n) if(l->defn == n)
l->type = r->type; l->type = r->type;
l = n->list->next->n; l = n->list->next->n;
if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et, nil) < 0) if(l->type != T)
yyerror("cannot assign bool value to %+N", l); checkassignto(types[TBOOL], l);
if(l->defn == n && l->ntype == N) if(l->defn == n && l->ntype == N)
l->type = types[TBOOL]; l->type = types[TBOOL];
goto out; goto out;

View File

@ -9,26 +9,6 @@ static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**); 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 // can this code branch reach the end
// without an undcontitional RETURN // without an undcontitional RETURN
// this is hard, so it is conservative // this is hard, so it is conservative
@ -169,8 +149,7 @@ walkdeftype(Node *n)
t->printed = 0; t->printed = 0;
t->deferwidth = 0; t->deferwidth = 0;
// double-check use of type as map key // double-check use of type as map key.
// TODO(rsc): also use of type as receiver?
if(maplineno) { if(maplineno) {
lineno = maplineno; lineno = maplineno;
maptype(n->type, types[TBOOL]); maptype(n->type, types[TBOOL]);
@ -441,7 +420,10 @@ walkstmt(Node **np)
walkstmtlist(n->ninit); walkstmtlist(n->ninit);
if(n->ntest != N) { if(n->ntest != N) {
walkstmtlist(n->ntest->ninit); 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); walkstmt(&n->nincr);
walkstmtlist(n->nbody); walkstmtlist(n->nbody);
@ -483,7 +465,7 @@ walkstmt(Node **np)
break; break;
} }
ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit); ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
n->list = reorder4(ll); n->list = ll;
break; break;
case OSELECT: case OSELECT:
@ -541,6 +523,7 @@ walkexpr(Node **np, NodeList **init)
int et; int et;
int32 lno; int32 lno;
Node *n, *fn; Node *n, *fn;
char buf[100], *p;
n = *np; n = *np;
@ -671,6 +654,7 @@ walkexpr(Node **np, NodeList **init)
// the output bool, so we clear it before the call. // the output bool, so we clear it before the call.
Node *b; Node *b;
b = nodbool(0); b = nodbool(0);
typecheck(&b, Erv);
lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init); lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
n->list = concat(n->list, lr); n->list = concat(n->list, lr);
} }
@ -710,7 +694,6 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OAS2: case OAS2:
as2:
*init = concat(*init, n->ninit); *init = concat(*init, n->ninit);
n->ninit = nil; n->ninit = nil;
walkexprlistsafe(n->list, init); walkexprlistsafe(n->list, init);
@ -802,41 +785,77 @@ walkexpr(Node **np, NodeList **init)
n->ninit = nil; n->ninit = nil;
r = n->rlist->n; r = n->rlist->n;
walkexprlistsafe(n->list, init); walkexprlistsafe(n->list, init);
walkdottype(r, init); r->op = ODOTTYPE2;
et = ifaceas1(r->type, r->left->type, 1); walkexpr(&r, init);
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);
ll = ascompatet(n->op, n->list, &r->type, 0, init); ll = ascompatet(n->op, n->list, &r->type, 0, init);
n = liststmt(concat(list1(r), ll)); n = liststmt(concat(list1(r), ll));
goto ret; goto ret;
case ODOTTYPE: case ODOTTYPE:
walkdottype(n, init); case ODOTTYPE2:
walkconv(&n, init); // 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; goto ret;
case OCONV: case OCONV:
@ -1176,7 +1195,7 @@ walkexpr(Node **np, NodeList **init)
case ORUNESTR: case ORUNESTR:
// sys_intstring(v) // sys_intstring(v)
n = mkcall("intstring", n->type, init, n = mkcall("intstring", n->type, init,
conv(n->left, types[TINT64])); // TODO(rsc): int64?! conv(n->left, types[TINT64]));
goto ret; goto ret;
case OARRAYBYTESTR: 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); n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
goto ret; goto ret;
case OCONVIFACE:
walkexpr(&n->left, init);
n = ifacecvt(n->type, n->left, n->etype, init);
goto ret;
case OCLOSURE: case OCLOSURE:
n = walkclosure(n, init); n = walkclosure(n, init);
goto ret; goto ret;
@ -1271,70 +1285,6 @@ makenewvar(Type *t, NodeList **init, Node **nstar)
return nvar; 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* Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init) 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)) { if(fncall(l, r->type)) {
tmp = nod(OXXX, N, N); tmp = nod(OXXX, N, N);
tempname(tmp, r->type); tempname(tmp, r->type);
typecheck(&tmp, Erv);
a = nod(OAS, l, tmp); a = nod(OAS, l, tmp);
a = convas(a, init); a = convas(a, init);
mm = list(mm, a); mm = list(mm, a);
@ -1517,6 +1468,7 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
var = nod(OXXX, N, N); var = nod(OXXX, N, N);
tempname(var, st); tempname(var, st);
var->sym = lookup(".ddd"); var->sym = lookup(".ddd");
typecheck(&var, Erv);
// assign the fields to the struct. // assign the fields to the struct.
// use the init list so that reorder1 doesn't reorder // use the init list so that reorder1 doesn't reorder
@ -1927,166 +1879,11 @@ bad:
return T; 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* Node*
convas(Node *n, NodeList **init) convas(Node *n, NodeList **init)
{ {
Node *l, *r; Node *l, *r;
Type *lt, *rt; Type *lt, *rt;
int et;
if(n->op != OAS) if(n->op != OAS)
fatal("convas: not OAS %O", n->op); fatal("convas: not OAS %O", n->op);
@ -2115,15 +1912,12 @@ convas(Node *n, NodeList **init)
n->left->left, n->left->right, n->right); n->left->left, n->left->right, n->right);
goto out; goto out;
} }
if(eqtype(lt, rt)) if(eqtype(lt, rt))
goto out; goto out;
et = ifaceas(lt, rt, 0); n->right = assignconv(r, lt, "assignment");
if(et != Inone) { walkexpr(&n->right, init);
n->right = ifacecvt(lt, r, et, init);
goto out;
}
out: out:
ullmancalc(n); ullmancalc(n);
@ -2292,24 +2086,6 @@ reorder3(NodeList *all)
return concat(all, r); 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. * walk through argin parameters.
* generate and return code to allocate * generate and return code to allocate

View File

@ -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

View File

@ -177,26 +177,26 @@ copyout(Type *t, void **src, void *dst)
algarray[alg].copy(wid, dst, *src); 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 #pragma textflag 7
void void
·ifaceT2I(InterfaceType *inter, Type *t, ...) ·convT2I(Type *t, InterfaceType *inter, ...)
{ {
byte *elem; byte *elem;
Iface *ret; Iface *ret;
int32 wid; int32 wid;
elem = (byte*)(&t+1); elem = (byte*)(&inter+1);
wid = t->size; wid = t->size;
ret = (Iface*)(elem + rnd(wid, Structrnd)); ret = (Iface*)(elem + rnd(wid, Structrnd));
ret->tab = itab(inter, t, 0); ret->tab = itab(inter, t, 0);
copyin(t, elem, &ret->data); copyin(t, elem, &ret->data);
} }
// ifaceT2E(sigt *byte, elem any) (ret Eface); // func convT2E(typ *byte, elem any) (ret any)
#pragma textflag 7 #pragma textflag 7
void void
·ifaceT2E(Type *t, ...) ·convT2E(Type *t, ...)
{ {
byte *elem; byte *elem;
Eface *ret; Eface *ret;
@ -205,15 +205,14 @@ void
elem = (byte*)(&t+1); elem = (byte*)(&t+1);
wid = t->size; wid = t->size;
ret = (Eface*)(elem + rnd(wid, Structrnd)); ret = (Eface*)(elem + rnd(wid, Structrnd));
ret->type = t; ret->type = t;
copyin(t, elem, &ret->data); copyin(t, elem, &ret->data);
} }
// ifaceI2T(sigt *byte, iface any) (ret any); // func ifaceI2T(typ *byte, iface any) (ret any)
#pragma textflag 7 #pragma textflag 7
void void
·ifaceI2T(Type *t, Iface i, ...) ·assertI2T(Type *t, Iface i, ...)
{ {
Itab *tab; Itab *tab;
byte *ret; byte *ret;
@ -236,10 +235,10 @@ void
copyout(t, &i.data, ret); 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 #pragma textflag 7
void void
·ifaceI2T2(Type *t, Iface i, ...) ·assertI2T2(Type *t, Iface i, ...)
{ {
byte *ret; byte *ret;
bool *ok; bool *ok;
@ -259,10 +258,10 @@ void
copyout(t, &i.data, ret); copyout(t, &i.data, ret);
} }
// ifaceE2T(sigt *byte, e Eface) (ret any); // func ifaceE2T(typ *byte, iface any) (ret any)
#pragma textflag 7 #pragma textflag 7
void void
·ifaceE2T(Type *t, Eface e, ...) ·assertE2T(Type *t, Eface e, ...)
{ {
byte *ret; byte *ret;
Eface err; Eface err;
@ -284,10 +283,10 @@ void
copyout(t, &e.data, ret); 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 #pragma textflag 7
void void
·ifaceE2T2(Type *t, Eface e, ...) ·assertE2T2(Type *t, Eface e, ...)
{ {
byte *ret; byte *ret;
bool *ok; bool *ok;
@ -307,50 +306,25 @@ void
copyout(t, &e.data, ret); copyout(t, &e.data, ret);
} }
// ifaceI2E(sigi *byte, iface any) (ret any); // func convI2E(elem any) (ret any)
// TODO(rsc): Move to back end, throw away function. #pragma textflag 7
void void
·ifaceI2E(Iface i, Eface ret) ·convI2E(Iface i, Eface ret)
{ {
Itab *tab; Itab *tab;
ret.data = i.data; ret.data = i.data;
tab = i.tab; if((tab = i.tab) == nil)
if(tab == nil)
ret.type = nil; ret.type = nil;
else else
ret.type = tab->type; ret.type = tab->type;
FLUSH(&ret); FLUSH(&ret);
} }
// ifaceI2I(sigi *byte, iface any) (ret any); // func ifaceI2E(typ *byte, iface any) (ret any)
// called only for implicit (no type assertion) conversions. #pragma textflag 7
// converting nil is okay.
void void
·ifaceI2I(InterfaceType *inter, Iface i, Iface ret) ·assertI2E(InterfaceType* inter, Iface i, Eface ret)
{
Itab *tab;
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;
} else {
ret = i;
if(tab->inter != inter)
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)
{ {
Itab *tab; Itab *tab;
Eface err; Eface err;
@ -362,45 +336,97 @@ void
nil, nil, inter->string, nil, nil, inter->string,
nil, &err); nil, &err);
·panic(err); ·panic(err);
} else {
ret = i;
if(tab->inter != inter)
ret.tab = itab(inter, tab->type, 0);
} }
ret.data = i.data;
ret.type = tab->type;
FLUSH(&ret); FLUSH(&ret);
} }
// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); // func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void void
·ifaceI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok) ·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
{ {
Itab *tab; Itab *tab;
USED(inter);
tab = i.tab; tab = i.tab;
if(tab == nil) { if(tab == nil) {
// If incoming interface is nil, the conversion fails. ret.type = nil;
ret.tab = nil; ok = 0;
ret.data = nil;
ok = false;
} else { } else {
ret = i; ret.type = tab->type;
ok = true; ok = 1;
if(tab->inter != inter) { }
ret.tab = itab(inter, tab->type, 1); ret.data = i.data;
if(ret.tab == nil) { FLUSH(&ret);
ret.data = nil; FLUSH(&ok);
ok = false; }
}
} // 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);
}
void
ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
{
Itab *tab;
Eface err;
tab = i.tab;
if(tab == 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->tab = itab(inter, tab->type, 0);
}
// func ifaceI2I(sigi *byte, iface any) (ret any)
#pragma textflag 7
void
·assertI2I(InterfaceType* inter, Iface i, Iface ret)
{
ifaceI2I(inter, i, &ret);
}
// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
{
Itab *tab;
tab = i.tab;
if(tab != nil && (tab->inter == inter || (tab = itab(inter, tab->type, 1)) != nil)) {
ret.data = i.data;
ret.tab = tab;
ok = 1;
} else {
ret.data = 0;
ret.tab = 0;
ok = 0;
} }
FLUSH(&ret); FLUSH(&ret);
FLUSH(&ok); FLUSH(&ok);
} }
// ifaceE2I(sigi *byte, iface any) (ret any);
// Called only for explicit conversions (with type assertion).
void void
ifaceE2I(InterfaceType *inter, Eface e, Iface *ret) ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
{ {
@ -414,45 +440,71 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
nil, nil, inter->string, nil, nil, inter->string,
nil, &err); nil, &err);
·panic(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); // func ifaceE2I(sigi *byte, iface any) (ret any)
// Called only for explicit conversions (with type assertion). #pragma textflag 7
void void
·ifaceE2I(InterfaceType *inter, Eface e, Iface ret) ·assertE2I(InterfaceType* inter, Eface e, Iface ret)
{ {
ifaceE2I(inter, e, &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 void
·ifaceE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok) ·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{ {
Type *t; if(e.type == nil) {
ok = 0;
t = e.type;
ok = true;
if(t == nil) {
// If incoming interface is nil, the conversion fails.
ret.data = nil; ret.data = nil;
ret.tab = nil; ret.tab = nil;
ok = false; } else if((ret.tab = itab(inter, e.type, 1)) == nil) {
ok = 0;
ret.data = nil;
} else { } else {
ok = 1;
ret.data = e.data; ret.data = e.data;
ret.tab = itab(inter, t, 1);
if(ret.tab == nil) {
ret.data = nil;
ok = false;
}
} }
FLUSH(&ret); FLUSH(&ret);
FLUSH(&ok); 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 static uintptr
ifacehash1(void *data, Type *t) ifacehash1(void *data, Type *t)
{ {

343
test/assign1.go Normal file
View File

@ -0,0 +1,343 @@
// errchk $G -e $D/$F.go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
type (
A [10]int
B []int
C chan int
F func() int
I interface {
m() int
}
M map[int]int
P *int
S struct {
X int
}
A1 [10]int
B1 []int
C1 chan int
F1 func() int
I1 interface {
m() int
}
M1 map[int]int
P1 *int
S1 struct {
X int
}
)
var (
a0 [10]int
b0 []int
c0 chan int
f0 func() int
i0 interface {
m() int
}
m0 map[int]int
p0 *int
s0 struct {
X int
}
a A
b B
c C
f F
i I
m M
p P
s S
a1 A1
b1 B1
c1 C1
f1 F1
i1 I1
m1 M1
p1 P1
s1 S1
pa0 *[10]int
pb0 *[]int
pc0 *chan int
pf0 *func() int
pi0 *interface {
m() int
}
pm0 *map[int]int
pp0 **int
ps0 *struct {
X int
}
pa *A
pb *B
pc *C
pf *F
pi *I
pm *M
pp *P
ps *S
pa1 *A1
pb1 *B1
pc1 *C1
pf1 *F1
pi1 *I1
pm1 *M1
pp1 *P1
ps1 *S1
)
func main() {
a0 = a
a0 = a1
a = a0
a = a1 // ERROR "cannot use"
a1 = a0
a1 = a // ERROR "cannot use"
b0 = b
b0 = b1
b = b0
b = b1 // ERROR "cannot use"
b1 = b0
b1 = b // ERROR "cannot use"
c0 = c
c0 = c1
c = c0
c = c1 // ERROR "cannot use"
c1 = c0
c1 = c // ERROR "cannot use"
f0 = f
f0 = f1
f = f0
f = f1 // ERROR "cannot use"
f1 = f0
f1 = f // ERROR "cannot use"
i0 = i
i0 = i1
i = i0
i = i1
i1 = i0
i1 = i
m0 = m
m0 = m1
m = m0
m = m1 // ERROR "cannot use"
m1 = m0
m1 = m // ERROR "cannot use"
p0 = p
p0 = p1
p = p0
p = p1 // ERROR "cannot use"
p1 = p0
p1 = p // ERROR "cannot use"
s0 = s
s0 = s1
s = s0
s = s1 // ERROR "cannot use"
s1 = s0
s1 = s // ERROR "cannot use"
pa0 = pa // ERROR "cannot use"
pa0 = pa1 // ERROR "cannot use"
pa = pa0 // ERROR "cannot use"
pa = pa1 // ERROR "cannot use"
pa1 = pa0 // ERROR "cannot use"
pa1 = pa // ERROR "cannot use"
pb0 = pb // ERROR "cannot use"
pb0 = pb1 // ERROR "cannot use"
pb = pb0 // ERROR "cannot use"
pb = pb1 // ERROR "cannot use"
pb1 = pb0 // ERROR "cannot use"
pb1 = pb // ERROR "cannot use"
pc0 = pc // ERROR "cannot use"
pc0 = pc1 // ERROR "cannot use"
pc = pc0 // ERROR "cannot use"
pc = pc1 // ERROR "cannot use"
pc1 = pc0 // ERROR "cannot use"
pc1 = pc // ERROR "cannot use"
pf0 = pf // ERROR "cannot use"
pf0 = pf1 // ERROR "cannot use"
pf = pf0 // ERROR "cannot use"
pf = pf1 // ERROR "cannot use"
pf1 = pf0 // ERROR "cannot use"
pf1 = pf // ERROR "cannot use"
pi0 = pi // ERROR "cannot use"
pi0 = pi1 // ERROR "cannot use"
pi = pi0 // ERROR "cannot use"
pi = pi1 // ERROR "cannot use"
pi1 = pi0 // ERROR "cannot use"
pi1 = pi // ERROR "cannot use"
pm0 = pm // ERROR "cannot use"
pm0 = pm1 // ERROR "cannot use"
pm = pm0 // ERROR "cannot use"
pm = pm1 // ERROR "cannot use"
pm1 = pm0 // ERROR "cannot use"
pm1 = pm // ERROR "cannot use"
pp0 = pp // ERROR "cannot use"
pp0 = pp1 // ERROR "cannot use"
pp = pp0 // ERROR "cannot use"
pp = pp1 // ERROR "cannot use"
pp1 = pp0 // ERROR "cannot use"
pp1 = pp // ERROR "cannot use"
ps0 = ps // ERROR "cannot use"
ps0 = ps1 // ERROR "cannot use"
ps = ps0 // ERROR "cannot use"
ps = ps1 // ERROR "cannot use"
ps1 = ps0 // ERROR "cannot use"
ps1 = ps // ERROR "cannot use"
a0 = [10]int(a)
a0 = [10]int(a1)
a = A(a0)
a = A(a1)
a1 = A1(a0)
a1 = A1(a)
b0 = []int(b)
b0 = []int(b1)
b = B(b0)
b = B(b1)
b1 = B1(b0)
b1 = B1(b)
c0 = chan int(c)
c0 = chan int(c1)
c = C(c0)
c = C(c1)
c1 = C1(c0)
c1 = C1(c)
f0 = func() int(f)
f0 = func() int(f1)
f = F(f0)
f = F(f1)
f1 = F1(f0)
f1 = F1(f)
i0 = interface {
m() int
}(i)
i0 = interface {
m() int
}(i1)
i = I(i0)
i = I(i1)
i1 = I1(i0)
i1 = I1(i)
m0 = map[int]int(m)
m0 = map[int]int(m1)
m = M(m0)
m = M(m1)
m1 = M1(m0)
m1 = M1(m)
p0 = (*int)(p)
p0 = (*int)(p1)
p = P(p0)
p = P(p1)
p1 = P1(p0)
p1 = P1(p)
s0 = struct {
X int
}(s)
s0 = struct {
X int
}(s1)
s = S(s0)
s = S(s1)
s1 = S1(s0)
s1 = S1(s)
pa0 = (*[10]int)(pa)
pa0 = (*[10]int)(pa1)
pa = (*A)(pa0)
pa = (*A)(pa1)
pa1 = (*A1)(pa0)
pa1 = (*A1)(pa)
pb0 = (*[]int)(pb)
pb0 = (*[]int)(pb1)
pb = (*B)(pb0)
pb = (*B)(pb1)
pb1 = (*B1)(pb0)
pb1 = (*B1)(pb)
pc0 = (*chan int)(pc)
pc0 = (*chan int)(pc1)
pc = (*C)(pc0)
pc = (*C)(pc1)
pc1 = (*C1)(pc0)
pc1 = (*C1)(pc)
pf0 = (*func() int)(pf)
pf0 = (*func() int)(pf1)
pf = (*F)(pf0)
pf = (*F)(pf1)
pf1 = (*F1)(pf0)
pf1 = (*F1)(pf)
pi0 = (*interface {
m() int
})(pi)
pi0 = (*interface {
m() int
})(pi1)
pi = (*I)(pi0)
pi = (*I)(pi1)
pi1 = (*I1)(pi0)
pi1 = (*I1)(pi)
pm0 = (*map[int]int)(pm)
pm0 = (*map[int]int)(pm1)
pm = (*M)(pm0)
pm = (*M)(pm1)
pm1 = (*M1)(pm0)
pm1 = (*M1)(pm)
pp0 = (**int)(pp)
pp0 = (**int)(pp1)
pp = (*P)(pp0)
pp = (*P)(pp1)
pp1 = (*P1)(pp0)
pp1 = (*P1)(pp)
ps0 = (*struct {
X int
})(ps)
ps0 = (*struct {
X int
})(ps1)
ps = (*S)(ps0)
ps = (*S)(ps1)
ps1 = (*S1)(ps0)
ps1 = (*S1)(ps)
}

View File

@ -18,8 +18,9 @@ var f2 = []int(e)
var g = []int(nil) var g = []int(nil)
type H *[4]int type H []int
type J []int type J []int
var h H var h H
var j1 J = h // ERROR "compat|illegal|cannot|cannot" var j1 J = h // ERROR "compat|illegal|cannot"
var j2 = J(h) var j2 = J(h)

View File

@ -34,14 +34,14 @@ func (t1) M(p1.T) {}
var i0 I0 = t0(0) // ok var i0 I0 = t0(0) // ok
var i1 I1 = t1(0) // ok var i1 I1 = t1(0) // ok
var i2 I0 = t1(0) // ERROR "is not|incompatible" var i2 I0 = t1(0) // ERROR "does not implement|incompatible"
var i3 I1 = t0(0) // ERROR "is not|incompatible" var i3 I1 = t0(0) // ERROR "does not implement|incompatible"
var p0i p0.I = t0(0) // ok var p0i p0.I = t0(0) // ok
var p1i p1.I = t1(0) // ok var p1i p1.I = t1(0) // ok
var p0i1 p0.I = t1(0) // ERROR "is not|incompatible" var p0i1 p0.I = t1(0) // ERROR "does not implement|incompatible"
var p0i2 p1.I = t0(0) // ERROR "is not|incompatible" var p0i2 p1.I = t0(0) // ERROR "does not implement|incompatible"
func main() { func main() {
// check that cannot assign one to the other, // check that cannot assign one to the other,
@ -52,14 +52,14 @@ func main() {
v0 = p0.T(v1) v0 = p0.T(v1)
v1 = p1.T(v0) v1 = p1.T(v0)
i0 = i1 // ERROR "need type assertion|incompatible" i0 = i1 // ERROR "cannot use|incompatible"
i1 = i0 // ERROR "need type assertion|incompatible" i1 = i0 // ERROR "cannot use|incompatible"
p0i = i1 // ERROR "need type assertion|incompatible" p0i = i1 // ERROR "cannot use|incompatible"
p1i = i0 // ERROR "need type assertion|incompatible" p1i = i0 // ERROR "cannot use|incompatible"
i0 = p1i // ERROR "need type assertion|incompatible" i0 = p1i // ERROR "cannot use|incompatible"
i1 = p0i // ERROR "need type assertion|incompatible" i1 = p0i // ERROR "cannot use|incompatible"
p0i = p1i // ERROR "need type assertion|incompatible" p0i = p1i // ERROR "cannot use|incompatible"
p1i = p0i // ERROR "need type assertion|incompatible" p1i = p0i // ERROR "cannot use|incompatible"
i0 = p0i i0 = p0i
p0i = i0 p0i = i0

View File

@ -12,10 +12,10 @@ type I1 interface {
} }
type I2 interface { type I2 interface {
I1 // ERROR "loop|interface" I1 // ERROR "loop|interface"
} }
var i1 I1 = i2 // ERROR "need type assertion" var i1 I1 = i2 // ERROR "missing m method|need type assertion"
var i2 I2 var i2 I2
var i2a I2 = i1 var i2a I2 = i1

View File

@ -1,4 +1,4 @@
// $G $D/$F.go && $L $F.go && ./$A.out || echo BUG: bug285 // $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug285
// Copyright 2010 The Go Authors. All rights reserved. // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style

View File

@ -180,58 +180,3 @@ BUG: bug260 failed
=========== bugs/bug274.go =========== bugs/bug274.go
BUG: errchk: command succeeded unexpectedly BUG: errchk: command succeeded unexpectedly
=========== bugs/bug284.go
BUG: errchk: bugs/bug284.go:33: missing expected error: 'cannot'
errchk: bugs/bug284.go:36: missing expected error: 'cannot'
errchk: bugs/bug284.go:37: missing expected error: 'cannot'
errchk: bugs/bug284.go:38: missing expected error: 'cannot'
errchk: bugs/bug284.go:56: missing expected error: 'cannot'
errchk: bugs/bug284.go:59: missing expected error: 'cannot'
errchk: bugs/bug284.go:60: missing expected error: 'cannot'
errchk: bugs/bug284.go:61: missing expected error: 'cannot'
errchk: bugs/bug284.go:71: missing expected error: 'cannot'
errchk: bugs/bug284.go:74: missing expected error: 'cannot'
errchk: bugs/bug284.go:75: missing expected error: 'cannot'
errchk: bugs/bug284.go:76: missing expected error: 'cannot'
errchk: bugs/bug284.go:96: missing expected error: 'cannot'
errchk: bugs/bug284.go:99: missing expected error: 'cannot'
errchk: bugs/bug284.go:101: missing expected error: 'cannot'
errchk: bugs/bug284.go:111: missing expected error: 'cannot'
errchk: bugs/bug284.go:114: missing expected error: 'cannot'
errchk: bugs/bug284.go:115: missing expected error: 'cannot'
errchk: bugs/bug284.go:116: missing expected error: 'cannot'
errchk: bugs/bug284.go:134: missing expected error: 'cannot|need type assertion'
errchk: bugs/bug284.go:137: missing expected error: 'cannot|need type assertion'
errchk: bugs/bug284.go:138: missing expected error: 'cannot|need type assertion'
errchk: bugs/bug284.go:139: missing expected error: 'cannot|need type assertion'
errchk: bugs/bug284.go:149: missing expected error: 'cannot'
errchk: bugs/bug284.go:152: missing expected error: 'cannot'
errchk: bugs/bug284.go:153: missing expected error: 'cannot'
errchk: bugs/bug284.go:154: missing expected error: 'cannot'
errchk: bugs/bug284.go:164: missing expected error: 'cannot'
errchk: bugs/bug284.go:167: missing expected error: 'cannot'
errchk: bugs/bug284.go:168: missing expected error: 'cannot'
errchk: bugs/bug284.go:169: missing expected error: 'cannot'
errchk: bugs/bug284.go:179: missing expected error: 'cannot'
errchk: bugs/bug284.go:182: missing expected error: 'cannot'
errchk: bugs/bug284.go:183: missing expected error: 'cannot'
errchk: bugs/bug284.go:184: missing expected error: 'cannot'
errchk: bugs/bug284.go: unmatched error messages:
==================================================
bugs/bug284.go:190: internal compiler error: typename ideal
==================================================
=========== bugs/bug285.go
bugs/bug285.go:23: invalid map index false - need type B
bugs/bug285.go:80: invalid map index z - need type interface { }
bugs/bug285.go:83: invalid map index new(struct { x int }) - need type interface { }
bugs/bug285.go:84: invalid map index p - need type interface { }
bugs/bug285.go:85: invalid map index false - need type interface { }
bugs/bug285.go:86: invalid map index 17 - need type interface { }
bugs/bug285.go:87: invalid map index "foo" - need type interface { }
bugs/bug285.go:93: invalid map index new(struct { x int }) - need type I1
bugs/bug285.go:94: invalid map index false - need type I1
bugs/bug285.go:95: invalid map index 17 - need type I1
bugs/bug285.go:95: too many errors
BUG: bug285

View File

@ -8,34 +8,45 @@
package main package main
type T struct { a int } type T struct {
a int
}
var t *T var t *T
type I interface { M() } type I interface {
M()
}
var i I var i I
type I2 interface { M(); N(); } type I2 interface {
M()
N()
}
var i2 I2 var i2 I2
type E interface { } type E interface{}
var e E var e E
func main() { func main() {
e = t; // ok e = t // ok
t = e; // ERROR "need explicit|need type assertion" t = e // ERROR "need explicit|need type assertion"
// neither of these can work, // neither of these can work,
// because i has an extra method // because i has an extra method
// that t does not, so i cannot contain a t. // that t does not, so i cannot contain a t.
i = t; // ERROR "missing|incompatible|is not" i = t // ERROR "incompatible|missing M method"
t = i; // ERROR "missing|incompatible|is not" t = i // ERROR "incompatible|need type assertion"
i = i2; // ok i = i2 // ok
i2 = i; // ERROR "need explicit|need type assertion" i2 = i // ERROR "missing N method"
i = I(i2); // ok
i2 = I2(i); // ERROR "need explicit|need type assertion"
e = E(t); // ok i = I(i2) // ok
t = T(e); // ERROR "need explicit|need type assertion|incompatible" i2 = I2(i) // ERROR "missing N method"
e = E(t) // ok
t = T(e) // ERROR "need explicit|need type assertion|incompatible"
} }

View File

@ -9,28 +9,28 @@
package main package main
type Inst interface { type Inst interface {
Next() *Inst; Next() *Inst
} }
type Regexp struct { type Regexp struct {
code []Inst; code []Inst
start Inst; start Inst
} }
type Start struct { type Start struct {
foo *Inst; foo *Inst
} }
func (start *Start) Next() *Inst { return nil } func (start *Start) Next() *Inst { return nil }
func AddInst(Inst) *Inst { func AddInst(Inst) *Inst {
print("ok in addinst\n"); print("ok in addinst\n")
return nil return nil
} }
func main() { func main() {
print("call addinst\n"); print("call addinst\n")
var x Inst = AddInst(new(Start)); // ERROR "illegal|incompatible|is not" var x Inst = AddInst(new(Start)) // ERROR "pointer to interface"
print("return from addinst\n"); print("return from addinst\n")
} }

View File

@ -9,41 +9,50 @@
package main package main
type T int type T int
func (t T) V() func (t T) V()
func (t *T) P() func (t *T) P()
type V interface { V() } type V interface {
type P interface { P(); V() } V()
}
type S struct { T; } type P interface {
type SP struct { *T; } P()
V()
func main() {
var t T;
var v V;
var p P;
var s S;
var sp SP;
v = t;
p = t; // ERROR "is not|requires a pointer"
_, _= v, p;
v = &t;
p = &t;
_, _= v, p;
v = s;
p = s; // ERROR "is not|requires a pointer"
_, _= v, p;
v = &s;
p = &s;
_, _= v, p;
v = sp;
p = sp; // no error!
_, _= v, p;
v = &sp;
p = &sp;
_, _= v, p;
} }
type S struct {
T
}
type SP struct {
*T
}
func main() {
var t T
var v V
var p P
var s S
var sp SP
v = t
p = t // ERROR "does not implement|requires a pointer"
_, _ = v, p
v = &t
p = &t
_, _ = v, p
v = s
p = s // ERROR "does not implement|requires a pointer"
_, _ = v, p
v = &s
p = &s
_, _ = v, p
v = sp
p = sp // no error!
_, _ = v, p
v = &sp
p = &sp
_, _ = v, p
}

View File

@ -20,13 +20,13 @@ type String string
// Calling these functions checks at compile time that the argument // Calling these functions checks at compile time that the argument
// can be converted implicitly to (used as) the given type. // can be converted implicitly to (used as) the given type.
func asArray(Array) {} func asArray(Array) {}
func asBool(Bool) {} func asBool(Bool) {}
func asChan(Chan) {} func asChan(Chan) {}
func asFloat(Float) {} func asFloat(Float) {}
func asInt(Int) {} func asInt(Int) {}
func asMap(Map) {} func asMap(Map) {}
func asSlice(Slice) {} func asSlice(Slice) {}
func asString(String) {} func asString(String) {}
func (Map) M() {} func (Map) M() {}
@ -35,247 +35,247 @@ func (Map) M() {}
// These functions check at run time that the default type // These functions check at run time that the default type
// (in the absence of any implicit conversion hints) // (in the absence of any implicit conversion hints)
// is the given type. // is the given type.
func isArray(x interface{}) { _ = x.(Array) } func isArray(x interface{}) { _ = x.(Array) }
func isBool(x interface{}) { _ = x.(Bool) } func isBool(x interface{}) { _ = x.(Bool) }
func isChan(x interface{}) { _ = x.(Chan) } func isChan(x interface{}) { _ = x.(Chan) }
func isFloat(x interface{}) { _ = x.(Float) } func isFloat(x interface{}) { _ = x.(Float) }
func isInt(x interface{}) { _ = x.(Int) } func isInt(x interface{}) { _ = x.(Int) }
func isMap(x interface{}) { _ = x.(Map) } func isMap(x interface{}) { _ = x.(Map) }
func isSlice(x interface{}) { _ = x.(Slice) } func isSlice(x interface{}) { _ = x.(Slice) }
func isString(x interface{}) { _ = x.(String) } func isString(x interface{}) { _ = x.(String) }
func main() { func main() {
var ( var (
a Array; a Array
b Bool = true; b Bool = true
c Chan = make(Chan); c Chan = make(Chan)
f Float = 1; f Float = 1
i Int = 1; i Int = 1
m Map = make(Map); m Map = make(Map)
slice Slice = make(Slice, 10); slice Slice = make(Slice, 10)
str String = "hello"; str String = "hello"
) )
asArray(a); asArray(a)
isArray(a); isArray(a)
asArray(*&a); asArray(*&a)
isArray(*&a); isArray(*&a)
asArray(Array{}); asArray(Array{})
isArray(Array{}); isArray(Array{})
asBool(b); asBool(b)
isBool(b); isBool(b)
asBool(!b); asBool(!b)
isBool(!b); isBool(!b)
asBool(true); asBool(true)
asBool(*&b); asBool(*&b)
isBool(*&b); isBool(*&b)
asBool(Bool(true)); asBool(Bool(true))
isBool(Bool(true)); isBool(Bool(true))
asChan(c); asChan(c)
isChan(c); isChan(c)
asChan(make(Chan)); asChan(make(Chan))
isChan(make(Chan)); isChan(make(Chan))
asChan(*&c); asChan(*&c)
isChan(*&c); isChan(*&c)
asChan(Chan(nil)); asChan(Chan(nil))
isChan(Chan(nil)); isChan(Chan(nil))
asFloat(f); asFloat(f)
isFloat(f); isFloat(f)
asFloat(-f); asFloat(-f)
isFloat(-f); isFloat(-f)
asFloat(+f); asFloat(+f)
isFloat(+f); isFloat(+f)
asFloat(f+1); asFloat(f + 1)
isFloat(f+1); isFloat(f + 1)
asFloat(1+f); asFloat(1 + f)
isFloat(1+f); isFloat(1 + f)
asFloat(f+f); asFloat(f + f)
isFloat(f+f); isFloat(f + f)
f++; f++
f+=2; f += 2
asFloat(f-1); asFloat(f - 1)
isFloat(f-1); isFloat(f - 1)
asFloat(1-f); asFloat(1 - f)
isFloat(1-f); isFloat(1 - f)
asFloat(f-f); asFloat(f - f)
isFloat(f-f); isFloat(f - f)
f--; f--
f-=2; f -= 2
asFloat(f*2.5); asFloat(f * 2.5)
isFloat(f*2.5); isFloat(f * 2.5)
asFloat(2.5*f); asFloat(2.5 * f)
isFloat(2.5*f); isFloat(2.5 * f)
asFloat(f*f); asFloat(f * f)
isFloat(f*f); isFloat(f * f)
f*=4; f *= 4
asFloat(f/2.5); asFloat(f / 2.5)
isFloat(f/2.5); isFloat(f / 2.5)
asFloat(2.5/f); asFloat(2.5 / f)
isFloat(2.5/f); isFloat(2.5 / f)
asFloat(f/f); asFloat(f / f)
isFloat(f/f); isFloat(f / f)
f/=4; f /= 4
asFloat(f); asFloat(f)
isFloat(f); isFloat(f)
f = 5; f = 5
asFloat(*&f); asFloat(*&f)
isFloat(*&f); isFloat(*&f)
asFloat(234); asFloat(234)
asFloat(Float(234)); asFloat(Float(234))
isFloat(Float(234)); isFloat(Float(234))
asFloat(1.2); asFloat(1.2)
asFloat(Float(i)); asFloat(Float(i))
isFloat(Float(i)); isFloat(Float(i))
asInt(i); asInt(i)
isInt(i); isInt(i)
asInt(-i); asInt(-i)
isInt(-i); isInt(-i)
asInt(^i); asInt(^i)
isInt(^i); isInt(^i)
asInt(+i); asInt(+i)
isInt(+i); isInt(+i)
asInt(i+1); asInt(i + 1)
isInt(i+1); isInt(i + 1)
asInt(1+i); asInt(1 + i)
isInt(1+i); isInt(1 + i)
asInt(i+i); asInt(i + i)
isInt(i+i); isInt(i + i)
i++; i++
i+=1; i += 1
asInt(i-1); asInt(i - 1)
isInt(i-1); isInt(i - 1)
asInt(1-i); asInt(1 - i)
isInt(1-i); isInt(1 - i)
asInt(i-i); asInt(i - i)
isInt(i-i); isInt(i - i)
i--; i--
i-=1; i -= 1
asInt(i*2); asInt(i * 2)
isInt(i*2); isInt(i * 2)
asInt(2*i); asInt(2 * i)
isInt(2*i); isInt(2 * i)
asInt(i*i); asInt(i * i)
isInt(i*i); isInt(i * i)
i*=2; i *= 2
asInt(i/5); asInt(i / 5)
isInt(i/5); isInt(i / 5)
asInt(5/i); asInt(5 / i)
isInt(5/i); isInt(5 / i)
asInt(i/i); asInt(i / i)
isInt(i/i); isInt(i / i)
i/=2; i /= 2
asInt(i%5); asInt(i % 5)
isInt(i%5); isInt(i % 5)
asInt(5%i); asInt(5 % i)
isInt(5%i); isInt(5 % i)
asInt(i%i); asInt(i % i)
isInt(i%i); isInt(i % i)
i%=2; i %= 2
asInt(i&5); asInt(i & 5)
isInt(i&5); isInt(i & 5)
asInt(5&i); asInt(5 & i)
isInt(5&i); isInt(5 & i)
asInt(i&i); asInt(i & i)
isInt(i&i); isInt(i & i)
i&=2; i &= 2
asInt(i&^5); asInt(i &^ 5)
isInt(i&^5); isInt(i &^ 5)
asInt(5&^i); asInt(5 &^ i)
isInt(5&^i); isInt(5 &^ i)
asInt(i&^i); asInt(i &^ i)
isInt(i&^i); isInt(i &^ i)
i&^=2; i &^= 2
asInt(i|5); asInt(i | 5)
isInt(i|5); isInt(i | 5)
asInt(5|i); asInt(5 | i)
isInt(5|i); isInt(5 | i)
asInt(i|i); asInt(i | i)
isInt(i|i); isInt(i | i)
i|=2; i |= 2
asInt(i^5); asInt(i ^ 5)
isInt(i^5); isInt(i ^ 5)
asInt(5^i); asInt(5 ^ i)
isInt(5^i); isInt(5 ^ i)
asInt(i^i); asInt(i ^ i)
isInt(i^i); isInt(i ^ i)
i^=2; i ^= 2
asInt(i<<4); asInt(i << 4)
isInt(i<<4); isInt(i << 4)
i<<=2; i <<= 2
asInt(i>>4); asInt(i >> 4)
isInt(i>>4); isInt(i >> 4)
i>>=2; i >>= 2
asInt(i); asInt(i)
isInt(i); isInt(i)
asInt(0); asInt(0)
asInt(Int(0)); asInt(Int(0))
isInt(Int(0)); isInt(Int(0))
i = 10; i = 10
asInt(*&i); asInt(*&i)
isInt(*&i); isInt(*&i)
asInt(23); asInt(23)
asInt(Int(f)); asInt(Int(f))
isInt(Int(f)); isInt(Int(f))
asMap(m); asMap(m)
isMap(m); isMap(m)
asMap(nil); asMap(nil)
m = nil; m = nil
asMap(make(Map)); asMap(make(Map))
isMap(make(Map)); isMap(make(Map))
asMap(*&m); asMap(*&m)
isMap(*&m); isMap(*&m)
asMap(Map(nil)); asMap(Map(nil))
isMap(Map(nil)); isMap(Map(nil))
asMap(Map{}); asMap(Map{})
isMap(Map{}); isMap(Map{})
asSlice(slice); asSlice(slice)
isSlice(slice); isSlice(slice)
asSlice(make(Slice, 5)); asSlice(make(Slice, 5))
isSlice(make(Slice, 5)); isSlice(make(Slice, 5))
asSlice([]byte{1,2,3}); asSlice([]byte{1, 2, 3})
asSlice([]byte{1,2,3}[0:2]); asSlice([]byte{1, 2, 3}[0:2])
asSlice(slice[0:4]); asSlice(slice[0:4])
isSlice(slice[0:4]); isSlice(slice[0:4])
asSlice(slice[3:8]); asSlice(slice[3:8])
isSlice(slice[3:8]); isSlice(slice[3:8])
asSlice(nil); asSlice(nil)
asSlice(Slice(nil)); asSlice(Slice(nil))
isSlice(Slice(nil)); isSlice(Slice(nil))
slice = nil; slice = nil
asSlice(Slice{1,2,3}); asSlice(Slice{1, 2, 3})
isSlice(Slice{1,2,3}); isSlice(Slice{1, 2, 3})
asSlice(Slice{}); asSlice(Slice{})
isSlice(Slice{}); isSlice(Slice{})
asSlice(*&slice); asSlice(*&slice)
isSlice(*&slice); isSlice(*&slice)
asString(str); asString(str)
isString(str); isString(str)
asString(str+"a"); asString(str + "a")
isString(str+"a"); isString(str + "a")
asString("a"+str); asString("a" + str)
isString("a"+str); isString("a" + str)
asString(str+str); asString(str + str)
isString(str+str); isString(str + str)
str += "a"; str += "a"
str += str; str += str
asString(String('a')); asString(String('a'))
isString(String('a')); isString(String('a'))
asString(String(slice)); asString(String([]byte(slice)))
isString(String(slice)); isString(String([]byte(slice)))
asString(String([]byte(nil))); asString(String([]byte(nil)))
isString(String([]byte(nil))); isString(String([]byte(nil)))
asString("hello"); asString("hello")
asString(String("hello")); asString(String("hello"))
isString(String("hello")); isString(String("hello"))
str = "hello"; str = "hello"
isString(str); isString(str)
asString(*&str); asString(*&str)
isString(*&str); isString(*&str)
} }

View File

@ -12,46 +12,57 @@ package main
type Bool bool type Bool bool
type Map map[int]int type Map map[int]int
func (Map) M() {} func (Map) M() {}
func asBool(Bool) {} type Slice []byte
var slice Slice
func asBool(Bool) {}
func asString(String) {}
type String string
func main() { func main() {
var ( var (
b Bool = true; b Bool = true
i, j int; i, j int
c = make(chan int); c = make(chan int)
m = make(Map); m = make(Map)
) )
asBool(b); asBool(b)
asBool(!b); asBool(!b)
asBool(true); asBool(true)
asBool(*&b); asBool(*&b)
asBool(Bool(true)); asBool(Bool(true))
asBool(1!=2); // ERROR "cannot use.*type bool.*as type Bool" asBool(1 != 2) // ERROR "cannot use.*type bool.*as type Bool"
asBool(i < j); // ERROR "cannot use.*type bool.*as type Bool" asBool(i < j) // ERROR "cannot use.*type bool.*as type Bool"
_, b = m[2]; // ERROR "cannot .* bool.*type Bool" _, b = m[2] // ERROR "cannot .* bool.*type Bool"
m[2] = 1, b; // ERROR "cannot use.*type Bool.*as type bool" m[2] = 1, b // ERROR "cannot use.*type Bool.*as type bool"
b = c<-1; // ERROR "cannot use.*type bool.*type Bool" b = c <- 1 // ERROR "cannot use.*type bool.*type Bool"
_ = b; _ = b
asBool(c<-1); // ERROR "cannot use.*type bool.*as type Bool" asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool"
_, b = <-c; // ERROR "cannot .* bool.*type Bool" _, b = <-c // ERROR "cannot .* bool.*type Bool"
_ = b; _ = b
var inter interface{}; var inter interface{}
_, b = inter.(Map); // ERROR "cannot .* bool.*type Bool" _, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
_ = b; _ = b
var minter interface{M()}; var minter interface {
_, b = minter.(Map); // ERROR "cannot .* bool.*type Bool" M()
_ = b; }
_, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
_ = b
asBool(closed(c)); // ERROR "cannot use.*type bool.*as type Bool" asBool(closed(c)) // ERROR "cannot use.*type bool.*as type Bool"
b = closed(c); // ERROR "cannot use.*type bool.*type Bool" b = closed(c) // ERROR "cannot use.*type bool.*type Bool"
_ = b; _ = b
asString(String(slice)) // ERROR "cannot convert slice"
} }