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