mirror of
https://github.com/golang/go
synced 2024-11-25 06:57:58 -07:00
update type switch to match spec.
R=ken OCL=34471 CL=34471
This commit is contained in:
parent
5438be4541
commit
5d16d23362
@ -4367,7 +4367,6 @@ The following minimal alignment properties are guaranteed:
|
|||||||
<h2 id="Implementation_differences"><font color=red>Implementation differences - TODO</font></h2>
|
<h2 id="Implementation_differences"><font color=red>Implementation differences - TODO</font></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><font color=red>Implementation does not honor the restriction on goto statements and targets (no intervening declarations).</font></li>
|
<li><font color=red>Implementation does not honor the restriction on goto statements and targets (no intervening declarations).</font></li>
|
||||||
<li><font color=red>A type switch must have an assignment in the guard expression and does not support multiple types per case.</font></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -375,7 +375,7 @@ enum
|
|||||||
OSELECT,
|
OSELECT,
|
||||||
OSWITCH,
|
OSWITCH,
|
||||||
OTYPECASE,
|
OTYPECASE,
|
||||||
OTYPESW,
|
OTYPESW, // l = r.(type)
|
||||||
|
|
||||||
// types
|
// types
|
||||||
OTCHAN,
|
OTCHAN,
|
||||||
@ -676,7 +676,8 @@ EXTERN Node* curfn;
|
|||||||
EXTERN int maxround;
|
EXTERN int maxround;
|
||||||
EXTERN int widthptr;
|
EXTERN int widthptr;
|
||||||
|
|
||||||
EXTERN Node* typeswvar;
|
EXTERN Node* typesw;
|
||||||
|
EXTERN Node* nblank;
|
||||||
|
|
||||||
EXTERN char* structpkg;
|
EXTERN char* structpkg;
|
||||||
extern int thechar;
|
extern int thechar;
|
||||||
|
@ -424,7 +424,7 @@ simple_stmt:
|
|||||||
yyerror("expr.(type) must be alone in list");
|
yyerror("expr.(type) must be alone in list");
|
||||||
else if($1->next != nil)
|
else if($1->next != nil)
|
||||||
yyerror("argument count mismatch: %d = %d", count($1), 1);
|
yyerror("argument count mismatch: %d = %d", count($1), 1);
|
||||||
$$ = nod(OTYPESW, $1->n, $3->n->left);
|
$$ = nod(OTYPESW, $1->n, $3->n->right);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$$ = colas($1, $3);
|
$$ = colas($1, $3);
|
||||||
@ -443,30 +443,19 @@ simple_stmt:
|
|||||||
case:
|
case:
|
||||||
LCASE expr_or_type_list ':'
|
LCASE expr_or_type_list ':'
|
||||||
{
|
{
|
||||||
Node *n, *ntype;
|
Node *n;
|
||||||
|
|
||||||
// will be converted to OCASE
|
// will be converted to OCASE
|
||||||
// right will point to next case
|
// right will point to next case
|
||||||
// done in casebody()
|
// done in casebody()
|
||||||
poptodcl();
|
poptodcl();
|
||||||
$$ = nod(OXCASE, N, N);
|
$$ = nod(OXCASE, N, N);
|
||||||
if(typeswvar != N && typeswvar->right != N) {
|
$$->list = $2;
|
||||||
// type switch
|
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
|
||||||
ntype = $2->n;
|
// type switch - declare variable
|
||||||
if($2->next != nil)
|
n = newname(n->sym);
|
||||||
yyerror("type switch case cannot be list");
|
|
||||||
if(ntype->op == OLITERAL && ntype->val.ctype == CTNIL) {
|
|
||||||
// case nil
|
|
||||||
$$->list = list1(nod(OTYPECASE, N, N));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
n = newname(typeswvar->right->sym);
|
|
||||||
declare(n, dclcontext);
|
declare(n, dclcontext);
|
||||||
n->ntype = ntype;
|
$$->nname = n;
|
||||||
$$->list = list1(nod(OTYPECASE, n, N));
|
|
||||||
} else {
|
|
||||||
// expr switch
|
|
||||||
$$->list = $2;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -490,8 +479,16 @@ case:
|
|||||||
}
|
}
|
||||||
| LDEFAULT ':'
|
| LDEFAULT ':'
|
||||||
{
|
{
|
||||||
|
Node *n;
|
||||||
|
|
||||||
poptodcl();
|
poptodcl();
|
||||||
$$ = nod(OXCASE, N, N);
|
$$ = nod(OXCASE, N, N);
|
||||||
|
if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
|
||||||
|
// type switch - declare variable
|
||||||
|
n = newname(n->sym);
|
||||||
|
declare(n, dclcontext);
|
||||||
|
$$->nname = n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compound_stmt:
|
compound_stmt:
|
||||||
@ -637,18 +634,16 @@ switch_stmt:
|
|||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
n = $3->ntest;
|
n = $3->ntest;
|
||||||
if(n != N && n->op == OTYPESW)
|
if(n != N && n->op != OTYPESW)
|
||||||
n = n->left;
|
|
||||||
else
|
|
||||||
n = N;
|
n = N;
|
||||||
typeswvar = nod(OXXX, typeswvar, n);
|
typesw = nod(OXXX, typesw, n);
|
||||||
}
|
}
|
||||||
switch_body
|
switch_body
|
||||||
{
|
{
|
||||||
$$ = $3;
|
$$ = $3;
|
||||||
$$->op = OSWITCH;
|
$$->op = OSWITCH;
|
||||||
$$->list = $5;
|
$$->list = $5;
|
||||||
typeswvar = typeswvar->left;
|
typesw = typesw->left;
|
||||||
popdcl();
|
popdcl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -823,7 +818,7 @@ pexpr:
|
|||||||
}
|
}
|
||||||
| pexpr '.' '(' LTYPE ')'
|
| pexpr '.' '(' LTYPE ')'
|
||||||
{
|
{
|
||||||
$$ = nod(OTYPESW, $1, N);
|
$$ = nod(OTYPESW, N, $1);
|
||||||
}
|
}
|
||||||
| pexpr '[' expr ']'
|
| pexpr '[' expr ']'
|
||||||
{
|
{
|
||||||
@ -1289,20 +1284,14 @@ arg_type:
|
|||||||
name_or_type
|
name_or_type
|
||||||
| sym name_or_type
|
| sym name_or_type
|
||||||
{
|
{
|
||||||
$$ = $1->def;
|
$$ = nod(ONONAME, N, N);
|
||||||
if($$ == N) {
|
$$->sym = $1;
|
||||||
$$ = nod(ONONAME, N, N);
|
|
||||||
$$->sym = $1;
|
|
||||||
}
|
|
||||||
$$ = nod(OKEY, $$, $2);
|
$$ = nod(OKEY, $$, $2);
|
||||||
}
|
}
|
||||||
| sym dotdotdot
|
| sym dotdotdot
|
||||||
{
|
{
|
||||||
$$ = $1->def;
|
$$ = nod(ONONAME, N, N);
|
||||||
if($$ == N) {
|
$$->sym = $1;
|
||||||
$$ = nod(ONONAME, N, N);
|
|
||||||
$$->sym = $1;
|
|
||||||
}
|
|
||||||
$$ = nod(OKEY, $$, $2);
|
$$ = nod(OKEY, $$, $2);
|
||||||
}
|
}
|
||||||
| dotdotdot
|
| dotdotdot
|
||||||
|
@ -1359,6 +1359,7 @@ lexinit(void)
|
|||||||
s->def->sym = s;
|
s->def->sym = s;
|
||||||
types[TBLANK] = typ(TBLANK);
|
types[TBLANK] = typ(TBLANK);
|
||||||
s->def->type = types[TBLANK];
|
s->def->type = types[TBLANK];
|
||||||
|
nblank = s->def;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
@ -249,13 +249,13 @@ newlabel(void)
|
|||||||
* deal with fallthrough, break, unreachable statements
|
* deal with fallthrough, break, unreachable statements
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
casebody(Node *sw)
|
casebody(Node *sw, Node *typeswvar)
|
||||||
{
|
{
|
||||||
Node *os, *oc, *n, *c, *last;
|
Node *os, *oc, *n, *c, *last;
|
||||||
Node *def;
|
Node *def;
|
||||||
NodeList *cas, *stat, *l, *lc;
|
NodeList *cas, *stat, *l, *lc;
|
||||||
Node *go, *br;
|
Node *go, *br;
|
||||||
int32 lno;
|
int32 lno, needvar;
|
||||||
|
|
||||||
lno = setlineno(sw);
|
lno = setlineno(sw);
|
||||||
if(sw->list == nil)
|
if(sw->list == nil)
|
||||||
@ -274,6 +274,7 @@ casebody(Node *sw)
|
|||||||
if(n->op != OXCASE)
|
if(n->op != OXCASE)
|
||||||
fatal("casebody %O", n->op);
|
fatal("casebody %O", n->op);
|
||||||
n->op = OCASE;
|
n->op = OCASE;
|
||||||
|
needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
|
||||||
|
|
||||||
go = nod(OGOTO, newlabel(), N);
|
go = nod(OGOTO, newlabel(), N);
|
||||||
if(n->list == nil) {
|
if(n->list == nil) {
|
||||||
@ -300,6 +301,14 @@ casebody(Node *sw)
|
|||||||
}
|
}
|
||||||
|
|
||||||
stat = list(stat, nod(OLABEL, go->left, N));
|
stat = list(stat, nod(OLABEL, go->left, N));
|
||||||
|
if(typeswvar && needvar && n->nname != N) {
|
||||||
|
NodeList *l;
|
||||||
|
|
||||||
|
l = list1(nod(ODCL, n->nname, N));
|
||||||
|
l = list(l, nod(OAS, n->nname, typeswvar));
|
||||||
|
typechecklist(l, Etop);
|
||||||
|
stat = concat(stat, l);
|
||||||
|
}
|
||||||
stat = concat(stat, n->nbody);
|
stat = concat(stat, n->nbody);
|
||||||
|
|
||||||
// botch - shouldnt fall thru declaration
|
// botch - shouldnt fall thru declaration
|
||||||
@ -348,16 +357,16 @@ mkcaselist(Node *sw, int arg)
|
|||||||
switch(arg) {
|
switch(arg) {
|
||||||
case Stype:
|
case Stype:
|
||||||
c->hash = 0;
|
c->hash = 0;
|
||||||
if(n->left->left == N) {
|
if(n->left->op == OLITERAL) {
|
||||||
c->type = Ttypenil;
|
c->type = Ttypenil;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(istype(n->left->left->type, TINTER)) {
|
if(istype(n->left->type, TINTER)) {
|
||||||
c->type = Ttypevar;
|
c->type = Ttypevar;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->hash = typehash(n->left->left->type);
|
c->hash = typehash(n->left->type);
|
||||||
c->type = Ttypeconst;
|
c->type = Ttypeconst;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -483,6 +492,7 @@ exprswitch(Node *sw)
|
|||||||
Type *t;
|
Type *t;
|
||||||
int arg, ncase;
|
int arg, ncase;
|
||||||
|
|
||||||
|
casebody(sw, N);
|
||||||
|
|
||||||
arg = Snorm;
|
arg = Snorm;
|
||||||
if(isconst(sw->ntest, CTBOOL)) {
|
if(isconst(sw->ntest, CTBOOL)) {
|
||||||
@ -564,13 +574,18 @@ typeone(Node *t)
|
|||||||
NodeList *init;
|
NodeList *init;
|
||||||
Node *a, *b, *var;
|
Node *a, *b, *var;
|
||||||
|
|
||||||
var = t->left->left;
|
var = t->nname;
|
||||||
init = list1(nod(ODCL, var, N));
|
init = nil;
|
||||||
|
if(var == N) {
|
||||||
|
typecheck(&nblank, Erv | Easgn);
|
||||||
|
var = nblank;
|
||||||
|
} else
|
||||||
|
init = list1(nod(ODCL, var, N));
|
||||||
|
|
||||||
a = nod(OAS2, N, N);
|
a = nod(OAS2, N, N);
|
||||||
a->list = list(list1(var), boolname); // var,bool =
|
a->list = list(list1(var), boolname); // var,bool =
|
||||||
b = nod(ODOTTYPE, facename, N);
|
b = nod(ODOTTYPE, facename, N);
|
||||||
b->type = t->left->left->type; // interface.(type)
|
b->type = t->left->type; // interface.(type)
|
||||||
a->rlist = list1(b);
|
a->rlist = list1(b);
|
||||||
typecheck(&a, Etop);
|
typecheck(&a, Etop);
|
||||||
init = list(init, a);
|
init = list(init, a);
|
||||||
@ -678,6 +693,8 @@ typeswitch(Node *sw)
|
|||||||
typecheck(&a, Etop);
|
typecheck(&a, Etop);
|
||||||
cas = list(cas, a);
|
cas = list(cas, a);
|
||||||
|
|
||||||
|
casebody(sw, facename);
|
||||||
|
|
||||||
boolname = nod(OXXX, N, N);
|
boolname = nod(OXXX, N, N);
|
||||||
tempname(boolname, types[TBOOL]);
|
tempname(boolname, types[TBOOL]);
|
||||||
typecheck(&boolname, Erv);
|
typecheck(&boolname, Erv);
|
||||||
@ -758,10 +775,10 @@ walkswitch(Node *sw)
|
|||||||
sw->ntest = nodbool(1);
|
sw->ntest = nodbool(1);
|
||||||
typecheck(&sw->ntest, Erv);
|
typecheck(&sw->ntest, Erv);
|
||||||
}
|
}
|
||||||
casebody(sw);
|
|
||||||
|
|
||||||
if(sw->ntest->op == OTYPESW) {
|
if(sw->ntest->op == OTYPESW) {
|
||||||
typeswitch(sw);
|
typeswitch(sw);
|
||||||
|
//dump("sw", sw);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
exprswitch(sw);
|
exprswitch(sw);
|
||||||
@ -776,7 +793,7 @@ typecheckswitch(Node *n)
|
|||||||
int top, lno;
|
int top, lno;
|
||||||
Type *t;
|
Type *t;
|
||||||
NodeList *l, *ll;
|
NodeList *l, *ll;
|
||||||
Node *ncase;
|
Node *ncase, *nvar;
|
||||||
Node *def;
|
Node *def;
|
||||||
|
|
||||||
lno = lineno;
|
lno = lineno;
|
||||||
@ -784,11 +801,11 @@ typecheckswitch(Node *n)
|
|||||||
|
|
||||||
if(n->ntest != N && n->ntest->op == OTYPESW) {
|
if(n->ntest != N && n->ntest->op == OTYPESW) {
|
||||||
// type switch
|
// type switch
|
||||||
typecheck(&n->ntest, Etop);
|
|
||||||
top = Etype;
|
top = Etype;
|
||||||
t = n->ntest->type;
|
typecheck(&n->ntest->right, Erv);
|
||||||
|
t = n->ntest->right->type;
|
||||||
if(t != T && t->etype != TINTER)
|
if(t != T && t->etype != TINTER)
|
||||||
yyerror("cannot type switch on non-interface value %+N", n->ntest);
|
yyerror("cannot type switch on non-interface value %+N", n->ntest->right);
|
||||||
} else {
|
} else {
|
||||||
// value switch
|
// value switch
|
||||||
top = Erv;
|
top = Erv;
|
||||||
@ -814,12 +831,37 @@ typecheckswitch(Node *n)
|
|||||||
} else {
|
} else {
|
||||||
for(ll=ncase->list; ll; ll=ll->next) {
|
for(ll=ncase->list; ll; ll=ll->next) {
|
||||||
setlineno(ll->n);
|
setlineno(ll->n);
|
||||||
typecheck(&ll->n, Erv); // TODO(rsc): top
|
typecheck(&ll->n, Erv | Etype);
|
||||||
if(ll->n->type == T || t == T || top != Erv)
|
if(ll->n->type == T || t == T)
|
||||||
continue;
|
continue;
|
||||||
defaultlit(&ll->n, t);
|
switch(top) {
|
||||||
if(ll->n->type != T && !eqtype(ll->n->type, t))
|
case Erv: // expression switch
|
||||||
yyerror("case %+N in switch of %+N %#O", ll->n, n->ntest, ll->n->op);
|
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 switch of %+N %#O", ll->n, n->ntest, ll->n->op);
|
||||||
|
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);
|
typechecklist(ncase->nbody, Etop);
|
||||||
|
@ -415,7 +415,7 @@ func (s *State) error(msg string) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
func typename(typ reflect.Type) string {
|
func typename(typ reflect.Type) string {
|
||||||
switch t := typ.(type) {
|
switch typ.(type) {
|
||||||
case *reflect.ArrayType:
|
case *reflect.ArrayType:
|
||||||
return "array";
|
return "array";
|
||||||
case *reflect.SliceType:
|
case *reflect.SliceType:
|
||||||
|
@ -19,12 +19,8 @@ type _StructBuilder struct {
|
|||||||
var nobuilder *_StructBuilder
|
var nobuilder *_StructBuilder
|
||||||
|
|
||||||
func isfloat(v reflect.Value) bool {
|
func isfloat(v reflect.Value) bool {
|
||||||
switch v := v.(type) {
|
switch v.(type) {
|
||||||
case *reflect.FloatValue:
|
case *reflect.FloatValue, *reflect.Float32Value, *reflect.Float64Value:
|
||||||
return true;
|
|
||||||
case *reflect.Float32Value:
|
|
||||||
return true;
|
|
||||||
case *reflect.Float64Value:
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
84
test/typeswitch1.go
Normal file
84
test/typeswitch1.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// $G $D/$F.go && $L $F.$A && ./$A.out
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const (
|
||||||
|
a = iota;
|
||||||
|
b;
|
||||||
|
c;
|
||||||
|
d;
|
||||||
|
e;
|
||||||
|
)
|
||||||
|
|
||||||
|
var x = []int{1,2,3}
|
||||||
|
|
||||||
|
func f(x int, len *byte) {
|
||||||
|
*len = byte(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
func whatis(x interface{}) string {
|
||||||
|
switch xx := x.(type) {
|
||||||
|
default:
|
||||||
|
return fmt.Sprint("default ", xx);
|
||||||
|
case int, int8, int16, int32:
|
||||||
|
return fmt.Sprint("signed ", xx);
|
||||||
|
case int64:
|
||||||
|
return fmt.Sprint("signed64 ", int64(xx));
|
||||||
|
case uint, uint8, uint16, uint32:
|
||||||
|
return fmt.Sprint("unsigned ", xx);
|
||||||
|
case uint64:
|
||||||
|
return fmt.Sprint("unsigned64 ", uint64(xx));
|
||||||
|
case nil:
|
||||||
|
return fmt.Sprint("nil ", xx);
|
||||||
|
}
|
||||||
|
panic("not reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
func whatis1(x interface{}) string {
|
||||||
|
xx := x;
|
||||||
|
switch xx.(type) {
|
||||||
|
default:
|
||||||
|
return fmt.Sprint("default ", xx);
|
||||||
|
case int, int8, int16, int32:
|
||||||
|
return fmt.Sprint("signed ", xx);
|
||||||
|
case int64:
|
||||||
|
return fmt.Sprint("signed64 ", xx.(int64));
|
||||||
|
case uint, uint8, uint16, uint32:
|
||||||
|
return fmt.Sprint("unsigned ", xx);
|
||||||
|
case uint64:
|
||||||
|
return fmt.Sprint("unsigned64 ", xx.(uint64));
|
||||||
|
case nil:
|
||||||
|
return fmt.Sprint("nil ", xx);
|
||||||
|
}
|
||||||
|
panic("not reached");
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(x interface{}, s string) {
|
||||||
|
w := whatis(x);
|
||||||
|
if w != s {
|
||||||
|
fmt.Println("whatis", x, "=>", w, "!=", s);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
w = whatis1(x);
|
||||||
|
if w != s {
|
||||||
|
fmt.Println("whatis1", x, "=>", w, "!=", s);
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
check(1, "signed 1");
|
||||||
|
check(uint(1), "unsigned 1");
|
||||||
|
check(int64(1), "signed64 1");
|
||||||
|
check(uint64(1), "unsigned64 1");
|
||||||
|
check(1.5, "default 1.5");
|
||||||
|
check(nil, "nil <nil>");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user