fix: do type check on assignment (#738)

* fix: do type check on assignment

* fix: check for recursive type rather than field
This commit is contained in:
Nicholas Wiersma
2020-07-03 10:28:51 +02:00
committed by GitHub
parent 097a745e72
commit 4058fd8c44
4 changed files with 34 additions and 1 deletions

11
_test/assign15.go Normal file
View File

@@ -0,0 +1,11 @@
package main
func main() {
var c chan<- struct{} = make(chan struct{})
var d <-chan struct{} = c
_ = d
}
// Error:
// _test/assign15.go:5:26: cannot use type chan<- struct{} as type <-chan struct{} in assignment

View File

@@ -518,6 +518,22 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
err = src.cfgErrorf("invalid float truncate") err = src.cfgErrorf("invalid float truncate")
return return
} }
// TODO: Rudimentary type check at this point,
// improvements need to be made to make it better.
switch {
case dest.typ.untyped || src.typ.untyped:
// Both side of the assignment must be typed.
case isRecursiveType(dest.typ, dest.typ.rtype) || isRecursiveType(src.typ, src.typ.rtype):
// Recursive types cannot be type checked.
case t0.Kind() == reflect.Interface || t0.Kind() == reflect.Func:
// We have no way of checking interfaces and functions.
case t1.AssignableTo(t0):
// All is well when they are assignable.
default:
err = src.cfgErrorf("cannot use type %s as type %s in assignment", src.typ.id(), dest.typ.id())
return
}
} }
n.findex = dest.findex n.findex = dest.findex
n.level = dest.level n.level = dest.level
@@ -1157,6 +1173,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
case n.ident == "iota": case n.ident == "iota":
n.rval = reflect.ValueOf(sc.iota) n.rval = reflect.ValueOf(sc.iota)
n.kind = basicLit n.kind = basicLit
n.typ.untyped = true
case n.ident == "nil": case n.ident == "nil":
n.kind = basicLit n.kind = basicLit
case sym.kind == binSym: case sym.kind == binSym:

View File

@@ -35,6 +35,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
if filepath.Ext(file.Name()) != ".go" || if filepath.Ext(file.Name()) != ".go" ||
file.Name() == "assign11.go" || // expect error file.Name() == "assign11.go" || // expect error
file.Name() == "assign12.go" || // expect error file.Name() == "assign12.go" || // expect error
file.Name() == "assign15.go" || // expect error
file.Name() == "bad0.go" || // expect error file.Name() == "bad0.go" || // expect error
file.Name() == "const9.go" || // expect error file.Name() == "const9.go" || // expect error
file.Name() == "export1.go" || // non-main package file.Name() == "export1.go" || // non-main package

View File

@@ -1013,7 +1013,11 @@ func (t *itype) id() (res string) {
case arrayT: case arrayT:
res = "[" + strconv.Itoa(t.size) + "]" + t.val.id() res = "[" + strconv.Itoa(t.size) + "]" + t.val.id()
case chanT: case chanT:
res = "<-" + t.val.id() res = "chan " + t.val.id()
case chanSendT:
res = "chan<- " + t.val.id()
case chanRecvT:
res = "<-chan " + t.val.id()
case funcT: case funcT:
res = "func(" res = "func("
for _, t := range t.arg { for _, t := range t.arg {