mirror of
https://github.com/golang/go
synced 2024-11-21 13:44:45 -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:
parent
6aaef04469
commit
565b5dc076
@ -431,7 +431,7 @@ agen(Node *n, Node *res)
|
||||
if(n == N || n->type == T)
|
||||
return;
|
||||
|
||||
if(!isptr[res->type->etype])
|
||||
if(!isptr[res->type->etype] && res->type->etype != TUINTPTR)
|
||||
fatal("agen: not tptr: %T", res->type);
|
||||
|
||||
while(n->op == OCONVNOP)
|
||||
|
@ -133,25 +133,22 @@ bitno(int32 b)
|
||||
int
|
||||
Qconv(Fmt *fp)
|
||||
{
|
||||
char str[STRINGSZ], ss[STRINGSZ], *s;
|
||||
Bits bits;
|
||||
int i;
|
||||
int i, first;
|
||||
|
||||
str[0] = 0;
|
||||
first = 1;
|
||||
bits = va_arg(fp->args, Bits);
|
||||
while(bany(&bits)) {
|
||||
i = bnum(bits);
|
||||
if(str[0])
|
||||
strcat(str, " ");
|
||||
if(var[i].sym == S) {
|
||||
sprint(ss, "$%lld", var[i].offset);
|
||||
s = ss;
|
||||
} else
|
||||
s = var[i].sym->name;
|
||||
if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
|
||||
break;
|
||||
strcat(str, s);
|
||||
if(first)
|
||||
first = 0;
|
||||
else
|
||||
fmtprint(fp, " ");
|
||||
if(var[i].sym == S)
|
||||
fmtprint(fp, "$%lld", var[i].offset);
|
||||
else
|
||||
fmtprint(fp, var[i].sym->name);
|
||||
bits.b[i/32] &= ~(1L << (i%32));
|
||||
}
|
||||
return fmtstrcpy(fp, str);
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,18 +33,22 @@ char *runtimeimport =
|
||||
"func \"\".stringiter (? string, ? int) int\n"
|
||||
"func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
|
||||
"func \"\".slicecopy (to any, fr any, wid uint32) int\n"
|
||||
"func \"\".ifaceI2E (iface any) any\n"
|
||||
"func \"\".ifaceE2I (typ *uint8, iface any) any\n"
|
||||
"func \"\".ifaceT2E (typ *uint8, elem any) any\n"
|
||||
"func \"\".ifaceE2T (typ *uint8, elem any) any\n"
|
||||
"func \"\".ifaceE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".ifaceE2T2 (typ *uint8, elem any) (ret any, ok bool)\n"
|
||||
"func \"\".ifaceT2I (typ1 *uint8, typ2 *uint8, elem any) any\n"
|
||||
"func \"\".ifaceI2T (typ *uint8, iface any) any\n"
|
||||
"func \"\".ifaceI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".ifaceI2I (typ *uint8, iface any) any\n"
|
||||
"func \"\".ifaceI2Ix (typ *uint8, iface any) any\n"
|
||||
"func \"\".ifaceI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".convI2E (elem any) any\n"
|
||||
"func \"\".convI2I (typ *uint8, elem any) any\n"
|
||||
"func \"\".convT2E (typ *uint8, elem any) any\n"
|
||||
"func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n"
|
||||
"func \"\".assertE2E (typ *uint8, iface any) any\n"
|
||||
"func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".assertE2I (typ *uint8, iface any) any\n"
|
||||
"func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".assertE2T (typ *uint8, iface any) any\n"
|
||||
"func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".assertI2E (typ *uint8, iface any) any\n"
|
||||
"func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".assertI2I (typ *uint8, iface any) any\n"
|
||||
"func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".assertI2T (typ *uint8, iface any) any\n"
|
||||
"func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
|
||||
"func \"\".ifaceeq (i1 any, i2 any) bool\n"
|
||||
"func \"\".efaceeq (i1 any, i2 any) bool\n"
|
||||
"func \"\".ifacethash (i1 any) uint32\n"
|
||||
|
@ -119,6 +119,7 @@ walkclosure(Node *func, NodeList **init)
|
||||
Node *xtype, *v, *addr, *xfunc, *call, *clos;
|
||||
NodeList *l, *in;
|
||||
static int closgen;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* wrap body in external function
|
||||
@ -134,8 +135,9 @@ walkclosure(Node *func, NodeList **init)
|
||||
if(v->op == 0)
|
||||
continue;
|
||||
addr = nod(ONAME, N, N);
|
||||
snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
|
||||
addr->sym = lookup(namebuf);
|
||||
p = smprint("&%s", v->sym->name);
|
||||
addr->sym = lookup(p);
|
||||
free(p);
|
||||
addr->ntype = nod(OIND, typenod(v->type), N);
|
||||
addr->class = PPARAM;
|
||||
addr->addable = 1;
|
||||
|
@ -93,8 +93,11 @@ convlit1(Node **np, Type *t, int explicit)
|
||||
return;
|
||||
case OLITERAL:
|
||||
// target is invalid type for a constant? leave alone.
|
||||
if(!okforconst[t->etype] && n->type->etype != TNIL)
|
||||
if(!okforconst[t->etype] && n->type->etype != TNIL) {
|
||||
defaultlit(&n, T);
|
||||
*np = n;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case OLSH:
|
||||
case ORSH:
|
||||
@ -109,10 +112,8 @@ convlit1(Node **np, Type *t, int explicit)
|
||||
}
|
||||
|
||||
// avoided repeated calculations, errors
|
||||
if(cvttype(n->type, t) == 1) {
|
||||
n->type = t;
|
||||
if(eqtype(n->type, t))
|
||||
return;
|
||||
}
|
||||
|
||||
ct = consttype(n);
|
||||
if(ct < 0)
|
||||
@ -968,6 +969,8 @@ defaultlit(Node **np, Type *t)
|
||||
break;
|
||||
case CTBOOL:
|
||||
n->type = types[TBOOL];
|
||||
if(t != T && t->etype == TBOOL)
|
||||
n->type = t;
|
||||
break;
|
||||
case CTINT:
|
||||
n->type = types[TINT];
|
||||
|
@ -281,6 +281,7 @@ updatetype(Type *n, Type *t)
|
||||
local = n->local;
|
||||
vargen = n->vargen;
|
||||
*n = *t;
|
||||
n->orig = t->orig;
|
||||
n->sym = s;
|
||||
n->local = local;
|
||||
n->siggen = 0;
|
||||
@ -759,7 +760,7 @@ typedcl2(Type *pt, Type *t)
|
||||
|
||||
if(pt->etype == TFORW)
|
||||
goto ok;
|
||||
if(!cvttype(pt, t))
|
||||
if(!eqtype(pt->orig, t))
|
||||
yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
|
||||
return;
|
||||
|
||||
@ -1154,7 +1155,7 @@ Sym*
|
||||
methodsym(Sym *nsym, Type *t0)
|
||||
{
|
||||
Sym *s;
|
||||
char buf[NSYMB];
|
||||
char *p;
|
||||
Type *t;
|
||||
|
||||
t = t0;
|
||||
@ -1177,8 +1178,10 @@ methodsym(Sym *nsym, Type *t0)
|
||||
if(t != t0 && t0->sym)
|
||||
t0 = ptrto(t);
|
||||
|
||||
snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
|
||||
return pkglookup(buf, s->pkg);
|
||||
p = smprint("%#hT·%s", t0, nsym->name);
|
||||
s = pkglookup(p, s->pkg);
|
||||
free(p);
|
||||
return s;
|
||||
|
||||
bad:
|
||||
yyerror("illegal receiver type: %T", t0);
|
||||
@ -1200,7 +1203,7 @@ Node*
|
||||
methodname1(Node *n, Node *t)
|
||||
{
|
||||
char *star;
|
||||
char buf[NSYMB];
|
||||
char *p;
|
||||
|
||||
star = "";
|
||||
if(t->op == OIND) {
|
||||
@ -1209,8 +1212,10 @@ methodname1(Node *n, Node *t)
|
||||
}
|
||||
if(t->sym == S || isblank(n))
|
||||
return newname(n->sym);
|
||||
snprint(buf, sizeof(buf), "%s%S·%S", star, t->sym, n->sym);
|
||||
return newname(pkglookup(buf, t->sym->pkg));
|
||||
p = smprint("%s%S·%S", star, t->sym, n->sym);
|
||||
n = newname(pkglookup(p, t->sym->pkg));
|
||||
free(p);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -182,10 +182,22 @@ dumpexporttype(Sym *s)
|
||||
Bprint(bout, "type %#T %l#T\n", t, t);
|
||||
}
|
||||
|
||||
static int
|
||||
methcmp(const void *va, const void *vb)
|
||||
{
|
||||
Type *a, *b;
|
||||
|
||||
a = *(Type**)va;
|
||||
b = *(Type**)vb;
|
||||
return strcmp(a->sym->name, b->sym->name);
|
||||
}
|
||||
|
||||
void
|
||||
dumpsym(Sym *s)
|
||||
{
|
||||
Type *f, *t;
|
||||
Type **m;
|
||||
int i, n;
|
||||
|
||||
if(s->flags & SymExported)
|
||||
return;
|
||||
@ -207,14 +219,23 @@ dumpsym(Sym *s)
|
||||
break;
|
||||
case OTYPE:
|
||||
t = s->def->type;
|
||||
// TODO(rsc): sort methods by name
|
||||
for(f=t->method; f!=T; f=f->down)
|
||||
n = 0;
|
||||
for(f=t->method; f!=T; f=f->down) {
|
||||
dumpprereq(f);
|
||||
n++;
|
||||
}
|
||||
m = mal(n*sizeof m[0]);
|
||||
i = 0;
|
||||
for(f=t->method; f!=T; f=f->down)
|
||||
m[i++] = f;
|
||||
qsort(m, n, sizeof m[0], methcmp);
|
||||
|
||||
dumpexporttype(s);
|
||||
for(f=t->method; f!=T; f=f->down)
|
||||
for(i=0; i<n; i++) {
|
||||
f = m[i];
|
||||
Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
|
||||
f->type->type->type, f->sym, f->type);
|
||||
}
|
||||
break;
|
||||
case ONAME:
|
||||
dumpexportvar(s);
|
||||
@ -357,7 +378,7 @@ importvar(Sym *s, Type *t, int ctxt)
|
||||
|
||||
importsym(s, ONAME);
|
||||
if(s->def != N && s->def->op == ONAME) {
|
||||
if(cvttype(t, s->def->type))
|
||||
if(eqtype(t, s->def->type))
|
||||
return;
|
||||
yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T",
|
||||
s, s->def->type, t);
|
||||
|
@ -158,6 +158,7 @@ struct Type
|
||||
uchar isddd; // TFIELD is ... argument
|
||||
|
||||
Node* nod; // canonical OTYPE node
|
||||
Type* orig; // original type (type literal or predefined type)
|
||||
int lineno;
|
||||
|
||||
// TFUNCT
|
||||
@ -361,11 +362,12 @@ enum
|
||||
OCLOSURE,
|
||||
OCMPIFACE, OCMPSTR,
|
||||
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
|
||||
OCONV, OCONVNOP, OCONVIFACE, OCONVSLICE,
|
||||
OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE,
|
||||
OCOPY,
|
||||
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
|
||||
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
|
||||
ODOTTYPE,
|
||||
ODOTTYPE2,
|
||||
OEQ, ONE, OLT, OLE, OGE, OGT,
|
||||
OIND,
|
||||
OINDEX, OINDEXSTR, OINDEXMAP,
|
||||
@ -904,26 +906,21 @@ NodeList* list(NodeList*, Node*);
|
||||
NodeList* concat(NodeList*, NodeList*);
|
||||
int count(NodeList*);
|
||||
Node* liststmt(NodeList*);
|
||||
|
||||
Type** getthis(Type*);
|
||||
Type** getoutarg(Type*);
|
||||
Type** getinarg(Type*);
|
||||
|
||||
Type* getthisx(Type*);
|
||||
Type* getoutargx(Type*);
|
||||
Type* getinargx(Type*);
|
||||
|
||||
Type* structfirst(Iter*, Type**);
|
||||
Type* structnext(Iter*);
|
||||
Type* funcfirst(Iter*, Type*);
|
||||
Type* funcnext(Iter*);
|
||||
|
||||
int brcom(int);
|
||||
int brrev(int);
|
||||
void setmaxarg(Type*);
|
||||
int dotoffset(Node*, int*, Node**);
|
||||
void tempname(Node*, Type*);
|
||||
|
||||
int Econv(Fmt*);
|
||||
int Jconv(Fmt*);
|
||||
int Lconv(Fmt*);
|
||||
@ -934,23 +931,22 @@ int Nconv(Fmt*);
|
||||
void exprfmt(Fmt*, Node*, int);
|
||||
int Wconv(Fmt*);
|
||||
int Zconv(Fmt*);
|
||||
|
||||
int lookdot0(Sym*, Type*, Type**);
|
||||
int adddot1(Sym*, Type*, int, Type**);
|
||||
Node* adddot(Node*);
|
||||
void expandmeth(Sym*, Type*);
|
||||
void genwrapper(Type*, Type*, Sym*);
|
||||
|
||||
int simsimtype(Type*);
|
||||
|
||||
int powtwo(Node*);
|
||||
Type* tounsigned(Type*);
|
||||
void smagic(Magic*);
|
||||
void umagic(Magic*);
|
||||
|
||||
void redeclare(Sym*, char*);
|
||||
Sym* ngotype(Node*);
|
||||
|
||||
int convertop(Type*, Type*, char**);
|
||||
int assignop(Type*, Type*, char**);
|
||||
Node* assignconv(Node*, Type*, char*);
|
||||
int implements(Type*, Type*, Type**, Type**);
|
||||
|
||||
/*
|
||||
* dcl.c
|
||||
@ -1053,7 +1049,6 @@ void walkstmt(Node**);
|
||||
void walkstmtlist(NodeList*);
|
||||
void walkexprlist(NodeList*, NodeList**);
|
||||
void walkconv(Node**, NodeList**);
|
||||
void walkdottype(Node*, NodeList**);
|
||||
void walkas(Node*);
|
||||
void walkswitch(Node*);
|
||||
void walkrange(Node*);
|
||||
@ -1071,8 +1066,6 @@ Type* fixchan(Type*);
|
||||
Node* ifacecvt(Type*, Node*, int, NodeList**);
|
||||
int ifaceas(Type*, Type*, int);
|
||||
int ifaceas1(Type*, Type*, int);
|
||||
void ifacecheck(Type*, Type*, int, int);
|
||||
void runifacechecks(void);
|
||||
Node* convas(Node*, NodeList**);
|
||||
Node* colas(NodeList*, NodeList*);
|
||||
void colasdefn(NodeList*, Node*);
|
||||
@ -1090,10 +1083,10 @@ void typecheckswitch(Node*);
|
||||
void typecheckselect(Node*);
|
||||
void typecheckrange(Node*);
|
||||
Node* typecheckconv(Node*, Node*, Type*, int, char*);
|
||||
int checkconv(Type*, Type*, int, int*, int*, char*);
|
||||
Node* typecheck(Node**, int);
|
||||
int islvalue(Node*);
|
||||
void queuemethod(Node*);
|
||||
int exportassignok(Type*, char*);
|
||||
|
||||
/*
|
||||
* const.c
|
||||
@ -1242,4 +1235,4 @@ int duintptr(Sym *s, int off, uint64 v);
|
||||
int duintxx(Sym *s, int off, uint64 v, int wid);
|
||||
void genembedtramp(Type*, Type*, Sym*);
|
||||
int gen_as_init(Node*);
|
||||
int anyregalloc();
|
||||
int anyregalloc(void);
|
||||
|
@ -148,8 +148,21 @@ main(int argc, char *argv[])
|
||||
typecheckok = 1;
|
||||
if(debug['f'])
|
||||
frame(1);
|
||||
|
||||
// Process top-level declarations in three phases.
|
||||
// Phase 1: const, type, and names and types of funcs.
|
||||
// This will gather all the information about types
|
||||
// and methods but doesn't depend on any of it.
|
||||
// Phase 2: Variable assignments.
|
||||
// To check interface assignments, depends on phase 1.
|
||||
// Phase 3: Function bodies.
|
||||
defercheckwidth();
|
||||
typechecklist(xtop, Etop);
|
||||
for(l=xtop; l; l=l->next)
|
||||
if(l->n->op != ODCL && l->n->op != OAS)
|
||||
typecheck(&l->n, Etop);
|
||||
for(l=xtop; l; l=l->next)
|
||||
if(l->n->op == ODCL || l->n->op == OAS)
|
||||
typecheck(&l->n, Etop);
|
||||
resumecheckwidth();
|
||||
for(l=xtop; l; l=l->next)
|
||||
if(l->n->op == ODCLFUNC)
|
||||
@ -164,7 +177,6 @@ main(int argc, char *argv[])
|
||||
}
|
||||
dclchecks();
|
||||
|
||||
runifacechecks();
|
||||
if(nerrors)
|
||||
errorexit();
|
||||
|
||||
@ -1155,7 +1167,7 @@ loop:
|
||||
int
|
||||
escchar(int e, int *escflg, vlong *val)
|
||||
{
|
||||
int i, c;
|
||||
int i, u, c;
|
||||
vlong l;
|
||||
|
||||
*escflg = 0;
|
||||
@ -1177,6 +1189,7 @@ escchar(int e, int *escflg, vlong *val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = 0;
|
||||
c = getr();
|
||||
switch(c) {
|
||||
case 'x':
|
||||
@ -1186,10 +1199,12 @@ escchar(int e, int *escflg, vlong *val)
|
||||
|
||||
case 'u':
|
||||
i = 4;
|
||||
u = 1;
|
||||
goto hex;
|
||||
|
||||
case 'U':
|
||||
i = 8;
|
||||
u = 1;
|
||||
goto hex;
|
||||
|
||||
case '0':
|
||||
@ -1239,6 +1254,10 @@ hex:
|
||||
ungetc(c);
|
||||
break;
|
||||
}
|
||||
if(u && l > Runemax) {
|
||||
yyerror("invalid Unicode code point in escape sequence: %#llx", l);
|
||||
l = Runeerror;
|
||||
}
|
||||
*val = l;
|
||||
return 0;
|
||||
|
||||
@ -1388,7 +1407,6 @@ lexinit(void)
|
||||
// (the type of x in var x string or var x = "hello").
|
||||
// this is the ideal form
|
||||
// (the type of x in const x = "hello").
|
||||
// TODO(rsc): this may need some more thought.
|
||||
idealstring = typ(TSTRING);
|
||||
idealbool = typ(TBOOL);
|
||||
|
||||
|
@ -39,6 +39,8 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||
case ODOTPTR:
|
||||
case ODOTINTER:
|
||||
case ODOTMETH:
|
||||
case ODOTTYPE:
|
||||
case ODOTTYPE2:
|
||||
case OARRAYBYTESTR:
|
||||
case OCAP:
|
||||
case OCLOSE:
|
||||
@ -54,7 +56,6 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||
case OCONV:
|
||||
case OCONVNOP:
|
||||
case OCONVSLICE:
|
||||
case OCONVIFACE:
|
||||
case OMAKESLICE:
|
||||
case ORUNESTR:
|
||||
case OADDR:
|
||||
@ -64,6 +65,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||
case ONOT:
|
||||
case OPLUS:
|
||||
case ORECV:
|
||||
case OCONVIFACE:
|
||||
nprec = 7;
|
||||
break;
|
||||
|
||||
@ -277,6 +279,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||
break;
|
||||
|
||||
case ODOTTYPE:
|
||||
case ODOTTYPE2:
|
||||
exprfmt(f, n->left, 7);
|
||||
fmtprint(f, ".(");
|
||||
if(n->right != N)
|
||||
@ -336,9 +339,9 @@ exprfmt(Fmt *f, Node *n, int prec)
|
||||
break;
|
||||
|
||||
case OCONV:
|
||||
case OCONVIFACE:
|
||||
case OCONVNOP:
|
||||
case OCONVSLICE:
|
||||
case OCONVIFACE:
|
||||
case OARRAYBYTESTR:
|
||||
case ORUNESTR:
|
||||
if(n->type == T || n->type->sym == S)
|
||||
|
@ -11,7 +11,7 @@
|
||||
void
|
||||
typecheckrange(Node *n)
|
||||
{
|
||||
int op, et;
|
||||
char *why;
|
||||
Type *t, *t1, *t2;
|
||||
Node *v1, *v2;
|
||||
NodeList *ll;
|
||||
@ -66,13 +66,13 @@ typecheckrange(Node *n)
|
||||
|
||||
if(v1->defn == n)
|
||||
v1->type = t1;
|
||||
else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et, "range") < 0)
|
||||
yyerror("cannot assign type %T to %+N", t1, v1);
|
||||
else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
|
||||
yyerror("cannot assign type %T to %+N in range%s", t1, v1, why);
|
||||
if(v2) {
|
||||
if(v2->defn == n)
|
||||
v2->type = t2;
|
||||
else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et, "range") < 0)
|
||||
yyerror("cannot assign type %T to %+N", t1, v1);
|
||||
else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
|
||||
yyerror("cannot assign type %T to %+N in range%s", t2, v2, why);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -47,18 +47,26 @@ func stringiter(string, int) int
|
||||
func stringiter2(string, int) (retk int, retv int)
|
||||
func slicecopy(to any, fr any, wid uint32) int
|
||||
|
||||
func ifaceI2E(iface any) (ret any)
|
||||
func ifaceE2I(typ *byte, iface any) (ret any)
|
||||
func ifaceT2E(typ *byte, elem any) (ret any)
|
||||
func ifaceE2T(typ *byte, elem any) (ret any)
|
||||
func ifaceE2I2(typ *byte, iface any) (ret any, ok bool)
|
||||
func ifaceE2T2(typ *byte, elem any) (ret any, ok bool)
|
||||
func ifaceT2I(typ1 *byte, typ2 *byte, elem any) (ret any)
|
||||
func ifaceI2T(typ *byte, iface any) (ret any)
|
||||
func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
|
||||
func ifaceI2I(typ *byte, iface any) (ret any)
|
||||
func ifaceI2Ix(typ *byte, iface any) (ret any)
|
||||
func ifaceI2I2(typ *byte, iface any) (ret any, ok bool)
|
||||
// interface conversions
|
||||
func convI2E(elem any) (ret any)
|
||||
func convI2I(typ *byte, elem any) (ret any)
|
||||
func convT2E(typ *byte, elem any) (ret any)
|
||||
func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
|
||||
|
||||
// interface type assertions x.(T)
|
||||
func assertE2E(typ *byte, iface any) (ret any)
|
||||
func assertE2E2(typ *byte, iface any) (ret any, ok bool)
|
||||
func assertE2I(typ *byte, iface any) (ret any)
|
||||
func assertE2I2(typ *byte, iface any) (ret any, ok bool)
|
||||
func assertE2T(typ *byte, iface any) (ret any)
|
||||
func assertE2T2(typ *byte, iface any) (ret any, ok bool)
|
||||
func assertI2E(typ *byte, iface any) (ret any)
|
||||
func assertI2E2(typ *byte, iface any) (ret any, ok bool)
|
||||
func assertI2I(typ *byte, iface any) (ret any)
|
||||
func assertI2I2(typ *byte, iface any) (ret any, ok bool)
|
||||
func assertI2T(typ *byte, iface any) (ret any)
|
||||
func assertI2T2(typ *byte, iface any) (ret any, ok bool)
|
||||
|
||||
func ifaceeq(i1 any, i2 any) (ret bool)
|
||||
func efaceeq(i1 any, i2 any) (ret bool)
|
||||
func ifacethash(i1 any) (ret uint32)
|
||||
|
@ -524,6 +524,7 @@ typ(int et)
|
||||
t->etype = et;
|
||||
t->width = BADWIDTH;
|
||||
t->lineno = lineno;
|
||||
t->orig = t;
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -863,16 +864,13 @@ goopnames[] =
|
||||
int
|
||||
Oconv(Fmt *fp)
|
||||
{
|
||||
char buf[500];
|
||||
int o;
|
||||
|
||||
o = va_arg(fp->args, int);
|
||||
if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
|
||||
return fmtstrcpy(fp, goopnames[o]);
|
||||
if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) {
|
||||
snprint(buf, sizeof(buf), "O-%d", o);
|
||||
return fmtstrcpy(fp, buf);
|
||||
}
|
||||
if(o < 0 || o >= nelem(opnames) || opnames[o] == nil)
|
||||
return fmtprint(fp, "O-%d", o);
|
||||
return fmtstrcpy(fp, opnames[o]);
|
||||
}
|
||||
|
||||
@ -992,14 +990,11 @@ etnames[] =
|
||||
int
|
||||
Econv(Fmt *fp)
|
||||
{
|
||||
char buf[500];
|
||||
int et;
|
||||
|
||||
et = va_arg(fp->args, int);
|
||||
if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) {
|
||||
snprint(buf, sizeof(buf), "E-%d", et);
|
||||
return fmtstrcpy(fp, buf);
|
||||
}
|
||||
if(et < 0 || et >= nelem(etnames) || etnames[et] == nil)
|
||||
return fmtprint(fp, "E-%d", et);
|
||||
return fmtstrcpy(fp, etnames[et]);
|
||||
}
|
||||
|
||||
@ -1139,6 +1134,13 @@ Tpretty(Fmt *fp, Type *t)
|
||||
{
|
||||
Type *t1;
|
||||
Sym *s;
|
||||
|
||||
if(debug['U']) {
|
||||
debug['U'] = 0;
|
||||
fmtprint(fp, "%T (orig=%T)", t, t->orig);
|
||||
debug['U'] = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(t->etype != TFIELD
|
||||
&& t->sym != S
|
||||
@ -1775,113 +1777,73 @@ iscomposite(Type *t)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return 1 if t1 and t2 are identical, following the spec rules.
|
||||
//
|
||||
// Any cyclic type must go through a named type, and if one is
|
||||
// named, it is only identical to the other if they are the same
|
||||
// pointer (t1 == t2), so there's no chance of chasing cycles
|
||||
// ad infinitum, so no need for a depth counter.
|
||||
int
|
||||
eqtype1(Type *t1, Type *t2, int d, int names)
|
||||
eqtype(Type *t1, Type *t2)
|
||||
{
|
||||
if(d >= 20)
|
||||
return 1;
|
||||
if(t1 == t2)
|
||||
return 1;
|
||||
if(t1 == T || t2 == T)
|
||||
return 0;
|
||||
if(t1->etype != t2->etype)
|
||||
return 0;
|
||||
if(names && t1->etype != TFIELD && t1->sym && t2->sym && t1 != t2)
|
||||
if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym)
|
||||
return 0;
|
||||
|
||||
switch(t1->etype) {
|
||||
case TINTER:
|
||||
case TSTRUCT:
|
||||
t1 = t1->type;
|
||||
t2 = t2->type;
|
||||
for(;;) {
|
||||
if(!eqtype1(t1, t2, d+1, names))
|
||||
for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
|
||||
if(t1->etype != TFIELD || t2->etype != TFIELD)
|
||||
fatal("struct/interface missing field: %T %T", t1, t2);
|
||||
if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type))
|
||||
return 0;
|
||||
if(t1 == T)
|
||||
return 1;
|
||||
if(t1->embedded != t2->embedded)
|
||||
return 0;
|
||||
if(t1->nname != N && t1->nname->sym != S) {
|
||||
if(t2->nname == N || t2->nname->sym == S)
|
||||
return 0;
|
||||
if(strcmp(t1->nname->sym->name, t2->nname->sym->name) != 0)
|
||||
return 0;
|
||||
}
|
||||
t1 = t1->down;
|
||||
t2 = t2->down;
|
||||
}
|
||||
return 1;
|
||||
return t1 == T && t2 == T;
|
||||
|
||||
case TFUNC:
|
||||
// Loop over structs: receiver, in, out.
|
||||
t1 = t1->type;
|
||||
t2 = t2->type;
|
||||
for(;;) {
|
||||
for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
|
||||
Type *ta, *tb;
|
||||
if(t1 == t2)
|
||||
break;
|
||||
if(t1 == T || t2 == T)
|
||||
return 0;
|
||||
|
||||
if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
|
||||
return 0;
|
||||
fatal("func missing struct: %T %T", t1, t2);
|
||||
|
||||
// Loop over fields in structs, checking type only.
|
||||
ta = t1->type;
|
||||
tb = t2->type;
|
||||
while(ta != tb) {
|
||||
if(ta == T || tb == T)
|
||||
// Loop over fields in structs, ignoring argument names.
|
||||
for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
|
||||
if(ta->etype != TFIELD || tb->etype != TFIELD)
|
||||
fatal("func struct missing field: %T %T", ta, tb);
|
||||
if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
|
||||
return 0;
|
||||
if(ta->etype != TFIELD || tb->etype != TFIELD || ta->isddd != tb->isddd)
|
||||
return 0;
|
||||
if(!eqtype1(ta->type, tb->type, d+1, names))
|
||||
return 0;
|
||||
ta = ta->down;
|
||||
tb = tb->down;
|
||||
}
|
||||
|
||||
t1 = t1->down;
|
||||
t2 = t2->down;
|
||||
if(ta != T || tb != T)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
return t1 == T && t2 == T;
|
||||
|
||||
case TARRAY:
|
||||
if(t1->bound != t2->bound)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
|
||||
case TCHAN:
|
||||
if(t1->chan != t2->chan)
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case TMAP:
|
||||
if(!eqtype1(t1->down, t2->down, d+1, names))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return eqtype1(t1->type, t2->type, d+1, names);
|
||||
}
|
||||
|
||||
int
|
||||
eqtype(Type *t1, Type *t2)
|
||||
{
|
||||
return eqtype1(t1, t2, 0, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* can we convert from type src to dst with
|
||||
* a trivial conversion (no bits changing)?
|
||||
*/
|
||||
int
|
||||
cvttype(Type *dst, Type *src)
|
||||
{
|
||||
return eqtype1(dst, src, 0, 0);
|
||||
|
||||
return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
|
||||
}
|
||||
|
||||
// Are t1 and t2 equal struct types when field names are ignored?
|
||||
// For deciding whether the result struct from g can be copied
|
||||
// directly when compiling f(g()).
|
||||
int
|
||||
eqtypenoname(Type *t1, Type *t2)
|
||||
{
|
||||
if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
|
||||
return eqtype(t1, t2);
|
||||
return 0;
|
||||
|
||||
t1 = t1->type;
|
||||
t2 = t2->type;
|
||||
@ -1895,6 +1857,216 @@ eqtypenoname(Type *t1, Type *t2)
|
||||
}
|
||||
}
|
||||
|
||||
// Is type src assignment compatible to type dst?
|
||||
// If so, return op code to use in conversion.
|
||||
// If not, return 0.
|
||||
//
|
||||
// It is the caller's responsibility to call exportassignok
|
||||
// to check for assignments to other packages' unexported fields,
|
||||
int
|
||||
assignop(Type *src, Type *dst, char **why)
|
||||
{
|
||||
Type *missing, *have;
|
||||
|
||||
if(why != nil)
|
||||
*why = "";
|
||||
|
||||
if(src == dst)
|
||||
return OCONVNOP;
|
||||
if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
|
||||
return 0;
|
||||
|
||||
// 1. src type is identical to dst.
|
||||
if(eqtype(src, dst))
|
||||
return OCONVNOP;
|
||||
|
||||
// 2. src and dst have identical underlying types
|
||||
// and either src or dst is not a named type.
|
||||
if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S))
|
||||
return OCONVNOP;
|
||||
|
||||
// 3. dst is an interface type and src implements dst.
|
||||
if(dst->etype == TINTER && src->etype != TNIL) {
|
||||
if(implements(src, dst, &missing, &have))
|
||||
return OCONVIFACE;
|
||||
if(why != nil) {
|
||||
if(isptrto(src, TINTER))
|
||||
*why = smprint(": %T is pointer to interface, not interface", src);
|
||||
else if(have)
|
||||
*why = smprint(": %T does not implement %T (wrong type for %S method)\n"
|
||||
"\thave %T\n\twant %T", src, dst, missing->sym, have->type, missing->type);
|
||||
else
|
||||
*why = smprint(": %T does not implement %T (missing %S method)",
|
||||
src, dst, missing->sym);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(src->etype == TINTER && dst->etype != TBLANK) {
|
||||
if(why != nil)
|
||||
*why = ": need type assertion";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 4. src is a bidirectional channel value, dst is a channel type,
|
||||
// src and dst have identical element types, and
|
||||
// either src or dst is not a named type.
|
||||
if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
|
||||
if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
|
||||
return OCONVNOP;
|
||||
|
||||
// 5. src is the predeclared identifier nil and dst is a nillable type.
|
||||
if(src->etype == TNIL) {
|
||||
switch(dst->etype) {
|
||||
case TARRAY:
|
||||
if(dst->bound != -100) // not slice
|
||||
break;
|
||||
case TPTR32:
|
||||
case TPTR64:
|
||||
case TFUNC:
|
||||
case TMAP:
|
||||
case TCHAN:
|
||||
case TINTER:
|
||||
return OCONVNOP;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. rule about untyped constants - already converted by defaultlit.
|
||||
|
||||
// 7. Any typed value can be assigned to the blank identifier.
|
||||
if(dst->etype == TBLANK)
|
||||
return OCONVNOP;
|
||||
|
||||
// 8. Array to slice.
|
||||
// TODO(rsc): Not for long.
|
||||
if(!src->sym || !dst->sym)
|
||||
if(isptr[src->etype] && isfixedarray(src->type) && isslice(dst))
|
||||
if(eqtype(src->type->type, dst->type))
|
||||
return OCONVSLICE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Can we convert a value of type src to a value of type dst?
|
||||
// If so, return op code to use in conversion (maybe OCONVNOP).
|
||||
// If not, return 0.
|
||||
int
|
||||
convertop(Type *src, Type *dst, char **why)
|
||||
{
|
||||
int op;
|
||||
|
||||
if(why != nil)
|
||||
*why = "";
|
||||
|
||||
if(src == dst)
|
||||
return OCONVNOP;
|
||||
if(src == T || dst == T)
|
||||
return 0;
|
||||
|
||||
// 1. src can be assigned to dst.
|
||||
if((op = assignop(src, dst, why)) != 0)
|
||||
return op;
|
||||
|
||||
// The rules for interfaces are no different in conversions
|
||||
// than assignments. If interfaces are involved, stop now
|
||||
// with the good message from assignop.
|
||||
// Otherwise clear the error.
|
||||
if(src->etype == TINTER || dst->etype == TINTER)
|
||||
return 0;
|
||||
if(why != nil)
|
||||
*why = "";
|
||||
|
||||
// 2. src and dst have identical underlying types.
|
||||
if(eqtype(src->orig, dst->orig))
|
||||
return OCONVNOP;
|
||||
|
||||
// 3. src and dst are unnamed pointer types
|
||||
// and their base types have identical underlying types.
|
||||
if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
|
||||
if(eqtype(src->type->orig, dst->type->orig))
|
||||
return OCONVNOP;
|
||||
|
||||
// 4. src and dst are both integer or floating point types.
|
||||
if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
|
||||
if(simtype[src->etype] == simtype[dst->etype])
|
||||
return OCONVNOP;
|
||||
return OCONV;
|
||||
}
|
||||
|
||||
// 5. src and dst are both complex types.
|
||||
if(iscomplex[src->etype] && iscomplex[dst->etype]) {
|
||||
if(simtype[src->etype] == simtype[dst->etype])
|
||||
return OCONVNOP;
|
||||
return OCONV;
|
||||
}
|
||||
|
||||
// 6. src is an integer or has type []byte or []int
|
||||
// and dst is a string type.
|
||||
if(isint[src->etype] && dst->etype == TSTRING)
|
||||
return ORUNESTR;
|
||||
|
||||
if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) {
|
||||
switch(src->type->etype) {
|
||||
case TUINT8:
|
||||
return OARRAYBYTESTR;
|
||||
case TINT:
|
||||
return OARRAYRUNESTR;
|
||||
}
|
||||
}
|
||||
|
||||
// 7. src is a string and dst is []byte or []int.
|
||||
// String to slice.
|
||||
if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) {
|
||||
switch(dst->type->etype) {
|
||||
case TUINT8:
|
||||
return OSTRARRAYBYTE;
|
||||
case TINT:
|
||||
return OSTRARRAYRUNE;
|
||||
}
|
||||
}
|
||||
|
||||
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
|
||||
if((isptr[src->etype] || src->etype == TUINTPTR) && isptrto(dst, TANY))
|
||||
return OCONVNOP;
|
||||
|
||||
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
|
||||
if(isptrto(src, TANY) && (isptr[dst->etype] || dst->etype == TUINTPTR))
|
||||
return OCONVNOP;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert node n for assignment to type t.
|
||||
Node*
|
||||
assignconv(Node *n, Type *t, char *context)
|
||||
{
|
||||
int op;
|
||||
Node *r;
|
||||
char *why;
|
||||
|
||||
if(n == N || n->type == T)
|
||||
return n;
|
||||
|
||||
defaultlit(&n, t);
|
||||
if(t->etype == TBLANK)
|
||||
return n;
|
||||
|
||||
exportassignok(n->type, context);
|
||||
if(eqtype(n->type, t))
|
||||
return n;
|
||||
|
||||
op = assignop(n->type, t, &why);
|
||||
if(op == 0) {
|
||||
yyerror("cannot use %+N as type %T in %s%s", n, t, context, why);
|
||||
op = OCONV;
|
||||
}
|
||||
|
||||
r = nod(op, n, N);
|
||||
r->type = t;
|
||||
r->typecheck = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
subtype(Type **stp, Type *t, int d)
|
||||
{
|
||||
@ -2026,6 +2198,8 @@ shallow(Type *t)
|
||||
return T;
|
||||
nt = typ(0);
|
||||
*nt = *t;
|
||||
if(t->orig == t)
|
||||
nt->orig = nt;
|
||||
return nt;
|
||||
}
|
||||
|
||||
@ -2941,43 +3115,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
|
||||
funccompile(fn, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* delayed interface type check.
|
||||
* remember that there is an interface conversion
|
||||
* on the given line. once the file is completely read
|
||||
* and all methods are known, we can check that
|
||||
* the conversions are valid.
|
||||
*/
|
||||
|
||||
typedef struct Icheck Icheck;
|
||||
struct Icheck
|
||||
{
|
||||
Icheck *next;
|
||||
Type *dst;
|
||||
Type *src;
|
||||
int lineno;
|
||||
int explicit;
|
||||
};
|
||||
Icheck *icheck;
|
||||
Icheck *ichecktail;
|
||||
|
||||
void
|
||||
ifacecheck(Type *dst, Type *src, int lineno, int explicit)
|
||||
{
|
||||
Icheck *p;
|
||||
|
||||
p = mal(sizeof *p);
|
||||
if(ichecktail)
|
||||
ichecktail->next = p;
|
||||
else
|
||||
icheck = p;
|
||||
p->dst = dst;
|
||||
p->src = src;
|
||||
p->lineno = lineno;
|
||||
p->explicit = explicit;
|
||||
ichecktail = p;
|
||||
}
|
||||
|
||||
Type*
|
||||
ifacelookdot(Sym *s, Type *t, int *followptr)
|
||||
{
|
||||
@ -3012,20 +3149,42 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
|
||||
return T;
|
||||
}
|
||||
|
||||
// check whether non-interface type t
|
||||
// satisifes inteface type iface.
|
||||
int
|
||||
ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
|
||||
implements(Type *t, Type *iface, Type **m, Type **samename)
|
||||
{
|
||||
Type *t, *im, *tm, *rcvr, *imtype;
|
||||
Type *t0, *im, *tm, *rcvr, *imtype;
|
||||
int followptr;
|
||||
|
||||
t = methtype(t0);
|
||||
t0 = t;
|
||||
if(t == T)
|
||||
return 0;
|
||||
|
||||
// if this is too slow,
|
||||
// could sort these first
|
||||
// and then do one loop.
|
||||
|
||||
if(t->etype == TINTER) {
|
||||
for(im=iface->type; im; im=im->down) {
|
||||
for(tm=t->type; tm; tm=tm->down) {
|
||||
if(tm->sym == im->sym) {
|
||||
if(eqtype(tm->type, im->type))
|
||||
goto found;
|
||||
*m = im;
|
||||
*samename = tm;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*m = im;
|
||||
*samename = nil;
|
||||
return 0;
|
||||
found:;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
t = methtype(t);
|
||||
if(t != T)
|
||||
expandmeth(t->sym, t);
|
||||
for(im=iface->type; im; im=im->down) {
|
||||
imtype = methodfunc(im->type, 0);
|
||||
tm = ifacelookdot(im->sym, t, &followptr);
|
||||
@ -3048,87 +3207,6 @@ ifaceokT2I(Type *t0, Type *iface, Type **m, Type **samename)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check whether interface type i1 satisifes interface type i2.
|
||||
int
|
||||
ifaceokI2I(Type *i1, Type *i2, Type **m)
|
||||
{
|
||||
Type *m1, *m2;
|
||||
|
||||
// if this is too slow,
|
||||
// could sort these first
|
||||
// and then do one loop.
|
||||
|
||||
for(m2=i2->type; m2; m2=m2->down) {
|
||||
for(m1=i1->type; m1; m1=m1->down)
|
||||
if(m1->sym == m2->sym && eqtype(m1, m2))
|
||||
goto found;
|
||||
*m = m2;
|
||||
return 0;
|
||||
found:;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
runifacechecks(void)
|
||||
{
|
||||
Icheck *p;
|
||||
int lno, wrong, needexplicit;
|
||||
Type *m, *t, *iface, *samename;
|
||||
|
||||
lno = lineno;
|
||||
for(p=icheck; p; p=p->next) {
|
||||
lineno = p->lineno;
|
||||
wrong = 0;
|
||||
needexplicit = 0;
|
||||
m = nil;
|
||||
samename = nil;
|
||||
if(isinter(p->dst) && isinter(p->src)) {
|
||||
iface = p->dst;
|
||||
t = p->src;
|
||||
needexplicit = !ifaceokI2I(t, iface, &m);
|
||||
}
|
||||
else if(isinter(p->dst)) {
|
||||
t = p->src;
|
||||
iface = p->dst;
|
||||
wrong = !ifaceokT2I(t, iface, &m, &samename);
|
||||
} else {
|
||||
t = p->dst;
|
||||
iface = p->src;
|
||||
wrong = !ifaceokT2I(t, iface, &m, &samename);
|
||||
needexplicit = 1;
|
||||
}
|
||||
if(wrong) {
|
||||
if(p->explicit) {
|
||||
if(samename)
|
||||
yyerror("%T cannot contain %T\n\tmissing %S%hhT\n\tdo have %S%hhT",
|
||||
iface, t, m->sym, m->type, samename->sym, samename->type);
|
||||
else
|
||||
yyerror("%T cannot contain %T\n\tmissing %S%hhT", iface, t, m->sym, m->type);
|
||||
} else {
|
||||
if(samename)
|
||||
yyerror("%T is not %T\n\tmissing %S%hhT\n\tdo have %S%hhT",
|
||||
t, iface, m->sym, m->type, samename->sym, samename->type);
|
||||
else
|
||||
yyerror("%T is not %T\n\tmissing %S%hhT", t, iface, m->sym, m->type);
|
||||
}
|
||||
}
|
||||
else if(!p->explicit && needexplicit) {
|
||||
if(m) {
|
||||
if(samename)
|
||||
yyerror("need type assertion to use %T as %T\n\tmissing %S %hhT\n\tdo have %S%hhT",
|
||||
p->src, p->dst, m->sym, m->type, samename->sym, samename->type);
|
||||
else
|
||||
yyerror("need type assertion to use %T as %T\n\tmissing %S%hhT",
|
||||
p->src, p->dst, m->sym, m->type);
|
||||
} else
|
||||
yyerror("need type assertion to use %T as %T",
|
||||
p->src, p->dst);
|
||||
}
|
||||
}
|
||||
lineno = lno;
|
||||
}
|
||||
|
||||
/*
|
||||
* even simpler simtype; get rid of ptr, bool.
|
||||
* assuming that the front end has rejected
|
||||
|
@ -21,7 +21,6 @@ static int onearg(Node*);
|
||||
static int twoarg(Node*);
|
||||
static int lookdot(Node*, Type*, int);
|
||||
static void typecheckaste(int, Type*, NodeList*, char*);
|
||||
static int exportassignok(Type*, char*);
|
||||
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
|
||||
static int nokeys(NodeList*);
|
||||
static void typecheckcomplit(Node**);
|
||||
@ -32,7 +31,6 @@ static void typecheckfunc(Node*);
|
||||
static void checklvalue(Node*, char*);
|
||||
static void checkassign(Node*);
|
||||
static void checkassignlist(NodeList*);
|
||||
static void toslice(Node**);
|
||||
static void stringtoarraylit(Node**);
|
||||
|
||||
void
|
||||
@ -57,6 +55,7 @@ typecheck(Node **np, int top)
|
||||
Type *t;
|
||||
Sym *sym;
|
||||
Val v;
|
||||
char *why;
|
||||
|
||||
// cannot type check until all the source has been parsed
|
||||
if(!typecheckok)
|
||||
@ -549,8 +548,8 @@ reswitch:
|
||||
case TMAP:
|
||||
n->etype = 0;
|
||||
defaultlit(&n->right, t->down);
|
||||
if(n->right->type != T && !eqtype(n->right->type, t->down))
|
||||
yyerror("invalid map index %#N - need type %T", n->right, t->down);
|
||||
if(n->right->type != T)
|
||||
n->right = assignconv(n->right, t->down, "map index");
|
||||
n->type = t->type;
|
||||
n->op = OINDEXMAP;
|
||||
break;
|
||||
@ -644,8 +643,6 @@ reswitch:
|
||||
l = n->left;
|
||||
if((t = l->type) == T)
|
||||
goto error;
|
||||
// TODO(rsc): 64-bit slice index needs to be checked
|
||||
// for overflow in generated code
|
||||
if(istype(t, TSTRING)) {
|
||||
n->type = t;
|
||||
n->op = OSLICESTR;
|
||||
@ -866,21 +863,19 @@ reswitch:
|
||||
typecheck(&n->right, Erv);
|
||||
if(n->left->type == T || n->right->type == T)
|
||||
goto error;
|
||||
toslice(&n->left);
|
||||
toslice(&n->right);
|
||||
defaultlit(&n->left, T);
|
||||
defaultlit(&n->right, T);
|
||||
if(!isslice(n->left->type) || !isslice(n->right->type)) {
|
||||
if(!isslice(n->left->type) && !isslice(n->right->type))
|
||||
yyerror("arguments to copy must be array pointer or slice; have %lT, %lT", n->left->type, n->right->type);
|
||||
yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
|
||||
else if(!isslice(n->left->type))
|
||||
yyerror("first argument to copy should be array pointer or slice; have %lT", n->left->type);
|
||||
yyerror("first argument to copy should be slice; have %lT", n->left->type);
|
||||
else
|
||||
yyerror("second argument to copy should be array pointer or slice; have %lT", n->right->type);
|
||||
yyerror("second argument to copy should be slice; have %lT", n->right->type);
|
||||
goto error;
|
||||
}
|
||||
if(!eqtype(n->left->type, n->right->type)) {
|
||||
yyerror("arguments to copy have different element types %lT and %lT", n->left->type, n->right->type);
|
||||
if(!eqtype(n->left->type->type, n->right->type->type)) {
|
||||
yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
|
||||
goto error;
|
||||
}
|
||||
goto ret;
|
||||
@ -892,10 +887,17 @@ reswitch:
|
||||
convlit1(&n->left, n->type, 1);
|
||||
if((t = n->left->type) == T || n->type == T)
|
||||
goto error;
|
||||
n = typecheckconv(n, n->left, n->type, 1, "conversion");
|
||||
if(n->type == T)
|
||||
goto error;
|
||||
if((n->op = convertop(t, n->type, &why)) == 0) {
|
||||
yyerror("cannot convert %+N to type %T%s", n->left, n->type, why);
|
||||
op = OCONV;
|
||||
}
|
||||
switch(n->op) {
|
||||
case OCONVNOP:
|
||||
if(n->left->op == OLITERAL) {
|
||||
n->op = OLITERAL;
|
||||
n->val = n->left->val;
|
||||
}
|
||||
break;
|
||||
case OSTRARRAYBYTE:
|
||||
case OSTRARRAYRUNE:
|
||||
if(n->left->op == OLITERAL)
|
||||
@ -1031,7 +1033,7 @@ reswitch:
|
||||
if(onearg(n) < 0)
|
||||
goto error;
|
||||
typecheck(&n->left, Erv);
|
||||
defaultlit(&n->left, types[TINTER]);
|
||||
defaultlit(&n->left, T);
|
||||
if(n->left->type == T)
|
||||
goto error;
|
||||
goto ret;
|
||||
@ -1242,25 +1244,6 @@ implicitstar(Node **nn)
|
||||
*nn = n;
|
||||
}
|
||||
|
||||
static void
|
||||
toslice(Node **nn)
|
||||
{
|
||||
Node *n;
|
||||
Type *t;
|
||||
|
||||
n = *nn;
|
||||
if(n->type == T)
|
||||
return;
|
||||
if(isptr[n->type->etype] && isfixedarray(n->type->type)) {
|
||||
// convert to slice
|
||||
t = typ(TARRAY);
|
||||
t->bound = -1;
|
||||
t->type = n->type->type->type;
|
||||
n = typecheckconv(nil, n, t, 0, "conversion of array pointer to slice");
|
||||
*nn = n;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
onearg(Node *n)
|
||||
{
|
||||
@ -1397,208 +1380,6 @@ nokeys(NodeList *l)
|
||||
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
|
||||
*/
|
||||
@ -1608,6 +1389,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
||||
Type *t, *tl, *tn;
|
||||
Node *n;
|
||||
int lno;
|
||||
char *why;
|
||||
|
||||
lno = lineno;
|
||||
|
||||
@ -1619,21 +1401,20 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
||||
setlineno(n);
|
||||
tn = n->type->type;
|
||||
for(tl=tstruct->type; tl; tl=tl->down) {
|
||||
int xx, yy;
|
||||
if(tl->isddd) {
|
||||
// TODO(rsc): delete if (but not body) in DDD cleanup.
|
||||
if(tl->type->etype != TINTER)
|
||||
for(; tn; tn=tn->down)
|
||||
if(checkconv(tn->type, tl->type->type, 0, &xx, &yy, desc) < 0)
|
||||
yyerror("cannot use %T as type %T in %s", tn->type, tl->type->type, desc);
|
||||
for(; tn; tn=tn->down)
|
||||
if(assignop(tn->type, tl->type->type, &why) == 0)
|
||||
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
|
||||
goto out;
|
||||
}
|
||||
if(tn == T) {
|
||||
yyerror("not enough arguments to %#O", op);
|
||||
goto out;
|
||||
}
|
||||
if(checkconv(tn->type, tl->type, 0, &xx, &yy, desc) < 0)
|
||||
yyerror("cannot use type %T as type %T in %s", tn->type, tl->type, desc);
|
||||
if(assignop(tn->type, tl->type, &why) == 0)
|
||||
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
|
||||
tn = tn->down;
|
||||
}
|
||||
if(tn != T)
|
||||
@ -1652,13 +1433,12 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
||||
if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
|
||||
goto out;
|
||||
for(; nl; nl=nl->next) {
|
||||
int xx, yy;
|
||||
setlineno(nl->n);
|
||||
defaultlit(&nl->n, t->type);
|
||||
// TODO(rsc): drop first if in DDD cleanup
|
||||
if(t->etype != TINTER)
|
||||
if(checkconv(nl->n->type, t->type, 0, &xx, &yy, desc) < 0)
|
||||
yyerror("cannot use %+N as type %T in %s", nl->n, t->type, desc);
|
||||
if(assignop(nl->n->type, t->type, &why) == 0)
|
||||
yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
@ -1669,7 +1449,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
||||
n = nl->n;
|
||||
setlineno(nl->n);
|
||||
if(n->type != T)
|
||||
nl->n = typecheckconv(nil, n, t, 0, desc);
|
||||
nl->n = assignconv(n, t, desc);
|
||||
nl = nl->next;
|
||||
}
|
||||
if(nl != nil) {
|
||||
@ -1686,7 +1466,7 @@ out:
|
||||
* cannot be implicitly assigning to any type with
|
||||
* an unavailable field.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
exportassignok(Type *t, char *desc)
|
||||
{
|
||||
Type *f;
|
||||
@ -1882,11 +1662,11 @@ typecheckcomplit(Node **np)
|
||||
}
|
||||
typecheck(&l->right, Erv);
|
||||
defaultlit(&l->right, t->type);
|
||||
l->right = typecheckconv(nil, l->right, t->type, 0, "array index");
|
||||
l->right = assignconv(l->right, t->type, "array index");
|
||||
} else {
|
||||
typecheck(&ll->n, Erv);
|
||||
defaultlit(&ll->n, t->type);
|
||||
ll->n = typecheckconv(nil, ll->n, t->type, 0, "array index");
|
||||
ll->n = assignconv(ll->n, t->type, "array index");
|
||||
ll->n = nod(OKEY, nodintconst(i), ll->n);
|
||||
ll->n->left->type = types[TINT];
|
||||
ll->n->left->typecheck = 1;
|
||||
@ -1922,8 +1702,8 @@ typecheckcomplit(Node **np)
|
||||
typecheck(&l->right, Erv);
|
||||
defaultlit(&l->left, t->down);
|
||||
defaultlit(&l->right, t->type);
|
||||
l->left = typecheckconv(nil, l->left, t->down, 0, "map key");
|
||||
l->right = typecheckconv(nil, l->right, t->type, 0, "map value");
|
||||
l->left = assignconv(l->left, t->down, "map key");
|
||||
l->right = assignconv(l->right, t->type, "map value");
|
||||
keydup(l->left, hash, nelem(hash));
|
||||
}
|
||||
n->op = OMAPLIT;
|
||||
@ -1944,7 +1724,7 @@ typecheckcomplit(Node **np)
|
||||
s = f->sym;
|
||||
if(s != nil && !exportname(s->name) && s->pkg != localpkg)
|
||||
yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
|
||||
ll->n = typecheckconv(nil, ll->n, f->type, 0, "field value");
|
||||
ll->n = assignconv(ll->n, f->type, "field value");
|
||||
ll->n = nod(OKEY, newname(f->sym), ll->n);
|
||||
ll->n->left->typecheck = 1;
|
||||
f = f->down;
|
||||
@ -1977,7 +1757,7 @@ typecheckcomplit(Node **np)
|
||||
}
|
||||
s = f->sym;
|
||||
fielddup(newname(s), hash, nelem(hash));
|
||||
l->right = typecheckconv(nil, l->right, f->type, 0, "field value");
|
||||
l->right = assignconv(l->right, f->type, "field value");
|
||||
}
|
||||
}
|
||||
n->op = OSTRUCTLIT;
|
||||
@ -2139,8 +1919,8 @@ typecheckas(Node *n)
|
||||
typecheck(&n->right, Erv);
|
||||
if(n->right && n->right->type != T) {
|
||||
if(n->left->type != T)
|
||||
n->right = typecheckconv(nil, n->right, n->left->type, 0, "assignment");
|
||||
else
|
||||
n->right = assignconv(n->right, n->left->type, "assignment");
|
||||
else if(!isblank(n->left))
|
||||
exportassignok(n->right->type, "assignment");
|
||||
}
|
||||
if(n->left->defn == n && n->left->ntype == N) {
|
||||
@ -2156,10 +1936,22 @@ typecheckas(Node *n)
|
||||
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
|
||||
typecheckas2(Node *n)
|
||||
{
|
||||
int cl, cr, op, et;
|
||||
int cl, cr;
|
||||
NodeList *ll, *lr;
|
||||
Node *l, *r;
|
||||
Iter s;
|
||||
@ -2182,7 +1974,7 @@ typecheckas2(Node *n)
|
||||
// easy
|
||||
for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
|
||||
if(ll->n->type != T && lr->n->type != T)
|
||||
lr->n = typecheckconv(nil, lr->n, ll->n->type, 0, nil);
|
||||
lr->n = assignconv(lr->n, ll->n->type, "assignment");
|
||||
if(ll->n->defn == n && ll->n->ntype == N) {
|
||||
defaultlit(&lr->n, T);
|
||||
ll->n->type = lr->n->type;
|
||||
@ -2200,9 +1992,9 @@ typecheckas2(Node *n)
|
||||
if(l->type == T)
|
||||
goto out;
|
||||
n->op = OAS2MAPW;
|
||||
n->rlist->n = typecheckconv(nil, r, l->type, 0, nil);
|
||||
n->rlist->n = assignconv(r, l->type, "assignment");
|
||||
r = n->rlist->next->n;
|
||||
n->rlist->next->n = typecheckconv(nil, r, types[TBOOL], 0, nil);
|
||||
n->rlist->next->n = assignconv(r, types[TBOOL], "assignment");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -2223,8 +2015,7 @@ typecheckas2(Node *n)
|
||||
t = structfirst(&s, &r->type);
|
||||
for(ll=n->list; ll; ll=ll->next) {
|
||||
if(ll->n->type != T)
|
||||
if(checkconv(t->type, ll->n->type, 0, &op, &et, nil) < 0)
|
||||
yyerror("cannot assign type %T to %+N", t->type, ll->n);
|
||||
checkassignto(t->type, ll->n);
|
||||
if(ll->n->defn == n && ll->n->ntype == N)
|
||||
ll->n->type = t->type;
|
||||
t = structnext(&s);
|
||||
@ -2246,14 +2037,15 @@ typecheckas2(Node *n)
|
||||
goto common;
|
||||
case ODOTTYPE:
|
||||
n->op = OAS2DOTTYPE;
|
||||
r->op = ODOTTYPE2;
|
||||
common:
|
||||
if(l->type != T && checkconv(r->type, l->type, 0, &op, &et, nil) < 0)
|
||||
yyerror("cannot assign %+N to %+N", r, l);
|
||||
if(l->type != T)
|
||||
checkassignto(r->type, l);
|
||||
if(l->defn == n)
|
||||
l->type = r->type;
|
||||
l = n->list->next->n;
|
||||
if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et, nil) < 0)
|
||||
yyerror("cannot assign bool value to %+N", l);
|
||||
if(l->type != T)
|
||||
checkassignto(types[TBOOL], l);
|
||||
if(l->defn == n && l->ntype == N)
|
||||
l->type = types[TBOOL];
|
||||
goto out;
|
||||
|
@ -9,26 +9,6 @@ static Node* conv(Node*, Type*);
|
||||
static Node* mapfn(char*, Type*);
|
||||
static Node* makenewvar(Type*, NodeList**, Node**);
|
||||
|
||||
enum
|
||||
{
|
||||
Inone,
|
||||
I2T,
|
||||
I2T2,
|
||||
I2I,
|
||||
I2Ix,
|
||||
I2I2,
|
||||
T2I,
|
||||
I2Isame,
|
||||
E2T,
|
||||
E2T2,
|
||||
E2I,
|
||||
E2I2,
|
||||
I2E,
|
||||
I2E2,
|
||||
T2E,
|
||||
E2Esame,
|
||||
};
|
||||
|
||||
// can this code branch reach the end
|
||||
// without an undcontitional RETURN
|
||||
// this is hard, so it is conservative
|
||||
@ -169,8 +149,7 @@ walkdeftype(Node *n)
|
||||
t->printed = 0;
|
||||
t->deferwidth = 0;
|
||||
|
||||
// double-check use of type as map key
|
||||
// TODO(rsc): also use of type as receiver?
|
||||
// double-check use of type as map key.
|
||||
if(maplineno) {
|
||||
lineno = maplineno;
|
||||
maptype(n->type, types[TBOOL]);
|
||||
@ -441,7 +420,10 @@ walkstmt(Node **np)
|
||||
walkstmtlist(n->ninit);
|
||||
if(n->ntest != N) {
|
||||
walkstmtlist(n->ntest->ninit);
|
||||
walkexpr(&n->ntest, &n->ninit);
|
||||
init = n->ntest->ninit;
|
||||
n->ntest->ninit = nil;
|
||||
walkexpr(&n->ntest, &init);
|
||||
n->ntest->ninit = concat(init, n->ntest->ninit);
|
||||
}
|
||||
walkstmt(&n->nincr);
|
||||
walkstmtlist(n->nbody);
|
||||
@ -483,7 +465,7 @@ walkstmt(Node **np)
|
||||
break;
|
||||
}
|
||||
ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
|
||||
n->list = reorder4(ll);
|
||||
n->list = ll;
|
||||
break;
|
||||
|
||||
case OSELECT:
|
||||
@ -541,6 +523,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
int et;
|
||||
int32 lno;
|
||||
Node *n, *fn;
|
||||
char buf[100], *p;
|
||||
|
||||
n = *np;
|
||||
|
||||
@ -671,6 +654,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
// the output bool, so we clear it before the call.
|
||||
Node *b;
|
||||
b = nodbool(0);
|
||||
typecheck(&b, Erv);
|
||||
lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
|
||||
n->list = concat(n->list, lr);
|
||||
}
|
||||
@ -710,7 +694,6 @@ walkexpr(Node **np, NodeList **init)
|
||||
goto ret;
|
||||
|
||||
case OAS2:
|
||||
as2:
|
||||
*init = concat(*init, n->ninit);
|
||||
n->ninit = nil;
|
||||
walkexprlistsafe(n->list, init);
|
||||
@ -802,41 +785,77 @@ walkexpr(Node **np, NodeList **init)
|
||||
n->ninit = nil;
|
||||
r = n->rlist->n;
|
||||
walkexprlistsafe(n->list, init);
|
||||
walkdottype(r, init);
|
||||
et = ifaceas1(r->type, r->left->type, 1);
|
||||
switch(et) {
|
||||
case I2Isame:
|
||||
case E2Esame:
|
||||
case I2E:
|
||||
n->rlist = list(list1(r->left), nodbool(1));
|
||||
typechecklist(n->rlist, Erv);
|
||||
goto as2;
|
||||
case I2T:
|
||||
et = I2T2;
|
||||
break;
|
||||
case I2Ix:
|
||||
et = I2I2;
|
||||
break;
|
||||
case E2I:
|
||||
et = E2I2;
|
||||
break;
|
||||
case E2T:
|
||||
et = E2T2;
|
||||
break;
|
||||
default:
|
||||
et = Inone;
|
||||
break;
|
||||
}
|
||||
if(et == Inone)
|
||||
break;
|
||||
r = ifacecvt(r->type, r->left, et, init);
|
||||
r->op = ODOTTYPE2;
|
||||
walkexpr(&r, init);
|
||||
ll = ascompatet(n->op, n->list, &r->type, 0, init);
|
||||
n = liststmt(concat(list1(r), ll));
|
||||
goto ret;
|
||||
|
||||
case ODOTTYPE:
|
||||
walkdottype(n, init);
|
||||
walkconv(&n, init);
|
||||
case ODOTTYPE2:
|
||||
// Build name of function: assertI2E2 etc.
|
||||
strcpy(buf, "assert");
|
||||
p = buf+strlen(buf);
|
||||
if(isnilinter(n->left->type))
|
||||
*p++ = 'E';
|
||||
else
|
||||
*p++ = 'I';
|
||||
*p++ = '2';
|
||||
if(isnilinter(n->type))
|
||||
*p++ = 'E';
|
||||
else if(isinter(n->type))
|
||||
*p++ = 'I';
|
||||
else
|
||||
*p++ = 'T';
|
||||
if(n->op == ODOTTYPE2)
|
||||
*p++ = '2';
|
||||
*p = '\0';
|
||||
|
||||
fn = syslook(buf, 1);
|
||||
ll = list1(typename(n->type));
|
||||
ll = list(ll, n->left);
|
||||
argtype(fn, n->left->type);
|
||||
argtype(fn, n->type);
|
||||
n = nod(OCALL, fn, N);
|
||||
n->list = ll;
|
||||
typecheck(&n, Erv | Efnstruct);
|
||||
walkexpr(&n, init);
|
||||
goto ret;
|
||||
|
||||
case OCONVIFACE:
|
||||
// Build name of function: convI2E etc.
|
||||
// Not all names are possible
|
||||
// (e.g., we'll never generate convE2E or convE2I).
|
||||
walkexpr(&n->left, init);
|
||||
strcpy(buf, "conv");
|
||||
p = buf+strlen(buf);
|
||||
if(isnilinter(n->left->type))
|
||||
*p++ = 'E';
|
||||
else if(isinter(n->left->type))
|
||||
*p++ = 'I';
|
||||
else
|
||||
*p++ = 'T';
|
||||
*p++ = '2';
|
||||
if(isnilinter(n->type))
|
||||
*p++ = 'E';
|
||||
else
|
||||
*p++ = 'I';
|
||||
*p = '\0';
|
||||
|
||||
fn = syslook(buf, 1);
|
||||
ll = nil;
|
||||
if(!isinter(n->left->type))
|
||||
ll = list(ll, typename(n->left->type));
|
||||
if(!isnilinter(n->type))
|
||||
ll = list(ll, typename(n->type));
|
||||
ll = list(ll, n->left);
|
||||
argtype(fn, n->left->type);
|
||||
argtype(fn, n->type);
|
||||
dowidth(fn->type);
|
||||
n = nod(OCALL, fn, N);
|
||||
n->list = ll;
|
||||
typecheck(&n, Erv);
|
||||
walkexpr(&n, init);
|
||||
goto ret;
|
||||
|
||||
case OCONV:
|
||||
@ -1176,7 +1195,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
case ORUNESTR:
|
||||
// sys_intstring(v)
|
||||
n = mkcall("intstring", n->type, init,
|
||||
conv(n->left, types[TINT64])); // TODO(rsc): int64?!
|
||||
conv(n->left, types[TINT64]));
|
||||
goto ret;
|
||||
|
||||
case OARRAYBYTESTR:
|
||||
@ -1234,11 +1253,6 @@ walkexpr(Node **np, NodeList **init)
|
||||
n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
|
||||
goto ret;
|
||||
|
||||
case OCONVIFACE:
|
||||
walkexpr(&n->left, init);
|
||||
n = ifacecvt(n->type, n->left, n->etype, init);
|
||||
goto ret;
|
||||
|
||||
case OCLOSURE:
|
||||
n = walkclosure(n, init);
|
||||
goto ret;
|
||||
@ -1271,70 +1285,6 @@ makenewvar(Type *t, NodeList **init, Node **nstar)
|
||||
return nvar;
|
||||
}
|
||||
|
||||
// TODO(rsc): cut
|
||||
void
|
||||
walkdottype(Node *n, NodeList **init)
|
||||
{
|
||||
walkexpr(&n->left, init);
|
||||
if(n->left == N)
|
||||
return;
|
||||
if(n->right != N) {
|
||||
walkexpr(&n->right, init);
|
||||
n->type = n->right->type;
|
||||
n->right = N;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(rsc): cut
|
||||
void
|
||||
walkconv(Node **np, NodeList **init)
|
||||
{
|
||||
int et;
|
||||
char *what;
|
||||
Type *t;
|
||||
Node *l;
|
||||
Node *n;
|
||||
|
||||
n = *np;
|
||||
t = n->type;
|
||||
if(t == T)
|
||||
return;
|
||||
walkexpr(&n->left, init);
|
||||
l = n->left;
|
||||
if(l == N)
|
||||
return;
|
||||
if(l->type == T)
|
||||
return;
|
||||
|
||||
// if using .(T), interface assertion.
|
||||
if(n->op == ODOTTYPE) {
|
||||
et = ifaceas1(t, l->type, 1);
|
||||
if(et == I2Isame || et == E2Esame) {
|
||||
n->op = OCONVNOP;
|
||||
return;
|
||||
}
|
||||
if(et != Inone) {
|
||||
n = ifacecvt(t, l, et, init);
|
||||
*np = n;
|
||||
return;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
|
||||
fatal("walkconv");
|
||||
|
||||
bad:
|
||||
if(n->diag)
|
||||
return;
|
||||
n->diag = 1;
|
||||
if(n->op == ODOTTYPE)
|
||||
what = "type assertion";
|
||||
else
|
||||
what = "conversion";
|
||||
if(l->type != T)
|
||||
yyerror("invalid %s: %T to %T", what, l->type, t);
|
||||
}
|
||||
|
||||
Node*
|
||||
ascompatee1(int op, Node *l, Node *r, NodeList **init)
|
||||
{
|
||||
@ -1418,6 +1368,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
|
||||
if(fncall(l, r->type)) {
|
||||
tmp = nod(OXXX, N, N);
|
||||
tempname(tmp, r->type);
|
||||
typecheck(&tmp, Erv);
|
||||
a = nod(OAS, l, tmp);
|
||||
a = convas(a, init);
|
||||
mm = list(mm, a);
|
||||
@ -1517,6 +1468,7 @@ mkdotargs(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
|
||||
var = nod(OXXX, N, N);
|
||||
tempname(var, st);
|
||||
var->sym = lookup(".ddd");
|
||||
typecheck(&var, Erv);
|
||||
|
||||
// assign the fields to the struct.
|
||||
// use the init list so that reorder1 doesn't reorder
|
||||
@ -1927,166 +1879,11 @@ bad:
|
||||
return T;
|
||||
}
|
||||
|
||||
/*
|
||||
* assigning src to dst involving interfaces?
|
||||
* return op to use.
|
||||
*/
|
||||
int
|
||||
ifaceas1(Type *dst, Type *src, int explicit)
|
||||
{
|
||||
if(src == T || dst == T)
|
||||
return Inone;
|
||||
|
||||
if(explicit && !isinter(src))
|
||||
yyerror("cannot use .(T) on non-interface type %T", src);
|
||||
|
||||
if(isinter(dst)) {
|
||||
if(isinter(src)) {
|
||||
if(isnilinter(dst)) {
|
||||
if(isnilinter(src))
|
||||
return E2Esame;
|
||||
return I2E;
|
||||
}
|
||||
if(eqtype(dst, src))
|
||||
return I2Isame;
|
||||
ifacecheck(dst, src, lineno, explicit);
|
||||
if(isnilinter(src))
|
||||
return E2I;
|
||||
if(explicit)
|
||||
return I2Ix;
|
||||
return I2I;
|
||||
}
|
||||
if(isnilinter(dst))
|
||||
return T2E;
|
||||
ifacecheck(dst, src, lineno, explicit);
|
||||
return T2I;
|
||||
}
|
||||
if(isinter(src)) {
|
||||
ifacecheck(dst, src, lineno, explicit);
|
||||
if(isnilinter(src))
|
||||
return E2T;
|
||||
return I2T;
|
||||
}
|
||||
return Inone;
|
||||
}
|
||||
|
||||
/*
|
||||
* treat convert T to T as noop
|
||||
*/
|
||||
int
|
||||
ifaceas(Type *dst, Type *src, int explicit)
|
||||
{
|
||||
int et;
|
||||
|
||||
et = ifaceas1(dst, src, explicit);
|
||||
if(et == I2Isame || et == E2Esame)
|
||||
et = Inone;
|
||||
return et;
|
||||
}
|
||||
|
||||
static char*
|
||||
ifacename[] =
|
||||
{
|
||||
[I2T] = "ifaceI2T",
|
||||
[I2T2] = "ifaceI2T2",
|
||||
[I2I] = "ifaceI2I",
|
||||
[I2Ix] = "ifaceI2Ix",
|
||||
[I2I2] = "ifaceI2I2",
|
||||
[I2Isame] = "ifaceI2Isame",
|
||||
[E2T] = "ifaceE2T",
|
||||
[E2T2] = "ifaceE2T2",
|
||||
[E2I] = "ifaceE2I",
|
||||
[E2I2] = "ifaceE2I2",
|
||||
[I2E] = "ifaceI2E",
|
||||
[I2E2] = "ifaceI2E2",
|
||||
[T2I] = "ifaceT2I",
|
||||
[T2E] = "ifaceT2E",
|
||||
[E2Esame] = "ifaceE2Esame",
|
||||
};
|
||||
|
||||
Node*
|
||||
ifacecvt(Type *tl, Node *n, int et, NodeList **init)
|
||||
{
|
||||
Type *tr;
|
||||
Node *r, *on;
|
||||
NodeList *args;
|
||||
|
||||
tr = n->type;
|
||||
|
||||
switch(et) {
|
||||
default:
|
||||
fatal("ifacecvt: unknown op %d\n", et);
|
||||
|
||||
case I2Isame:
|
||||
case E2Esame:
|
||||
return n;
|
||||
|
||||
case T2I:
|
||||
// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
|
||||
args = list1(typename(tl)); // sigi
|
||||
args = list(args, typename(tr)); // sigt
|
||||
args = list(args, n); // elem
|
||||
|
||||
on = syslook("ifaceT2I", 1);
|
||||
argtype(on, tr);
|
||||
argtype(on, tl);
|
||||
dowidth(on->type);
|
||||
break;
|
||||
|
||||
case I2T:
|
||||
case I2T2:
|
||||
case I2I:
|
||||
case I2Ix:
|
||||
case I2I2:
|
||||
case E2T:
|
||||
case E2T2:
|
||||
case E2I:
|
||||
case E2I2:
|
||||
// iface[IT]2[IT][2](sigt *byte, iface any) (ret any[, ok bool]);
|
||||
args = list1(typename(tl)); // sigi or sigt
|
||||
args = list(args, n); // iface
|
||||
|
||||
on = syslook(ifacename[et], 1);
|
||||
argtype(on, tr);
|
||||
argtype(on, tl);
|
||||
break;
|
||||
|
||||
case I2E:
|
||||
// TODO(rsc): Should do this in back end, without a call.
|
||||
// ifaceI2E(elem any) (ret any);
|
||||
args = list1(n); // elem
|
||||
|
||||
on = syslook("ifaceI2E", 1);
|
||||
argtype(on, tr);
|
||||
argtype(on, tl);
|
||||
break;
|
||||
|
||||
case T2E:
|
||||
// TODO(rsc): Should do this in back end for pointer case, without a call.
|
||||
// ifaceT2E(sigt *byte, elem any) (ret any);
|
||||
args = list1(typename(tr)); // sigt
|
||||
args = list(args, n); // elem
|
||||
|
||||
on = syslook("ifaceT2E", 1);
|
||||
argtype(on, tr);
|
||||
argtype(on, tl);
|
||||
break;
|
||||
}
|
||||
|
||||
dowidth(on->type);
|
||||
r = nod(OCALL, on, N);
|
||||
r->list = args;
|
||||
typecheck(&r, Erv | Efnstruct);
|
||||
walkexpr(&r, init);
|
||||
return r;
|
||||
}
|
||||
|
||||
Node*
|
||||
convas(Node *n, NodeList **init)
|
||||
{
|
||||
Node *l, *r;
|
||||
Type *lt, *rt;
|
||||
int et;
|
||||
|
||||
if(n->op != OAS)
|
||||
fatal("convas: not OAS %O", n->op);
|
||||
@ -2115,15 +1912,12 @@ convas(Node *n, NodeList **init)
|
||||
n->left->left, n->left->right, n->right);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if(eqtype(lt, rt))
|
||||
goto out;
|
||||
|
||||
et = ifaceas(lt, rt, 0);
|
||||
if(et != Inone) {
|
||||
n->right = ifacecvt(lt, r, et, init);
|
||||
goto out;
|
||||
}
|
||||
|
||||
n->right = assignconv(r, lt, "assignment");
|
||||
walkexpr(&n->right, init);
|
||||
|
||||
out:
|
||||
ullmancalc(n);
|
||||
@ -2292,24 +2086,6 @@ reorder3(NodeList *all)
|
||||
return concat(all, r);
|
||||
}
|
||||
|
||||
NodeList*
|
||||
reorder4(NodeList *ll)
|
||||
{
|
||||
/*
|
||||
* from ascompat[te]
|
||||
* return c,d
|
||||
* return expression assigned to output
|
||||
* parameters. there may be no problems.
|
||||
*
|
||||
* TODO(rsc): i don't believe that.
|
||||
* func f() (a, b int) {
|
||||
* a, b = 1, 2;
|
||||
* return b, a;
|
||||
* }
|
||||
*/
|
||||
return ll;
|
||||
}
|
||||
|
||||
/*
|
||||
* walk through argin parameters.
|
||||
* generate and return code to allocate
|
||||
|
67
src/pkg/math/fltasm_amd64.s
Normal file
67
src/pkg/math/fltasm_amd64.s
Normal 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
|
@ -177,26 +177,26 @@ copyout(Type *t, void **src, void *dst)
|
||||
algarray[alg].copy(wid, dst, *src);
|
||||
}
|
||||
|
||||
// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret Iface);
|
||||
// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceT2I(InterfaceType *inter, Type *t, ...)
|
||||
·convT2I(Type *t, InterfaceType *inter, ...)
|
||||
{
|
||||
byte *elem;
|
||||
Iface *ret;
|
||||
int32 wid;
|
||||
|
||||
elem = (byte*)(&t+1);
|
||||
elem = (byte*)(&inter+1);
|
||||
wid = t->size;
|
||||
ret = (Iface*)(elem + rnd(wid, Structrnd));
|
||||
ret->tab = itab(inter, t, 0);
|
||||
copyin(t, elem, &ret->data);
|
||||
}
|
||||
|
||||
// ifaceT2E(sigt *byte, elem any) (ret Eface);
|
||||
// func convT2E(typ *byte, elem any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceT2E(Type *t, ...)
|
||||
·convT2E(Type *t, ...)
|
||||
{
|
||||
byte *elem;
|
||||
Eface *ret;
|
||||
@ -205,15 +205,14 @@ void
|
||||
elem = (byte*)(&t+1);
|
||||
wid = t->size;
|
||||
ret = (Eface*)(elem + rnd(wid, Structrnd));
|
||||
|
||||
ret->type = t;
|
||||
copyin(t, elem, &ret->data);
|
||||
}
|
||||
|
||||
// ifaceI2T(sigt *byte, iface any) (ret any);
|
||||
// func ifaceI2T(typ *byte, iface any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceI2T(Type *t, Iface i, ...)
|
||||
·assertI2T(Type *t, Iface i, ...)
|
||||
{
|
||||
Itab *tab;
|
||||
byte *ret;
|
||||
@ -236,10 +235,10 @@ void
|
||||
copyout(t, &i.data, ret);
|
||||
}
|
||||
|
||||
// ifaceI2T2(sigt *byte, i Iface) (ret any, ok bool);
|
||||
// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceI2T2(Type *t, Iface i, ...)
|
||||
·assertI2T2(Type *t, Iface i, ...)
|
||||
{
|
||||
byte *ret;
|
||||
bool *ok;
|
||||
@ -259,10 +258,10 @@ void
|
||||
copyout(t, &i.data, ret);
|
||||
}
|
||||
|
||||
// ifaceE2T(sigt *byte, e Eface) (ret any);
|
||||
// func ifaceE2T(typ *byte, iface any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceE2T(Type *t, Eface e, ...)
|
||||
·assertE2T(Type *t, Eface e, ...)
|
||||
{
|
||||
byte *ret;
|
||||
Eface err;
|
||||
@ -284,10 +283,10 @@ void
|
||||
copyout(t, &e.data, ret);
|
||||
}
|
||||
|
||||
// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
|
||||
// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceE2T2(Type *t, Eface e, ...)
|
||||
·assertE2T2(Type *t, Eface e, ...)
|
||||
{
|
||||
byte *ret;
|
||||
bool *ok;
|
||||
@ -307,50 +306,25 @@ void
|
||||
copyout(t, &e.data, ret);
|
||||
}
|
||||
|
||||
// ifaceI2E(sigi *byte, iface any) (ret any);
|
||||
// TODO(rsc): Move to back end, throw away function.
|
||||
// func convI2E(elem any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceI2E(Iface i, Eface ret)
|
||||
·convI2E(Iface i, Eface ret)
|
||||
{
|
||||
Itab *tab;
|
||||
|
||||
ret.data = i.data;
|
||||
tab = i.tab;
|
||||
if(tab == nil)
|
||||
if((tab = i.tab) == nil)
|
||||
ret.type = nil;
|
||||
else
|
||||
ret.type = tab->type;
|
||||
FLUSH(&ret);
|
||||
}
|
||||
|
||||
// ifaceI2I(sigi *byte, iface any) (ret any);
|
||||
// called only for implicit (no type assertion) conversions.
|
||||
// converting nil is okay.
|
||||
// func ifaceI2E(typ *byte, iface any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceI2I(InterfaceType *inter, Iface i, Iface ret)
|
||||
{
|
||||
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)
|
||||
·assertI2E(InterfaceType* inter, Iface i, Eface ret)
|
||||
{
|
||||
Itab *tab;
|
||||
Eface err;
|
||||
@ -362,45 +336,97 @@ void
|
||||
nil, nil, inter->string,
|
||||
nil, &err);
|
||||
·panic(err);
|
||||
} else {
|
||||
ret = i;
|
||||
if(tab->inter != inter)
|
||||
ret.tab = itab(inter, tab->type, 0);
|
||||
}
|
||||
|
||||
ret.data = i.data;
|
||||
ret.type = tab->type;
|
||||
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
|
||||
·ifaceI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
|
||||
·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
|
||||
{
|
||||
Itab *tab;
|
||||
|
||||
USED(inter);
|
||||
tab = i.tab;
|
||||
if(tab == nil) {
|
||||
// If incoming interface is nil, the conversion fails.
|
||||
ret.tab = nil;
|
||||
ret.data = nil;
|
||||
ok = false;
|
||||
ret.type = nil;
|
||||
ok = 0;
|
||||
} else {
|
||||
ret = i;
|
||||
ok = true;
|
||||
if(tab->inter != inter) {
|
||||
ret.tab = itab(inter, tab->type, 1);
|
||||
if(ret.tab == nil) {
|
||||
ret.data = nil;
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
ret.type = tab->type;
|
||||
ok = 1;
|
||||
}
|
||||
ret.data = i.data;
|
||||
FLUSH(&ret);
|
||||
FLUSH(&ok);
|
||||
}
|
||||
|
||||
// func convI2I(typ *byte, elem any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·convI2I(InterfaceType* inter, Iface i, Iface ret)
|
||||
{
|
||||
Itab *tab;
|
||||
|
||||
ret.data = i.data;
|
||||
if((tab = i.tab) == nil)
|
||||
ret.tab = nil;
|
||||
else if(tab->inter == inter)
|
||||
ret.tab = tab;
|
||||
else
|
||||
ret.tab = itab(inter, tab->type, 0);
|
||||
FLUSH(&ret);
|
||||
}
|
||||
|
||||
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(&ok);
|
||||
}
|
||||
|
||||
// ifaceE2I(sigi *byte, iface any) (ret any);
|
||||
// Called only for explicit conversions (with type assertion).
|
||||
void
|
||||
ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
|
||||
{
|
||||
@ -414,45 +440,71 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
|
||||
nil, nil, inter->string,
|
||||
nil, &err);
|
||||
·panic(err);
|
||||
} else {
|
||||
ret->data = e.data;
|
||||
ret->tab = itab(inter, t, 0);
|
||||
}
|
||||
ret->data = e.data;
|
||||
ret->tab = itab(inter, t, 0);
|
||||
}
|
||||
|
||||
// ifaceE2I(sigi *byte, iface any) (ret any);
|
||||
// Called only for explicit conversions (with type assertion).
|
||||
// func ifaceE2I(sigi *byte, iface any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceE2I(InterfaceType *inter, Eface e, Iface ret)
|
||||
·assertE2I(InterfaceType* inter, Eface e, Iface ret)
|
||||
{
|
||||
ifaceE2I(inter, e, &ret);
|
||||
}
|
||||
|
||||
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
|
||||
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·ifaceE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
|
||||
·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
|
||||
{
|
||||
Type *t;
|
||||
|
||||
t = e.type;
|
||||
ok = true;
|
||||
if(t == nil) {
|
||||
// If incoming interface is nil, the conversion fails.
|
||||
if(e.type == nil) {
|
||||
ok = 0;
|
||||
ret.data = nil;
|
||||
ret.tab = nil;
|
||||
ok = false;
|
||||
} else if((ret.tab = itab(inter, e.type, 1)) == nil) {
|
||||
ok = 0;
|
||||
ret.data = nil;
|
||||
} else {
|
||||
ok = 1;
|
||||
ret.data = e.data;
|
||||
ret.tab = itab(inter, t, 1);
|
||||
if(ret.tab == nil) {
|
||||
ret.data = nil;
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
FLUSH(&ret);
|
||||
FLUSH(&ok);
|
||||
}
|
||||
|
||||
// func ifaceE2E(typ *byte, iface any) (ret any)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·assertE2E(InterfaceType* inter, Eface e, Eface ret)
|
||||
{
|
||||
Type *t;
|
||||
Eface err;
|
||||
|
||||
t = e.type;
|
||||
if(t == nil) {
|
||||
// explicit conversions require non-nil interface value.
|
||||
·newTypeAssertionError(nil, nil, inter,
|
||||
nil, nil, inter->string,
|
||||
nil, &err);
|
||||
·panic(err);
|
||||
}
|
||||
ret = e;
|
||||
FLUSH(&ret);
|
||||
}
|
||||
|
||||
// func ifaceE2E2(iface any) (ret any, ok bool)
|
||||
#pragma textflag 7
|
||||
void
|
||||
·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
|
||||
{
|
||||
USED(inter);
|
||||
ret = e;
|
||||
ok = e.type != nil;
|
||||
FLUSH(&ret);
|
||||
FLUSH(&ok);
|
||||
}
|
||||
|
||||
static uintptr
|
||||
ifacehash1(void *data, Type *t)
|
||||
{
|
||||
|
343
test/assign1.go
Normal file
343
test/assign1.go
Normal 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)
|
||||
|
||||
}
|
@ -18,8 +18,9 @@ var f2 = []int(e)
|
||||
|
||||
var g = []int(nil)
|
||||
|
||||
type H *[4]int
|
||||
type H []int
|
||||
type J []int
|
||||
|
||||
var h H
|
||||
var j1 J = h // ERROR "compat|illegal|cannot|cannot"
|
||||
var j1 J = h // ERROR "compat|illegal|cannot"
|
||||
var j2 = J(h)
|
||||
|
@ -34,14 +34,14 @@ func (t1) M(p1.T) {}
|
||||
var i0 I0 = t0(0) // ok
|
||||
var i1 I1 = t1(0) // ok
|
||||
|
||||
var i2 I0 = t1(0) // ERROR "is not|incompatible"
|
||||
var i3 I1 = t0(0) // ERROR "is not|incompatible"
|
||||
var i2 I0 = t1(0) // ERROR "does not implement|incompatible"
|
||||
var i3 I1 = t0(0) // ERROR "does not implement|incompatible"
|
||||
|
||||
var p0i p0.I = t0(0) // ok
|
||||
var p1i p1.I = t1(0) // ok
|
||||
|
||||
var p0i1 p0.I = t1(0) // ERROR "is not|incompatible"
|
||||
var p0i2 p1.I = t0(0) // ERROR "is not|incompatible"
|
||||
var p0i1 p0.I = t1(0) // ERROR "does not implement|incompatible"
|
||||
var p0i2 p1.I = t0(0) // ERROR "does not implement|incompatible"
|
||||
|
||||
func main() {
|
||||
// check that cannot assign one to the other,
|
||||
@ -52,14 +52,14 @@ func main() {
|
||||
v0 = p0.T(v1)
|
||||
v1 = p1.T(v0)
|
||||
|
||||
i0 = i1 // ERROR "need type assertion|incompatible"
|
||||
i1 = i0 // ERROR "need type assertion|incompatible"
|
||||
p0i = i1 // ERROR "need type assertion|incompatible"
|
||||
p1i = i0 // ERROR "need type assertion|incompatible"
|
||||
i0 = p1i // ERROR "need type assertion|incompatible"
|
||||
i1 = p0i // ERROR "need type assertion|incompatible"
|
||||
p0i = p1i // ERROR "need type assertion|incompatible"
|
||||
p1i = p0i // ERROR "need type assertion|incompatible"
|
||||
i0 = i1 // ERROR "cannot use|incompatible"
|
||||
i1 = i0 // ERROR "cannot use|incompatible"
|
||||
p0i = i1 // ERROR "cannot use|incompatible"
|
||||
p1i = i0 // ERROR "cannot use|incompatible"
|
||||
i0 = p1i // ERROR "cannot use|incompatible"
|
||||
i1 = p0i // ERROR "cannot use|incompatible"
|
||||
p0i = p1i // ERROR "cannot use|incompatible"
|
||||
p1i = p0i // ERROR "cannot use|incompatible"
|
||||
|
||||
i0 = p0i
|
||||
p0i = i0
|
||||
|
@ -12,10 +12,10 @@ type I1 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 i2a I2 = i1
|
||||
|
@ -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.
|
||||
// Use of this source code is governed by a BSD-style
|
@ -180,58 +180,3 @@ BUG: bug260 failed
|
||||
|
||||
=========== bugs/bug274.go
|
||||
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
|
||||
|
@ -8,34 +8,45 @@
|
||||
|
||||
package main
|
||||
|
||||
type T struct { a int }
|
||||
type T struct {
|
||||
a int
|
||||
}
|
||||
|
||||
var t *T
|
||||
|
||||
type I interface { M() }
|
||||
type I interface {
|
||||
M()
|
||||
}
|
||||
|
||||
var i I
|
||||
|
||||
type I2 interface { M(); N(); }
|
||||
type I2 interface {
|
||||
M()
|
||||
N()
|
||||
}
|
||||
|
||||
var i2 I2
|
||||
|
||||
type E interface { }
|
||||
type E interface{}
|
||||
|
||||
var e E
|
||||
|
||||
func main() {
|
||||
e = t; // ok
|
||||
t = e; // ERROR "need explicit|need type assertion"
|
||||
e = t // ok
|
||||
t = e // ERROR "need explicit|need type assertion"
|
||||
|
||||
// neither of these can work,
|
||||
// because i has an extra method
|
||||
// that t does not, so i cannot contain a t.
|
||||
i = t; // ERROR "missing|incompatible|is not"
|
||||
t = i; // ERROR "missing|incompatible|is not"
|
||||
i = t // ERROR "incompatible|missing M method"
|
||||
t = i // ERROR "incompatible|need type assertion"
|
||||
|
||||
i = i2; // ok
|
||||
i2 = i; // ERROR "need explicit|need type assertion"
|
||||
|
||||
i = I(i2); // ok
|
||||
i2 = I2(i); // ERROR "need explicit|need type assertion"
|
||||
i = i2 // ok
|
||||
i2 = i // ERROR "missing N method"
|
||||
|
||||
e = E(t); // ok
|
||||
t = T(e); // ERROR "need explicit|need type assertion|incompatible"
|
||||
i = I(i2) // ok
|
||||
i2 = I2(i) // ERROR "missing N method"
|
||||
|
||||
e = E(t) // ok
|
||||
t = T(e) // ERROR "need explicit|need type assertion|incompatible"
|
||||
}
|
||||
|
@ -9,28 +9,28 @@
|
||||
package main
|
||||
|
||||
type Inst interface {
|
||||
Next() *Inst;
|
||||
Next() *Inst
|
||||
}
|
||||
|
||||
type Regexp struct {
|
||||
code []Inst;
|
||||
start Inst;
|
||||
code []Inst
|
||||
start Inst
|
||||
}
|
||||
|
||||
type Start struct {
|
||||
foo *Inst;
|
||||
foo *Inst
|
||||
}
|
||||
|
||||
func (start *Start) Next() *Inst { return nil }
|
||||
|
||||
|
||||
func AddInst(Inst) *Inst {
|
||||
print("ok in addinst\n");
|
||||
print("ok in addinst\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
print("call addinst\n");
|
||||
var x Inst = AddInst(new(Start)); // ERROR "illegal|incompatible|is not"
|
||||
print("return from addinst\n");
|
||||
print("call addinst\n")
|
||||
var x Inst = AddInst(new(Start)) // ERROR "pointer to interface"
|
||||
print("return from addinst\n")
|
||||
}
|
||||
|
@ -9,41 +9,50 @@
|
||||
package main
|
||||
|
||||
type T int
|
||||
|
||||
func (t T) V()
|
||||
func (t *T) P()
|
||||
|
||||
type V interface { V() }
|
||||
type P interface { P(); V() }
|
||||
|
||||
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 "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 V interface {
|
||||
V()
|
||||
}
|
||||
type P interface {
|
||||
P()
|
||||
V()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
474
test/named.go
474
test/named.go
@ -20,13 +20,13 @@ type String string
|
||||
|
||||
// Calling these functions checks at compile time that the argument
|
||||
// can be converted implicitly to (used as) the given type.
|
||||
func asArray(Array) {}
|
||||
func asBool(Bool) {}
|
||||
func asChan(Chan) {}
|
||||
func asFloat(Float) {}
|
||||
func asInt(Int) {}
|
||||
func asMap(Map) {}
|
||||
func asSlice(Slice) {}
|
||||
func asArray(Array) {}
|
||||
func asBool(Bool) {}
|
||||
func asChan(Chan) {}
|
||||
func asFloat(Float) {}
|
||||
func asInt(Int) {}
|
||||
func asMap(Map) {}
|
||||
func asSlice(Slice) {}
|
||||
func asString(String) {}
|
||||
|
||||
func (Map) M() {}
|
||||
@ -35,247 +35,247 @@ func (Map) M() {}
|
||||
// These functions check at run time that the default type
|
||||
// (in the absence of any implicit conversion hints)
|
||||
// is the given type.
|
||||
func isArray(x interface{}) { _ = x.(Array) }
|
||||
func isBool(x interface{}) { _ = x.(Bool) }
|
||||
func isChan(x interface{}) { _ = x.(Chan) }
|
||||
func isFloat(x interface{}) { _ = x.(Float) }
|
||||
func isInt(x interface{}) { _ = x.(Int) }
|
||||
func isMap(x interface{}) { _ = x.(Map) }
|
||||
func isSlice(x interface{}) { _ = x.(Slice) }
|
||||
func isArray(x interface{}) { _ = x.(Array) }
|
||||
func isBool(x interface{}) { _ = x.(Bool) }
|
||||
func isChan(x interface{}) { _ = x.(Chan) }
|
||||
func isFloat(x interface{}) { _ = x.(Float) }
|
||||
func isInt(x interface{}) { _ = x.(Int) }
|
||||
func isMap(x interface{}) { _ = x.(Map) }
|
||||
func isSlice(x interface{}) { _ = x.(Slice) }
|
||||
func isString(x interface{}) { _ = x.(String) }
|
||||
|
||||
func main() {
|
||||
var (
|
||||
a Array;
|
||||
b Bool = true;
|
||||
c Chan = make(Chan);
|
||||
f Float = 1;
|
||||
i Int = 1;
|
||||
m Map = make(Map);
|
||||
slice Slice = make(Slice, 10);
|
||||
str String = "hello";
|
||||
a Array
|
||||
b Bool = true
|
||||
c Chan = make(Chan)
|
||||
f Float = 1
|
||||
i Int = 1
|
||||
m Map = make(Map)
|
||||
slice Slice = make(Slice, 10)
|
||||
str String = "hello"
|
||||
)
|
||||
|
||||
asArray(a);
|
||||
isArray(a);
|
||||
asArray(*&a);
|
||||
isArray(*&a);
|
||||
asArray(Array{});
|
||||
isArray(Array{});
|
||||
asArray(a)
|
||||
isArray(a)
|
||||
asArray(*&a)
|
||||
isArray(*&a)
|
||||
asArray(Array{})
|
||||
isArray(Array{})
|
||||
|
||||
asBool(b);
|
||||
isBool(b);
|
||||
asBool(!b);
|
||||
isBool(!b);
|
||||
asBool(true);
|
||||
asBool(*&b);
|
||||
isBool(*&b);
|
||||
asBool(Bool(true));
|
||||
isBool(Bool(true));
|
||||
asBool(b)
|
||||
isBool(b)
|
||||
asBool(!b)
|
||||
isBool(!b)
|
||||
asBool(true)
|
||||
asBool(*&b)
|
||||
isBool(*&b)
|
||||
asBool(Bool(true))
|
||||
isBool(Bool(true))
|
||||
|
||||
asChan(c);
|
||||
isChan(c);
|
||||
asChan(make(Chan));
|
||||
isChan(make(Chan));
|
||||
asChan(*&c);
|
||||
isChan(*&c);
|
||||
asChan(Chan(nil));
|
||||
isChan(Chan(nil));
|
||||
asChan(c)
|
||||
isChan(c)
|
||||
asChan(make(Chan))
|
||||
isChan(make(Chan))
|
||||
asChan(*&c)
|
||||
isChan(*&c)
|
||||
asChan(Chan(nil))
|
||||
isChan(Chan(nil))
|
||||
|
||||
asFloat(f);
|
||||
isFloat(f);
|
||||
asFloat(-f);
|
||||
isFloat(-f);
|
||||
asFloat(+f);
|
||||
isFloat(+f);
|
||||
asFloat(f+1);
|
||||
isFloat(f+1);
|
||||
asFloat(1+f);
|
||||
isFloat(1+f);
|
||||
asFloat(f+f);
|
||||
isFloat(f+f);
|
||||
f++;
|
||||
f+=2;
|
||||
asFloat(f-1);
|
||||
isFloat(f-1);
|
||||
asFloat(1-f);
|
||||
isFloat(1-f);
|
||||
asFloat(f-f);
|
||||
isFloat(f-f);
|
||||
f--;
|
||||
f-=2;
|
||||
asFloat(f*2.5);
|
||||
isFloat(f*2.5);
|
||||
asFloat(2.5*f);
|
||||
isFloat(2.5*f);
|
||||
asFloat(f*f);
|
||||
isFloat(f*f);
|
||||
f*=4;
|
||||
asFloat(f/2.5);
|
||||
isFloat(f/2.5);
|
||||
asFloat(2.5/f);
|
||||
isFloat(2.5/f);
|
||||
asFloat(f/f);
|
||||
isFloat(f/f);
|
||||
f/=4;
|
||||
asFloat(f);
|
||||
isFloat(f);
|
||||
f = 5;
|
||||
asFloat(*&f);
|
||||
isFloat(*&f);
|
||||
asFloat(234);
|
||||
asFloat(Float(234));
|
||||
isFloat(Float(234));
|
||||
asFloat(1.2);
|
||||
asFloat(Float(i));
|
||||
isFloat(Float(i));
|
||||
asFloat(f)
|
||||
isFloat(f)
|
||||
asFloat(-f)
|
||||
isFloat(-f)
|
||||
asFloat(+f)
|
||||
isFloat(+f)
|
||||
asFloat(f + 1)
|
||||
isFloat(f + 1)
|
||||
asFloat(1 + f)
|
||||
isFloat(1 + f)
|
||||
asFloat(f + f)
|
||||
isFloat(f + f)
|
||||
f++
|
||||
f += 2
|
||||
asFloat(f - 1)
|
||||
isFloat(f - 1)
|
||||
asFloat(1 - f)
|
||||
isFloat(1 - f)
|
||||
asFloat(f - f)
|
||||
isFloat(f - f)
|
||||
f--
|
||||
f -= 2
|
||||
asFloat(f * 2.5)
|
||||
isFloat(f * 2.5)
|
||||
asFloat(2.5 * f)
|
||||
isFloat(2.5 * f)
|
||||
asFloat(f * f)
|
||||
isFloat(f * f)
|
||||
f *= 4
|
||||
asFloat(f / 2.5)
|
||||
isFloat(f / 2.5)
|
||||
asFloat(2.5 / f)
|
||||
isFloat(2.5 / f)
|
||||
asFloat(f / f)
|
||||
isFloat(f / f)
|
||||
f /= 4
|
||||
asFloat(f)
|
||||
isFloat(f)
|
||||
f = 5
|
||||
asFloat(*&f)
|
||||
isFloat(*&f)
|
||||
asFloat(234)
|
||||
asFloat(Float(234))
|
||||
isFloat(Float(234))
|
||||
asFloat(1.2)
|
||||
asFloat(Float(i))
|
||||
isFloat(Float(i))
|
||||
|
||||
asInt(i);
|
||||
isInt(i);
|
||||
asInt(-i);
|
||||
isInt(-i);
|
||||
asInt(^i);
|
||||
isInt(^i);
|
||||
asInt(+i);
|
||||
isInt(+i);
|
||||
asInt(i+1);
|
||||
isInt(i+1);
|
||||
asInt(1+i);
|
||||
isInt(1+i);
|
||||
asInt(i+i);
|
||||
isInt(i+i);
|
||||
i++;
|
||||
i+=1;
|
||||
asInt(i-1);
|
||||
isInt(i-1);
|
||||
asInt(1-i);
|
||||
isInt(1-i);
|
||||
asInt(i-i);
|
||||
isInt(i-i);
|
||||
i--;
|
||||
i-=1;
|
||||
asInt(i*2);
|
||||
isInt(i*2);
|
||||
asInt(2*i);
|
||||
isInt(2*i);
|
||||
asInt(i*i);
|
||||
isInt(i*i);
|
||||
i*=2;
|
||||
asInt(i/5);
|
||||
isInt(i/5);
|
||||
asInt(5/i);
|
||||
isInt(5/i);
|
||||
asInt(i/i);
|
||||
isInt(i/i);
|
||||
i/=2;
|
||||
asInt(i%5);
|
||||
isInt(i%5);
|
||||
asInt(5%i);
|
||||
isInt(5%i);
|
||||
asInt(i%i);
|
||||
isInt(i%i);
|
||||
i%=2;
|
||||
asInt(i&5);
|
||||
isInt(i&5);
|
||||
asInt(5&i);
|
||||
isInt(5&i);
|
||||
asInt(i&i);
|
||||
isInt(i&i);
|
||||
i&=2;
|
||||
asInt(i&^5);
|
||||
isInt(i&^5);
|
||||
asInt(5&^i);
|
||||
isInt(5&^i);
|
||||
asInt(i&^i);
|
||||
isInt(i&^i);
|
||||
i&^=2;
|
||||
asInt(i|5);
|
||||
isInt(i|5);
|
||||
asInt(5|i);
|
||||
isInt(5|i);
|
||||
asInt(i|i);
|
||||
isInt(i|i);
|
||||
i|=2;
|
||||
asInt(i^5);
|
||||
isInt(i^5);
|
||||
asInt(5^i);
|
||||
isInt(5^i);
|
||||
asInt(i^i);
|
||||
isInt(i^i);
|
||||
i^=2;
|
||||
asInt(i<<4);
|
||||
isInt(i<<4);
|
||||
i<<=2;
|
||||
asInt(i>>4);
|
||||
isInt(i>>4);
|
||||
i>>=2;
|
||||
asInt(i);
|
||||
isInt(i);
|
||||
asInt(0);
|
||||
asInt(Int(0));
|
||||
isInt(Int(0));
|
||||
i = 10;
|
||||
asInt(*&i);
|
||||
isInt(*&i);
|
||||
asInt(23);
|
||||
asInt(Int(f));
|
||||
isInt(Int(f));
|
||||
asInt(i)
|
||||
isInt(i)
|
||||
asInt(-i)
|
||||
isInt(-i)
|
||||
asInt(^i)
|
||||
isInt(^i)
|
||||
asInt(+i)
|
||||
isInt(+i)
|
||||
asInt(i + 1)
|
||||
isInt(i + 1)
|
||||
asInt(1 + i)
|
||||
isInt(1 + i)
|
||||
asInt(i + i)
|
||||
isInt(i + i)
|
||||
i++
|
||||
i += 1
|
||||
asInt(i - 1)
|
||||
isInt(i - 1)
|
||||
asInt(1 - i)
|
||||
isInt(1 - i)
|
||||
asInt(i - i)
|
||||
isInt(i - i)
|
||||
i--
|
||||
i -= 1
|
||||
asInt(i * 2)
|
||||
isInt(i * 2)
|
||||
asInt(2 * i)
|
||||
isInt(2 * i)
|
||||
asInt(i * i)
|
||||
isInt(i * i)
|
||||
i *= 2
|
||||
asInt(i / 5)
|
||||
isInt(i / 5)
|
||||
asInt(5 / i)
|
||||
isInt(5 / i)
|
||||
asInt(i / i)
|
||||
isInt(i / i)
|
||||
i /= 2
|
||||
asInt(i % 5)
|
||||
isInt(i % 5)
|
||||
asInt(5 % i)
|
||||
isInt(5 % i)
|
||||
asInt(i % i)
|
||||
isInt(i % i)
|
||||
i %= 2
|
||||
asInt(i & 5)
|
||||
isInt(i & 5)
|
||||
asInt(5 & i)
|
||||
isInt(5 & i)
|
||||
asInt(i & i)
|
||||
isInt(i & i)
|
||||
i &= 2
|
||||
asInt(i &^ 5)
|
||||
isInt(i &^ 5)
|
||||
asInt(5 &^ i)
|
||||
isInt(5 &^ i)
|
||||
asInt(i &^ i)
|
||||
isInt(i &^ i)
|
||||
i &^= 2
|
||||
asInt(i | 5)
|
||||
isInt(i | 5)
|
||||
asInt(5 | i)
|
||||
isInt(5 | i)
|
||||
asInt(i | i)
|
||||
isInt(i | i)
|
||||
i |= 2
|
||||
asInt(i ^ 5)
|
||||
isInt(i ^ 5)
|
||||
asInt(5 ^ i)
|
||||
isInt(5 ^ i)
|
||||
asInt(i ^ i)
|
||||
isInt(i ^ i)
|
||||
i ^= 2
|
||||
asInt(i << 4)
|
||||
isInt(i << 4)
|
||||
i <<= 2
|
||||
asInt(i >> 4)
|
||||
isInt(i >> 4)
|
||||
i >>= 2
|
||||
asInt(i)
|
||||
isInt(i)
|
||||
asInt(0)
|
||||
asInt(Int(0))
|
||||
isInt(Int(0))
|
||||
i = 10
|
||||
asInt(*&i)
|
||||
isInt(*&i)
|
||||
asInt(23)
|
||||
asInt(Int(f))
|
||||
isInt(Int(f))
|
||||
|
||||
asMap(m);
|
||||
isMap(m);
|
||||
asMap(nil);
|
||||
m = nil;
|
||||
asMap(make(Map));
|
||||
isMap(make(Map));
|
||||
asMap(*&m);
|
||||
isMap(*&m);
|
||||
asMap(Map(nil));
|
||||
isMap(Map(nil));
|
||||
asMap(Map{});
|
||||
isMap(Map{});
|
||||
asMap(m)
|
||||
isMap(m)
|
||||
asMap(nil)
|
||||
m = nil
|
||||
asMap(make(Map))
|
||||
isMap(make(Map))
|
||||
asMap(*&m)
|
||||
isMap(*&m)
|
||||
asMap(Map(nil))
|
||||
isMap(Map(nil))
|
||||
asMap(Map{})
|
||||
isMap(Map{})
|
||||
|
||||
asSlice(slice);
|
||||
isSlice(slice);
|
||||
asSlice(make(Slice, 5));
|
||||
isSlice(make(Slice, 5));
|
||||
asSlice([]byte{1,2,3});
|
||||
asSlice([]byte{1,2,3}[0:2]);
|
||||
asSlice(slice[0:4]);
|
||||
isSlice(slice[0:4]);
|
||||
asSlice(slice[3:8]);
|
||||
isSlice(slice[3:8]);
|
||||
asSlice(nil);
|
||||
asSlice(Slice(nil));
|
||||
isSlice(Slice(nil));
|
||||
slice = nil;
|
||||
asSlice(Slice{1,2,3});
|
||||
isSlice(Slice{1,2,3});
|
||||
asSlice(Slice{});
|
||||
isSlice(Slice{});
|
||||
asSlice(*&slice);
|
||||
isSlice(*&slice);
|
||||
asSlice(slice)
|
||||
isSlice(slice)
|
||||
asSlice(make(Slice, 5))
|
||||
isSlice(make(Slice, 5))
|
||||
asSlice([]byte{1, 2, 3})
|
||||
asSlice([]byte{1, 2, 3}[0:2])
|
||||
asSlice(slice[0:4])
|
||||
isSlice(slice[0:4])
|
||||
asSlice(slice[3:8])
|
||||
isSlice(slice[3:8])
|
||||
asSlice(nil)
|
||||
asSlice(Slice(nil))
|
||||
isSlice(Slice(nil))
|
||||
slice = nil
|
||||
asSlice(Slice{1, 2, 3})
|
||||
isSlice(Slice{1, 2, 3})
|
||||
asSlice(Slice{})
|
||||
isSlice(Slice{})
|
||||
asSlice(*&slice)
|
||||
isSlice(*&slice)
|
||||
|
||||
asString(str);
|
||||
isString(str);
|
||||
asString(str+"a");
|
||||
isString(str+"a");
|
||||
asString("a"+str);
|
||||
isString("a"+str);
|
||||
asString(str+str);
|
||||
isString(str+str);
|
||||
str += "a";
|
||||
str += str;
|
||||
asString(String('a'));
|
||||
isString(String('a'));
|
||||
asString(String(slice));
|
||||
isString(String(slice));
|
||||
asString(String([]byte(nil)));
|
||||
isString(String([]byte(nil)));
|
||||
asString("hello");
|
||||
asString(String("hello"));
|
||||
isString(String("hello"));
|
||||
str = "hello";
|
||||
isString(str);
|
||||
asString(*&str);
|
||||
isString(*&str);
|
||||
asString(str)
|
||||
isString(str)
|
||||
asString(str + "a")
|
||||
isString(str + "a")
|
||||
asString("a" + str)
|
||||
isString("a" + str)
|
||||
asString(str + str)
|
||||
isString(str + str)
|
||||
str += "a"
|
||||
str += str
|
||||
asString(String('a'))
|
||||
isString(String('a'))
|
||||
asString(String([]byte(slice)))
|
||||
isString(String([]byte(slice)))
|
||||
asString(String([]byte(nil)))
|
||||
isString(String([]byte(nil)))
|
||||
asString("hello")
|
||||
asString(String("hello"))
|
||||
isString(String("hello"))
|
||||
str = "hello"
|
||||
isString(str)
|
||||
asString(*&str)
|
||||
isString(*&str)
|
||||
}
|
||||
|
@ -12,46 +12,57 @@ package main
|
||||
type Bool bool
|
||||
|
||||
type Map map[int]int
|
||||
|
||||
func (Map) M() {}
|
||||
|
||||
func asBool(Bool) {}
|
||||
type Slice []byte
|
||||
|
||||
var slice Slice
|
||||
|
||||
func asBool(Bool) {}
|
||||
func asString(String) {}
|
||||
|
||||
type String string
|
||||
|
||||
func main() {
|
||||
var (
|
||||
b Bool = true;
|
||||
i, j int;
|
||||
c = make(chan int);
|
||||
m = make(Map);
|
||||
b Bool = true
|
||||
i, j int
|
||||
c = make(chan int)
|
||||
m = make(Map)
|
||||
)
|
||||
|
||||
asBool(b);
|
||||
asBool(!b);
|
||||
asBool(true);
|
||||
asBool(*&b);
|
||||
asBool(Bool(true));
|
||||
asBool(1!=2); // ERROR "cannot use.*type bool.*as type Bool"
|
||||
asBool(i < j); // ERROR "cannot use.*type bool.*as type Bool"
|
||||
asBool(b)
|
||||
asBool(!b)
|
||||
asBool(true)
|
||||
asBool(*&b)
|
||||
asBool(Bool(true))
|
||||
asBool(1 != 2) // 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"
|
||||
m[2] = 1, b; // ERROR "cannot use.*type Bool.*as type bool"
|
||||
_, b = m[2] // ERROR "cannot .* bool.*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;
|
||||
asBool(c<-1); // ERROR "cannot use.*type bool.*as type Bool"
|
||||
b = c <- 1 // ERROR "cannot use.*type bool.*type Bool"
|
||||
_ = b
|
||||
asBool(c <- 1) // ERROR "cannot use.*type bool.*as type Bool"
|
||||
|
||||
_, b = <-c; // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b;
|
||||
_, b = <-c // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b
|
||||
|
||||
var inter interface{};
|
||||
_, b = inter.(Map); // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b;
|
||||
var inter interface{}
|
||||
_, b = inter.(Map) // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b
|
||||
|
||||
var minter interface{M()};
|
||||
_, b = minter.(Map); // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b;
|
||||
var minter interface {
|
||||
M()
|
||||
}
|
||||
_, b = minter.(Map) // ERROR "cannot .* bool.*type Bool"
|
||||
_ = b
|
||||
|
||||
asBool(closed(c)); // ERROR "cannot use.*type bool.*as type Bool"
|
||||
b = closed(c); // ERROR "cannot use.*type bool.*type Bool"
|
||||
_ = b;
|
||||
asBool(closed(c)) // ERROR "cannot use.*type bool.*as type Bool"
|
||||
b = closed(c) // ERROR "cannot use.*type bool.*type Bool"
|
||||
_ = b
|
||||
|
||||
asString(String(slice)) // ERROR "cannot convert slice"
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user