mirror of
https://github.com/golang/go
synced 2024-11-21 22:04:39 -07:00
gc: Better typechecks and errors in switches.
Allow any type in switch on interface value. Statically check typeswitch early. Fixes #2423. Fixes #2424. R=rsc, dsymonds CC=golang-dev https://golang.org/cl/5339045
This commit is contained in:
parent
820523d091
commit
13e92e4d75
@ -810,8 +810,8 @@ walkswitch(Node *sw)
|
|||||||
void
|
void
|
||||||
typecheckswitch(Node *n)
|
typecheckswitch(Node *n)
|
||||||
{
|
{
|
||||||
int top, lno;
|
int top, lno, ptr;
|
||||||
Type *t;
|
Type *t, *missing, *have;
|
||||||
NodeList *l, *ll;
|
NodeList *l, *ll;
|
||||||
Node *ncase, *nvar;
|
Node *ncase, *nvar;
|
||||||
Node *def;
|
Node *def;
|
||||||
@ -854,21 +854,35 @@ typecheckswitch(Node *n)
|
|||||||
typecheck(&ll->n, Erv | Etype);
|
typecheck(&ll->n, Erv | Etype);
|
||||||
if(ll->n->type == T || t == T)
|
if(ll->n->type == T || t == T)
|
||||||
continue;
|
continue;
|
||||||
|
setlineno(ncase);
|
||||||
switch(top) {
|
switch(top) {
|
||||||
case Erv: // expression switch
|
case Erv: // expression switch
|
||||||
defaultlit(&ll->n, t);
|
defaultlit(&ll->n, t);
|
||||||
if(ll->n->op == OTYPE)
|
if(ll->n->op == OTYPE)
|
||||||
yyerror("type %T is not an expression", ll->n->type);
|
yyerror("type %T is not an expression", ll->n->type);
|
||||||
else if(ll->n->type != T && !eqtype(ll->n->type, t))
|
else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
|
||||||
yyerror("case %lN in %T switch", ll->n, t);
|
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, n->ntest, ll->n->type, t);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Etype: // type switch
|
case Etype: // type switch
|
||||||
if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
|
if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
|
||||||
;
|
;
|
||||||
} else if(ll->n->op != OTYPE && ll->n->type != T) {
|
} else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||?
|
||||||
yyerror("%lN is not a type", ll->n);
|
yyerror("%lN is not a type", ll->n);
|
||||||
// reset to original type
|
// reset to original type
|
||||||
ll->n = n->ntest->right;
|
ll->n = n->ntest->right;
|
||||||
|
} else if(!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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
// $G $D/$F.go
|
|
||||||
|
|
||||||
// Copyright 2010 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.
|
|
||||||
|
|
||||||
// http://code.google.com/p/go/issues/detail?id=746
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
type I interface { F() }
|
|
||||||
|
|
||||||
type T struct{}
|
|
||||||
|
|
||||||
func (T) F() {}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
switch I(T{}).(type) {
|
|
||||||
case interface{}:
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,8 +10,8 @@ package main
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var x interface{}
|
var x interface{}
|
||||||
switch t := x.(type) { // GC_ERROR "is not a type"
|
switch t := x.(type) {
|
||||||
case 0: // GCCGO_ERROR "expected type"
|
case 0: // ERROR "type"
|
||||||
t.x = 1 // ERROR "type interface \{\}|reference to undefined field or method"
|
t.x = 1 // ERROR "type interface \{\}|reference to undefined field or method"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
test/fixedbugs/bug375.go
Normal file
19
test/fixedbugs/bug375.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug375
|
||||||
|
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// Issue 2423
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var x interface{} = "hello"
|
||||||
|
|
||||||
|
switch x {
|
||||||
|
case "hello":
|
||||||
|
default:
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
}
|
38
test/switch3.go
Normal file
38
test/switch3.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
|
// Copyright 2011 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 I interface {
|
||||||
|
M()
|
||||||
|
}
|
||||||
|
|
||||||
|
func bad() {
|
||||||
|
var i I
|
||||||
|
var s string
|
||||||
|
|
||||||
|
switch i {
|
||||||
|
case s: // ERROR "mismatched types string and I"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case i: // ERROR "mismatched types I and string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func good() {
|
||||||
|
var i interface{}
|
||||||
|
var s string
|
||||||
|
|
||||||
|
switch i {
|
||||||
|
case s:
|
||||||
|
}
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case i:
|
||||||
|
}
|
||||||
|
}
|
20
test/typeswitch3.go
Normal file
20
test/typeswitch3.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
|
// Copyright 2011 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 I interface {
|
||||||
|
M()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main(){
|
||||||
|
var x I
|
||||||
|
switch x.(type) {
|
||||||
|
case string: // ERROR "impossible"
|
||||||
|
println("FAIL")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user