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:
11
_test/assign15.go
Normal file
11
_test/assign15.go
Normal 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
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user