mirror of
https://github.com/golang/go
synced 2024-11-21 21:14:47 -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
|
||||
typecheckswitch(Node *n)
|
||||
{
|
||||
int top, lno;
|
||||
Type *t;
|
||||
int top, lno, ptr;
|
||||
Type *t, *missing, *have;
|
||||
NodeList *l, *ll;
|
||||
Node *ncase, *nvar;
|
||||
Node *def;
|
||||
@ -854,21 +854,35 @@ typecheckswitch(Node *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 && !eqtype(ll->n->type, t))
|
||||
yyerror("case %lN in %T switch", ll->n, t);
|
||||
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, n->ntest, ll->n->type, 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) {
|
||||
} 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(!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;
|
||||
}
|
||||
|
@ -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() {
|
||||
var x interface{}
|
||||
switch t := x.(type) { // GC_ERROR "is not a type"
|
||||
case 0: // GCCGO_ERROR "expected type"
|
||||
switch t := x.(type) {
|
||||
case 0: // ERROR "type"
|
||||
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