/* * type check switch statement */ void typecheckswitch(Node *n) { int top, lno; Type *t; NodeList *l, *ll; Node *ncase, *nvar; Node *def; lno = lineno; typechecklist(n->ninit, Etop); if(n->ntest != N && n->ntest->op == OTYPESW) { // type switch top = Etype; typecheck(&n->ntest->right, Erv); t = n->ntest->right->type; if(t != T && t->etype != TINTER) yyerror("cannot type switch on non-interface value %+N", n->ntest->right); } else { // value switch top = Erv; if(n->ntest) { typecheck(&n->ntest, Erv); defaultlit(&n->ntest, T); t = n->ntest->type; } else t = types[TBOOL]; } n->type = t; def = N; for(l=n->list; l; l=l->next) { ncase = l->n; setlineno(n); if(ncase->list == nil) { // default if(def != N) yyerror("multiple defaults in switch (first at %L)", def->lineno); else def = ncase; } else { for(ll=ncase->list; ll; ll=ll->next) { setlineno(ll->n); typecheck(&ll->n, Erv | Etype); if(ll->n->type == T || t == T) continue; switch(top) { case Erv: // expression switch defaultlit(&ll->n, t); if(ll->n->op == OTYPE) yyerror("type %T is not an expression", ll->n->type); else if(ll->n->type != T && !eqtype(ll->n->type, t)) yyerror("case %+N in %T switch", ll->n, t); break; case Etype: // type switch if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) ; else if(ll->n->op != OTYPE && ll->n->type != T) yyerror("%#N is not a type", ll->n); break; } } } if(top == Etype && n->type != T) { ll = ncase->list; nvar = ncase->nname; if(nvar != N) { if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) { // single entry type switch nvar->ntype = typenod(ll->n->type); } else { // multiple entry type switch or default nvar->ntype = typenod(n->type); } } } typechecklist(ncase->nbody, Etop); } lineno = lno; }
/* * type check switch statement */ void typecheckswitch(Node *n) { int top, lno, ptr; char *nilonly; Type *t, *badtype, *missing, *have; NodeList *l, *ll; Node *ncase, *nvar; Node *def; lno = lineno; typechecklist(n->ninit, Etop); nilonly = nil; if(n->ntest != N && n->ntest->op == OTYPESW) { // type switch top = Etype; typecheck(&n->ntest->right, Erv); t = n->ntest->right->type; if(t != T && t->etype != TINTER) yyerror("cannot type switch on non-interface value %lN", n->ntest->right); } else { // value switch top = Erv; if(n->ntest) { typecheck(&n->ntest, Erv); defaultlit(&n->ntest, T); t = n->ntest->type; } else t = types[TBOOL]; if(t) { if(!okforeq[t->etype]) yyerror("cannot switch on %lN", n->ntest); else if(t->etype == TARRAY && !isfixedarray(t)) nilonly = "slice"; else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ) yyerror("cannot switch on %lN", n->ntest); else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ) yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype); else if(t->etype == TFUNC) nilonly = "func"; else if(t->etype == TMAP) nilonly = "map"; } } n->type = t; def = N; for(l=n->list; l; l=l->next) { ncase = l->n; setlineno(n); if(ncase->list == nil) { // default if(def != N) yyerror("multiple defaults in switch (first at %L)", def->lineno); else def = ncase; } else { for(ll=ncase->list; ll; ll=ll->next) { setlineno(ll->n); typecheck(&ll->n, Erv | Etype); if(ll->n->type == T || t == T) continue; setlineno(ncase); switch(top) { case Erv: // expression switch defaultlit(&ll->n, t); if(ll->n->op == OTYPE) yyerror("type %T is not an expression", ll->n->type); else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) { if(n->ntest) yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t); else yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type); } else if(nilonly && !isconst(ll->n, CTNIL)) { yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest); } break; case Etype: // type switch if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) { ; } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||? yyerror("%lN is not a type", ll->n); // reset to original type ll->n = n->ntest->right; } else if(ll->n->type->etype != TINTER && t->etype == TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) { if(have && !missing->broke && !have->broke) yyerror("impossible type switch case: %lN cannot have dynamic type %T" " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT", n->ntest->right, ll->n->type, missing->sym, have->sym, have->type, missing->sym, missing->type); else if(!missing->broke) yyerror("impossible type switch case: %lN cannot have dynamic type %T" " (missing %S method)", n->ntest->right, ll->n->type, missing->sym); } break; } } } if(top == Etype && n->type != T) { ll = ncase->list; nvar = ncase->nname; if(nvar != N) { if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) { // single entry type switch nvar->ntype = typenod(ll->n->type); } else { // multiple entry type switch or default nvar->ntype = typenod(n->type); } } } typechecklist(ncase->nbody, Etop); } lineno = lno; }
/* * look for * unsafe.Sizeof * unsafe.Offsetof * rewrite with a constant */ Node* unsafenmagic(Node *nn) { Node *r, *n; Sym *s; Type *t, *tr; long v; Val val; Node *fn; NodeList *args; fn = nn->left; args = nn->list; if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S) goto no; if(s->pkg != unsafepkg) goto no; if(args == nil) { yyerror("missing argument for %S", s); goto no; } r = args->n; if(strcmp(s->name, "Sizeof") == 0) { typecheck(&r, Erv); defaultlit(&r, T); tr = r->type; if(tr == T) goto bad; dowidth(tr); v = tr->width; goto yes; } if(strcmp(s->name, "Offsetof") == 0) { typecheck(&r, Erv); if(r->op != ODOT && r->op != ODOTPTR) goto bad; typecheck(&r, Erv); v = r->xoffset; goto yes; } if(strcmp(s->name, "Alignof") == 0) { typecheck(&r, Erv); defaultlit(&r, T); tr = r->type; if(tr == T) goto bad; // make struct { byte; T; } t = typ(TSTRUCT); t->type = typ(TFIELD); t->type->type = types[TUINT8]; t->type->down = typ(TFIELD); t->type->down->type = tr; // compute struct widths dowidth(t); // the offset of T is its required alignment v = t->type->down->width; goto yes; } no: return N; bad: yyerror("invalid expression %#N", nn); v = 0; goto ret; yes: if(args->next != nil) yyerror("extra arguments for %S", s); ret: // any side effects disappear; ignore init val.ctype = CTINT; val.u.xval = mal(sizeof(*n->val.u.xval)); mpmovecfix(val.u.xval, v); n = nod(OLITERAL, N, N); n->val = val; n->type = types[TINT]; return n; }