summaryrefslogtreecommitdiff
path: root/src/cmd/gc/typecheck.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/typecheck.c')
-rw-r--r--src/cmd/gc/typecheck.c255
1 files changed, 204 insertions, 51 deletions
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 31a2f2c5c..c50b2285b 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -310,7 +310,7 @@ typecheck1(Node **np, int top)
int ok, ntop;
Type *t, *tp, *missing, *have, *badtype;
Val v;
- char *why;
+ char *why, *desc, descbuf[64];
n = *np;
@@ -368,7 +368,7 @@ reswitch:
goto ret;
case OPACK:
- yyerror("use of package %S not in selector", n->sym);
+ yyerror("use of package %S without selector", n->sym);
goto error;
case ODDD:
@@ -535,6 +535,19 @@ reswitch:
op = n->etype;
goto arith;
+ case OADDPTR:
+ ok |= Erv;
+ l = typecheck(&n->left, Erv);
+ r = typecheck(&n->right, Erv);
+ if(l->type == T || r->type == T)
+ goto error;
+ if(l->type->etype != tptr)
+ fatal("bad OADDPTR left type %E for %N", l->type->etype, n->left);
+ if(r->type->etype != TUINTPTR)
+ fatal("bad OADDPTR right type %E for %N", r->type->etype, n->right);
+ n->type = types[tptr];
+ goto ret;
+
case OADD:
case OAND:
case OANDAND:
@@ -654,8 +667,20 @@ reswitch:
if(iscmp[n->op]) {
n->etype = n->op;
n->op = OCMPSTR;
- } else if(n->op == OADD)
+ } else if(n->op == OADD) {
+ // create OADDSTR node with list of strings in x + y + z + (w + v) + ...
n->op = OADDSTR;
+ if(l->op == OADDSTR)
+ n->list = l->list;
+ else
+ n->list = list1(l);
+ if(r->op == OADDSTR)
+ n->list = concat(n->list, r->list);
+ else
+ n->list = list(n->list, r);
+ n->left = N;
+ n->right = N;
+ }
}
if(et == TINTER) {
if(l->op == OLITERAL && l->val.ctype == CTNIL) {
@@ -721,8 +746,11 @@ reswitch:
if(n->left->type == T)
goto error;
checklvalue(n->left, "take the address of");
- for(l=n->left; l->op == ODOT; l=l->left)
+ r = outervalue(n->left);
+ for(l = n->left; l != r; l = l->left)
l->addrtaken = 1;
+ if(l->orig != l && l->op == ONAME)
+ fatal("found non-orig name node %N", l);
l->addrtaken = 1;
defaultlit(&n->left, T);
l = n->left;
@@ -864,7 +892,7 @@ reswitch:
goto error;
switch(t->etype) {
default:
- yyerror("invalid operation: %N (index of type %T)", n, t);
+ yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
goto error;
@@ -947,7 +975,7 @@ reswitch:
r = n->right;
if(r->type == T)
goto error;
- r = assignconv(r, l->type->type, "send");
+ n->right = assignconv(r, l->type->type, "send");
// TODO: more aggressive
n->etype = 0;
n->type = T;
@@ -1062,6 +1090,7 @@ reswitch:
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
+ n->diag |= n->left->diag;
l = n->left;
if(l->op == ONAME && l->etype != 0) {
if(n->isddd && l->etype != OAPPEND)
@@ -1123,7 +1152,11 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
+ if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf)
+ desc = descbuf;
+ else
+ desc = "function argument";
+ typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc);
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -1209,17 +1242,29 @@ reswitch:
case OCOMPLEX:
ok |= Erv;
- if(twoarg(n) < 0)
- goto error;
- l = typecheck(&n->left, Erv | (top & Eiota));
- r = typecheck(&n->right, Erv | (top & Eiota));
- if(l->type == T || r->type == T)
- goto error;
- defaultlit2(&l, &r, 0);
- if(l->type == T || r->type == T)
- goto error;
- n->left = l;
- n->right = r;
+ if(count(n->list) == 1) {
+ typechecklist(n->list, Efnstruct);
+ t = n->list->n->left->type;
+ if(t->outtuple != 2) {
+ yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple);
+ goto error;
+ }
+ t = n->list->n->type->type;
+ l = t->nname;
+ r = t->down->nname;
+ } else {
+ if(twoarg(n) < 0)
+ goto error;
+ l = typecheck(&n->left, Erv | (top & Eiota));
+ r = typecheck(&n->right, Erv | (top & Eiota));
+ if(l->type == T || r->type == T)
+ goto error;
+ defaultlit2(&l, &r, 0);
+ if(l->type == T || r->type == T)
+ goto error;
+ n->left = l;
+ n->right = r;
+ }
if(!eqtype(l->type, r->type)) {
yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error;
@@ -1298,9 +1343,22 @@ reswitch:
yyerror("missing arguments to append");
goto error;
}
- typechecklist(args, Erv);
+
+ if(count(args) == 1 && !n->isddd)
+ typecheck(&args->n, Erv | Efnstruct);
+ else
+ typechecklist(args, Erv);
+
if((t = args->n->type) == T)
goto error;
+
+ // Unpack multiple-return result before type-checking.
+ if(istype(t, TSTRUCT)) {
+ t = t->type;
+ if(istype(t, TFIELD))
+ t = t->type;
+ }
+
n->type = t;
if(!isslice(t)) {
if(isconst(args->n, CTNIL)) {
@@ -1355,6 +1413,8 @@ reswitch:
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
+ if(n->left->type == T || n->right->type == T)
+ goto error;
// copy([]byte, string)
if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
@@ -1406,6 +1466,9 @@ reswitch:
}
break;
case OSTRARRAYBYTE:
+ // do not use stringtoarraylit.
+ // generated code and compiler memory footprint is better without it.
+ break;
case OSTRARRAYRUNE:
if(n->left->op == OLITERAL)
stringtoarraylit(&n);
@@ -1621,6 +1684,7 @@ reswitch:
case OGOTO:
case OLABEL:
case OXFALL:
+ case OVARKILL:
ok |= Etop;
goto ret;
@@ -2116,6 +2180,31 @@ nokeys(NodeList *l)
return 1;
}
+static int
+hasddd(Type *t)
+{
+ Type *tl;
+
+ for(tl=t->type; tl; tl=tl->down) {
+ if(tl->isddd)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+downcount(Type *t)
+{
+ Type *tl;
+ int n;
+
+ n = 0;
+ for(tl=t->type; tl; tl=tl->down) {
+ n++;
+ }
+ return n;
+}
+
/*
* typecheck assignment: type list = expression list
*/
@@ -2126,14 +2215,25 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
Node *n;
int lno;
char *why;
+ int n1, n2;
lno = lineno;
if(tstruct->broke)
goto out;
+ n = N;
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
if(n->type->etype == TSTRUCT && n->type->funarg) {
+ if(!hasddd(tstruct)) {
+ n1 = downcount(tstruct);
+ n2 = downcount(n->type);
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+
tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) {
if(tl->isddd) {
@@ -2162,6 +2262,26 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *
goto out;
}
+ n1 = downcount(tstruct);
+ n2 = count(nl);
+ if(!hasddd(tstruct)) {
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+ else {
+ if(!isddd) {
+ if(n2 < n1-1)
+ goto notenough;
+ } else {
+ if(n2 > n1)
+ goto toomany;
+ if(n2 < n1)
+ goto notenough;
+ }
+ }
+
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(tl->isddd) {
@@ -2206,10 +2326,14 @@ out:
return;
notenough:
- if(call != N)
- yyerror("not enough arguments in call to %N", call);
- else
- yyerror("not enough arguments to %O", op);
+ if(n == N || !n->diag) {
+ if(call != N)
+ yyerror("not enough arguments in call to %N", call);
+ else
+ yyerror("not enough arguments to %O", op);
+ if(n != N)
+ n->diag = 1;
+ }
goto out;
toomany:
@@ -2252,10 +2376,13 @@ keydup(Node *n, Node *hash[], ulong nhash)
ulong b;
double d;
int i;
- Node *a;
+ Node *a, *orign;
Node cmp;
char *s;
+ orign = n;
+ if(n->op == OCONVIFACE)
+ n = n->left;
evconst(n);
if(n->op != OLITERAL)
return; // we dont check variables
@@ -2288,17 +2415,25 @@ keydup(Node *n, Node *hash[], ulong nhash)
for(a=hash[h]; a!=N; a=a->ntest) {
cmp.op = OEQ;
cmp.left = n;
- cmp.right = a;
- evconst(&cmp);
- b = cmp.val.u.bval;
+ b = 0;
+ if(a->op == OCONVIFACE && orign->op == OCONVIFACE) {
+ if(eqtype(a->left->type, n->type)) {
+ cmp.right = a->left;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ }
+ } else if(eqtype(a->type, n->type)) {
+ cmp.right = a;
+ evconst(&cmp);
+ b = cmp.val.u.bval;
+ }
if(b) {
- // too lazy to print the literal
yyerror("duplicate key %N in map literal", n);
return;
}
}
- n->ntest = hash[h];
- hash[h] = n;
+ orign->ntest = hash[h];
+ hash[h] = orign;
}
static void
@@ -2486,8 +2621,9 @@ typecheckcomplit(Node **np)
typecheck(&l->left, Erv);
evconst(l->left);
i = nonnegconst(l->left);
- if(i < 0) {
+ if(i < 0 && !l->left->diag) {
yyerror("array index must be non-negative integer constant");
+ l->left->diag = 1;
i = -(1<<30); // stay negative for a while
}
if(i >= 0)
@@ -2497,7 +2633,7 @@ typecheckcomplit(Node **np)
len = i;
if(t->bound >= 0 && len > t->bound) {
setlineno(l);
- yyerror("array index %d out of bounds [0:%d]", len, t->bound);
+ yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound);
t->bound = -1; // no more errors
}
}
@@ -2680,6 +2816,11 @@ checkassign(Node *n)
n->etype = 1;
return;
}
+
+ // have already complained about n being undefined
+ if(n->op == ONONAME)
+ return;
+
yyerror("cannot assign to %N", n);
}
@@ -2804,7 +2945,7 @@ typecheckas2(Node *n)
n->op = OAS2FUNC;
t = structfirst(&s, &r->type);
for(ll=n->list; ll; ll=ll->next) {
- if(ll->n->type != T)
+ if(t->type != T && ll->n->type != T)
checkassignto(t->type, ll->n);
if(ll->n->defn == n && ll->n->ntype == N)
ll->n->type = t->type;
@@ -3130,7 +3271,10 @@ typecheckdef(Node *n)
goto ret;
}
if(e->type != T && e->op != OLITERAL || !isgoconst(e)) {
- yyerror("const initializer %N is not a constant", e);
+ if(!e->diag) {
+ yyerror("const initializer %N is not a constant", e);
+ e->diag = 1;
+ }
goto ret;
}
t = n->type;
@@ -3220,29 +3364,38 @@ static int
checkmake(Type *t, char *arg, Node *n)
{
if(n->op == OLITERAL) {
- n->val = toint(n->val);
- if(mpcmpfixc(n->val.u.xval, 0) < 0) {
- yyerror("negative %s argument in make(%T)", arg, t);
- return -1;
- }
- if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
- yyerror("%s argument too large in make(%T)", arg, t);
- return -1;
+ switch(n->val.ctype) {
+ case CTINT:
+ case CTRUNE:
+ case CTFLT:
+ case CTCPLX:
+ n->val = toint(n->val);
+ if(mpcmpfixc(n->val.u.xval, 0) < 0) {
+ yyerror("negative %s argument in make(%T)", arg, t);
+ return -1;
+ }
+ if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
+ yyerror("%s argument too large in make(%T)", arg, t);
+ return -1;
+ }
+
+ // Delay defaultlit until after we've checked range, to avoid
+ // a redundant "constant NNN overflows int" error.
+ defaultlit(&n, types[TINT]);
+ return 0;
+ default:
+ break;
}
-
- // Delay defaultlit until after we've checked range, to avoid
- // a redundant "constant NNN overflows int" error.
- defaultlit(&n, types[TINT]);
- return 0;
}
-
- // Defaultlit still necessary for non-constant: n might be 1<<k.
- defaultlit(&n, types[TINT]);
- if(!isint[n->type->etype]) {
+ if(!isint[n->type->etype] && n->type->etype != TIDEAL) {
yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type);
return -1;
}
+
+ // Defaultlit still necessary for non-constant: n might be 1<<k.
+ defaultlit(&n, types[TINT]);
+
return 0;
}