1
0
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:
Luuk van Dijk 2011-11-09 10:58:53 +01:00
parent 820523d091
commit 13e92e4d75
6 changed files with 98 additions and 28 deletions

View File

@ -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;
} }

View File

@ -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{}:
}
}

View File

@ -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
View 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
View 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
View 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")
}
}